]> Dogcows Code - chaz/tar/commitdiff
Fix listing of volume labels (in particular in PAX archives).
authorSergey Poznyakoff <gray@gnu.org.ua>
Fri, 22 Jan 2010 16:09:57 +0000 (18:09 +0200)
committerSergey Poznyakoff <gray@gnu.org.ua>
Sun, 24 Jan 2010 13:52:22 +0000 (15:52 +0200)
* src/buffer.c (match_volume_label): Call set_volume_label.
(check_label_pattern): Get label string
as argument.
(match_volume_label): Handle volume labels stored in
global PAX headers.
* src/common.c (print_header,read_header): Change signature.
(read_header_primitive): Remove prototype.
* src/list.c (recent_global_header): New static.
(list_archive): Always print volume labels.
(read_header_primitive): Remove.
(read_header): Change the signature (all callers updated)
Save the recent global header.
(volume_label_printed): New static.
(simple_print_header): New function (ex-print_header).
(print_header): Change the signature (all callers updated).
For POSIX formats, print first volume header (if set).
* src/xheader.c (xheader_write_global): Write the data
accumulated in xhdr->stk even if keyword_global_override_list
is empty.
(xheader_read): On unexpected EOF, report error instead of
coredumping.
(XHDR_PROTECTED, XHDR_GLOBAL): New defines.
(struct xhdr_tab): Remove `protected' with `flags'. All uses updated.
(decg): If XHDR_GLOBAL bit is set, call the keyword's decode
method instead of adding it to `kwl'.

* src/compare.c: Update calls to read_header.
* src/create.c: Likewise.
* src/delete.c: Likewise.
* src/update.c: Likewise.
* src/extract.c: Likewise.
(extract_volhdr): Do not print "Reading <label>" statement, because
it is inconsistent: it is not printed if the volume begins with a
member continued from the previous volume.

* tests/label01.at: New testcase.
* tests/label02.at: New testcase.
* tests/Makefile.am, tests/testsuite.at: Add new testcases.

13 files changed:
src/buffer.c
src/common.h
src/compare.c
src/create.c
src/delete.c
src/extract.c
src/list.c
src/update.c
src/xheader.c
tests/Makefile.am
tests/label01.at [new file with mode: 0644]
tests/label02.at [new file with mode: 0644]
tests/testsuite.at

index 613a7e8449f87a0dcbed2ae4e72f3f5323ffcbc1..ed7530342398c15f316c3c2e372db25a3c81a7f3 100644 (file)
@@ -1,7 +1,8 @@
 /* Buffer management for tar.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+   Foundation, Inc.
 
    Written by John Gilmore, on 1985-08-25.
 
@@ -1167,7 +1168,7 @@ read_header0 (struct tar_stat_info *info)
   enum read_header rc;
 
   tar_stat_init (info);
-  rc = read_header_primitive (false, info);
+  rc = read_header (&current_header, info, false);
   if (rc == HEADER_SUCCESS)
     {
       set_next_block_after (current_header);
@@ -1312,20 +1313,17 @@ try_new_volume ()
 }
 
 \f
-/* Check the LABEL block against the volume label, seen as a globbing
+/* Check LABEL against the volume label, seen as a globbing
    pattern.  Return true if the pattern matches.  In case of failure,
    retry matching a volume sequence number before giving up in
    multi-volume mode.  */
 static bool
-check_label_pattern (union block *label)
+check_label_pattern (const char *label)
 {
   char *string;
   bool result;
 
-  if (! memchr (label->header.name, '\0', sizeof label->header.name))
-    return false;
-
-  if (fnmatch (volume_label_option, label->header.name, 0) == 0)
+  if (fnmatch (volume_label_option, label, 0) == 0)
     return true;
 
   if (!multi_volume_option)
@@ -1335,7 +1333,7 @@ check_label_pattern (union block *label)
                     + sizeof VOLUME_LABEL_APPEND + 1);
   strcpy (string, volume_label_option);
   strcat (string, VOLUME_LABEL_APPEND);
-  result = fnmatch (string, label->header.name, 0) == 0;
+  result = fnmatch (string, label, 0) == 0;
   free (string);
   return result;
 }
@@ -1345,14 +1343,43 @@ check_label_pattern (union block *label)
 static void
 match_volume_label (void)
 {
-  union block *label = find_next_block ();
-
-  if (!label)
+  if (!volume_label)
+    {
+      union block *label = find_next_block ();
+  
+      if (!label)
+       FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
+                     quote (volume_label_option)));
+      if (label->header.typeflag == GNUTYPE_VOLHDR)
+       {
+         if (memchr (label->header.name, '\0', sizeof label->header.name))
+           assign_string (&volume_label, label->header.name);
+         else
+           {
+             volume_label = xmalloc (sizeof (label->header.name) + 1);
+             memcpy (volume_label, label->header.name,
+                     sizeof (label->header.name));
+             volume_label[sizeof (label->header.name)] = 0;
+           }
+       }
+      else if (label->header.typeflag == XGLTYPE)
+       {
+         struct tar_stat_info st;
+         tar_stat_init (&st);
+         xheader_read (&st.xhdr, label,
+                       OFF_FROM_HEADER (label->header.size));
+         xheader_decode (&st);
+         tar_stat_destroy (&st);
+       }
+    }
+  
+  if (!volume_label)
     FATAL_ERROR ((0, 0, _("Archive not labeled to match %s"),
                   quote (volume_label_option)));
-  if (!check_label_pattern (label))
+  
+  if (!check_label_pattern (volume_label))
     FATAL_ERROR ((0, 0, _("Volume %s does not match %s"),
-                  quote_n (0, label->header.name),
+                  quote_n (0, volume_label),
                   quote_n (1, volume_label_option)));
 }
 
index 360fb861ed7ebfa97e027d7d6689d0ec12372a87..2af403c102535725e4279b2526242071edd5b3b1 100644 (file)
@@ -1,7 +1,8 @@
 /* Common declarations for the tar program.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, 
+   Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -396,6 +397,7 @@ extern enum access_mode access_mode;
 extern FILE *stdlis;
 extern bool write_archive_to_stdout;
 extern char *volume_label;
+extern size_t volume_label_count;
 extern char *continued_file_name;
 extern uintmax_t continued_file_size;
 extern uintmax_t continued_file_offset;
@@ -577,11 +579,12 @@ uintmax_t uintmax_from_header (const char *buf, size_t size);
 
 void list_archive (void);
 void print_for_mkdir (char *dirname, int length, mode_t mode);
-void print_header (struct tar_stat_info *st, off_t block_ordinal);
+void print_header (struct tar_stat_info *st, union block *blk,
+                  off_t block_ordinal);
 void read_and (void (*do_something) (void));
-enum read_header read_header_primitive (bool raw_extended_headers,
-                                       struct tar_stat_info *info);
-enum read_header read_header (bool raw_extended_headers);
+enum read_header read_header (union block **return_block,
+                             struct tar_stat_info *info,
+                             bool raw_extended_headers);
 enum read_header tar_checksum (union block *header, bool silent);
 void skip_file (off_t size);
 void skip_member (void);
index cb1f3a8bd2b0b94569067f74bdb6db82a520e679..9385d40940c2de3fc75cc55ba069e999282c0139 100644 (file)
@@ -1,7 +1,7 @@
 /* Diff files from a tar archive.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1987-04-30.
 
@@ -460,7 +460,7 @@ diff_archive (void)
     {
       if (now_verifying)
        fprintf (stdlis, _("Verify "));
-      print_header (&current_stat_info, -1);
+      print_header (&current_stat_info, current_header, -1);
     }
 
   switch (current_header->header.typeflag)
@@ -578,7 +578,8 @@ verify_volume (void)
   flush_read ();
   while (1)
     {
-      enum read_header status = read_header (false);
+      enum read_header status = read_header (&current_header, 
+                                             &current_stat_info, false);
 
       if (status == HEADER_FAILURE)
        {
@@ -588,7 +589,8 @@ verify_volume (void)
            {
              counter++;
              set_next_block_after (current_header);
-             status = read_header (false);
+             status = read_header (&current_header, &current_stat_info,
+                                   false);
            }
          while (status == HEADER_FAILURE);
 
@@ -606,7 +608,7 @@ verify_volume (void)
             {
              char buf[UINTMAX_STRSIZE_BOUND];
 
-             status = read_header (false);
+             status = read_header (&current_header, &current_stat_info, false);
              if (status == HEADER_ZERO_BLOCK)
                break;
              WARNOPT (WARN_ALONE_ZERO_BLOCK,
index 8c66d9bc768b55bbd29290794065df10d6fab45c..748f2747d25bd0b618ebba6d38d8df0e5fdcc03a 100644 (file)
@@ -1,7 +1,7 @@
 /* Create a tar archive.
 
    Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-08-25.
 
@@ -996,11 +996,11 @@ finish_header (struct tar_stat_info *st,
       && header->header.typeflag != XHDTYPE
       && header->header.typeflag != XGLTYPE)
     {
-      /* These globals are parameters to print_header, sigh.  */
+      /* FIXME: These globals are parameters to print_header, sigh.  */
 
       current_header = header;
       current_format = archive_format;
-      print_header (st, block_ordinal);
+      print_header (st, current_header, block_ordinal);
     }
 
   header = write_extended (false, st, header);
index a67993cb9be91e92b2d5677622ddde372099cf41..8f729ba20a3fe4fe56984e0fe33e434b2c63f416 100644 (file)
@@ -1,7 +1,7 @@
 /* Delete entries from a tar archive.
 
    Copyright (C) 1988, 1992, 1994, 1996, 1997, 2000, 2001, 2003, 2004,
-   2005, 2006 Free Software Foundation, Inc.
+   2005, 2006, 2010 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -165,7 +165,9 @@ delete_archive_members (void)
 
   do
     {
-      enum read_header status = read_header (true);
+      enum read_header status = read_header (&current_header,
+                                             &current_stat_info,
+                                             true);
 
       switch (status)
        {
@@ -260,7 +262,7 @@ delete_archive_members (void)
 
          if (current_block == record_end)
            flush_archive ();
-         status = read_header (false);
+         status = read_header (&current_header, &current_stat_info, false);
 
          xheader_decode (&current_stat_info);
 
index 5f12cf9aa483b3584bf02e9daa3678db976dc534..32a883f6592f23a505410a4b09d03b2e066f1e1f 100644 (file)
@@ -1,7 +1,7 @@
 /* Extract files from a tar archive.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
-   2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2001, 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-11-19.
 
@@ -1092,8 +1092,6 @@ extract_fifo (char *file_name, int typeflag)
 static int
 extract_volhdr (char *file_name, int typeflag)
 {
-  if (verbose_option)
-    fprintf (stdlis, _("Reading %s\n"), quote (current_stat_info.file_name));
   skip_member ();
   return 0;
 }
@@ -1259,7 +1257,7 @@ extract_archive (void)
 
   /* Print the block from current_header and current_stat.  */
   if (verbose_option)
-    print_header (&current_stat_info, -1);
+    print_header (&current_stat_info, current_header, -1);
 
   /* Restore stats for all non-ancestor directories, unless
      it is an incremental archive.
index bba430ad8531ed73ec15f8b707fa861e3de97321..3394e90d30d8896f7544e233c7a9455aaacccd76 100644 (file)
@@ -1,7 +1,7 @@
 /* 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 Free Software Foundation, Inc.
+   2001, 2003, 2004, 2005, 2006, 2007, 2010 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-08-26.
 
@@ -33,6 +33,7 @@ union block *recent_long_name;        /* recent long name header and contents */
 union block *recent_long_link; /* likewise, for long link */
 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 */
 
 static uintmax_t from_header (const char *, size_t, const char *,
                              uintmax_t, uintmax_t, bool, bool);
@@ -77,7 +78,7 @@ read_and (void (*do_something) (void))
       prev_status = status;
       tar_stat_destroy (&current_stat_info);
 
-      status = read_header (false);
+      status = read_header (&current_header, &current_stat_info, false);
       switch (status)
        {
        case HEADER_STILL_UNREAD:
@@ -138,7 +139,7 @@ read_and (void (*do_something) (void))
            {
              char buf[UINTMAX_STRSIZE_BOUND];
 
-             status = read_header (false);
+             status = read_header (&current_header, &current_stat_info, false);
              if (status == HEADER_ZERO_BLOCK)
                break;
              WARNOPT (WARN_ALONE_ZERO_BLOCK,
@@ -205,11 +206,12 @@ void
 list_archive (void)
 {
   off_t block_ordinal = current_block_ordinal ();
-  /* Print the header block.  */
 
+  /* Print the header block.  */
+  
   decode_header (current_header, &current_stat_info, &current_format, 0);
   if (verbose_option)
-    print_header (&current_stat_info, block_ordinal);
+    print_header (&current_stat_info, current_header, block_ordinal);
 
   if (incremental_option)
     {
@@ -293,7 +295,8 @@ tar_checksum (union block *header, bool silent)
    the header which this routine reads.  */
 
 enum read_header
-read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
+read_header (union block **return_block, struct tar_stat_info *info,
+            bool raw_extended_headers)
 {
   union block *header;
   union block *header_copy;
@@ -310,7 +313,7 @@ read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
       enum read_header status;
 
       header = find_next_block ();
-      current_header = header;
+      *return_block = header;
       if (!header)
        return HEADER_END_OF_FILE;
 
@@ -392,6 +395,11 @@ read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
          else if (header->header.typeflag == XGLTYPE)
            {
              struct xheader xhdr;
+
+             if (!recent_global_header)
+               recent_global_header = xmalloc (sizeof *recent_global_header);
+             memcpy (recent_global_header, header,
+                     sizeof *recent_global_header);
              memset (&xhdr, 0, sizeof xhdr);
              xheader_read (&xhdr, header,
                            OFF_FROM_HEADER (header->header.size));
@@ -405,7 +413,7 @@ read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
       else
        {
          char const *name;
-         struct posix_header const *h = &current_header->header;
+         struct posix_header const *h = &header->header;
          char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
 
          if (recent_long_name)
@@ -464,12 +472,6 @@ read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
     }
 }
 
-enum read_header
-read_header (bool raw_extended_headers)
-{
-  return read_header_primitive (raw_extended_headers, &current_stat_info);
-}
-
 static char *
 decode_xform (char *file_name, void *data)
 {
@@ -1019,9 +1021,6 @@ tartime (struct timespec t, bool full_time)
    they shouldn't.  Unix tar is pretty random here anyway.  */
 
 
-/* FIXME: Note that print_header uses the globals HEAD, HSTAT, and
-   HEAD_STANDARD, which must be set up in advance.  Not very clean..  */
-
 /* Width of "user/group size", with initial value chosen
    heuristically.  This grows as needed, though this may cause some
    stairstepping in the output.  Make it too small and the output will
@@ -1034,8 +1033,11 @@ static int ugswidth = 19;
    USGWIDTH, some stairstepping may occur.  */
 static int datewidth = sizeof "YYYY-MM-DD HH:MM" - 1;
 
-void
-print_header (struct tar_stat_info *st, off_t block_ordinal)
+static bool volume_label_printed = false;
+
+static void
+simple_print_header (struct tar_stat_info *st, union block *blk,
+                    off_t block_ordinal)
 {
   char modes[11];
   char const *time_stamp;
@@ -1051,7 +1053,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
   int pad;
   int sizelen;
 
-  if (test_label_option && current_header->header.typeflag != GNUTYPE_VOLHDR)
+  if (test_label_option && blk->header.typeflag != GNUTYPE_VOLHDR)
     return;
 
   if (show_transformed_names_option)
@@ -1080,9 +1082,10 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
       /* File type and modes.  */
 
       modes[0] = '?';
-      switch (current_header->header.typeflag)
+      switch (blk->header.typeflag)
        {
        case GNUTYPE_VOLHDR:
+         volume_label_printed = true;
          modes[0] = 'V';
          break;
 
@@ -1150,8 +1153,8 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
          /* Try parsing it as an unsigned integer first, and as a
             uid_t if that fails.  This method can list positive user
             ids that are too large to fit in a uid_t.  */
-         uintmax_t u = from_header (current_header->header.uid,
-                                    sizeof current_header->header.uid, 0,
+         uintmax_t u = from_header (blk->header.uid,
+                                    sizeof blk->header.uid, 0,
                                     (uintmax_t) 0,
                                     (uintmax_t) TYPE_MAXIMUM (uintmax_t),
                                     false, false);
@@ -1160,7 +1163,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
          else
            {
              sprintf (uform, "%ld",
-                      (long) UID_FROM_HEADER (current_header->header.uid));
+                      (long) UID_FROM_HEADER (blk->header.uid));
              user = uform;
            }
        }
@@ -1175,8 +1178,8 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
          /* Try parsing it as an unsigned integer first, and as a
             gid_t if that fails.  This method can list positive group
             ids that are too large to fit in a gid_t.  */
-         uintmax_t g = from_header (current_header->header.gid,
-                                    sizeof current_header->header.gid, 0,
+         uintmax_t g = from_header (blk->header.gid,
+                                    sizeof blk->header.gid, 0,
                                     (uintmax_t) 0,
                                     (uintmax_t) TYPE_MAXIMUM (uintmax_t),
                                     false, false);
@@ -1185,14 +1188,14 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
          else
            {
              sprintf (gform, "%ld",
-                      (long) GID_FROM_HEADER (current_header->header.gid));
+                      (long) GID_FROM_HEADER (blk->header.gid));
              group = gform;
            }
        }
 
       /* Format the file size or major/minor device numbers.  */
 
-      switch (current_header->header.typeflag)
+      switch (blk->header.typeflag)
        {
        case CHRTYPE:
        case BLKTYPE:
@@ -1222,7 +1225,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
 
       fprintf (stdlis, " %s", quotearg (temp_name));
 
-      switch (current_header->header.typeflag)
+      switch (blk->header.typeflag)
        {
        case SYMTYPE:
          fprintf (stdlis, " -> %s\n", quotearg (st->link_name));
@@ -1235,7 +1238,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
        default:
          {
            char type_string[2];
-           type_string[0] = current_header->header.typeflag;
+           type_string[0] = blk->header.typeflag;
            type_string[1] = '\0';
            fprintf (stdlis, _(" unknown file type %s\n"),
                     quote (type_string));
@@ -1269,7 +1272,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
        case GNUTYPE_MULTIVOL:
          strcpy (size,
                  STRINGIFY_BIGINT
-                 (UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset),
+                 (UINTMAX_FROM_HEADER (blk->oldgnu_header.offset),
                   uintbuf));
          fprintf (stdlis, _("--Continued at byte %s--\n"), size);
          break;
@@ -1278,6 +1281,34 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
   fflush (stdlis);
 }
 
+
+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;
+
+      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);
+}
+
 /* Print a similar line when we make a directory automatically.  */
 void
 print_for_mkdir (char *dirname, int length, mode_t mode)
index 0f5dadf71e49b5616b985981ccb79b88fd0c40bb..468c6458d2eea904583db52bc914263d3ed2906f 100644 (file)
@@ -1,7 +1,7 @@
 /* Update a tar archive.
 
    Copyright (C) 1988, 1992, 1994, 1996, 1997, 1999, 2000, 2001, 2003,
-   2004, 2005, 2007 Free Software Foundation, Inc.
+   2004, 2005, 2007, 2010 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -114,7 +114,8 @@ update_archive (void)
 
   while (!found_end)
     {
-      enum read_header status = read_header (false);
+      enum read_header status = read_header (&current_header, 
+                                             &current_stat_info, false);
 
       switch (status)
        {
index 5eabdfb4318ecaae63b034cfb6138cc2b4868abf..724837f6171ee2582ad1cab5aa1a028b10ac1d9d 100644 (file)
@@ -1,6 +1,7 @@
 /* POSIX extended headers for tar.
 
-   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software
+   Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the
@@ -440,30 +441,37 @@ xheader_write (char type, char *name, time_t t, struct xheader *xhdr)
 void
 xheader_write_global (struct xheader *xhdr)
 {
-  char *name;
-  struct keyword_list *kp;
-
-  if (!keyword_global_override_list)
-    return;
+  if (keyword_global_override_list)
+    {
+      struct keyword_list *kp;
 
-  xheader_init (xhdr);
-  for (kp = keyword_global_override_list; kp; kp = kp->next)
-    code_string (kp->value, kp->pattern, xhdr);
-  xheader_finish (xhdr);
-  xheader_write (XGLTYPE, name = xheader_ghdr_name (), time (NULL), xhdr);
-  free (name);
+      xheader_init (xhdr);
+      for (kp = keyword_global_override_list; kp; kp = kp->next)
+       code_string (kp->value, kp->pattern, xhdr);
+    }
+  if (xhdr->stk)
+    {
+      char *name;
+      
+      xheader_finish (xhdr);
+      xheader_write (XGLTYPE, name = xheader_ghdr_name (), time (NULL), xhdr);
+      free (name);
+    }
 }
 
 \f
 /* General Interface */
 
+#define XHDR_PROTECTED 0x01
+#define XHDR_GLOBAL    0x02
+
 struct xhdr_tab
 {
   char const *keyword;
   void (*coder) (struct tar_stat_info const *, char const *,
                 struct xheader *, void const *data);
   void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t);
-  bool protect;
+  int flags;
 };
 
 /* This declaration must be extern, because ISO C99 section 6.9.2
@@ -491,7 +499,7 @@ xheader_protected_pattern_p (const char *pattern)
   struct xhdr_tab const *p;
 
   for (p = xhdr_tab; p->keyword; p++)
-    if (p->protect && fnmatch (pattern, p->keyword, 0) == 0)
+    if ((p->flags & XHDR_PROTECTED) && fnmatch (pattern, p->keyword, 0) == 0)
       return true;
   return false;
 }
@@ -502,7 +510,7 @@ xheader_protected_keyword_p (const char *keyword)
   struct xhdr_tab const *p;
 
   for (p = xhdr_tab; p->keyword; p++)
-    if (p->protect && strcmp (p->keyword, keyword) == 0)
+    if ((p->flags & XHDR_PROTECTED) && strcmp (p->keyword, keyword) == 0)
       return true;
   return false;
 }
@@ -633,7 +641,11 @@ decg (void *data, char const *keyword, char const *value,
       size_t size __attribute__((unused)))
 {
   struct keyword_list **kwl = data;
-  xheader_list_append (kwl, keyword, value);
+  struct xhdr_tab const *tab = locate_handler (keyword);
+  if (tab && (tab->flags & XHDR_GLOBAL))
+    tab->decoder (data, keyword, value, size);
+  else
+    xheader_list_append (kwl, keyword, value);
 }
 
 void
@@ -695,6 +707,9 @@ xheader_read (struct xheader *xhdr, union block *p, size_t size)
       if (len > BLOCKSIZE)
        len = BLOCKSIZE;
 
+      if (!p)
+       FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+      
       memcpy (&xhdr->buffer[j], p->buffer, len);
       set_next_block_after (p);
 
@@ -1491,51 +1506,53 @@ sparse_minor_decoder (struct tar_stat_info *st,
 }
 
 struct xhdr_tab const xhdr_tab[] = {
-  { "atime",   atime_coder,    atime_decoder,    false },
-  { "comment", dummy_coder,    dummy_decoder,    false },
-  { "charset", dummy_coder,    dummy_decoder,    false },
-  { "ctime",   ctime_coder,    ctime_decoder,    false },
-  { "gid",     gid_coder,      gid_decoder,      false },
-  { "gname",   gname_coder,    gname_decoder,    false },
-  { "linkpath", linkpath_coder, linkpath_decoder, false },
-  { "mtime",   mtime_coder,    mtime_decoder,    false },
-  { "path",    path_coder,     path_decoder,     false },
-  { "size",    size_coder,     size_decoder,     false },
-  { "uid",     uid_coder,      uid_decoder,      false },
-  { "uname",   uname_coder,    uname_decoder,    false },
+  { "atime",   atime_coder,    atime_decoder,    0 },
+  { "comment", dummy_coder,    dummy_decoder,    0 },
+  { "charset", dummy_coder,    dummy_decoder,    0 },
+  { "ctime",   ctime_coder,    ctime_decoder,    0 },
+  { "gid",     gid_coder,      gid_decoder,      0 },
+  { "gname",   gname_coder,    gname_decoder,    0 },
+  { "linkpath", linkpath_coder, linkpath_decoder, 0 },
+  { "mtime",   mtime_coder,    mtime_decoder,    0 },
+  { "path",    path_coder,     path_decoder,     0 },
+  { "size",    size_coder,     size_decoder,     0 },
+  { "uid",     uid_coder,      uid_decoder,      0 },
+  { "uname",   uname_coder,    uname_decoder,    0 },
 
   /* Sparse file handling */
   { "GNU.sparse.name",       path_coder, path_decoder,
-    true },
+    XHDR_PROTECTED },
   { "GNU.sparse.major",      sparse_major_coder, sparse_major_decoder,
-    true },
+    XHDR_PROTECTED },
   { "GNU.sparse.minor",      sparse_minor_coder, sparse_minor_decoder,
-    true },
+    XHDR_PROTECTED },
   { "GNU.sparse.realsize",   sparse_size_coder, sparse_size_decoder,
-    true },
+    XHDR_PROTECTED },
   { "GNU.sparse.numblocks",  sparse_numblocks_coder, sparse_numblocks_decoder,
-    true },
+    XHDR_PROTECTED },
 
   /* tar 1.14 - 1.15.90 keywords. */
-  { "GNU.sparse.size",       sparse_size_coder, sparse_size_decoder, true },
+  { "GNU.sparse.size",       sparse_size_coder, sparse_size_decoder,
+    XHDR_PROTECTED },
   /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
      headers, and each of them was meaningful. It confilcted with POSIX specs,
      which requires that "when extended header records conflict, the last one
      given in the header shall take precedence." */
   { "GNU.sparse.offset",     sparse_offset_coder, sparse_offset_decoder,
-    true },
+    XHDR_PROTECTED },
   { "GNU.sparse.numbytes",   sparse_numbytes_coder, sparse_numbytes_decoder,
-    true },
+    XHDR_PROTECTED },
   /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
   { "GNU.sparse.map",        NULL /* Unused, see pax_dump_header() */,
-    sparse_map_decoder, false },
+    sparse_map_decoder, 0 },
 
   { "GNU.dumpdir",           dumpdir_coder, dumpdir_decoder,
-    true },
+    XHDR_PROTECTED },
 
   /* Keeps the tape/volume label. May be present only in the global headers.
      Equivalent to GNUTYPE_VOLHDR.  */
-  { "GNU.volume.label", volume_label_coder, volume_label_decoder, true },
+  { "GNU.volume.label", volume_label_coder, volume_label_decoder,
+    XHDR_PROTECTED | XHDR_GLOBAL },
 
   /* These may be present in a first global header of the archive.
      They provide the same functionality as GNUTYPE_MULTIVOL header.
@@ -1544,9 +1561,11 @@ struct xhdr_tab const xhdr_tab[] = {
      GNU.volume.offset keeps the offset of the start of this volume,
      otherwise kept in oldgnu_header.offset.  */
   { "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
-    true },
-  { "GNU.volume.size", volume_size_coder, volume_size_decoder, true },
-  { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true },
+    XHDR_PROTECTED | XHDR_GLOBAL },
+  { "GNU.volume.size", volume_size_coder, volume_size_decoder,
+    XHDR_PROTECTED | XHDR_GLOBAL },
+  { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder,
+    XHDR_PROTECTED | XHDR_GLOBAL },
 
-  { NULL, NULL, NULL, false }
+  { NULL, NULL, NULL, 0 }
 };
index 006a6941935c5d23ffb31830426bd7917b78e3dd..1b3b2c1b991113d89979484382836f1dbf895922 100644 (file)
@@ -87,6 +87,8 @@ TESTSUITE_AT = \
  incr06.at\
  indexfile.at\
  ignfail.at\
+ label01.at\
+ label02.at\
  link01.at\
  link02.at\
  link03.at\
diff --git a/tests/label01.at b/tests/label01.at
new file mode 100644 (file)
index 0000000..933682b
--- /dev/null
@@ -0,0 +1,35 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([single-volume label])
+AT_KEYWORDS([label label01])
+
+AT_TAR_CHECK([
+genfile --file foo
+genfile --file bar
+tar -cf archive --label=Test foo bar
+tar tf archive
+],
+[0],
+[Test
+foo
+bar
+],
+[],[],[],[gnu,oldgnu,posix])
+
+AT_CLEANUP
diff --git a/tests/label02.at b/tests/label02.at
new file mode 100644 (file)
index 0000000..3aa5ce7
--- /dev/null
@@ -0,0 +1,38 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+
+# Test suite for GNU tar.
+# Copyright (C) 2010 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([multi-volume label])
+AT_KEYWORDS([label label02 multi-label multivolume multiv])
+
+AT_TAR_CHECK([
+exec <&-
+genfile --length 0 --file foo
+genfile --length 12288 --file bar
+genfile --length 12288 --file baz
+tar --label=Test -cM -L10 -f 1.tar -f 2.tar -f 3.tar -f 4.tar foo bar baz
+tar -Mt -f 1.tar -f 2.tar -f 3.tar -f 4.tar 
+],
+[0],
+[Test Volume 1
+foo
+bar
+baz
+],
+[],[],[],[gnu,oldgnu,posix])
+
+AT_CLEANUP
index b67d016bdb8f58e5d5cf41899c255796268a57a8..6dbd6b3ba3881f18f43f4acefa7ab3d4e5491fc3 100644 (file)
@@ -146,6 +146,9 @@ m4_include([extrac06.at])
 m4_include([extrac07.at])
 m4_include([extrac08.at])
 
+m4_include([label01.at])
+m4_include([label02.at])
+
 m4_include([backup01.at])
 
 m4_include([gzip.at])
This page took 0.093568 seconds and 4 git commands to generate.