Browse Source

(sparse_diff_file): Bugfix: set seekable.
(pax_dump_header): Store sparse map in GNU.sparse.map. If this
variable has been explicitely deleted, use GNU.sparse.offset/
GNU.sparse.numbytes variables.

Sergey Poznyakoff 19 years ago
parent
commit
1b9c48d934
1 changed files with 51 additions and 8 deletions
  1. 51 8
      src/sparse.c

+ 51 - 8
src/sparse.c

@@ -54,7 +54,7 @@ struct tar_sparse_file
   off_t dumped_size;                /* Number of bytes actually written
   off_t dumped_size;                /* Number of bytes actually written
 				       to the archive */
 				       to the archive */
   struct tar_stat_info *stat_info;  /* Information about the file */
   struct tar_stat_info *stat_info;  /* Information about the file */
-  struct tar_sparse_optab const *optab;
+  struct tar_sparse_optab const *optab; /* Operation table */
   void *closure;                    /* Any additional data optab calls might
   void *closure;                    /* Any additional data optab calls might
 				       require */
 				       require */
 };
 };
@@ -565,13 +565,14 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
 
 
   file.stat_info = st;
   file.stat_info = st;
   file.fd = fd;
   file.fd = fd;
-
+  file.seekable = true; /* File *must* be seekable for compare to work */
+  
   rc = tar_sparse_decode_header (&file);
   rc = tar_sparse_decode_header (&file);
   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
     {
     {
       rc = check_sparse_region (&file,
       rc = check_sparse_region (&file,
 				offset, file.stat_info->sparse_map[i].offset)
 				offset, file.stat_info->sparse_map[i].offset)
-	&& check_data_region (&file, i);
+	    && check_data_region (&file, i);
       offset = file.stat_info->sparse_map[i].offset
       offset = file.stat_info->sparse_map[i].offset
 	        + file.stat_info->sparse_map[i].numbytes;
 	        + file.stat_info->sparse_map[i].numbytes;
     }
     }
@@ -838,10 +839,28 @@ static struct tar_sparse_optab const star_optab = {
 
 
    GNU.sparse.size      Real size of the stored file
    GNU.sparse.size      Real size of the stored file
    GNU.sparse.numblocks Number of blocks in the sparse map
    GNU.sparse.numblocks Number of blocks in the sparse map
+   GNU.sparse.map       Map of non-null data chunks. A string consisting
+                       of comma-separated values "offset,size[,offset,size]..."
+
+   Tar versions 1.14-1.15.1 instead of the latter used:
+   
    repeat numblocks time
    repeat numblocks time
      GNU.sparse.offset    Offset of the next data block
      GNU.sparse.offset    Offset of the next data block
      GNU.sparse.numbytes  Size of the next data block
      GNU.sparse.numbytes  Size of the next data block
    end repeat
    end repeat
+
+   This has been reported as conflicting with the POSIX specs. The reason is
+   that offsets and sizes of non-zero data blocks were stored in multiple
+   instances of GNU.sparse.offset/GNU.sparse.numbytes variables. However,
+   POSIX requires the latest occurrence of the variable to override all
+   previous occurrences.
+     
+   To avoid this incompatibility new keyword GNU.sparse.map was introduced
+   in tar 1.15.2. Some people might still need the 1.14 way of handling
+   sparse files for the compatibility reasons: it can be achieved by
+   specifying `--pax-option delete=GNU.sparse.map' in the command line.
+
+   See FIXME-1.14-1.15.1-1.20, below.
 */
 */
 
 
 static bool
 static bool
@@ -856,16 +875,40 @@ pax_dump_header (struct tar_sparse_file *file)
   off_t block_ordinal = current_block_ordinal ();
   off_t block_ordinal = current_block_ordinal ();
   union block *blk;
   union block *blk;
   size_t i;
   size_t i;
-
+  char nbuf[UINTMAX_STRSIZE_BOUND];
+  struct sp_array *map = file->stat_info->sparse_map;
+    
   /* Store the real file size */
   /* Store the real file size */
   xheader_store ("GNU.sparse.size", file->stat_info, NULL);
   xheader_store ("GNU.sparse.size", file->stat_info, NULL);
   xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
   xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
-  for (i = 0; i < file->stat_info->sparse_map_avail; i++)
+
+  /* FIXME-1.14-1.15.1-1.20: See the comment above.
+     Starting with 1.17 this should display a warning about POSIX-incompatible
+     keywords being generated. In 1.20, the true branch of the if block below
+     will be removed and GNU.sparse.map will be marked in xhdr_tab as
+     protected. */
+  
+  if (xheader_keyword_deleted_p ("GNU.sparse.map"))
     {
     {
-      xheader_store ("GNU.sparse.offset", file->stat_info, &i);
-      xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
+      for (i = 0; i < file->stat_info->sparse_map_avail; i++)
+	{
+	  xheader_store ("GNU.sparse.offset", file->stat_info, &i);
+	  xheader_store ("GNU.sparse.numbytes", file->stat_info, &i);
+	}
+    }
+  else
+    {
+      xheader_string_begin ();
+      for (i = 0; i < file->stat_info->sparse_map_avail; i++)
+	{
+	  if (i)
+	    xheader_string_add (",");
+	  xheader_string_add (umaxtostr (map[i].offset, nbuf));
+	  xheader_string_add (",");
+	  xheader_string_add (umaxtostr (map[i].numbytes, nbuf));
+	}
+      xheader_string_end ("GNU.sparse.map");
     }
     }
-
   blk = start_header (file->stat_info);
   blk = start_header (file->stat_info);
   /* Store the effective (shrunken) file size */
   /* Store the effective (shrunken) file size */
   OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
   OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);