]> Dogcows Code - chaz/tar/blobdiff - src/sparse.c
Relicense under GPLv3
[chaz/tar] / src / sparse.c
index 799a00fc0bc93256b78c1e1427ad4237defb588e..9fde5080d5304a32253fd67d72e1a99a0c69bf56 100644 (file)
@@ -1,10 +1,10 @@
 /* Functions for dealing with sparse files
 
-   Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006, 2007 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 2, or (at your option) any later
+   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
@@ -409,15 +409,6 @@ sparse_dump_file (int fd, struct tar_stat_info *st)
   return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
 }
 
-/* Returns true if the file represented by stat is a sparse one */
-bool
-sparse_file_p (struct tar_stat_info *st)
-{
-  return (ST_NBLOCKS (st->stat)
-         < (st->stat.st_size / ST_NBLOCKSIZE
-            + (st->stat.st_size % ST_NBLOCKSIZE != 0)));
-}
-
 bool
 sparse_member_p (struct tar_stat_info *st)
 {
@@ -475,7 +466,7 @@ sparse_skip_file (struct tar_stat_info *st)
   file.fd = -1;
 
   rc = tar_sparse_decode_header (&file);
-  skip_file (file.stat_info->archive_file_size);
+  skip_file (file.stat_info->archive_file_size - file.dumped_size);
   return (tar_sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
 }
 
@@ -843,7 +834,6 @@ static struct tar_sparse_optab const star_optab = {
 \f
 /* GNU PAX sparse file format. There are several versions:
 
-
    * 0.0
 
    The initial version of sparse format used by tar 1.14-1.15.1.
@@ -874,7 +864,7 @@ 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.map       Map of non-null data chunks. A string consisting
-                        of comma-separated values "offset,size[,offset,size]..."
+                       of comma-separated values "offset,size[,offset,size]..."
 
    The resulting GNU.sparse.map string can be *very* long. While POSIX does not
    impose any limit on the length of a x header variable, this can confuse some
@@ -882,8 +872,8 @@ static struct tar_sparse_optab const star_optab = {
 
    * 1.0
 
-   Starting from this version, the exact sparse format version is specified explicitely
-   in the header using the following variables:
+   Starting from this version, the exact sparse format version is specified
+   explicitely in the header using the following variables:
 
    GNU.sparse.major     Major version 
    GNU.sparse.minor     Minor version
@@ -898,22 +888,24 @@ static struct tar_sparse_optab const star_optab = {
    "%d/GNUSparseFile.%p/%f".
    
    The sparse map itself is stored in the file data block, preceding the actual
-   file data. It consists of a series of octal numbers of arbitrary length, delimited 
-   by newlines. The map is padded with nulls to the nearest block boundary.
+   file data. It consists of a series of octal numbers of arbitrary length,
+   delimited by newlines. The map is padded with nulls to the nearest block
+   boundary.
 
-   The first number gives the number of entries in the map. Following are map entries,
-   each one consisting of two numbers giving the offset and size of the
-   data block it describes.
+   The first number gives the number of entries in the map. Following are map
+   entries, each one consisting of two numbers giving the offset and size of
+   the data block it describes.
 
    The format is designed in such a way that non-posix aware tars and tars not
-   supporting GNU.sparse.* keywords will extract each sparse file in its condensed
-   form with the file map attached and will place it into a separate directory.
-   Then, using a simple program it would be possible to expand the file to its
-   original form even without GNU tar.
-
-   Bu default, v.1.0 archives are created. To use other formats, --sparse-version
-   option is provided. Additionally, v.0.0 can be obtained by deleting GNU.sparse.map
-   from 0.1 format: --sparse-version 0.1 --pax-option delete=GNU.sparse.map
+   supporting GNU.sparse.* keywords will extract each sparse file in its
+   condensed form with the file map attached and will place it into a separate
+   directory. Then, using a simple program it would be possible to expand the
+   file to its original form even without GNU tar.
+
+   Bu default, v.1.0 archives are created. To use other formats,
+   --sparse-version option is provided. Additionally, v.0.0 can be obtained
+   by deleting GNU.sparse.map from 0.1 format: --sparse-version 0.1
+   --pax-option delete=GNU.sparse.map
 */
 
 static bool
@@ -953,16 +945,24 @@ pax_dump_header_0 (struct tar_sparse_file *file)
       file->stat_info->file_name = xheader_format_name (file->stat_info,
                                               "%d/GNUSparseFile.%p/%f", 0);
 
-      xheader_string_begin ();
+      xheader_string_begin (&file->stat_info->xhdr);
       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_add (&file->stat_info->xhdr, ",");
+         xheader_string_add (&file->stat_info->xhdr,
+                             umaxtostr (map[i].offset, nbuf));
+         xheader_string_add (&file->stat_info->xhdr, ",");
+         xheader_string_add (&file->stat_info->xhdr,
+                             umaxtostr (map[i].numbytes, nbuf));
+       }
+      if (!xheader_string_end (&file->stat_info->xhdr,
+                              "GNU.sparse.map"))
+       {
+         free (file->stat_info->file_name);
+         file->stat_info->file_name = save_file_name;
+         return false;
        }
-      xheader_string_end ("GNU.sparse.map");
     }
   blk = start_header (file->stat_info);
   /* Store the effective (shrunken) file size */
@@ -1017,6 +1017,7 @@ pax_dump_header_1 (struct tar_sparse_file *file)
     }
   size = (size + BLOCKSIZE - 1) / BLOCKSIZE;
   file->stat_info->archive_file_size += size * BLOCKSIZE;
+  file->dumped_size += size * BLOCKSIZE;
   
   /* Store sparse file identification */
   xheader_store ("GNU.sparse.major", file->stat_info, NULL);
@@ -1058,11 +1059,9 @@ pax_dump_header (struct tar_sparse_file *file)
 {
   file->stat_info->sparse_major = tar_sparse_major;
   file->stat_info->sparse_minor = tar_sparse_minor;
-  
-  if (file->stat_info->sparse_major == 0)
-    pax_dump_header_0 (file);
-  else
-    pax_dump_header_1 (file);
+
+  return (file->stat_info->sparse_major == 0) ?
+           pax_dump_header_0 (file) : pax_dump_header_1 (file);
 }
 
 static bool
@@ -1102,14 +1101,15 @@ pax_decode_header (struct tar_sparse_file *file)
      {                                                             \
        if (dst == buf + UINTMAX_STRSIZE_BOUND -1)                  \
          {                                                         \
-           ERROR ((0, 0, _("%s: numeric overflow in sparse archive member"),   \
+           ERROR ((0, 0, _("%s: numeric overflow in sparse archive member"), \
                  file->stat_info->orig_file_name));               \
            return false;                                           \
          }                                                         \
-        if (src == endp)                                           \
+       if (src == endp)                                            \
         {                                                         \
           set_next_block_after (b);                               \
-          b = find_next_block ();                                 \
+           file->dumped_size += BLOCKSIZE;                         \
+           b = find_next_block ();                                 \
            src = b->buffer;                                        \
           endp = b->buffer + BLOCKSIZE;                           \
         }                                                         \
@@ -1120,6 +1120,7 @@ pax_decode_header (struct tar_sparse_file *file)
  } while (0)                       
 
       set_next_block_after (current_header);
+      file->dumped_size += BLOCKSIZE;
       blk = find_next_block ();
       p = blk->buffer;
       COPY_BUF (blk,nbuf,p);
This page took 0.025796 seconds and 4 git commands to generate.