diff options
author | kientzle <kientzle@FreeBSD.org> | 2007-05-29 01:00:21 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2007-05-29 01:00:21 +0000 |
commit | 013be331bc10706807599a452a143f4744398e9f (patch) | |
tree | 793787ab8615d768ba51341dfd934a5fb3039728 /lib/libarchive/archive_write_set_format_ar.c | |
parent | c611006e893ac2bf962cabe02743954e3b3c3314 (diff) | |
download | FreeBSD-src-013be331bc10706807599a452a143f4744398e9f.zip FreeBSD-src-013be331bc10706807599a452a143f4744398e9f.tar.gz |
libarchive 2.2.3
* "compression_program" support uses an external program
* Portability: no longer uses "struct stat" as a primary
data interchange structure internally
* Part of the above: refactor archive_entry to separate
out copy_stat() and stat() functions
* More complete tests for archive_entry
* Finish archive_entry_clone()
* Isolate major()/minor()/makedev() in archive_entry; remove
these from everywhere else.
* Bug fix: properly handle decompression look-ahead at end-of-data
* Bug fixes to 'ar' support
* Fix memory leak in ZIP reader
* Portability: better timegm() emulation in iso9660 reader
* New write_disk flags to suppress auto dir creation and not
overwrite newer files (for future cpio front-end)
* Simplify trailing-'/' fixup when writing tar and pax
* Test enhancements: fix various compiler warnings, improve
portability, add lots of new tests.
* Documentation: document new functions, first draft of
libarchive_internals.3
MFC after: 14 days
Thanks to: Joerg Sonnenberger (compression_program)
Thanks to: Kai Wang (ar)
Thanks to: Colin Percival (many small fixes)
Thanks to: Many others who sent me various patches and problem reports.
Diffstat (limited to 'lib/libarchive/archive_write_set_format_ar.c')
-rw-r--r-- | lib/libarchive/archive_write_set_format_ar.c | 168 |
1 files changed, 102 insertions, 66 deletions
diff --git a/lib/libarchive/archive_write_set_format_ar.c b/lib/libarchive/archive_write_set_format_ar.c index 7658a8f..1b17282 100644 --- a/lib/libarchive/archive_write_set_format_ar.c +++ b/lib/libarchive/archive_write_set_format_ar.c @@ -28,9 +28,6 @@ #include "archive_platform.h" __FBSDID("$FreeBSD$"); -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif #ifdef HAVE_ERRNO_H #include <errno.h> #endif @@ -72,31 +69,22 @@ struct ar_w { #define AR_fmag_offset 58 #define AR_fmag_size 2 -/* - * "ar" magic numbers. - */ -#define ARMAG "!<arch>\n" -#define SARMAG 8 /* strlen(ARMAG); */ -#define AR_EFMT1 "#1/" -#define SAR_EFMT1 3 /* strlen(AR_EFMT1); */ -#define ARFMAG "`\n" -#define SARFMAG 2 /* strlen(ARFMAG); */ - -static int __archive_write_set_format_ar(struct archive_write *); -static int archive_write_ar_header(struct archive_write *, - struct archive_entry *); -static ssize_t archive_write_ar_data(struct archive_write *, const void *buff, - size_t s); -static int archive_write_ar_destroy(struct archive_write *); -static int archive_write_ar_finish_entry(struct archive_write *); -static int format_octal(int64_t v, char *p, int s); -static int format_decimal(int64_t v, char *p, int s); +static int archive_write_set_format_ar(struct archive_write *); +static int archive_write_ar_header(struct archive_write *, + struct archive_entry *); +static ssize_t archive_write_ar_data(struct archive_write *, + const void *buff, size_t s); +static int archive_write_ar_destroy(struct archive_write *); +static int archive_write_ar_finish_entry(struct archive_write *); +static const char *basename(const char *path); +static int format_octal(int64_t v, char *p, int s); +static int format_decimal(int64_t v, char *p, int s); int archive_write_set_format_ar_bsd(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; - int r = __archive_write_set_format_ar(a); + int r = archive_write_set_format_ar(a); if (r == ARCHIVE_OK) { a->archive_format = ARCHIVE_FORMAT_AR_BSD; a->archive_format_name = "ar (BSD)"; @@ -108,7 +96,7 @@ int archive_write_set_format_ar_svr4(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; - int r = __archive_write_set_format_ar(a); + int r = archive_write_set_format_ar(a); if (r == ARCHIVE_OK) { a->archive_format = ARCHIVE_FORMAT_AR_GNU; a->archive_format_name = "ar (GNU/SVR4)"; @@ -120,7 +108,7 @@ archive_write_set_format_ar_svr4(struct archive *_a) * Generic initialization. */ static int -__archive_write_set_format_ar(struct archive_write *a) +archive_write_set_format_ar(struct archive_write *a) { struct ar_w *ar; @@ -151,40 +139,48 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) char buff[60]; char *ss, *se; struct ar_w *ar; - const char *pp; - const struct stat *st; + const char *pathname; + const char *filename; ret = 0; append_fn = 0; ar = (struct ar_w *)a->format_data; ar->is_strtab = 0; - - if (a->archive.file_position == 0) { - /* - * We are now at the beginning of the archive, - * so we need first write the ar global header. - */ - (a->compression_write)(a, ARMAG, SARMAG); + filename = NULL; + + /* + * Reject files with empty name. + */ + pathname = archive_entry_pathname(entry); + if (*pathname == '\0') { + archive_set_error(&a->archive, EINVAL, + "Invalid filename"); + return (ARCHIVE_WARN); } - memset(buff, ' ', 60); - strncpy(&buff[AR_fmag_offset], ARFMAG, SARFMAG); + /* + * If we are now at the beginning of the archive, + * we need first write the ar global header. + */ + if (a->archive.file_position == 0) + (a->compressor.write)(a, "!<arch>\n", 8); - pp = archive_entry_pathname(entry); + memset(buff, ' ', 60); + strncpy(&buff[AR_fmag_offset], "`\n", 2); - if (strcmp(pp, "/") == 0 ) { + if (strcmp(pathname, "/") == 0 ) { /* Entry is archive symbol table in GNU format */ buff[AR_name_offset] = '/'; goto stat; } - if (strcmp(pp, "__.SYMDEF") == 0) { + if (strcmp(pathname, "__.SYMDEF") == 0) { /* Entry is archive symbol table in BSD format */ strncpy(buff + AR_name_offset, "__.SYMDEF", 9); goto stat; } - if (strcmp(pp, "//") == 0) { + if (strcmp(pathname, "//") == 0) { /* - * Entry is archive string table, inform that we should + * Entry is archive filename table, inform that we should * collect strtab in next _data call. */ ar->is_strtab = 1; @@ -196,7 +192,17 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) goto size; } - /* Otherwise, entry is a normal archive member. */ + /* + * Otherwise, entry is a normal archive member. + * Strip leading paths from filenames, if any. + */ + if ((filename = basename(pathname)) == NULL) { + /* Reject filenames with trailing "/" */ + archive_set_error(&a->archive, EINVAL, + "Invalid filename"); + return (ARCHIVE_WARN); + } + if (a->archive_format == ARCHIVE_FORMAT_AR_GNU) { /* * SVR4/GNU variant use a "/" to mark then end of the filename, @@ -204,9 +210,10 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) * So, the longest filename here (without extension) is * actually 15 bytes. */ - if (strlen(pp) <= 15) { - strncpy(&buff[AR_name_offset], pp, strlen(pp)); - buff[AR_name_offset + strlen(pp)] = '/'; + if (strlen(filename) <= 15) { + strncpy(&buff[AR_name_offset], + filename, strlen(filename)); + buff[AR_name_offset + strlen(filename)] = '/'; } else { /* * For filename longer than 15 bytes, GNU variant @@ -220,15 +227,15 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) return (ARCHIVE_WARN); } - se = (char *)malloc(strlen(pp) + 3); + se = (char *)malloc(strlen(filename) + 3); if (se == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate filename buffer"); return (ARCHIVE_FATAL); } - strncpy(se, pp, strlen(pp)); - strcpy(se + strlen(pp), "/\n"); + strncpy(se, filename, strlen(filename)); + strcpy(se + strlen(filename), "/\n"); ss = strstr(ar->strtab, se); free(se); @@ -263,47 +270,55 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) * The name is then written immediately following the * archive header. */ - if (strlen(pp) <= 16 && strchr(pp, ' ') == NULL) { - strncpy(&buff[AR_name_offset], pp, strlen(pp)); - buff[AR_name_offset + strlen(pp)] = ' '; + if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) { + strncpy(&buff[AR_name_offset], filename, strlen(filename)); + buff[AR_name_offset + strlen(filename)] = ' '; } else { - strncpy(buff + AR_name_offset, AR_EFMT1, SAR_EFMT1); - if (format_decimal(strlen(pp), - buff + AR_name_offset + SAR_EFMT1, - AR_name_size - SAR_EFMT1)) { + strncpy(buff + AR_name_offset, "#1/", 3); + if (format_decimal(strlen(filename), + buff + AR_name_offset + 3, + AR_name_size - 3)) { archive_set_error(&a->archive, ERANGE, "File name too long"); return (ARCHIVE_WARN); } append_fn = 1; archive_entry_set_size(entry, - archive_entry_size(entry) + strlen(pp)); + archive_entry_size(entry) + strlen(filename)); } } stat: - st = archive_entry_stat(entry); - if (format_decimal(st->st_mtime, buff + AR_date_offset, AR_date_size)) { + if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) { archive_set_error(&a->archive, ERANGE, "File modification time too large"); return (ARCHIVE_WARN); } - if (format_decimal(st->st_uid, buff + AR_uid_offset, AR_uid_size)) { + if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) { archive_set_error(&a->archive, ERANGE, "Numeric user ID too large"); return (ARCHIVE_WARN); } - if (format_decimal(st->st_gid, buff + AR_gid_offset, AR_gid_size)) { + if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) { archive_set_error(&a->archive, ERANGE, "Numeric group ID too large"); return (ARCHIVE_WARN); } - if (format_octal(st->st_mode, buff + AR_mode_offset, AR_mode_size)) { + if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) { archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); return (ARCHIVE_WARN); } + /* + * Sanity Check: A non-pseudo archive member should always be + * a regular file. + */ + if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) { + archive_set_error(&a->archive, EINVAL, + "Regular file required for non-pseudo member"); + return (ARCHIVE_WARN); + } size: if (format_decimal(archive_entry_size(entry), buff + AR_size_offset, @@ -313,7 +328,7 @@ size: return (ARCHIVE_WARN); } - ret = (a->compression_write)(a, buff, 60); + ret = (a->compressor.write)(a, buff, 60); if (ret != ARCHIVE_OK) return (ret); @@ -321,10 +336,10 @@ size: ar->entry_padding = ar->entry_bytes_remaining % 2; if (append_fn > 0) { - ret = (a->compression_write)(a, pp, strlen(pp)); + ret = (a->compressor.write)(a, filename, strlen(filename)); if (ret != ARCHIVE_OK) return (ret); - ar->entry_bytes_remaining -= strlen(pp); + ar->entry_bytes_remaining -= strlen(filename); } return (ARCHIVE_OK); @@ -357,7 +372,7 @@ archive_write_ar_data(struct archive_write *a, const void *buff, size_t s) ar->has_strtab = 1; } - ret = (a->compression_write)(a, buff, s); + ret = (a->compressor.write)(a, buff, s); if (ret != ARCHIVE_OK) return (ret); @@ -407,7 +422,7 @@ archive_write_ar_finish_entry(struct archive_write *a) return (ARCHIVE_WARN); } - ret = (a->compression_write)(a, "\n", 1); + ret = (a->compressor.write)(a, "\n", 1); return (ret); } @@ -490,3 +505,24 @@ format_decimal(int64_t v, char *p, int s) return (-1); } + +static const char * +basename(const char *path) +{ + const char *endp, *startp; + + endp = path + strlen(path) - 1; + /* + * For filename with trailing slash(es), we return + * NULL indicating an error. + */ + if (*endp == '/') + return (NULL); + + /* Find the start of the base */ + startp = endp; + while (startp > path && *(startp - 1) != '/') + startp--; + + return (startp); +} |