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);
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:
/* 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
quotearg_colon (current_stat_info.file_name)));
/* Fall through. */
default:
- decode_header (current_header,
- ¤t_stat_info, ¤t_format, 0);
skip_member ();
continue;
}
{
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,
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);
}
/* 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;
|| 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)
OFF_FROM_HEADER (header->header.size));
xheader_decode_global (&xhdr);
xheader_destroy (&xhdr);
+ if (mode == read_header_x_global)
+ return HEADER_SUCCESS_EXTENDED;
}
/* Loop! */
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,
return file_name;
}
-bool
+static bool
transform_member_name (char **pinput, int type)
{
return transform_name_fp (pinput, type, decode_xform, &type);
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
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);
}
{
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;
return -1;
}
-gid_t
+static gid_t
gid_from_header (const char *p, size_t s)
{
return from_header (p, s, "gid_t",
false, false);
}
-major_t
+static major_t
major_from_header (const char *p, size_t s)
{
return from_header (p, s, "major_t",
(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",
/* 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",
(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",
(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",
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
/* 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;
}
+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);
}
{
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)
{
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);
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 ();
+}