root/src/vfs/tar/tar-sparse.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. decode_num
  2. sparse_select_optab
  3. sparse_init
  4. sparse_done
  5. sparse_member_p
  6. sparse_fixup_header
  7. sparse_decode_header
  8. sparse_add_map
  9. oldgnu_add_sparse
  10. oldgnu_sparse_member_p
  11. oldgnu_fixup_header
  12. oldgnu_get_sparse_info
  13. star_sparse_member_p
  14. star_fixup_header
  15. star_get_sparse_info
  16. pax_sparse_member_p
  17. pax_decode_header
  18. tar_sparse_member_p
  19. tar_sparse_fixup_header
  20. tar_sparse_skip_file

   1 /*
   2    Virtual File System: GNU Tar file system.
   3 
   4    Copyright (C) 2003-2024
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Andrew Borodin <aborodin@vmail.ru>, 2023
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24  */
  25 
  26 /**
  27  * \file
  28  * \brief Source: Virtual File System: GNU Tar file system
  29  */
  30 
  31 /*
  32  * Avoid following error:
  33  *   comparison of unsigned expression < 0 is always false [-Werror=type-limits]
  34  *
  35  * https://www.boost.org/doc/libs/1_55_0/libs/integer/test/cstdint_test.cpp
  36  *   We can't suppress this warning on the command line as not all GCC versions support -Wno-type-limits
  37  */
  38 #if defined(__GNUC__) && (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4))
  39 #pragma GCC diagnostic ignored "-Wtype-limits"
  40 #endif
  41 
  42 #include <config.h>
  43 
  44 #include <ctype.h>              /* isdigit() */
  45 #include <errno.h>
  46 #include <inttypes.h>           /* uintmax_t */
  47 
  48 #include "lib/global.h"
  49 
  50 #include "tar-internal.h"
  51 
  52 /* Old GNU Format.
  53    The sparse file information is stored in the oldgnu_header in the following manner:
  54 
  55    The header is marked with type 'S'. Its 'size' field contains the cumulative size
  56    of all non-empty blocks of the file. The actual file size is stored in `realsize'
  57    member of oldgnu_header.
  58 
  59    The map of the file is stored in a list of 'struct sparse'. Each struct contains
  60    offset to the block of data and its size (both as octal numbers). The first file
  61    header contains at most 4 such structs (SPARSES_IN_OLDGNU_HEADER). If the map
  62    contains more structs, then the field 'isextended' of the main header is set to
  63    1 (binary) and the 'struct sparse_header' header follows, containing at most
  64    21 following structs (SPARSES_IN_SPARSE_HEADER). If more structs follow, 'isextended'
  65    field of the extended header is set and next  next extension header follows, etc...
  66  */
  67 
  68 /*** global variables ****************************************************************************/
  69 
  70 /*** file scope macro definitions ****************************************************************/
  71 
  72 /* The width in bits of the integer type or expression T.
  73    Do not evaluate T.  T must not be a bit-field expression.
  74    Padding bits are not supported; this is checked at compile-time below.  */
  75 #define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
  76 
  77 /* Bound on length of the string representing an unsigned integer
  78    value representable in B bits.  log10 (2.0) < 146/485.  The
  79    smallest value of B where this bound is not tight is 2621.  */
  80 #define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)
  81 
  82 /* Does the __typeof__ keyword work?  This could be done by
  83    'configure', but for now it's easier to do it by hand.  */
  84 #if (2 <= __GNUC__                                                      \
  85      || (4 <= __clang_major__)                                          \
  86      || (1210 <= __IBMC__ && defined __IBM__TYPEOF__)                   \
  87      || (0x5110 <= __SUNPRO_C && !__STDC__))
  88 #define _GL_HAVE___TYPEOF__ 1
  89 #else
  90 #define _GL_HAVE___TYPEOF__ 0
  91 #endif
  92 
  93 /* Return 1 if the integer type or expression T might be signed.  Return 0
  94    if it is definitely unsigned.  T must not be a bit-field expression.
  95    This macro does not evaluate its argument, and expands to an
  96    integer constant expression.  */
  97 #if _GL_HAVE___TYPEOF__
  98 #define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t))
  99 #else
 100 #define _GL_SIGNED_TYPE_OR_EXPR(t) 1
 101 #endif
 102 
 103 /* Return a value with the common real type of E and V and the value of V.
 104    Do not evaluate E.  */
 105 #define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
 106 
 107 /* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
 108    <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>.  */
 109 #define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
 110 
 111 /* Return 1 if the real expression E, after promotion, has a
 112    signed or floating type.  Do not evaluate E.  */
 113 #define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
 114 
 115 #define _GL_SIGNED_INT_MAXIMUM(e)                                       \
 116     (((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
 117 
 118 /* The maximum and minimum values for the type of the expression E,
 119    after integer promotion.  E is not evaluated.  */
 120 #define _GL_INT_MINIMUM(e)                                              \
 121     (EXPR_SIGNED (e)                                                    \
 122         ? ~_GL_SIGNED_INT_MAXIMUM (e)                                   \
 123         : _GL_INT_CONVERT (e, 0))
 124 #define _GL_INT_MAXIMUM(e)                                              \
 125     (EXPR_SIGNED (e)                                                    \
 126         ? _GL_SIGNED_INT_MAXIMUM (e)                                    \
 127         : _GL_INT_NEGATE_CONVERT (e, 1))
 128 
 129 /* Return 1 if the expression A <op> B would overflow,
 130    where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test,
 131    assuming MIN and MAX are the minimum and maximum for the result type.
 132    Arguments should be free of side effects.  */
 133 #define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow)                \
 134   op_result_overflow (a, b,                                             \
 135                       _GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)),         \
 136                       _GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
 137 
 138 #define INT_ADD_RANGE_OVERFLOW(a, b, min, max)                          \
 139     ((b) < 0                                                            \
 140         ? (a) < (min) - (b)                                             \
 141         : (max) - (b) < (a))
 142 
 143 
 144 /* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
 145    __builtin_sub_overflow_p and __builtin_mul_overflow_p.  */
 146 #if defined __clang__ || defined __ICC
 147 /* Clang 11 lacks __builtin_mul_overflow_p, and even if it did it
 148    would presumably run afoul of Clang bug 16404.  ICC 2021.1's
 149    __builtin_add_overflow_p etc. are not treated as integral constant
 150    expressions even when all arguments are.  */
 151 #define _GL_HAS_BUILTIN_OVERFLOW_P 0
 152 #elif defined __has_builtin
 153 #define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p)
 154 #else
 155 #define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
 156 #endif
 157 
 158 /* The _GL*_OVERFLOW macros have the same restrictions as the
 159  *_RANGE_OVERFLOW macros, except that they do not assume that operands
 160  (e.g., A and B) have the same type as MIN and MAX.  Instead, they assume
 161  that the result (e.g., A + B) has that type.  */
 162 #if _GL_HAS_BUILTIN_OVERFLOW_P
 163 #define _GL_ADD_OVERFLOW(a, b, min, max)                                \
 164    __builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0)
 165 #else
 166 #define _GL_ADD_OVERFLOW(a, b, min, max)                                \
 167    ((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max)                 \
 168     : (a) < 0 ? (b) <= (a) + (b)                                        \
 169     : (b) < 0 ? (a) <= (a) + (b)                                        \
 170     : (a) + (b) < (b))
 171 #endif
 172 
 173 /* Bound on length of the string representing an integer type or expression T.
 174    T must not be a bit-field expression.
 175 
 176    Subtract 1 for the sign bit if T is signed, and then add 1 more for
 177    a minus sign if needed.
 178 
 179    Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 1 when its argument is
 180    unsigned, this macro may overestimate the true bound by one byte when
 181    applied to unsigned types of size 2, 4, 16, ... bytes.  */
 182 #define INT_STRLEN_BOUND(t)                                               \
 183     (INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \
 184         + _GL_SIGNED_TYPE_OR_EXPR (t))
 185 
 186 /* Bound on buffer size needed to represent an integer type or expression T,
 187    including the terminating null.  T must not be a bit-field expression.  */
 188 #define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
 189 
 190 #define UINTMAX_STRSIZE_BOUND INT_BUFSIZE_BOUND (uintmax_t)
 191 
 192 #define INT_ADD_OVERFLOW(a, b) \
 193     _GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW)
 194 
 195 #define SPARSES_INIT_COUNT SPARSES_IN_SPARSE_HEADER
 196 
 197 #define COPY_BUF(arch,b,buf,src)                                         \
 198 do                                                                       \
 199 {                                                                        \
 200     char *endp = b->buffer + BLOCKSIZE;                                  \
 201     char *dst = buf;                                                     \
 202     do                                                                   \
 203     {                                                                    \
 204         if (dst == buf + UINTMAX_STRSIZE_BOUND - 1)                      \
 205             /* numeric overflow in sparse archive member */              \
 206             return FALSE;                                                \
 207         if (src == endp)                                                 \
 208         {                                                                \
 209             tar_set_next_block_after (b);                                \
 210             b = tar_find_next_block (arch);                              \
 211             if (b == NULL)                                               \
 212                 /* unexpected EOF in archive */                          \
 213                 return FALSE;                                            \
 214             src = b->buffer;                                             \
 215             endp = b->buffer + BLOCKSIZE;                                \
 216         }                                                                \
 217         *dst = *src++;                                                   \
 218     }                                                                    \
 219     while (*dst++ != '\n');                                              \
 220     dst[-1] = '\0';                                                      \
 221 }                                                                        \
 222 while (FALSE)
 223 
 224 /*** file scope type declarations ****************************************************************/
 225 
 226 struct tar_sparse_file;
 227 
 228 struct tar_sparse_optab
 229 {
 230     gboolean (*init) (struct tar_sparse_file * file);
 231     gboolean (*done) (struct tar_sparse_file * file);
 232     gboolean (*sparse_member_p) (struct tar_sparse_file * file);
 233     gboolean (*fixup_header) (struct tar_sparse_file * file);
 234     gboolean (*decode_header) (tar_super_t * archive, struct tar_sparse_file * file);
 235 };
 236 
 237 struct tar_sparse_file
 238 {
 239     int fd;                     /**< File descriptor */
 240     off_t dumped_size;          /**< Number of bytes actually written to the archive */
 241     struct tar_stat_info *stat_info;    /**< Information about the file */
 242     struct tar_sparse_optab const *optab;
 243     void *closure;              /**< Any additional data optab calls might reqiure */
 244 };
 245 
 246 enum oldgnu_add_status
 247 {
 248     add_ok,
 249     add_finish,
 250     add_fail
 251 };
 252 
 253 /*** forward declarations (file scope functions) *************************************************/
 254 
 255 static gboolean oldgnu_sparse_member_p (struct tar_sparse_file *file);
 256 static gboolean oldgnu_fixup_header (struct tar_sparse_file *file);
 257 static gboolean oldgnu_get_sparse_info (tar_super_t * archive, struct tar_sparse_file *file);
 258 
 259 static gboolean star_sparse_member_p (struct tar_sparse_file *file);
 260 static gboolean star_fixup_header (struct tar_sparse_file *file);
 261 static gboolean star_get_sparse_info (tar_super_t * archive, struct tar_sparse_file *file);
 262 
 263 static gboolean pax_sparse_member_p (struct tar_sparse_file *file);
 264 static gboolean pax_decode_header (tar_super_t * archive, struct tar_sparse_file *file);
 265 
 266 /*** file scope variables ************************************************************************/
 267 
 268 /* *INDENT-OFF* */
 269 static struct tar_sparse_optab const oldgnu_optab =
 270 {
 271     .init = NULL,               /* No init function */
 272     .done = NULL,               /* No done function */
 273     .sparse_member_p = oldgnu_sparse_member_p,
 274     .fixup_header = oldgnu_fixup_header,
 275     .decode_header = oldgnu_get_sparse_info
 276 };
 277 /* *INDENT-ON* */
 278 
 279 /* *INDENT-OFF* */
 280 static struct tar_sparse_optab const star_optab =
 281 {
 282     .init = NULL,               /* No init function */
 283     .done = NULL,               /* No done function */
 284     .sparse_member_p = star_sparse_member_p,
 285     .fixup_header = star_fixup_header,
 286     .decode_header = star_get_sparse_info
 287 };
 288 /* *INDENT-ON* */
 289 
 290 /* GNU PAX sparse file format. There are several versions:
 291  * 0.0
 292 
 293  The initial version of sparse format used by tar 1.14-1.15.1.
 294  The sparse file map is stored in x header:
 295 
 296  GNU.sparse.size      Real size of the stored file
 297  GNU.sparse.numblocks Number of blocks in the sparse map repeat numblocks time
 298  GNU.sparse.offset    Offset of the next data block
 299  GNU.sparse.numbytes  Size of the next data block end repeat
 300 
 301  This has been reported as conflicting with the POSIX specs. The reason is
 302  that offsets and sizes of non-zero data blocks were stored in multiple instances
 303  of GNU.sparse.offset/GNU.sparse.numbytes variables, whereas POSIX requires the
 304  latest occurrence of the variable to override all previous occurrences.
 305 
 306  To avoid this incompatibility two following versions were introduced.
 307 
 308  * 0.1
 309 
 310  Used by tar 1.15.2 -- 1.15.91 (alpha releases).
 311 
 312  The sparse file map is stored in x header:
 313 
 314  GNU.sparse.size      Real size of the stored file
 315  GNU.sparse.numblocks Number of blocks in the sparse map
 316  GNU.sparse.map       Map of non-null data chunks. A string consisting of comma-separated
 317  values "offset,size[,offset,size]..."
 318 
 319  The resulting GNU.sparse.map string can be *very* long. While POSIX does not impose
 320  any limit on the length of a x header variable, this can confuse some tars.
 321 
 322  * 1.0
 323 
 324  Starting from this version, the exact sparse format version is specified explicitly
 325  in the header using the following variables:
 326 
 327  GNU.sparse.major     Major version 
 328  GNU.sparse.minor     Minor version
 329 
 330  X header keeps the following variables:
 331 
 332  GNU.sparse.name      Real file name of the sparse file
 333  GNU.sparse.realsize  Real size of the stored file (corresponds to the old GNU.sparse.size
 334  variable)
 335 
 336  The name field of the ustar header is constructed using the pattern "%d/GNUSparseFile.%p/%f".
 337 
 338  The sparse map itself is stored in the file data block, preceding the actual file data.
 339  It consists of a series of octal numbers of arbitrary length, delimited by newlines.
 340  The map is padded with nulls to the nearest block boundary.
 341 
 342  The first number gives the number of entries in the map. Following are map entries, each one
 343  consisting of two numbers giving the offset and size of the data block it describes.
 344 
 345  The format is designed in such a way that non-posix aware tars and tars not supporting
 346  GNU.sparse.* keywords will extract each sparse file in its condensed form with the file map
 347  attached and will place it into a separate directory. Then, using a simple program it would be
 348  possible to expand the file to its original form even without GNU tar.
 349 
 350  Bu default, v.1.0 archives are created. To use other formats, --sparse-version option is provided.
 351  Additionally, v.0.0 can be obtained by deleting GNU.sparse.map from 0.1 format:
 352  --sparse-version 0.1 --pax-option delete=GNU.sparse.map
 353  */
 354 
 355 static struct tar_sparse_optab const pax_optab = {
 356     .init = NULL,               /* No init function */
 357     .done = NULL,               /* No done function */
 358     .sparse_member_p = pax_sparse_member_p,
 359     .fixup_header = NULL,       /* No fixup_header function */
 360     .decode_header = pax_decode_header
 361 };
 362 
 363 /* --------------------------------------------------------------------------------------------- */
 364 /*** file scope functions ************************************************************************/
 365 /* --------------------------------------------------------------------------------------------- */
 366 
 367 static gboolean
 368 decode_num (uintmax_t * num, const char *arg, uintmax_t maxval)
     /* [previous][next][first][last][top][bottom][index][help]  */
 369 {
 370     uintmax_t u;
 371     char *arg_lim;
 372 
 373     if (!isdigit (*arg))
 374         return FALSE;
 375 
 376     errno = 0;
 377     u = (uintmax_t) g_ascii_strtoll (arg, &arg_lim, 10);
 378 
 379     if (!(u <= maxval && errno != ERANGE) || *arg_lim != '\0')
 380         return FALSE;
 381 
 382     *num = u;
 383     return TRUE;
 384 }
 385 
 386 /* --------------------------------------------------------------------------------------------- */
 387 
 388 static gboolean
 389 sparse_select_optab (const tar_super_t * archive, struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 390 {
 391     switch (archive->type)
 392     {
 393     case TAR_V7:
 394     case TAR_USTAR:
 395         return FALSE;
 396 
 397     case TAR_OLDGNU:
 398     case TAR_GNU:              /* FIXME: This one should disappear? */
 399         file->optab = &oldgnu_optab;
 400         break;
 401 
 402     case TAR_POSIX:
 403         file->optab = &pax_optab;
 404         break;
 405 
 406     case TAR_STAR:
 407         file->optab = &star_optab;
 408         break;
 409 
 410     default:
 411         return FALSE;
 412     }
 413 
 414     return TRUE;
 415 }
 416 
 417 /* --------------------------------------------------------------------------------------------- */
 418 
 419 static gboolean
 420 sparse_init (tar_super_t * archive, struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 421 {
 422     memset (file, 0, sizeof (*file));
 423 
 424     if (!sparse_select_optab (archive, file))
 425         return FALSE;
 426 
 427     if (file->optab->init != NULL)
 428         return file->optab->init (file);
 429 
 430     return TRUE;
 431 }
 432 
 433 /* --------------------------------------------------------------------------------------------- */
 434 
 435 static gboolean
 436 sparse_done (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 437 {
 438     if (file->optab->done != NULL)
 439         return file->optab->done (file);
 440 
 441     return TRUE;
 442 }
 443 
 444 /* --------------------------------------------------------------------------------------------- */
 445 
 446 static gboolean
 447 sparse_member_p (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 448 {
 449     if (file->optab->sparse_member_p != NULL)
 450         return file->optab->sparse_member_p (file);
 451 
 452     return FALSE;
 453 }
 454 
 455 /* --------------------------------------------------------------------------------------------- */
 456 
 457 static gboolean
 458 sparse_fixup_header (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 459 {
 460     if (file->optab->fixup_header != NULL)
 461         return file->optab->fixup_header (file);
 462 
 463     return TRUE;
 464 }
 465 
 466 /* --------------------------------------------------------------------------------------------- */
 467 
 468 static gboolean
 469 sparse_decode_header (tar_super_t * archive, struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 470 {
 471     if (file->optab->decode_header != NULL)
 472         return file->optab->decode_header (archive, file);
 473 
 474     return TRUE;
 475 }
 476 
 477 /* --------------------------------------------------------------------------------------------- */
 478 
 479 static inline void
 480 sparse_add_map (struct tar_stat_info *st, struct sp_array *sp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 481 {
 482     if (st->sparse_map == NULL)
 483         st->sparse_map = g_array_sized_new (FALSE, FALSE, sizeof (struct sp_array), 1);
 484     g_array_append_val (st->sparse_map, *sp);
 485 }
 486 
 487 /* --------------------------------------------------------------------------------------------- */
 488 
 489 /**
 490  * Add a sparse item to the sparse file
 491  */
 492 static enum oldgnu_add_status
 493 oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 494 {
 495     struct sp_array sp;
 496 
 497     if (s->numbytes[0] == '\0')
 498         return add_finish;
 499 
 500     sp.offset = OFF_FROM_HEADER (s->offset);
 501     sp.numbytes = OFF_FROM_HEADER (s->numbytes);
 502 
 503     if (sp.offset < 0 || sp.numbytes < 0
 504         || INT_ADD_OVERFLOW (sp.offset, sp.numbytes)
 505         || file->stat_info->stat.st_size < sp.offset + sp.numbytes
 506         || file->stat_info->archive_file_size < 0)
 507         return add_fail;
 508 
 509     sparse_add_map (file->stat_info, &sp);
 510 
 511     return add_ok;
 512 }
 513 
 514 /* --------------------------------------------------------------------------------------------- */
 515 
 516 static gboolean
 517 oldgnu_sparse_member_p (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 518 {
 519     (void) file;
 520 
 521     return current_header->header.typeflag == GNUTYPE_SPARSE;
 522 }
 523 
 524 /* --------------------------------------------------------------------------------------------- */
 525 
 526 static gboolean
 527 oldgnu_fixup_header (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 528 {
 529     /* NOTE! st_size was initialized from the header which actually contains archived size.
 530        The following fixes it */
 531     off_t realsize;
 532 
 533     realsize = OFF_FROM_HEADER (current_header->oldgnu_header.realsize);
 534     file->stat_info->archive_file_size = file->stat_info->stat.st_size;
 535     file->stat_info->stat.st_size = MAX (0, realsize);
 536 
 537     return (realsize >= 0);
 538 }
 539 
 540 /* --------------------------------------------------------------------------------------------- */
 541 
 542 /**
 543  * Convert old GNU format sparse data to internal representation.
 544  */
 545 static gboolean
 546 oldgnu_get_sparse_info (tar_super_t * archive, struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 547 {
 548     size_t i;
 549     union block *h = current_header;
 550     gboolean ext_p;
 551     enum oldgnu_add_status rc = add_fail;
 552 
 553     if (file->stat_info->sparse_map != NULL)
 554         g_array_set_size (file->stat_info->sparse_map, 0);
 555 
 556     for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++)
 557     {
 558         rc = oldgnu_add_sparse (file, &h->oldgnu_header.sp[i]);
 559         if (rc != add_ok)
 560             break;
 561     }
 562 
 563     for (ext_p = h->oldgnu_header.isextended != 0; rc == add_ok && ext_p;
 564          ext_p = h->sparse_header.isextended != 0)
 565     {
 566         h = tar_find_next_block (archive);
 567         if (h == NULL)
 568             return FALSE;
 569 
 570         tar_set_next_block_after (h);
 571 
 572         for (i = 0; i < SPARSES_IN_SPARSE_HEADER && rc == add_ok; i++)
 573             rc = oldgnu_add_sparse (file, &h->sparse_header.sp[i]);
 574     }
 575 
 576     return (rc != add_fail);
 577 }
 578 
 579 /* --------------------------------------------------------------------------------------------- */
 580 
 581 static gboolean
 582 star_sparse_member_p (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 583 {
 584     (void) file;
 585 
 586     return current_header->header.typeflag == GNUTYPE_SPARSE;
 587 }
 588 
 589 /* --------------------------------------------------------------------------------------------- */
 590 
 591 static gboolean
 592 star_fixup_header (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 593 {
 594     /* NOTE! st_size was initialized from the header which actually contains archived size.
 595        The following fixes it */
 596     off_t realsize;
 597 
 598     realsize = OFF_FROM_HEADER (current_header->star_in_header.realsize);
 599     file->stat_info->archive_file_size = file->stat_info->stat.st_size;
 600     file->stat_info->stat.st_size = MAX (0, realsize);
 601 
 602     return (realsize >= 0);
 603 }
 604 
 605 /* --------------------------------------------------------------------------------------------- */
 606 
 607 /**
 608  * Convert STAR format sparse data to internal representation
 609  */
 610 static gboolean
 611 star_get_sparse_info (tar_super_t * archive, struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 612 {
 613     size_t i;
 614     union block *h = current_header;
 615     gboolean ext_p = TRUE;
 616     enum oldgnu_add_status rc = add_ok;
 617 
 618     if (file->stat_info->sparse_map != NULL)
 619         g_array_set_size (file->stat_info->sparse_map, 0);
 620 
 621     if (h->star_in_header.prefix[0] == '\0' && h->star_in_header.sp[0].offset[10] != '\0')
 622     {
 623         /* Old star format */
 624         for (i = 0; i < SPARSES_IN_STAR_HEADER; i++)
 625         {
 626             rc = oldgnu_add_sparse (file, &h->star_in_header.sp[i]);
 627             if (rc != add_ok)
 628                 break;
 629         }
 630 
 631         ext_p = h->star_in_header.isextended != 0;
 632     }
 633 
 634     for (; rc == add_ok && ext_p; ext_p = h->star_ext_header.isextended != 0)
 635     {
 636         h = tar_find_next_block (archive);
 637         if (h == NULL)
 638             return FALSE;
 639 
 640         tar_set_next_block_after (h);
 641 
 642         for (i = 0; i < SPARSES_IN_STAR_EXT_HEADER && rc == add_ok; i++)
 643             rc = oldgnu_add_sparse (file, &h->star_ext_header.sp[i]);
 644 
 645         file->dumped_size += BLOCKSIZE;
 646     }
 647 
 648     return (rc != add_fail);
 649 }
 650 
 651 /* --------------------------------------------------------------------------------------------- */
 652 
 653 static gboolean
 654 pax_sparse_member_p (struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 655 {
 656     return file->stat_info->sparse_map != NULL && file->stat_info->sparse_map->len > 0
 657         && file->stat_info->sparse_major > 0;
 658 }
 659 
 660 /* --------------------------------------------------------------------------------------------- */
 661 
 662 static gboolean
 663 pax_decode_header (tar_super_t * archive, struct tar_sparse_file *file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 664 {
 665     if (file->stat_info->sparse_major > 0)
 666     {
 667         uintmax_t u;
 668         char nbuf[UINTMAX_STRSIZE_BOUND];
 669         union block *blk;
 670         char *p;
 671         size_t sparse_map_len;
 672         size_t i;
 673         off_t start;
 674 
 675         start = tar_current_block_ordinal (archive);
 676         tar_set_next_block_after (current_header);
 677         blk = tar_find_next_block (archive);
 678         if (blk == NULL)
 679             /* unexpected EOF in archive */
 680             return FALSE;
 681         p = blk->buffer;
 682         COPY_BUF (archive, blk, nbuf, p);
 683 
 684         if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)))
 685         {
 686             /* malformed sparse archive member */
 687             return FALSE;
 688         }
 689 
 690         if (file->stat_info->sparse_map == NULL)
 691             file->stat_info->sparse_map =
 692                 g_array_sized_new (FALSE, FALSE, sizeof (struct sp_array), u);
 693         else
 694             g_array_set_size (file->stat_info->sparse_map, u);
 695 
 696         sparse_map_len = u;
 697 
 698         for (i = 0; i < sparse_map_len; i++)
 699         {
 700             struct sp_array sp;
 701 
 702             COPY_BUF (archive, blk, nbuf, p);
 703             if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t)))
 704             {
 705                 /* malformed sparse archive member */
 706                 return FALSE;
 707             }
 708             sp.offset = u;
 709             COPY_BUF (archive, blk, nbuf, p);
 710             if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t)) || INT_ADD_OVERFLOW (sp.offset, u)
 711                 || (uintmax_t) file->stat_info->stat.st_size < sp.offset + u)
 712             {
 713                 /* malformed sparse archive member */
 714                 return FALSE;
 715             }
 716             sp.numbytes = u;
 717             sparse_add_map (file->stat_info, &sp);
 718         }
 719 
 720         tar_set_next_block_after (blk);
 721 
 722         file->dumped_size += BLOCKSIZE * (tar_current_block_ordinal (archive) - start);
 723     }
 724 
 725     return TRUE;
 726 }
 727 
 728 /* --------------------------------------------------------------------------------------------- */
 729 /*** public functions ****************************************************************************/
 730 /* --------------------------------------------------------------------------------------------- */
 731 
 732 gboolean
 733 tar_sparse_member_p (tar_super_t * archive, struct tar_stat_info * st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 734 {
 735     struct tar_sparse_file file;
 736 
 737     if (!sparse_init (archive, &file))
 738         return FALSE;
 739 
 740     file.stat_info = st;
 741     return sparse_member_p (&file);
 742 }
 743 
 744 /* --------------------------------------------------------------------------------------------- */
 745 
 746 gboolean
 747 tar_sparse_fixup_header (tar_super_t * archive, struct tar_stat_info * st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 748 {
 749     struct tar_sparse_file file;
 750 
 751     if (!sparse_init (archive, &file))
 752         return FALSE;
 753 
 754     file.stat_info = st;
 755     return sparse_fixup_header (&file);
 756 }
 757 
 758 /* --------------------------------------------------------------------------------------------- */
 759 
 760 enum dump_status
 761 tar_sparse_skip_file (tar_super_t * archive, struct tar_stat_info *st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 762 {
 763     gboolean rc = TRUE;
 764     struct tar_sparse_file file;
 765 
 766     if (!sparse_init (archive, &file))
 767         return dump_status_not_implemented;
 768 
 769     file.stat_info = st;
 770     file.fd = -1;
 771 
 772     rc = sparse_decode_header (archive, &file);
 773     (void) tar_skip_file (archive, file.stat_info->archive_file_size - file.dumped_size);
 774     return (sparse_done (&file) && rc) ? dump_status_ok : dump_status_short;
 775 }
 776 
 777 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */