]> Dogcows Code - chaz/tar/blobdiff - src/sparse.c
Initial documentation for --quoting-style, --quote-chars and --no-quote-chars option.
[chaz/tar] / src / sparse.c
index d3f716492b894cd0134711e2de3b8b540d0f1550..30bf03157c962c09f51fc8b8be07eb6f287e1000 100644 (file)
@@ -22,6 +22,7 @@
 #include "common.h"
 
 struct tar_sparse_file;
 #include "common.h"
 
 struct tar_sparse_file;
+static bool sparse_select_optab (struct tar_sparse_file *file);
 
 enum sparse_scan_state
   {
 
 enum sparse_scan_state
   {
@@ -53,7 +54,7 @@ struct tar_sparse_file
   off_t dumped_size;                /* Number of bytes actually written
                                       to the archive */
   struct tar_stat_info *stat_info;  /* Information about the file */
   off_t dumped_size;                /* Number of bytes actually written
                                       to the archive */
   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
                                       require */
 };
   void *closure;                    /* Any additional data optab calls might
                                       require */
 };
@@ -102,9 +103,14 @@ tar_sparse_member_p (struct tar_sparse_file *file)
 static bool
 tar_sparse_init (struct tar_sparse_file *file)
 {
 static bool
 tar_sparse_init (struct tar_sparse_file *file)
 {
-  file->dumped_size = 0;
+  memset (file, 0, sizeof *file);
+
+  if (!sparse_select_optab (file))
+    return false;
+
   if (file->optab->init)
     return file->optab->init (file);
   if (file->optab->init)
     return file->optab->init (file);
+
   return true;
 }
 
   return true;
 }
 
@@ -217,6 +223,8 @@ sparse_scan_file (struct tar_sparse_file *file)
   if (!lseek_or_error (file, 0))
     return false;
 
   if (!lseek_or_error (file, 0))
     return false;
 
+  st->archive_file_size = 0;
+  
   if (!tar_sparse_scan (file, scan_begin, NULL))
     return false;
 
   if (!tar_sparse_scan (file, scan_begin, NULL))
     return false;
 
@@ -316,6 +324,7 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i)
       memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
       bytes_left -= bytes_read;
       file->dumped_size += bytes_read;
       memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read);
       bytes_left -= bytes_read;
       file->dumped_size += bytes_read;
+      mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
       set_next_block_after (blk);
     }
 
       set_next_block_after (blk);
     }
 
@@ -352,6 +361,7 @@ sparse_extract_region (struct tar_sparse_file *file, size_t i)
       count = full_write (file->fd, blk->buffer, wrbytes);
       write_size -= count;
       file->dumped_size += count;
       count = full_write (file->fd, blk->buffer, wrbytes);
       write_size -= count;
       file->dumped_size += count;
+      mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
       file->offset += count;
       if (count != wrbytes)
        {
       file->offset += count;
       if (count != wrbytes)
        {
@@ -370,16 +380,15 @@ enum dump_status
 sparse_dump_file (int fd, struct tar_stat_info *st)
 {
   bool rc;
 sparse_dump_file (int fd, struct tar_stat_info *st)
 {
   bool rc;
-  struct tar_sparse_file file = { 0, };
+  struct tar_sparse_file file;
+
+  if (!tar_sparse_init (&file))
+    return dump_status_not_implemented;
 
   file.stat_info = st;
   file.fd = fd;
   file.seekable = true; /* File *must* be seekable for dump to work */
 
 
   file.stat_info = st;
   file.fd = fd;
   file.seekable = true; /* File *must* be seekable for dump to work */
 
-  if (!sparse_select_optab (&file)
-      || !tar_sparse_init (&file))
-    return dump_status_not_implemented;
-
   rc = sparse_scan_file (&file);
   if (rc && file.optab->dump_region)
     {
   rc = sparse_scan_file (&file);
   if (rc && file.optab->dump_region)
     {
@@ -389,8 +398,10 @@ sparse_dump_file (int fd, struct tar_stat_info *st)
        {
          size_t i;
 
        {
          size_t i;
 
+         mv_begin (file.stat_info);
          for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
            rc = tar_sparse_dump_region (&file, i);
          for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
            rc = tar_sparse_dump_region (&file, i);
+         mv_end ();
        }
     }
 
        }
     }
 
@@ -412,7 +423,7 @@ sparse_member_p (struct tar_stat_info *st)
 {
   struct tar_sparse_file file;
 
 {
   struct tar_sparse_file file;
 
-  if (!sparse_select_optab (&file))
+  if (!tar_sparse_init (&file))
     return false;
   file.stat_info = st;
   return tar_sparse_member_p (&file);
     return false;
   file.stat_info = st;
   return tar_sparse_member_p (&file);
@@ -423,7 +434,7 @@ sparse_fixup_header (struct tar_stat_info *st)
 {
   struct tar_sparse_file file;
 
 {
   struct tar_sparse_file file;
 
-  if (!sparse_select_optab (&file))
+  if (!tar_sparse_init (&file))
     return false;
   file.stat_info = st;
   return tar_sparse_fixup_header (&file);
     return false;
   file.stat_info = st;
   return tar_sparse_fixup_header (&file);
@@ -436,15 +447,14 @@ sparse_extract_file (int fd, struct tar_stat_info *st, off_t *size)
   struct tar_sparse_file file;
   size_t i;
 
   struct tar_sparse_file file;
   size_t i;
 
+  if (!tar_sparse_init (&file))
+    return dump_status_not_implemented;
+
   file.stat_info = st;
   file.fd = fd;
   file.seekable = lseek (fd, 0, SEEK_SET) == 0;
   file.offset = 0;
 
   file.stat_info = st;
   file.fd = fd;
   file.seekable = lseek (fd, 0, SEEK_SET) == 0;
   file.offset = 0;
 
-  if (!sparse_select_optab (&file)
-      || !tar_sparse_init (&file))
-    return dump_status_not_implemented;
-
   rc = tar_sparse_decode_header (&file);
   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
     rc = tar_sparse_extract_region (&file, i);
   rc = tar_sparse_decode_header (&file);
   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
     rc = tar_sparse_extract_region (&file, i);
@@ -458,13 +468,12 @@ sparse_skip_file (struct tar_stat_info *st)
   bool rc = true;
   struct tar_sparse_file file;
 
   bool rc = true;
   struct tar_sparse_file file;
 
+  if (!tar_sparse_init (&file))
+    return dump_status_not_implemented;
+
   file.stat_info = st;
   file.fd = -1;
 
   file.stat_info = st;
   file.fd = -1;
 
-  if (!sparse_select_optab (&file)
-      || !tar_sparse_init (&file))
-    return dump_status_not_implemented;
-
   rc = tar_sparse_decode_header (&file);
   skip_file (file.stat_info->archive_file_size);
   return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
   rc = tar_sparse_decode_header (&file);
   skip_file (file.stat_info->archive_file_size);
   return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
@@ -513,6 +522,8 @@ check_data_region (struct tar_sparse_file *file, size_t i)
   if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
     return false;
   size_left = file->stat_info->sparse_map[i].numbytes;
   if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset))
     return false;
   size_left = file->stat_info->sparse_map[i].numbytes;
+  mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
+      
   while (size_left > 0)
     {
       size_t bytes_read;
   while (size_left > 0)
     {
       size_t bytes_read;
@@ -538,6 +549,7 @@ check_data_region (struct tar_sparse_file *file, size_t i)
        }
       file->dumped_size += bytes_read;
       size_left -= bytes_read;
        }
       file->dumped_size += bytes_read;
       size_left -= bytes_read;
+      mv_size_left (file->stat_info->archive_file_size - file->dumped_size);
       if (memcmp (blk->buffer, diff_buffer, rdsize))
        {
          report_difference (file->stat_info, _("Contents differ"));
       if (memcmp (blk->buffer, diff_buffer, rdsize))
        {
          report_difference (file->stat_info, _("Contents differ"));
@@ -555,26 +567,28 @@ sparse_diff_file (int fd, struct tar_stat_info *st)
   size_t i;
   off_t offset = 0;
 
   size_t i;
   off_t offset = 0;
 
-  file.stat_info = st;
-  file.fd = fd;
-
-  if (!sparse_select_optab (&file)
-      || !tar_sparse_init (&file))
+  if (!tar_sparse_init (&file))
     return dump_status_not_implemented;
 
     return dump_status_not_implemented;
 
+  file.stat_info = st;
+  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);
+  mv_begin (st);
   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
     {
       rc = check_sparse_region (&file,
                                offset, file.stat_info->sparse_map[i].offset)
   for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++)
     {
       rc = check_sparse_region (&file,
                                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
                + file.stat_info->sparse_map[i].numbytes;
     }
 
   if (!rc)
     skip_file (file.stat_info->archive_file_size - file.dumped_size);
       offset = file.stat_info->sparse_map[i].offset
                + file.stat_info->sparse_map[i].numbytes;
     }
 
   if (!rc)
     skip_file (file.stat_info->archive_file_size - file.dumped_size);
-
+  mv_end ();
+  
   tar_sparse_done (&file);
   return rc;
 }
   tar_sparse_done (&file);
   return rc;
 }
@@ -834,16 +848,34 @@ static struct tar_sparse_optab const star_optab = {
 
    GNU.sparse.size      Real size of the stored file
    GNU.sparse.numblocks Number of blocks in the sparse map
 
    GNU.sparse.size      Real size of the stored file
    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
      GNU.sparse.offset    Offset of the next data block
      GNU.sparse.numbytes  Size of the next data block
    end repeat
    repeat numblocks time
      GNU.sparse.offset    Offset of the next data block
      GNU.sparse.numbytes  Size of the next data block
    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
 pax_sparse_member_p (struct tar_sparse_file *file)
 {
 */
 
 static bool
 pax_sparse_member_p (struct tar_sparse_file *file)
 {
-  return file->stat_info->archive_file_size != file->stat_info->stat.st_size;
+  return file->stat_info->sparse_map_avail > 0;
 }
 
 static bool
 }
 
 static bool
@@ -852,16 +884,40 @@ pax_dump_header (struct tar_sparse_file *file)
   off_t block_ordinal = current_block_ordinal ();
   union block *blk;
   size_t i;
   off_t block_ordinal = current_block_ordinal ();
   union block *blk;
   size_t i;
-
+  char nbuf[UINTMAX_STRSIZE_BOUND];
+  struct sp_array *map = file->stat_info->sparse_map;
+    
   /* Store the real file size */
   xheader_store ("GNU.sparse.size", file->stat_info, NULL);
   xheader_store ("GNU.sparse.numblocks", file->stat_info, NULL);
   /* Store the real file size */
   xheader_store ("GNU.sparse.size", 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);
   /* Store the effective (shrunken) file size */
   OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
   blk = start_header (file->stat_info);
   /* Store the effective (shrunken) file size */
   OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
This page took 0.031488 seconds and 4 git commands to generate.