diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libarchive/archive_write_set_format_pax.c | 39 | ||||
-rw-r--r-- | lib/libarchive/archive_write_set_format_shar.c | 91 | ||||
-rw-r--r-- | lib/libarchive/archive_write_set_format_ustar.c | 16 |
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); } |