X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Flist.c;h=f2605ad0c258d68ab6214ed5af1eeb8e68707951;hb=3c4e51fad6dbd595a2fb1e34f11e5a804b9b33ab;hp=0474fb1e5ad40a02cab4f5c76f076ed7e1e9ffc3;hpb=0ba8bdf5f3401fdc8c1595857ab69f6c65e04353;p=chaz%2Ftar diff --git a/src/list.c b/src/list.c index 0474fb1..f2605ad 100644 --- a/src/list.c +++ b/src/list.c @@ -1,7 +1,8 @@ /* List a tar archive, with support routines for reading a tar archive. Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000, - 2001, 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc. + 2001, 2003, 2004, 2005, 2006, 2007, 2010, 2012 + Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-26. @@ -35,6 +36,20 @@ size_t recent_long_name_blocks; /* number of blocks in recent_long_name */ size_t recent_long_link_blocks; /* likewise, for long link */ union block *recent_global_header; /* Recent global header block */ +#define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where)) +#define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where)) +#define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where)) +#define MODE_FROM_HEADER(where, hbits) \ + mode_from_header (where, sizeof (where), hbits) +#define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where)) +#define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where)) + +static gid_t gid_from_header (const char *buf, size_t size); +static major_t major_from_header (const char *buf, size_t size); +static minor_t minor_from_header (const char *buf, size_t size); +static mode_t mode_from_header (const char *buf, size_t size, unsigned *hbits); +static time_t time_from_header (const char *buf, size_t size); +static uid_t uid_from_header (const char *buf, size_t size); static uintmax_t from_header (const char *, size_t, const char *, uintmax_t, uintmax_t, bool, bool); @@ -61,6 +76,66 @@ base64_init (void) base64_map[(int) base_64_digits[i]] = i; } +static char * +decode_xform (char *file_name, void *data) +{ + int type = *(int*)data; + + switch (type) + { + case XFORM_SYMLINK: + /* FIXME: It is not quite clear how and to which extent are the symbolic + links subject to filename transformation. In the absence of another + solution, symbolic links are exempt from component stripping and + name suffix normalization, but subject to filename transformation + proper. */ + return file_name; + + case XFORM_LINK: + file_name = safer_name_suffix (file_name, true, absolute_names_option); + break; + + case XFORM_REGFILE: + file_name = safer_name_suffix (file_name, false, absolute_names_option); + break; + } + + if (strip_name_components) + { + size_t prefix_len = stripped_prefix_len (file_name, + strip_name_components); + if (prefix_len == (size_t) -1) + prefix_len = strlen (file_name); + file_name += prefix_len; + } + return file_name; +} + +static bool +transform_member_name (char **pinput, int type) +{ + return transform_name_fp (pinput, type, decode_xform, &type); +} + +void +transform_stat_info (int typeflag, struct tar_stat_info *stat_info) +{ + if (typeflag == GNUTYPE_VOLHDR) + /* Name transformations don't apply to volume headers. */ + return; + + transform_member_name (&stat_info->file_name, XFORM_REGFILE); + switch (typeflag) + { + case SYMTYPE: + transform_member_name (&stat_info->link_name, XFORM_SYMLINK); + break; + + case LNKTYPE: + transform_member_name (&stat_info->link_name, XFORM_LINK); + } +} + /* Main loop for reading an archive. */ void read_and (void (*do_something) (void)) @@ -78,7 +153,7 @@ read_and (void (*do_something) (void)) prev_status = status; tar_stat_destroy (¤t_stat_info); - status = read_header (¤t_header, ¤t_stat_info, + status = read_header (¤t_header, ¤t_stat_info, read_header_auto); switch (status) { @@ -90,7 +165,8 @@ read_and (void (*do_something) (void)) /* Valid header. We should decode next field (mode) first. Ensure incoming names are null terminated. */ - + decode_header (current_header, ¤t_stat_info, + ¤t_format, 1); if (! name_match (current_stat_info.file_name) || (NEWER_OPTION_INITIALIZED (newer_mtime_option) /* FIXME: We get mtime now, and again later; this causes @@ -116,13 +192,12 @@ read_and (void (*do_something) (void)) quotearg_colon (current_stat_info.file_name))); /* Fall through. */ default: - decode_header (current_header, - ¤t_stat_info, ¤t_format, 0); skip_member (); continue; } } - + transform_stat_info (current_header->header.typeflag, + ¤t_stat_info); (*do_something) (); continue; @@ -140,7 +215,7 @@ read_and (void (*do_something) (void)) { char buf[UINTMAX_STRSIZE_BOUND]; - status = read_header (¤t_header, ¤t_stat_info, + status = read_header (¤t_header, ¤t_stat_info, read_header_auto); if (status == HEADER_ZERO_BLOCK) break; @@ -210,8 +285,6 @@ list_archive (void) off_t block_ordinal = current_block_ordinal (); /* Print the header block. */ - - decode_header (current_header, ¤t_stat_info, ¤t_format, 0); if (verbose_option) print_header (¤t_stat_info, current_header, block_ordinal); @@ -361,15 +434,13 @@ read_header (union block **return_block, struct tar_stat_info *info, if (header->header.typeflag == GNUTYPE_LONGNAME) { - if (next_long_name) - free (next_long_name); + free (next_long_name); next_long_name = header_copy; next_long_name_blocks = size / BLOCKSIZE; } else { - if (next_long_link) - free (next_long_link); + free (next_long_link); next_long_link = header_copy; next_long_link_blocks = size / BLOCKSIZE; } @@ -428,8 +499,7 @@ read_header (union block **return_block, struct tar_stat_info *info, struct posix_header const *h = &header->header; char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1]; - if (recent_long_name) - free (recent_long_name); + free (recent_long_name); if (next_long_name) { @@ -460,8 +530,7 @@ read_header (union block **return_block, struct tar_stat_info *info, assign_string (&info->file_name, name); info->had_trailing_slash = strip_trailing_slashes (info->file_name); - if (recent_long_link) - free (recent_long_link); + free (recent_long_link); if (next_long_link) { @@ -484,47 +553,6 @@ read_header (union block **return_block, struct tar_stat_info *info, } } -static char * -decode_xform (char *file_name, void *data) -{ - int type = *(int*)data; - - switch (type) - { - case XFORM_SYMLINK: - /* FIXME: It is not quite clear how and to which extent are the symbolic - links subject to filename transformation. In the absence of another - solution, symbolic links are exempt from component stripping and - name suffix normalization, but subject to filename transformation - proper. */ - return file_name; - - case XFORM_LINK: - file_name = safer_name_suffix (file_name, true, absolute_names_option); - break; - - case XFORM_REGFILE: - file_name = safer_name_suffix (file_name, false, absolute_names_option); - break; - } - - if (strip_name_components) - { - size_t prefix_len = stripped_prefix_len (file_name, - strip_name_components); - if (prefix_len == (size_t) -1) - prefix_len = strlen (file_name); - file_name += prefix_len; - } - return file_name; -} - -bool -transform_member_name (char **pinput, int type) -{ - return transform_name_fp (pinput, type, decode_xform, &type); -} - #define ISOCTAL(c) ((c)>='0'&&(c)<='7') /* Decode things from a file HEADER block into STAT_INFO, also setting @@ -547,7 +575,7 @@ decode_header (union block *header, struct tar_stat_info *stat_info, enum archive_format format; unsigned hbits; /* high bits of the file mode. */ mode_t mode = MODE_FROM_HEADER (header->header.mode, &hbits); - + if (strcmp (header->header.magic, TMAGIC) == 0) { if (header->star_header.prefix[130] == 0 @@ -561,7 +589,9 @@ decode_header (union block *header, struct tar_stat_info *stat_info, else format = USTAR_FORMAT; } - else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0) + else if (strcmp (header->buffer + offsetof (struct posix_header, magic), + OLDGNU_MAGIC) + == 0) format = hbits ? OLDGNU_FORMAT : GNU_FORMAT; else format = V7_FORMAT; @@ -575,6 +605,8 @@ decode_header (union block *header, struct tar_stat_info *stat_info, assign_string (&stat_info->gname, header->header.gname[0] ? header->header.gname : NULL); + xheader_xattr_init (stat_info); + if (format == OLDGNU_FORMAT && incremental_option) { stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime); @@ -644,19 +676,9 @@ decode_header (union block *header, struct tar_stat_info *stat_info, || stat_info->dumpdir) stat_info->is_dumpdir = true; } - - transform_member_name (&stat_info->file_name, XFORM_REGFILE); - switch (header->header.typeflag) - { - case SYMTYPE: - transform_member_name (&stat_info->link_name, XFORM_SYMLINK); - break; - - case LNKTYPE: - transform_member_name (&stat_info->link_name, XFORM_LINK); - } } + /* Convert buffer at WHERE0 of size DIGS from external format to uintmax_t. DIGS must be positive. If TYPE is nonnull, the data are of type TYPE. The buffer must represent a value in the range @@ -877,7 +899,7 @@ from_header (char const *where0, size_t digs, char const *type, return -1; } -gid_t +static gid_t gid_from_header (const char *p, size_t s) { return from_header (p, s, "gid_t", @@ -886,7 +908,7 @@ gid_from_header (const char *p, size_t s) false, false); } -major_t +static major_t major_from_header (const char *p, size_t s) { return from_header (p, s, "major_t", @@ -894,7 +916,7 @@ major_from_header (const char *p, size_t s) (uintmax_t) TYPE_MAXIMUM (major_t), false, false); } -minor_t +static minor_t minor_from_header (const char *p, size_t s) { return from_header (p, s, "minor_t", @@ -904,7 +926,7 @@ minor_from_header (const char *p, size_t s) /* Convert P to the file mode, as understood by tar. Store unrecognized mode bits (from 10th up) in HBITS. */ -mode_t +static mode_t mode_from_header (const char *p, size_t s, unsigned *hbits) { unsigned u = from_header (p, s, "mode_t", @@ -935,14 +957,7 @@ off_from_header (const char *p, size_t s) (uintmax_t) TYPE_MAXIMUM (off_t), false, false); } -size_t -size_from_header (const char *p, size_t s) -{ - return from_header (p, s, "size_t", (uintmax_t) 0, - (uintmax_t) TYPE_MAXIMUM (size_t), false, false); -} - -time_t +static time_t time_from_header (const char *p, size_t s) { return from_header (p, s, "time_t", @@ -950,7 +965,7 @@ time_from_header (const char *p, size_t s) (uintmax_t) TYPE_MAXIMUM (time_t), false, false); } -uid_t +static uid_t uid_from_header (const char *p, size_t s) { return from_header (p, s, "uid_t", @@ -1052,7 +1067,7 @@ static void simple_print_header (struct tar_stat_info *st, union block *blk, off_t block_ordinal) { - char modes[11]; + char modes[12]; char const *time_stamp; int time_stamp_len; char *temp_name; @@ -1144,9 +1159,12 @@ simple_print_header (struct tar_stat_info *st, union block *blk, pax_decode_mode (st->stat.st_mode, modes + 1); + /* extended attributes: GNU `ls -l'-like preview */ + xattrs_print_char (st, modes + 10); + /* Time stamp. */ - time_stamp = tartime (st->mtime, false); + time_stamp = tartime (st->mtime, full_time_option); time_stamp_len = strlen (time_stamp); if (datewidth < time_stamp_len) datewidth = time_stamp_len; @@ -1289,11 +1307,12 @@ simple_print_header (struct tar_stat_info *st, union block *blk, } } fflush (stdlis); + xattrs_print (st); } -void -print_volume_label () +static void +print_volume_label (void) { struct tar_stat_info vstat; union block vblk; @@ -1345,8 +1364,8 @@ print_for_mkdir (char *dirname, int length, mode_t mode) STRINGIFY_BIGINT (current_block_ordinal (), buf)); } - fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + 1 + datewidth, - _("Creating directory:"), length, quotearg (dirname)); + fprintf (stdlis, "%s %*s %s\n", modes, ugswidth + 1 + datewidth, + _("Creating directory:"), quotearg (dirname)); } } @@ -1356,7 +1375,7 @@ skip_file (off_t size) { union block *x; - /* FIXME: Make sure mv_begin is always called before it */ + /* FIXME: Make sure mv_begin_read is always called before it */ if (seekable_archive) { @@ -1391,7 +1410,7 @@ skip_member (void) char save_typeflag = current_header->header.typeflag; set_next_block_after (current_header); - mv_begin (¤t_stat_info); + mv_begin_read (¤t_stat_info); if (current_stat_info.is_sparse) sparse_skip_file (¤t_stat_info); @@ -1403,7 +1422,7 @@ skip_member (void) } void -test_archive_label () +test_archive_label (void) { base64_init (); name_gather (); @@ -1416,7 +1435,7 @@ test_archive_label () ¤t_stat_info, ¤t_format, 0); if (current_header->header.typeflag == GNUTYPE_VOLHDR) assign_string (&volume_label, current_header->header.name); - + if (volume_label) { if (verbose_option)