X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2Flist.c;h=d15653d3b39530a2fd27caa8ec1fa0519d1e9d87;hb=502abd93bd8bfba15677aceb221c4530d257bbab;hp=3394e90d30d8896f7544e233c7a9455aaacccd76;hpb=166b7c7d028c3dbcfded5c834b9bf752d2fb41f0;p=chaz%2Ftar diff --git a/src/list.c b/src/list.c index 3394e90..d15653d 100644 --- a/src/list.c +++ b/src/list.c @@ -35,6 +35,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); @@ -78,7 +92,8 @@ read_and (void (*do_something) (void)) prev_status = status; tar_stat_destroy (¤t_stat_info); - status = read_header (¤t_header, ¤t_stat_info, false); + status = read_header (¤t_header, ¤t_stat_info, + read_header_auto); switch (status) { case HEADER_STILL_UNREAD: @@ -89,7 +104,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 @@ -115,8 +131,6 @@ 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; } @@ -139,7 +153,8 @@ read_and (void (*do_something) (void)) { char buf[UINTMAX_STRSIZE_BOUND]; - status = read_header (¤t_header, ¤t_stat_info, false); + status = read_header (¤t_header, ¤t_stat_info, + read_header_auto); if (status == HEADER_ZERO_BLOCK) break; WARNOPT (WARN_ALONE_ZERO_BLOCK, @@ -208,8 +223,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); @@ -282,21 +295,29 @@ tar_checksum (union block *header, bool silent) } /* Read a block that's supposed to be a header block. Return its - address in "current_header", and if it is good, the file's size - and names (file name, link name) in *info. + address in *RETURN_BLOCK, and if it is good, the file's size + and names (file name, link name) in *INFO. + + Return one of enum read_header describing the status of the + operation. - Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a - block full of zeros (EOF marker). + The MODE parameter instructs read_header what to do with special + header blocks, i.e.: extended POSIX, GNU long name or long link, + etc.: - If RAW_EXTENDED_HEADERS is nonzero, do not automagically fold the - GNU long name and link headers into later headers. + read_header_auto process them automatically, + read_header_x_raw when a special header is read, return + HEADER_SUCCESS_EXTENDED without actually + processing the header, + read_header_x_global when a POSIX global header is read, + decode it and return HEADER_SUCCESS_EXTENDED. - You must always set_next_block_after(current_header) to skip past + You must always set_next_block_after(*return_block) to skip past the header which this routine reads. */ enum read_header read_header (union block **return_block, struct tar_stat_info *info, - bool raw_extended_headers) + enum read_header_mode mode) { union block *header; union block *header_copy; @@ -333,7 +354,7 @@ read_header (union block **return_block, struct tar_stat_info *info, || header->header.typeflag == XGLTYPE || header->header.typeflag == SOLARIS_XHDTYPE) { - if (raw_extended_headers) + if (mode == read_header_x_raw) return HEADER_SUCCESS_EXTENDED; else if (header->header.typeflag == GNUTYPE_LONGNAME || header->header.typeflag == GNUTYPE_LONGLINK) @@ -405,6 +426,8 @@ read_header (union block **return_block, struct tar_stat_info *info, OFF_FROM_HEADER (header->header.size)); xheader_decode_global (&xhdr); xheader_destroy (&xhdr); + if (mode == read_header_x_global) + return HEADER_SUCCESS_EXTENDED; } /* Loop! */ @@ -484,18 +507,18 @@ decode_xform (char *file_name, void *data) 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. */ + 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, @@ -507,7 +530,7 @@ decode_xform (char *file_name, void *data) return file_name; } -bool +static bool transform_member_name (char **pinput, int type) { return transform_name_fp (pinput, type, decode_xform, &type); @@ -535,7 +558,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 @@ -633,13 +656,17 @@ decode_header (union block *header, struct tar_stat_info *stat_info, stat_info->is_dumpdir = true; } + if (header->header.typeflag == GNUTYPE_VOLHDR) + /* Name transformations don't apply to volume headers. */ + return; + 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); } @@ -672,7 +699,8 @@ from_header (char const *where0, size_t digs, char const *type, { if (type && !silent) ERROR ((0, 0, - /* TRANSLATORS: %s is type of the value (gid_t, uid_t, etc.) */ + /* TRANSLATORS: %s is type of the value (gid_t, uid_t, + etc.) */ _("Blanks in header where numeric %s value expected"), type)); return -1; @@ -864,7 +892,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", @@ -873,7 +901,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", @@ -881,7 +909,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", @@ -891,7 +919,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", @@ -922,14 +950,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", @@ -937,7 +958,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", @@ -1053,9 +1074,6 @@ simple_print_header (struct tar_stat_info *st, union block *blk, int pad; int sizelen; - if (test_label_option && blk->header.typeflag != GNUTYPE_VOLHDR) - return; - if (show_transformed_names_option) temp_name = st->file_name ? st->file_name : st->orig_file_name; else @@ -1136,7 +1154,7 @@ simple_print_header (struct tar_stat_info *st, union block *blk, /* 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; @@ -1282,30 +1300,36 @@ simple_print_header (struct tar_stat_info *st, union block *blk, } +static void +print_volume_label (void) +{ + struct tar_stat_info vstat; + union block vblk; + enum archive_format dummy; + + memset (&vblk, 0, sizeof (vblk)); + vblk.header.typeflag = GNUTYPE_VOLHDR; + if (recent_global_header) + memcpy (vblk.header.mtime, recent_global_header->header.mtime, + sizeof vblk.header.mtime); + tar_stat_init (&vstat); + assign_string (&vstat.file_name, "."); + decode_header (&vblk, &vstat, &dummy, 0); + assign_string (&vstat.file_name, volume_label); + simple_print_header (&vstat, &vblk, 0); + tar_stat_destroy (&vstat); +} + void print_header (struct tar_stat_info *st, union block *blk, off_t block_ordinal) { if (current_format == POSIX_FORMAT && !volume_label_printed && volume_label) { - struct tar_stat_info vstat; - union block vblk; - enum archive_format dummy; - + print_volume_label (); volume_label_printed = true; - - memset (&vblk, 0, sizeof (vblk)); - vblk.header.typeflag = GNUTYPE_VOLHDR; - if (recent_global_header) - memcpy (vblk.header.mtime, recent_global_header->header.mtime, - sizeof vblk.header.mtime); - tar_stat_init (&vstat); - assign_string (&vstat.file_name, "."); - decode_header (&vblk, &vstat, &dummy, 0); - assign_string (&vstat.file_name, volume_label); - simple_print_header (&vstat, &vblk, block_ordinal); - tar_stat_destroy (&vstat); } + simple_print_header (st, blk, block_ordinal); } @@ -1340,7 +1364,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) { @@ -1375,7 +1399,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); @@ -1385,3 +1409,34 @@ skip_member (void) mv_end (); } } + +void +test_archive_label () +{ + base64_init (); + name_gather (); + + open_archive (ACCESS_READ); + if (read_header (¤t_header, ¤t_stat_info, read_header_auto) + == HEADER_SUCCESS) + { + decode_header (current_header, + ¤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) + print_volume_label (); + if (!name_match (volume_label) && multi_volume_option) + { + char *s = drop_volume_label_suffix (volume_label); + name_match (s); + free (s); + } + } + } + close_archive (); + label_notfound (); +}