bug-tar
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Bug-tar] Labels in multivolume archives and long length filenames


From: Sergey Poznyakoff
Subject: Re: [Bug-tar] Labels in multivolume archives and long length filenames
Date: Fri, 22 Jan 2010 18:33:42 +0200

µÒÓÕÝØÙ <address@hidden> ha escrit:

> For gnu tar format everything is ok, but for posix tar format - can't
> read label.

Please, try the attached patch.

Regards,
Sergey

diff -pur orig/tar-1.22/src/buffer.c tar-1.22/src/buffer.c
--- orig/tar-1.22/src/buffer.c  2009-03-05 09:04:13.000000000 +0200
+++ tar-1.22/src/buffer.c       2010-01-22 18:15:25.000000000 +0200
@@ -1264,20 +1264,17 @@ try_new_volume ()
 }
 
 
-/* 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)
@@ -1287,7 +1284,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;
 }
@@ -1297,14 +1294,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)));
 }
 
diff -pur orig/tar-1.22/src/list.c tar-1.22/src/list.c
--- orig/tar-1.22/src/list.c    2008-10-30 13:10:04.000000000 +0200
+++ tar-1.22/src/list.c 2010-01-22 18:15:25.000000000 +0200
@@ -33,6 +33,7 @@ union block *recent_long_name;        /* recent
 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);
@@ -199,16 +200,50 @@ read_and (void (*do_something) (void))
   names_notfound ();           /* print names not found */
 }
 
+static void print_header0 (struct tar_stat_info *st, union block *blk,
+                          off_t block_ordinal);
+
 /* Print a header block, based on tar options.  */
 void
 list_archive (void)
 {
+  static bool first_call = true;
   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 (first_call)
+    {
+      first_call = false;
+      if (volume_label)
+       {
+         if (verbose_option)
+           {
+             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);
+             print_header0 (&vstat, &vblk, block_ordinal);
+             tar_stat_destroy (&vstat);
+           }
+         else
+           fprintf (stdlis, "%s\n", volume_label);
+       }
+      if (current_format == POSIX_FORMAT && test_label_option)
+       exit (0);
+    }
   if (verbose_option)
-    print_header (&current_stat_info, block_ordinal);
+    print_header0 (&current_stat_info, current_header, block_ordinal);
 
   if (incremental_option)
     {
@@ -391,6 +426,11 @@ read_header_primitive (bool raw_extended
          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));
@@ -1028,8 +1068,8 @@ 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 void
+print_header0 (struct tar_stat_info *st, union block *blk, off_t block_ordinal)
 {
   char modes[11];
   char const *time_stamp;
@@ -1045,7 +1085,7 @@ print_header (struct tar_stat_info *st, 
   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)
@@ -1074,7 +1114,7 @@ print_header (struct tar_stat_info *st, 
       /* File type and modes.  */
 
       modes[0] = '?';
-      switch (current_header->header.typeflag)
+      switch (blk->header.typeflag)
        {
        case GNUTYPE_VOLHDR:
          modes[0] = 'V';
@@ -1144,8 +1184,8 @@ print_header (struct tar_stat_info *st, 
          /* 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);
@@ -1154,7 +1194,7 @@ print_header (struct tar_stat_info *st, 
          else
            {
              sprintf (uform, "%ld",
-                      (long) UID_FROM_HEADER (current_header->header.uid));
+                      (long) UID_FROM_HEADER (blk->header.uid));
              user = uform;
            }
        }
@@ -1169,8 +1209,8 @@ print_header (struct tar_stat_info *st, 
          /* 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);
@@ -1179,14 +1219,14 @@ print_header (struct tar_stat_info *st, 
          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:
@@ -1216,7 +1256,7 @@ print_header (struct tar_stat_info *st, 
 
       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));
@@ -1229,7 +1269,7 @@ print_header (struct tar_stat_info *st, 
        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));
@@ -1263,7 +1303,7 @@ print_header (struct tar_stat_info *st, 
        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;
@@ -1272,6 +1312,12 @@ print_header (struct tar_stat_info *st, 
   fflush (stdlis);
 }
 
+void
+print_header (struct tar_stat_info *st, off_t block_ordinal)
+{
+  print_header0 (st, current_header, block_ordinal);
+}
+
 /* Print a similar line when we make a directory automatically.  */
 void
 print_for_mkdir (char *dirname, int length, mode_t mode)
diff -pur orig/tar-1.22/src/xheader.c tar-1.22/src/xheader.c
--- orig/tar-1.22/src/xheader.c 2008-11-30 14:30:54.000000000 +0200
+++ tar-1.22/src/xheader.c      2010-01-22 18:22:28.000000000 +0200
@@ -403,18 +403,22 @@ xheader_write (char type, char *name, st
 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 (), 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 (), xhdr);
+      free (name);
+    }
 }
 
 
@@ -657,6 +661,9 @@ xheader_read (struct xheader *xhdr, unio
       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);
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]