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

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

DEFINITIONS

This source file includes following definitions.
  1. locate_handler
  2. keyword_item_run
  3. keyword_item_free
  4. xheader_list_append
  5. xheader_list_destroy
  6. run_override_list
  7. decode_timespec
  8. decode_time
  9. decode_signed_num
  10. decode_num
  11. raw_path_decoder
  12. dummy_decoder
  13. atime_decoder
  14. gid_decoder
  15. gname_decoder
  16. linkpath_decoder
  17. ctime_decoder
  18. mtime_decoder
  19. path_decoder
  20. size_decoder
  21. uid_decoder
  22. uname_decoder
  23. dumpdir_decoder
  24. decode_record
  25. decg
  26. decx
  27. sparse_path_decoder
  28. sparse_major_decoder
  29. sparse_minor_decoder
  30. sparse_size_decoder
  31. sparse_numblocks_decoder
  32. sparse_offset_decoder
  33. sparse_numbytes_decoder
  34. sparse_map_decoder
  35. tar_xheader_decode
  36. tar_xheader_read
  37. tar_xheader_decode_global
  38. tar_xheader_destroy

   1 /*
   2    Virtual File System: GNU Tar file system.
   3 
   4    Copyright (C) 1995-2025
   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 <https://www.gnu.org/licenses/>.
  24  */
  25 
  26 /**
  27  * \file
  28  * \brief Source: Virtual File System: GNU Tar file system
  29  */
  30 
  31 #include <config.h>
  32 
  33 #include <ctype.h>  // isdigit()
  34 #include <stdlib.h>
  35 #include <string.h>
  36 
  37 #include "lib/global.h"
  38 #include "lib/util.h"  // MC_PTR_FREE
  39 
  40 #include "tar-internal.h"
  41 
  42 /*** global variables ****************************************************************************/
  43 
  44 /*** file scope macro definitions ****************************************************************/
  45 
  46 #define XHDR_PROTECTED 0x01
  47 #define XHDR_GLOBAL    0x02
  48 
  49 /*** file scope type declarations ****************************************************************/
  50 
  51 /* General Interface */
  52 
  53 /* Since tar VFS is read-only, inplement decodes only */
  54 struct xhdr_tab
  55 {
  56     const char *keyword;
  57     gboolean (*decoder) (struct tar_stat_info *st, const char *keyword, const char *arg,
  58                          size_t size);
  59     int flags;
  60 };
  61 
  62 /* Keyword options */
  63 struct keyword_item
  64 {
  65     char *pattern;
  66     char *value;
  67 };
  68 
  69 enum decode_record_status
  70 {
  71     decode_record_ok,
  72     decode_record_finish,
  73     decode_record_fail
  74 };
  75 
  76 /*** forward declarations (file scope functions) *************************************************/
  77 
  78 static gboolean dummy_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  79                                size_t size);
  80 static gboolean atime_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  81                                size_t size);
  82 static gboolean gid_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  83                              size_t size);
  84 #if 0
  85 static gboolean gname_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  86                                size_t size);
  87 #endif
  88 static gboolean linkpath_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  89                                   size_t size);
  90 static gboolean mtime_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  91                                size_t size);
  92 static gboolean ctime_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  93                                size_t size);
  94 static gboolean path_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  95                               size_t size);
  96 static gboolean size_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  97                               size_t size);
  98 static gboolean uid_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
  99                              size_t size);
 100 #if 0
 101 static gboolean uname_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
 102                                size_t size);
 103 #endif
 104 static gboolean sparse_path_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
 105                                      size_t size);
 106 static gboolean sparse_major_decoder (struct tar_stat_info *st, const char *keyword,
 107                                       const char *arg, size_t size);
 108 static gboolean sparse_minor_decoder (struct tar_stat_info *st, const char *keyword,
 109                                       const char *arg, size_t size);
 110 static gboolean sparse_size_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
 111                                      size_t size);
 112 static gboolean sparse_numblocks_decoder (struct tar_stat_info *st, const char *keyword,
 113                                           const char *arg, size_t size);
 114 static gboolean sparse_offset_decoder (struct tar_stat_info *st, const char *keyword,
 115                                        const char *arg, size_t size);
 116 static gboolean sparse_numbytes_decoder (struct tar_stat_info *st, const char *keyword,
 117                                          const char *arg, size_t size);
 118 static gboolean sparse_map_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
 119                                     size_t size);
 120 static gboolean dumpdir_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
 121                                  size_t size);
 122 
 123 /*** file scope variables ************************************************************************/
 124 
 125 enum
 126 {
 127     BILLION = 1000000000,
 128     LOG10_BILLION = 9
 129 };
 130 
 131 static struct xhdr_tab xhdr_tab[] = {
 132     { "atime", atime_decoder, 0 },
 133     { "comment", dummy_decoder, 0 },
 134     { "charset", dummy_decoder, 0 },
 135     { "ctime", ctime_decoder, 0 },
 136     { "gid", gid_decoder, 0 },
 137 #if 0
 138     { "gname",                gname_decoder,            0  },
 139 #endif
 140     { "linkpath", linkpath_decoder, 0 },
 141     { "mtime", mtime_decoder, 0 },
 142     { "path", path_decoder, 0 },
 143     { "size", size_decoder, 0 },
 144     { "uid", uid_decoder, 0 },
 145 #if 0
 146     { "uname",                uname_decoder,            0  },
 147 #endif
 148 
 149     // Sparse file handling
 150     { "GNU.sparse.name", sparse_path_decoder, XHDR_PROTECTED },
 151     { "GNU.sparse.major", sparse_major_decoder, XHDR_PROTECTED },
 152     { "GNU.sparse.minor", sparse_minor_decoder, XHDR_PROTECTED },
 153     { "GNU.sparse.realsize", sparse_size_decoder, XHDR_PROTECTED },
 154     { "GNU.sparse.numblocks", sparse_numblocks_decoder, XHDR_PROTECTED },
 155 
 156     { "GNU.sparse.size", sparse_size_decoder, XHDR_PROTECTED },
 157     /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
 158        headers, and each of them was meaningful. It confilcted with POSIX specs,
 159        which requires that "when extended header records conflict, the last one
 160        given in the header shall take precedence." */
 161     { "GNU.sparse.offset", sparse_offset_decoder, XHDR_PROTECTED },
 162     { "GNU.sparse.numbytes", sparse_numbytes_decoder, XHDR_PROTECTED },
 163     // tar 1.15.90 keyword, introduced to remove the above-mentioned conflict.
 164     { "GNU.sparse.map", sparse_map_decoder, 0 },
 165 
 166     { "GNU.dumpdir", dumpdir_decoder, XHDR_PROTECTED },
 167 
 168     { NULL, NULL, 0 },
 169 };
 170 
 171 /* List of keyword/value pairs decoded from the last 'g' type header */
 172 static GSList *global_header_override_list = NULL;
 173 
 174 /* --------------------------------------------------------------------------------------------- */
 175 /*** file scope functions ************************************************************************/
 176 /* --------------------------------------------------------------------------------------------- */
 177 
 178 static struct xhdr_tab *
 179 locate_handler (const char *keyword)
     /* [previous][next][first][last][top][bottom][index][help]  */
 180 {
 181     struct xhdr_tab *p;
 182 
 183     for (p = xhdr_tab; p->keyword != NULL; p++)
 184         if (strcmp (p->keyword, keyword) == 0)
 185             return p;
 186 
 187     return NULL;
 188 }
 189 
 190 /* --------------------------------------------------------------------------------------------- */
 191 
 192 static gboolean
 193 keyword_item_run (gpointer data, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 194 {
 195     struct keyword_item *kp = (struct keyword_item *) data;
 196     struct tar_stat_info *st = (struct tar_stat_info *) user_data;
 197     struct xhdr_tab const *t;
 198 
 199     t = locate_handler (kp->pattern);
 200     if (t != NULL)
 201         return t->decoder (st, t->keyword, kp->value, strlen (kp->value));
 202 
 203     return TRUE;  // FIXME
 204 }
 205 
 206 /* --------------------------------------------------------------------------------------------- */
 207 
 208 static void
 209 keyword_item_free (gpointer data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 210 {
 211     struct keyword_item *kp = (struct keyword_item *) data;
 212 
 213     g_free (kp->pattern);
 214     g_free (kp->value);
 215     g_free (kp);
 216 }
 217 
 218 /* --------------------------------------------------------------------------------------------- */
 219 
 220 static void
 221 xheader_list_append (GSList **root, const char *kw, const char *value)
     /* [previous][next][first][last][top][bottom][index][help]  */
 222 {
 223     struct keyword_item *kp;
 224 
 225     kp = g_new (struct keyword_item, 1);
 226     kp->pattern = g_strdup (kw);
 227     kp->value = g_strdup (value);
 228     *root = g_slist_prepend (*root, kp);
 229 }
 230 
 231 /* --------------------------------------------------------------------------------------------- */
 232 
 233 static inline void
 234 xheader_list_destroy (GSList **root)
     /* [previous][next][first][last][top][bottom][index][help]  */
 235 {
 236     g_slist_free_full (*root, keyword_item_free);
 237     *root = NULL;
 238 }
 239 
 240 /* --------------------------------------------------------------------------------------------- */
 241 
 242 static inline void
 243 run_override_list (GSList *kp, struct tar_stat_info *st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 244 {
 245     g_slist_foreach (kp, (GFunc) keyword_item_run, st);
 246 }
 247 
 248 /* --------------------------------------------------------------------------------------------- */
 249 
 250 static struct timespec
 251 decode_timespec (const char *arg, char **arg_lim, gboolean parse_fraction)
     /* [previous][next][first][last][top][bottom][index][help]  */
 252 {
 253     int ns = -1;
 254     gboolean overflow = FALSE;
 255     time_t s;
 256     char const *p;
 257     struct timespec r;
 258 
 259     s = stoint (arg, arg_lim, &overflow, TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t));
 260     p = *arg_lim;
 261 
 262     if (p != arg)
 263     {
 264         ns = 0;
 265 
 266         if (parse_fraction && *p == '.')
 267         {
 268             int digits = 0;
 269             gboolean trailing_nonzero = FALSE;
 270 
 271             while (isdigit (*++p))
 272                 if (digits < LOG10_BILLION)
 273                 {
 274                     digits++;
 275                     ns = 10 * ns + (*p - '0');
 276                 }
 277                 else if (*p != '0')
 278                     trailing_nonzero = TRUE;
 279 
 280             *arg_lim = (char *) p;
 281 
 282             while (digits < LOG10_BILLION)
 283             {
 284                 digits++;
 285                 ns *= 10;
 286             }
 287 
 288             if (*arg == '-')
 289             {
 290                 /* Convert "-1.10000000000001" to s == -2, ns == 89999999.
 291                    I.e., truncate time stamps towards minus infinity while
 292                    converting them to internal form.  */
 293                 if (trailing_nonzero)
 294                     ns++;
 295                 if (ns != 0)
 296                     ns = ckd_sub (&s, s, 1) ? -1 : BILLION - ns;
 297             }
 298         }
 299 
 300         if (overflow)
 301             ns = -1;
 302     }
 303 
 304     r.tv_sec = s;
 305     r.tv_nsec = ns;
 306     return r;
 307 }
 308 
 309 /* --------------------------------------------------------------------------------------------- */
 310 
 311 static gboolean
 312 decode_time (struct timespec *ts, const char *arg, const char *keyword)
     /* [previous][next][first][last][top][bottom][index][help]  */
 313 {
 314     char *arg_lim = NULL;
 315     struct timespec t;
 316 
 317     (void) keyword;
 318 
 319     t = decode_timespec (arg, &arg_lim, TRUE);
 320 
 321     if (t.tv_nsec < 0)
 322         // Malformed extended header
 323         return FALSE;
 324 
 325     if (*arg_lim != '\0')
 326         // Malformed extended header
 327         return FALSE;
 328 
 329     *ts = t;
 330 
 331     return TRUE;
 332 }
 333 
 334 /* --------------------------------------------------------------------------------------------- */
 335 
 336 static gboolean
 337 decode_signed_num (intmax_t *num, const char *arg, intmax_t minval, uintmax_t maxval,
     /* [previous][next][first][last][top][bottom][index][help]  */
 338                    const char *keyword)
 339 {
 340     char *arg_lim = NULL;
 341     gboolean overflow = FALSE;
 342     intmax_t u;
 343 
 344     (void) keyword;
 345 
 346     u = stoint (arg, &arg_lim, &overflow, minval, maxval);
 347 
 348     if (arg_lim == arg || *arg_lim != '\0')
 349         return FALSE;  // malformed extended header
 350 
 351     if (overflow)
 352         return FALSE;  // out of range
 353 
 354     *num = u;
 355     return TRUE;
 356 }
 357 
 358 /* --------------------------------------------------------------------------------------------- */
 359 
 360 static gboolean
 361 decode_num (uintmax_t *num, const char *arg, uintmax_t maxval, const char *keyword)
     /* [previous][next][first][last][top][bottom][index][help]  */
 362 {
 363     intmax_t i;
 364 
 365     if (!decode_signed_num (&i, arg, 0, maxval, keyword))
 366         return FALSE;
 367 
 368     *num = i;
 369     return TRUE;
 370 }
 371 
 372 /* --------------------------------------------------------------------------------------------- */
 373 
 374 static gboolean
 375 raw_path_decoder (struct tar_stat_info *st, const char *arg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 376 {
 377     if (*arg != '\0')
 378     {
 379         tar_assign_string_dup (&st->orig_file_name, arg);
 380         tar_assign_string_dup (&st->file_name, arg);
 381     }
 382 
 383     return TRUE;
 384 }
 385 
 386 /* --------------------------------------------------------------------------------------------- */
 387 
 388 static gboolean
 389 dummy_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 390 {
 391     (void) st;
 392     (void) keyword;
 393     (void) arg;
 394     (void) size;
 395 
 396     return TRUE;
 397 }
 398 
 399 /* --------------------------------------------------------------------------------------------- */
 400 
 401 static gboolean
 402 atime_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 403 {
 404     struct timespec ts;
 405 
 406     (void) size;
 407 
 408     if (!decode_time (&ts, arg, keyword))
 409         return FALSE;
 410 
 411     st->atime = ts;
 412     return TRUE;
 413 }
 414 
 415 /* --------------------------------------------------------------------------------------------- */
 416 
 417 static gboolean
 418 gid_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 419 {
 420     intmax_t u;
 421 
 422     (void) size;
 423 
 424     if (!decode_signed_num (&u, arg, TYPE_MINIMUM (gid_t), TYPE_MINIMUM (gid_t), keyword))
 425         return FALSE;
 426 
 427     st->stat.st_gid = u;
 428     return TRUE;
 429 }
 430 
 431 /* --------------------------------------------------------------------------------------------- */
 432 
 433 #if 0
 434 static gboolean
 435 gname_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 436 {
 437     (void) keyword;
 438     (void) size;
 439 
 440     tar_assign_string_dup (&st->gname, arg);
 441     return TRUE;
 442 }
 443 #endif
 444 
 445 /* --------------------------------------------------------------------------------------------- */
 446 
 447 static gboolean
 448 linkpath_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 449 {
 450     (void) keyword;
 451     (void) size;
 452 
 453     tar_assign_string_dup (&st->link_name, arg);
 454     return TRUE;
 455 }
 456 
 457 /* --------------------------------------------------------------------------------------------- */
 458 
 459 static gboolean
 460 ctime_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 461 {
 462     struct timespec ts;
 463 
 464     (void) size;
 465 
 466     if (!decode_time (&ts, arg, keyword))
 467         return FALSE;
 468 
 469     st->ctime = ts;
 470     return TRUE;
 471 }
 472 
 473 /* --------------------------------------------------------------------------------------------- */
 474 
 475 static gboolean
 476 mtime_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 477 {
 478     struct timespec ts;
 479 
 480     (void) size;
 481 
 482     if (!decode_time (&ts, arg, keyword))
 483         return FALSE;
 484 
 485     st->mtime = ts;
 486     return TRUE;
 487 }
 488 
 489 /* --------------------------------------------------------------------------------------------- */
 490 
 491 static gboolean
 492 path_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 493 {
 494     (void) keyword;
 495     (void) size;
 496 
 497     if (!st->sparse_name_done)
 498         return raw_path_decoder (st, arg);
 499 
 500     return TRUE;  // FIXME
 501 }
 502 
 503 /* --------------------------------------------------------------------------------------------- */
 504 
 505 static gboolean
 506 size_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 507 {
 508     uintmax_t u;
 509 
 510     (void) size;
 511 
 512     if (!decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
 513         return FALSE;
 514 
 515     st->stat.st_size = u;
 516     return TRUE;
 517 }
 518 
 519 /* --------------------------------------------------------------------------------------------- */
 520 
 521 static gboolean
 522 uid_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 523 {
 524     intmax_t u;
 525 
 526     (void) size;
 527 
 528     if (!decode_signed_num (&u, arg, TYPE_MINIMUM (uid_t), TYPE_MAXIMUM (uid_t), keyword))
 529         return FALSE;
 530 
 531     st->stat.st_uid = u;
 532     return TRUE;
 533 }
 534 
 535 /* --------------------------------------------------------------------------------------------- */
 536 
 537 #if 0
 538 static gboolean
 539 uname_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 540 {
 541     (void) keyword;
 542     (void) size;
 543 
 544     tar_assign_string_dup (&st->uname, arg);
 545     return TRUE;
 546 }
 547 #endif
 548 
 549 /* --------------------------------------------------------------------------------------------- */
 550 
 551 static gboolean
 552 dumpdir_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 553 {
 554     (void) keyword;
 555 
 556 #if GLIB_CHECK_VERSION(2, 68, 0)
 557     st->dumpdir = g_memdup2 (arg, size);
 558 #else
 559     st->dumpdir = g_memdup (arg, size);
 560 #endif
 561     return TRUE;
 562 }
 563 
 564 /* --------------------------------------------------------------------------------------------- */
 565 
 566 /**
 567  * Decodes a single extended header record, advancing @ptr to the next record.
 568  *
 569  * @param p pointer to extended header record
 570  * @param st stat info
 571  *
 572  * @return decode_record_ok or decode_record_finish on success, decode_record_fail otherwize
 573  */
 574 static enum decode_record_status
 575 decode_record (struct xheader *xhdr, char **ptr,
     /* [previous][next][first][last][top][bottom][index][help]  */
 576                gboolean (*handler) (void *data, const char *keyword, const char *value,
 577                                     size_t size),
 578                void *data)
 579 {
 580     char *start = *ptr;
 581     char *p = start;
 582     idx_t len;
 583     char *len_lim = NULL;
 584     const char *keyword;
 585     char *nextp;
 586     idx_t len_max;
 587     gboolean ret;
 588 
 589     len_max = xhdr->buffer + xhdr->size - start;
 590 
 591     while (*p == ' ' || *p == '\t')
 592         p++;
 593 
 594     len = stoint (p, &len_lim, NULL, 0, IDX_MAX);
 595 
 596     if (len_lim == p)
 597         // Is the length missing?
 598         return (*p != '\0' ? decode_record_fail : decode_record_finish);
 599 
 600     if (len_max < len)
 601         return decode_record_fail;
 602 
 603     nextp = start + len;
 604 
 605     for (p = len_lim; *p == ' ' || *p == '\t'; p++)
 606         ;
 607 
 608     if (p == len_lim)
 609         return decode_record_fail;
 610 
 611     keyword = p;
 612     p = strchr (p, '=');
 613     if (!(p != NULL && p < nextp))
 614         return decode_record_fail;
 615 
 616     if (nextp[-1] != '\n')
 617         return decode_record_fail;
 618 
 619     *p = nextp[-1] = '\0';
 620     ret = handler (data, keyword, p + 1, nextp - p - 2);  // '=' + trailing '\n'
 621     *p = '=';
 622     nextp[-1] = '\n';
 623     *ptr = nextp;
 624 
 625     return (ret ? decode_record_ok : decode_record_fail);
 626 }
 627 
 628 /* --------------------------------------------------------------------------------------------- */
 629 
 630 static gboolean
 631 decg (void *data, const char *keyword, const char *value, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 632 {
 633     GSList **kwl = (GSList **) data;
 634     struct xhdr_tab const *tab;
 635 
 636     (void) size;
 637 
 638     tab = locate_handler (keyword);
 639     if (tab != NULL && (tab->flags & XHDR_GLOBAL) != 0)
 640     {
 641         if (!tab->decoder (data, keyword, value, size))
 642             return FALSE;
 643     }
 644     else
 645         xheader_list_append (kwl, keyword, value);
 646 
 647     return TRUE;
 648 }
 649 
 650 /* --------------------------------------------------------------------------------------------- */
 651 
 652 static gboolean
 653 decx (void *data, const char *keyword, const char *value, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 654 {
 655     struct keyword_item kp = {
 656         .pattern = (char *) keyword,
 657         .value = (char *) value,
 658     };
 659 
 660     (void) size;
 661 
 662     return keyword_item_run (&kp, data);
 663 }
 664 
 665 /* --------------------------------------------------------------------------------------------- */
 666 
 667 static gboolean
 668 sparse_path_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 669 {
 670     (void) keyword;
 671     (void) size;
 672 
 673     st->sparse_name_done = TRUE;
 674     return raw_path_decoder (st, arg);
 675 }
 676 
 677 /* --------------------------------------------------------------------------------------------- */
 678 
 679 static gboolean
 680 sparse_major_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 681 {
 682     uintmax_t u;
 683 
 684     (void) size;
 685 
 686     if (!decode_num (&u, arg, INTMAX_MAX, keyword))
 687         return FALSE;
 688 
 689     st->sparse_major = u;
 690     return TRUE;
 691 }
 692 
 693 /* --------------------------------------------------------------------------------------------- */
 694 
 695 static gboolean
 696 sparse_minor_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 697 {
 698     uintmax_t u;
 699 
 700     (void) size;
 701 
 702     if (!decode_num (&u, arg, INTMAX_MAX, keyword))
 703         return FALSE;
 704 
 705     st->sparse_minor = u;
 706     return TRUE;
 707 }
 708 
 709 /* --------------------------------------------------------------------------------------------- */
 710 
 711 static gboolean
 712 sparse_size_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 713 {
 714     uintmax_t u;
 715 
 716     (void) size;
 717 
 718     if (!decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
 719         return FALSE;
 720 
 721     st->real_size_set = TRUE;
 722     st->real_size = u;
 723     return TRUE;
 724 }
 725 
 726 /* --------------------------------------------------------------------------------------------- */
 727 
 728 static gboolean
 729 sparse_numblocks_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
     /* [previous][next][first][last][top][bottom][index][help]  */
 730                           size_t size)
 731 {
 732     uintmax_t u;
 733 
 734     (void) size;
 735 
 736     if (!decode_num (&u, arg, SIZE_MAX, keyword))
 737         return FALSE;
 738 
 739     if (st->sparse_map == NULL)
 740         st->sparse_map = g_array_sized_new (FALSE, FALSE, sizeof (struct sp_array), u);
 741     else
 742         g_array_set_size (st->sparse_map, u);
 743 
 744     return TRUE;
 745 }
 746 
 747 /* --------------------------------------------------------------------------------------------- */
 748 
 749 static gboolean
 750 sparse_offset_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 751 {
 752     uintmax_t u;
 753     struct sp_array *s;
 754 
 755     (void) size;
 756 
 757     if (!decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword))
 758         return FALSE;
 759 
 760     s = &g_array_index (st->sparse_map, struct sp_array, st->sparse_map->len - 1);
 761     s->offset = u;
 762     return TRUE;
 763 }
 764 
 765 /* --------------------------------------------------------------------------------------------- */
 766 
 767 static gboolean
 768 sparse_numbytes_decoder (struct tar_stat_info *st, const char *keyword, const char *arg,
     /* [previous][next][first][last][top][bottom][index][help]  */
 769                          size_t size)
 770 {
 771     uintmax_t u;
 772     struct sp_array s;
 773 
 774     (void) size;
 775 
 776     if (!decode_num (&u, arg, SIZE_MAX, keyword))
 777         return FALSE;
 778 
 779     s.offset = 0;
 780     s.numbytes = u;
 781     g_array_append_val (st->sparse_map, s);
 782     return TRUE;
 783 }
 784 
 785 /* --------------------------------------------------------------------------------------------- */
 786 
 787 static gboolean
 788 sparse_map_decoder (struct tar_stat_info *st, const char *keyword, const char *arg, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 789 {
 790     gboolean offset = TRUE;
 791     struct sp_array e;
 792 
 793     (void) keyword;
 794     (void) size;
 795 
 796     if (st->sparse_map != NULL)
 797         g_array_set_size (st->sparse_map, 0);
 798 
 799     while (TRUE)
 800     {
 801         off_t u;
 802         char *delim = NULL;
 803         gboolean overflow = FALSE;
 804 
 805         u = stoint (arg, &delim, &overflow, 0, TYPE_MAXIMUM (off_t));
 806 
 807         if (delim == arg)
 808         {
 809             // malformed extended header
 810             return FALSE;
 811         }
 812 
 813         if (offset)
 814         {
 815             e.offset = u;
 816             if (overflow)
 817             {
 818                 // out of range
 819                 return FALSE;
 820             }
 821         }
 822         else
 823         {
 824             e.numbytes = u;
 825             if (overflow)
 826             {
 827                 // out of range
 828                 return FALSE;
 829             }
 830 
 831             g_array_append_val (st->sparse_map, e);
 832         }
 833 
 834         offset = !offset;
 835 
 836         if (*delim == '\0')
 837             break;
 838         if (*delim != ',')
 839         {
 840             // malformed extended header
 841             return FALSE;
 842         }
 843 
 844         arg = delim + 1;
 845     }
 846 
 847     if (!offset)
 848     {
 849         // malformed extended header
 850         return FALSE;
 851     }
 852 
 853     return TRUE;
 854 }
 855 
 856 /* --------------------------------------------------------------------------------------------- */
 857 /*** public functions ****************************************************************************/
 858 /* --------------------------------------------------------------------------------------------- */
 859 
 860 /**
 861  * Decodes an extended header.
 862  *
 863  * @param st stat info
 864  *
 865  * @return TRUE on success, FALSE otherwize
 866  */
 867 gboolean
 868 tar_xheader_decode (struct tar_stat_info *st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 869 {
 870     char *p;
 871     enum decode_record_status status;
 872 
 873     run_override_list (global_header_override_list, st);
 874 
 875     p = st->xhdr.buffer + BLOCKSIZE;
 876 
 877     while ((status = decode_record (&st->xhdr, &p, decx, st)) == decode_record_ok)
 878         ;
 879 
 880     if (status == decode_record_fail)
 881         return FALSE;
 882 
 883     /* The archived (effective) file size is always set directly in tar header
 884        field, possibly overridden by "size" extended header - in both cases,
 885        result is now decoded in st->stat.st_size */
 886     st->archive_file_size = st->stat.st_size;
 887 
 888     /* The real file size (given by stat()) may be redefined for sparse
 889        files in "GNU.sparse.realsize" extended header */
 890     if (st->real_size_set)
 891         st->stat.st_size = st->real_size;
 892 
 893     return TRUE;
 894 }
 895 
 896 /* --------------------------------------------------------------------------------------------- */
 897 
 898 gboolean
 899 tar_xheader_read (tar_super_t *archive, struct xheader *xhdr, union block *p, off_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 900 {
 901     size_t j = 0;
 902     size_t size_plus_1;
 903 
 904     size = MAX (0, size);
 905     if (ckd_add (&size_plus_1, size, BLOCKSIZE + 1))
 906         return FALSE;
 907     size = size_plus_1 - 1;
 908     xhdr->size = size;
 909     xhdr->buffer = g_malloc (size_plus_1);
 910     xhdr->buffer[size] = '\0';
 911 
 912     do
 913     {
 914         size_t len;
 915 
 916         if (p == NULL)
 917             return FALSE;  // Unexpected EOF in archive
 918 
 919         len = MIN (size, BLOCKSIZE);
 920 
 921         memcpy (xhdr->buffer + j, p->buffer, len);
 922         tar_set_next_block_after (p);
 923         p = tar_find_next_block (archive);
 924 
 925         j += len;
 926         size -= len;
 927     }
 928     while (size > 0);
 929 
 930     return TRUE;
 931 }
 932 
 933 /* --------------------------------------------------------------------------------------------- */
 934 
 935 gboolean
 936 tar_xheader_decode_global (struct xheader *xhdr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 937 {
 938     char *p;
 939     gboolean ret;
 940 
 941     p = xhdr->buffer + BLOCKSIZE;
 942 
 943     xheader_list_destroy (&global_header_override_list);
 944 
 945     while ((ret = decode_record (xhdr, &p, decg, &global_header_override_list)) == decode_record_ok)
 946         ;
 947 
 948     return (ret == decode_record_finish);
 949 }
 950 
 951 /* --------------------------------------------------------------------------------------------- */
 952 
 953 void
 954 tar_xheader_destroy (struct xheader *xhdr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 955 {
 956     MC_PTR_FREE (xhdr->buffer);
 957     xhdr->size = 0;
 958 }
 959 
 960 /* --------------------------------------------------------------------------------------------- */

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