diff options
Diffstat (limited to 'lib/libarchive/archive_write_set_format_ustar.c')
-rw-r--r-- | lib/libarchive/archive_write_set_format_ustar.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c index 75766d5..b977317 100644 --- a/lib/libarchive/archive_write_set_format_ustar.c +++ b/lib/libarchive/archive_write_set_format_ustar.c @@ -243,7 +243,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], { unsigned int checksum; int i, ret; - size_t copy_length; + size_t copy_length, ps, extra_slash; const char *p, *pp; const struct stat *st; int mytartype; @@ -256,6 +256,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], * elements. */ memcpy(h, &template_header, 512); + st = archive_entry_stat(entry); /* * Because the block is already null-filled, and strings @@ -264,11 +265,18 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], */ pp = archive_entry_pathname(entry); - if (strlen(pp) <= USTAR_name_size) - memcpy(h + USTAR_name_offset, pp, strlen(pp)); - else { + ps = strlen(pp); + if (S_ISDIR(st->st_mode) && pp[ps - 1] != '/') + extra_slash = 1; + else + extra_slash = 0; + if (ps + extra_slash <= USTAR_name_size) { + memcpy(h + USTAR_name_offset, pp, ps); + if (extra_slash) + h[USTAR_name_offset + ps] = '/'; + } else { /* Store in two pieces, splitting at a '/'. */ - p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/'); + p = strchr(pp + ps + extra_slash - USTAR_name_size - 1, '/'); /* * If there is no path separator, or the prefix or * remaining name are too large, return an error. @@ -284,7 +292,9 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], } else { /* Copy prefix and remainder to appropriate places */ memcpy(h + USTAR_prefix_offset, pp, p - pp); - memcpy(h + USTAR_name_offset, p + 1, pp + strlen(pp) - p - 1); + memcpy(h + USTAR_name_offset, p + 1, pp + ps - p - 1); + if (extra_slash) + h[USTAR_name_offset + pp + ps - p - 1] = '/'; } } @@ -328,8 +338,6 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], memcpy(h + USTAR_gname_offset, p, copy_length); } - st = archive_entry_stat(entry); - if (format_number(st->st_mode & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); ret = ARCHIVE_WARN; |