summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c39
-rw-r--r--lib/libarchive/archive_write_set_format_shar.c91
-rw-r--r--lib/libarchive/archive_write_set_format_ustar.c16
3 files changed, 110 insertions, 36 deletions
diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c
index bee95d3..9b3d7819 100644
--- a/lib/libarchive/archive_write_set_format_pax.c
+++ b/lib/libarchive/archive_write_set_format_pax.c
@@ -458,6 +458,31 @@ archive_write_pax_header(struct archive *a,
st_main->st_nlink);
}
+ /* Only regular files have data. */
+ if (!S_ISREG(archive_entry_mode(entry_main)))
+ archive_entry_set_size(entry_main, 0);
+
+ /*
+ * Pax-restricted does not store data for hardlinks, in order
+ * to improve compatibility with ustar.
+ */
+ if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
+ archive_entry_hardlink(entry_main) != NULL)
+ archive_entry_set_size(entry_main, 0);
+
+ /*
+ * XXX Full pax interchange format does permit a hardlink
+ * entry to have data associated with it. I'm not supporting
+ * that here because the client expects me to tell them whether
+ * or not this format expects data for hardlinks. If I
+ * don't check here, then every pax archive will end up with
+ * duplicated data for hardlinks. Someday, there may be
+ * need to select this behavior, in which case the following
+ * will need to be revisited. XXX
+ */
+ if (archive_entry_hardlink(entry_main) != NULL)
+ archive_entry_set_size(entry_main, 0);
+
/* Format 'ustar' header for main entry. */
/* We don't care if this returns an error. */
__archive_write_format_header_ustar(a, ustarbuff, entry_main);
@@ -528,13 +553,13 @@ archive_write_pax_header(struct archive *a,
if (ret != ARCHIVE_OK)
ret = (r < 512) ? ARCHIVE_FATAL : ARCHIVE_OK;
- /* Only regular files have data. Note that pax, unlike ustar,
- * does permit a hardlink to have data associated with it. */
- if (!S_ISREG(archive_entry_mode(entry_main)))
- pax->entry_bytes_remaining = 0;
- else
- pax->entry_bytes_remaining = archive_entry_size(entry_main);
-
+ /*
+ * Inform the client of the on-disk size we're using, so
+ * they can avoid unnecessarily writing a body for something
+ * that we're just going to ignore.
+ */
+ archive_entry_set_size(entry_original, archive_entry_size(entry_main));
+ pax->entry_bytes_remaining = archive_entry_size(entry_main);
pax->entry_padding = 0x1ff & (- pax->entry_bytes_remaining);
archive_entry_free(entry_main);
diff --git a/lib/libarchive/archive_write_set_format_shar.c b/lib/libarchive/archive_write_set_format_shar.c
index 52f5509..676f997 100644
--- a/lib/libarchive/archive_write_set_format_shar.c
+++ b/lib/libarchive/archive_write_set_format_shar.c
@@ -56,6 +56,7 @@ struct shar {
int end_of_line;
struct archive_entry *entry;
int has_data;
+ char *last_dir;
char outbuff[1024];
size_t outbytes;
size_t outpos;
@@ -130,6 +131,7 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
{
const char *linkname;
const char *name;
+ char *p, *pp;
struct shar *shar;
const struct stat *st;
@@ -140,28 +142,74 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
shar->wrote_header = 1;
}
- /* Save the entry for the closing */
+ /* Save the entry for the closing. */
if (shar->entry)
archive_entry_free(shar->entry);
shar->entry = archive_entry_clone(entry);
name = archive_entry_pathname(entry);
st = archive_entry_stat(entry);
+ /* Handle some preparatory issues. */
+ switch(st->st_mode & S_IFMT) {
+ case S_IFREG:
+ /* Only regular files have non-zero size. */
+ break;
+ case S_IFDIR:
+ case S_IFIFO:
+ case S_IFCHR:
+ case S_IFBLK:
+ /* All other file types have zero size in the archive. */
+ archive_entry_set_size(entry, 0);
+ break;
+ default:
+ archive_entry_set_size(entry, 0);
+ if (archive_entry_hardlink(entry) == NULL &&
+ archive_entry_symlink(entry) == NULL) {
+ archive_set_error(a, -1,
+ "shar format cannot archive this");
+ return (ARCHIVE_WARN);
+ }
+ }
+
+ /* Stock preparation for all file types. */
+ shar_printf(a, "echo x %s\n", name);
+
+ if (!S_ISDIR(st->st_mode)) {
+ /* Try to create the dir. */
+ p = strdup(name);
+ pp = strrchr(p, '/');
+ if (pp != NULL)
+ *pp = '\0';
+
+ if (shar->last_dir == NULL) {
+ shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n", p);
+ shar->last_dir = p;
+ } else if (strcmp(p, shar->last_dir) == 0) {
+ /* We've already created this exact dir. */
+ free(p);
+ } else if (strlen(p) < strlen(shar->last_dir) &&
+ strncmp(p, shar->last_dir, strlen(p)) == 0) {
+ /* We've already created a subdir. */
+ free(p);
+ } else {
+ shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n", p);
+ free(shar->last_dir);
+ shar->last_dir = p;
+ }
+ }
+
+ /* Handle file-type specific issues. */
shar->has_data = 0;
- if ((linkname = archive_entry_hardlink(entry)) != NULL) {
- shar_printf(a, "echo x %s\n", name);
+ if ((linkname = archive_entry_hardlink(entry)) != NULL)
shar_printf(a, "ln -f %s %s\n", linkname, name);
- } else if ((linkname = archive_entry_symlink(entry)) != NULL) {
- shar_printf(a, "echo x %s\n", name);
+ else if ((linkname = archive_entry_symlink(entry)) != NULL)
shar_printf(a, "ln -fs %s %s\n", linkname, name);
- } else {
+ else {
switch(st->st_mode & S_IFMT) {
case S_IFREG:
- shar_printf(a, "echo x %s\n", name);
- if (archive_entry_size(entry) == 0) {
+ if (archive_entry_size(entry) == 0)
shar_printf(a, "touch %s\n", name);
- shar->has_data = 0;
- } else {
+ else {
if (shar->dump) {
shar_printf(a,
"uudecode -o %s << 'SHAR_END'\n",
@@ -180,36 +228,35 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
}
break;
case S_IFDIR:
- shar_printf(a, "echo x %s\n", name);
shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n", name);
+ /* Record that we just created this directory. */
+ if (shar->last_dir != NULL)
+ free(shar->last_dir);
+
+ shar->last_dir = strdup(name);
+ /* Trim a trailing '/'. */
+ pp = strrchr(shar->last_dir, '/');
+ if (pp != NULL && pp[1] == '\0')
+ *pp = '\0';
/*
* TODO: Put dir name/mode on a list to be fixed
* up at end of archive.
*/
break;
case S_IFIFO:
- shar_printf(a, "echo x %s\n", name);
shar_printf(a, "mkfifo %s\n", name);
break;
case S_IFCHR:
- shar_printf(a, "echo x %s\n", name);
shar_printf(a, "mknod %s c %d %d\n", name,
archive_entry_devmajor(entry),
archive_entry_devminor(entry));
break;
case S_IFBLK:
- shar_printf(a, "echo x %s\n", name);
shar_printf(a, "mknod %s b %d %d\n", name,
archive_entry_devmajor(entry),
archive_entry_devminor(entry));
break;
- case S_IFSOCK:
- archive_set_error(a, -1,
- "shar format cannot archive socket");
- return (ARCHIVE_WARN);
default:
- archive_set_error(a, -1,
- "shar format cannot archive this");
return (ARCHIVE_WARN);
}
}
@@ -395,8 +442,10 @@ archive_write_shar_finish(struct archive *a)
* uncompressed data within gzip/bzip2 streams.
*/
}
- if (shar->entry)
+ if (shar->entry != NULL)
archive_entry_free(shar->entry);
+ if (shar->last_dir != NULL)
+ free(shar->last_dir);
free(shar);
a->format_data = NULL;
return (ARCHIVE_OK);
diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c
index 1a67a1d..649be5e 100644
--- a/lib/libarchive/archive_write_set_format_ustar.c
+++ b/lib/libarchive/archive_write_set_format_ustar.c
@@ -125,6 +125,13 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
ustar = a->format_data;
ustar->written = 1;
+
+ /* Only regular files (not hardlinks) have data. */
+ if (archive_entry_hardlink(entry) != NULL ||
+ archive_entry_symlink(entry) != NULL ||
+ !S_ISREG(archive_entry_mode(entry)))
+ archive_entry_set_size(entry, 0);
+
ret = __archive_write_format_header_ustar(a, buff, entry);
if (ret != ARCHIVE_OK)
return (ret);
@@ -132,14 +139,7 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
if (ret < 512)
return (ARCHIVE_FATAL);
- /* Only regular files (not hardlinks) have data. */
- if (archive_entry_hardlink(entry) != NULL ||
- archive_entry_symlink(entry) != NULL ||
- !S_ISREG(archive_entry_mode(entry)))
- ustar->entry_bytes_remaining = 0;
- else
- ustar->entry_bytes_remaining = archive_entry_size(entry);
-
+ ustar->entry_bytes_remaining = archive_entry_size(entry);
ustar->entry_padding = 0x1ff & (- ustar->entry_bytes_remaining);
return (ARCHIVE_OK);
}
OpenPOWER on IntegriCloud