root/src/vfs/tar/tar.c

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

DEFINITIONS

This source file includes following definitions.
  1. tar_from_oct
  2. tar_new_archive
  3. tar_free_archive
  4. tar_open_archive_int
  5. tar_get_next_block
  6. tar_skip_n_records
  7. tar_checksum
  8. tar_decode_header
  9. tar_fill_stat
  10. tar_read_header
  11. tar_open_archive
  12. tar_super_check
  13. tar_super_same
  14. tar_read
  15. tar_fh_open
  16. vfs_init_tarfs

   1 /*
   2    Virtual File System: GNU Tar file system.
   3 
   4    Copyright (C) 1995-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Jakub Jelinek, 1995
   9    Pavel Machek, 1998
  10    Slava Zanko <slavazanko@gmail.com>, 2013
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  26  */
  27 
  28 /**
  29  * \file
  30  * \brief Source: Virtual File System: GNU Tar file system
  31  * \author Jakub Jelinek
  32  * \author Pavel Machek
  33  * \date 1995, 1998
  34  *
  35  * Namespace: init_tarfs
  36  */
  37 
  38 #include <config.h>
  39 #include <sys/types.h>
  40 #include <errno.h>
  41 #include <ctype.h>
  42 
  43 #ifdef hpux
  44 /* major() and minor() macros (among other things) defined here for hpux */
  45 #include <sys/mknod.h>
  46 #endif
  47 
  48 #include "lib/global.h"
  49 #include "lib/util.h"
  50 #include "lib/unixcompat.h"     /* makedev() */
  51 #include "lib/widget.h"         /* message() */
  52 
  53 #include "lib/vfs/vfs.h"
  54 #include "lib/vfs/utilvfs.h"
  55 #include "lib/vfs/xdirentry.h"
  56 #include "lib/vfs/gc.h"         /* vfs_rmstamp */
  57 
  58 #include "tar.h"
  59 
  60 /*** global variables ****************************************************************************/
  61 
  62 /*** file scope macro definitions ****************************************************************/
  63 
  64 #define TAR_SUPER(super) ((tar_super_t *) (super))
  65 
  66 
  67 /* tar Header Block, from POSIX 1003.1-1990.  */
  68 
  69 /* The magic field is filled with this if uname and gname are valid. */
  70 #define TMAGIC "ustar"          /* ustar and a null */
  71 
  72 #define XHDTYPE 'x'             /* Extended header referring to the next file in the archive */
  73 #define XGLTYPE 'g'             /* Global extended header */
  74 
  75 /* Values used in typeflag field.  */
  76 #define LNKTYPE  '1'            /* link */
  77 #define SYMTYPE  '2'            /* symbolic link */
  78 #define CHRTYPE  '3'            /* character special */
  79 #define BLKTYPE  '4'            /* block special */
  80 #define DIRTYPE  '5'            /* directory */
  81 #define FIFOTYPE '6'            /* FIFO special */
  82 
  83 
  84 /* tar Header Block, GNU extensions.  */
  85 
  86 /* *BEWARE* *BEWARE* *BEWARE* that the following information is still
  87    boiling, and may change.  Even if the OLDGNU format description should be
  88    accurate, the so-called GNU format is not yet fully decided.  It is
  89    surely meant to use only extensions allowed by POSIX, but the sketch
  90    below repeats some ugliness from the OLDGNU format, which should rather
  91    go away.  Sparse files should be saved in such a way that they do *not*
  92    require two passes at archive creation time.  Huge files get some POSIX
  93    fields to overflow, alternate solutions have to be sought for this.  */
  94 
  95 
  96 /* Sparse files are not supported in POSIX ustar format.  For sparse files
  97    with a POSIX header, a GNU extra header is provided which holds overall
  98    sparse information and a few sparse descriptors.  When an old GNU header
  99    replaces both the POSIX header and the GNU extra header, it holds some
 100    sparse descriptors too.  Whether POSIX or not, if more sparse descriptors
 101    are still needed, they are put into as many successive sparse headers as
 102    necessary.  The following constants tell how many sparse descriptors fit
 103    in each kind of header able to hold them.  */
 104 
 105 #define SPARSES_IN_EXTRA_HEADER  16
 106 #define SPARSES_IN_OLDGNU_HEADER 4
 107 #define SPARSES_IN_SPARSE_HEADER 21
 108 
 109 /* OLDGNU_MAGIC uses both magic and version fields, which are contiguous.
 110    Found in an archive, it indicates an old GNU header format, which will be
 111    hopefully become obsolescent.  With OLDGNU_MAGIC, uname and gname are
 112    valid, though the header is not truly POSIX conforming.  */
 113 #define OLDGNU_MAGIC "ustar  "  /* 7 chars and a null */
 114 
 115 /* The standards committee allows only capital A through capital Z for user-defined expansion.  */
 116 
 117 /* This is a dir entry that contains the names of files that were in the
 118    dir at the time the dump was made.  */
 119 #define GNUTYPE_DUMPDIR 'D'
 120 
 121 /* Identifies the *next* file on the tape as having a long linkname.  */
 122 #define GNUTYPE_LONGLINK 'K'
 123 
 124 /* Identifies the *next* file on the tape as having a long name.  */
 125 #define GNUTYPE_LONGNAME 'L'
 126 
 127 
 128 /* tar Header Block, overall structure.  */
 129 
 130 /* tar files are made in basic blocks of this size.  */
 131 #define BLOCKSIZE 512
 132 
 133 
 134 #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
 135 
 136 /*** file scope type declarations ****************************************************************/
 137 
 138 /* *INDENT-OFF* */
 139 
 140 /* POSIX header */
 141 struct posix_header
 142 {                               /* byte offset */
 143     char name[100];             /*   0 */
 144     char mode[8];               /* 100 */
 145     char uid[8];                /* 108 */
 146     char gid[8];                /* 116 */
 147     char size[12];              /* 124 */
 148     char mtime[12];             /* 136 */
 149     char chksum[8];             /* 148 */
 150     char typeflag;              /* 156 */
 151     char linkname[100];         /* 157 */
 152     char magic[6];              /* 257 */
 153     char version[2];            /* 263 */
 154     char uname[32];             /* 265 */
 155     char gname[32];             /* 297 */
 156     char devmajor[8];           /* 329 */
 157     char devminor[8];           /* 337 */
 158     char prefix[155];           /* 345 */
 159                                 /* 500 */
 160 };
 161 
 162 /* Descriptor for a single file hole */
 163 struct sparse
 164 {                               /* byte offset */
 165     /* cppcheck-suppress unusedStructMember */
 166     char offset[12];            /*   0 */
 167     /* cppcheck-suppress unusedStructMember */
 168     char numbytes[12];          /*  12 */
 169                                 /*  24 */
 170 };
 171 
 172 /* The GNU extra header contains some information GNU tar needs, but not
 173    foreseen in POSIX header format.  It is only used after a POSIX header
 174    (and never with old GNU headers), and immediately follows this POSIX
 175    header, when typeflag is a letter rather than a digit, so signaling a GNU
 176    extension.  */
 177 struct extra_header
 178 {                               /* byte offset */
 179     char atime[12];             /*   0 */
 180     char ctime[12];             /*  12 */
 181     char offset[12];            /*  24 */
 182     char realsize[12];          /*  36 */
 183     char longnames[4];          /*  48 */
 184     char unused_pad1[68];       /*  52 */
 185     struct sparse sp[SPARSES_IN_EXTRA_HEADER];
 186                                 /* 120 */
 187     char isextended;            /* 504 */
 188                                 /* 505 */
 189 };
 190 
 191 /* Extension header for sparse files, used immediately after the GNU extra
 192    header, and used only if all sparse information cannot fit into that
 193    extra header.  There might even be many such extension headers, one after
 194    the other, until all sparse information has been recorded.  */
 195 struct sparse_header
 196 {                               /* byte offset */
 197     struct sparse sp[SPARSES_IN_SPARSE_HEADER];
 198                                 /*   0 */
 199     char isextended;            /* 504 */
 200                                 /* 505 */
 201 };
 202 
 203 /* The old GNU format header conflicts with POSIX format in such a way that
 204    POSIX archives may fool old GNU tar's, and POSIX tar's might well be
 205    fooled by old GNU tar archives.  An old GNU format header uses the space
 206    used by the prefix field in a POSIX header, and cumulates information
 207    normally found in a GNU extra header.  With an old GNU tar header, we
 208    never see any POSIX header nor GNU extra header.  Supplementary sparse
 209    headers are allowed, however.  */
 210 struct oldgnu_header
 211 {                               /* byte offset */
 212     char unused_pad1[345];      /*   0 */
 213     char atime[12];             /* 345 */
 214     char ctime[12];             /* 357 */
 215     char offset[12];            /* 369 */
 216     char longnames[4];          /* 381 */
 217     char unused_pad2;           /* 385 */
 218     struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
 219                                 /* 386 */
 220     char isextended;            /* 482 */
 221     char realsize[12];          /* 483 */
 222                                 /* 495 */
 223 };
 224 
 225 /* *INDENT-ON* */
 226 
 227 /* tar Header Block, overall structure */
 228 union block
 229 {
 230     char buffer[BLOCKSIZE];
 231     struct posix_header header;
 232     struct extra_header extra_header;
 233     struct oldgnu_header oldgnu_header;
 234     struct sparse_header sparse_header;
 235 };
 236 
 237 enum archive_format
 238 {
 239     TAR_UNKNOWN = 0,
 240     TAR_V7,
 241     TAR_USTAR,
 242     TAR_POSIX,
 243     TAR_GNU
 244 };
 245 
 246 typedef enum
 247 {
 248     STATUS_BADCHECKSUM,
 249     STATUS_SUCCESS,
 250     STATUS_EOFMARK,
 251     STATUS_EOF
 252 } ReadStatus;
 253 
 254 typedef struct
 255 {
 256     struct vfs_s_super base;    /* base class */
 257 
 258     int fd;
 259     struct stat st;
 260     enum archive_format type;   /* Type of the archive */
 261 } tar_super_t;
 262 
 263 /*** file scope variables ************************************************************************/
 264 
 265 static struct vfs_s_subclass tarfs_subclass;
 266 static struct vfs_class *vfs_tarfs_ops = VFS_CLASS (&tarfs_subclass);
 267 
 268 /* As we open one archive at a time, it is safe to have this static */
 269 static off_t current_tar_position = 0;
 270 
 271 static union block block_buf;
 272 
 273 /* --------------------------------------------------------------------------------------------- */
 274 /*** file scope functions ************************************************************************/
 275 /* --------------------------------------------------------------------------------------------- */
 276 /**
 277  * Quick and dirty octal conversion.
 278  *
 279  * Result is -1 if the field is invalid (all blank, or nonoctal).
 280  */
 281 static long
 282 tar_from_oct (int digs, const char *where)
     /* [previous][next][first][last][top][bottom][index][help]  */
 283 {
 284     long value;
 285 
 286     while (isspace ((unsigned char) *where))
 287     {                           /* Skip spaces */
 288         where++;
 289         if (--digs <= 0)
 290             return -1;          /* All blank field */
 291     }
 292     value = 0;
 293     while (digs > 0 && isodigit (*where))
 294     {                           /* Scan till nonoctal */
 295         value = (value << 3) | (*where++ - '0');
 296         --digs;
 297     }
 298 
 299     if (digs > 0 && *where && !isspace ((unsigned char) *where))
 300         return -1;              /* Ended on non-space/nul */
 301 
 302     return value;
 303 }
 304 
 305 /* --------------------------------------------------------------------------------------------- */
 306 
 307 static struct vfs_s_super *
 308 tar_new_archive (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 309 {
 310     tar_super_t *arch;
 311 
 312     arch = g_new0 (tar_super_t, 1);
 313     arch->base.me = me;
 314     arch->fd = -1;
 315     arch->type = TAR_UNKNOWN;
 316 
 317     return VFS_SUPER (arch);
 318 }
 319 
 320 /* --------------------------------------------------------------------------------------------- */
 321 
 322 static void
 323 tar_free_archive (struct vfs_class *me, struct vfs_s_super *archive)
     /* [previous][next][first][last][top][bottom][index][help]  */
 324 {
 325     tar_super_t *arch = TAR_SUPER (archive);
 326 
 327     (void) me;
 328 
 329     if (arch->fd != -1)
 330     {
 331         mc_close (arch->fd);
 332         arch->fd = -1;
 333     }
 334 }
 335 
 336 /* --------------------------------------------------------------------------------------------- */
 337 
 338 /* Returns fd of the open tar file */
 339 static int
 340 tar_open_archive_int (struct vfs_class *me, const vfs_path_t * vpath, struct vfs_s_super *archive)
     /* [previous][next][first][last][top][bottom][index][help]  */
 341 {
 342     int result, type;
 343     tar_super_t *arch;
 344     mode_t mode;
 345     struct vfs_s_inode *root;
 346 
 347     result = mc_open (vpath, O_RDONLY);
 348     if (result == -1)
 349     {
 350         message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), vfs_path_as_str (vpath));
 351         ERRNOR (ENOENT, -1);
 352     }
 353 
 354     archive->name = g_strdup (vfs_path_as_str (vpath));
 355     arch = TAR_SUPER (archive);
 356     mc_stat (vpath, &arch->st);
 357 
 358     /* Find out the method to handle this tar file */
 359     type = get_compression_type (result, archive->name);
 360     if (type == COMPRESSION_NONE)
 361         mc_lseek (result, 0, SEEK_SET);
 362     else
 363     {
 364         char *s;
 365         vfs_path_t *tmp_vpath;
 366 
 367         mc_close (result);
 368         s = g_strconcat (archive->name, decompress_extension (type), (char *) NULL);
 369         tmp_vpath = vfs_path_from_str_flags (s, VPF_NO_CANON);
 370         result = mc_open (tmp_vpath, O_RDONLY);
 371         vfs_path_free (tmp_vpath);
 372         if (result == -1)
 373             message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), s);
 374         g_free (s);
 375         if (result == -1)
 376         {
 377             MC_PTR_FREE (archive->name);
 378             ERRNOR (ENOENT, -1);
 379         }
 380     }
 381 
 382     arch->fd = result;
 383     mode = arch->st.st_mode & 07777;
 384     if (mode & 0400)
 385         mode |= 0100;
 386     if (mode & 0040)
 387         mode |= 0010;
 388     if (mode & 0004)
 389         mode |= 0001;
 390     mode |= S_IFDIR;
 391 
 392     root = vfs_s_new_inode (me, archive, &arch->st);
 393     root->st.st_mode = mode;
 394     root->data_offset = -1;
 395     root->st.st_nlink++;
 396     root->st.st_dev = VFS_SUBCLASS (me)->rdev++;
 397 
 398     archive->root = root;
 399 
 400     return result;
 401 }
 402 
 403 /* --------------------------------------------------------------------------------------------- */
 404 
 405 static union block *
 406 tar_get_next_block (struct vfs_s_super *archive, int tard)
     /* [previous][next][first][last][top][bottom][index][help]  */
 407 {
 408     int n;
 409 
 410     (void) archive;
 411 
 412     n = mc_read (tard, block_buf.buffer, sizeof (block_buf.buffer));
 413     if (n != sizeof (block_buf.buffer))
 414         return NULL;            /* An error has occurred */
 415     current_tar_position += sizeof (block_buf.buffer);
 416     return &block_buf;
 417 }
 418 
 419 /* --------------------------------------------------------------------------------------------- */
 420 
 421 static void
 422 tar_skip_n_records (struct vfs_s_super *archive, int tard, size_t n)
     /* [previous][next][first][last][top][bottom][index][help]  */
 423 {
 424     (void) archive;
 425 
 426     mc_lseek (tard, n * sizeof (block_buf.buffer), SEEK_CUR);
 427     current_tar_position += n * sizeof (block_buf.buffer);
 428 }
 429 
 430 /* --------------------------------------------------------------------------------------------- */
 431 
 432 static ReadStatus
 433 tar_checksum (const union block *header)
     /* [previous][next][first][last][top][bottom][index][help]  */
 434 {
 435     long recsum;
 436     long signed_sum = 0;
 437     long sum = 0;
 438     int i;
 439     const char *p = header->buffer;
 440 
 441     recsum = tar_from_oct (8, header->header.chksum);
 442 
 443     for (i = sizeof (*header); --i >= 0;)
 444     {
 445         /*
 446          * We can't use unsigned char here because of old compilers,
 447          * e.g. V7.
 448          */
 449         signed_sum += *p;
 450         sum += 0xFF & *p++;
 451     }
 452 
 453     /* Adjust checksum to count the "chksum" field as blanks. */
 454     for (i = sizeof (header->header.chksum); --i >= 0;)
 455     {
 456         sum -= 0xFF & header->header.chksum[i];
 457         signed_sum -= (char) header->header.chksum[i];
 458     }
 459 
 460     sum += ' ' * sizeof (header->header.chksum);
 461     signed_sum += ' ' * sizeof (header->header.chksum);
 462 
 463     /*
 464      * This is a zeroed block... whole block is 0's except
 465      * for the 8 blanks we faked for the checksum field.
 466      */
 467     if (sum == 8 * ' ')
 468         return STATUS_EOFMARK;
 469 
 470     if (sum != recsum && signed_sum != recsum)
 471         return STATUS_BADCHECKSUM;
 472 
 473     return STATUS_SUCCESS;
 474 }
 475 
 476 /* --------------------------------------------------------------------------------------------- */
 477 
 478 static size_t
 479 tar_decode_header (union block *header, tar_super_t * arch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 480 {
 481     size_t size;
 482 
 483     /*
 484      * Try to determine the archive format.
 485      */
 486     if (arch->type == TAR_UNKNOWN)
 487     {
 488         if (strcmp (header->header.magic, TMAGIC) == 0)
 489         {
 490             if (header->header.typeflag == XGLTYPE)
 491                 arch->type = TAR_POSIX;
 492             else
 493                 arch->type = TAR_USTAR;
 494         }
 495         else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
 496             arch->type = TAR_GNU;
 497     }
 498 
 499     /*
 500      * typeflag on BSDI tar (pax) always '\000'
 501      */
 502     if (header->header.typeflag == '\000')
 503     {
 504         size_t len;
 505 
 506         if (header->header.name[sizeof (header->header.name) - 1] != '\0')
 507             len = sizeof (header->header.name);
 508         else
 509             len = strlen (header->header.name);
 510 
 511         if (len != 0 && IS_PATH_SEP (header->header.name[len - 1]))
 512             header->header.typeflag = DIRTYPE;
 513     }
 514 
 515     /*
 516      * Good block.  Decode file size and return.
 517      */
 518     if (header->header.typeflag == LNKTYPE || header->header.typeflag == DIRTYPE)
 519         size = 0;               /* Links 0 size on tape */
 520     else
 521         size = tar_from_oct (1 + 12, header->header.size);
 522 
 523     if (header->header.typeflag == GNUTYPE_DUMPDIR)
 524         if (arch->type == TAR_UNKNOWN)
 525             arch->type = TAR_GNU;
 526 
 527     return size;
 528 }
 529 
 530 /* --------------------------------------------------------------------------------------------- */
 531 
 532 static void
 533 tar_fill_stat (struct vfs_s_super *archive, struct stat *st, union block *header, size_t h_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 534 {
 535     tar_super_t *arch = TAR_SUPER (archive);
 536 
 537     st->st_mode = tar_from_oct (8, header->header.mode);
 538 
 539     /* Adjust st->st_mode because there are tar-files with
 540      * typeflag==SYMTYPE and S_ISLNK(mod)==0. I don't 
 541      * know about the other modes but I think I cause no new
 542      * problem when I adjust them, too. -- Norbert.
 543      */
 544     if (header->header.typeflag == DIRTYPE || header->header.typeflag == GNUTYPE_DUMPDIR)
 545         st->st_mode |= S_IFDIR;
 546     else if (header->header.typeflag == SYMTYPE)
 547         st->st_mode |= S_IFLNK;
 548     else if (header->header.typeflag == CHRTYPE)
 549         st->st_mode |= S_IFCHR;
 550     else if (header->header.typeflag == BLKTYPE)
 551         st->st_mode |= S_IFBLK;
 552     else if (header->header.typeflag == FIFOTYPE)
 553         st->st_mode |= S_IFIFO;
 554     else
 555         st->st_mode |= S_IFREG;
 556 
 557     st->st_dev = 0;
 558 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 559     st->st_rdev = 0;
 560 #endif
 561 
 562     switch (arch->type)
 563     {
 564     case TAR_USTAR:
 565     case TAR_POSIX:
 566     case TAR_GNU:
 567         /* *INDENT-OFF* */
 568         st->st_uid = *header->header.uname
 569             ? vfs_finduid (header->header.uname)
 570             : tar_from_oct (8, header->header.uid);
 571         st->st_gid = *header->header.gname
 572             ? vfs_findgid (header->header.gname)
 573             : tar_from_oct (8,header->header.gid);
 574         /* *INDENT-ON* */
 575 
 576         switch (header->header.typeflag)
 577         {
 578         case BLKTYPE:
 579         case CHRTYPE:
 580 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 581             st->st_rdev =
 582                 makedev (tar_from_oct (8, header->header.devmajor),
 583                          tar_from_oct (8, header->header.devminor));
 584 #endif
 585             break;
 586         default:
 587             break;
 588         }
 589         break;
 590 
 591     default:
 592         st->st_uid = tar_from_oct (8, header->header.uid);
 593         st->st_gid = tar_from_oct (8, header->header.gid);
 594         break;
 595     }
 596 
 597     st->st_size = h_size;
 598 #ifdef HAVE_STRUCT_STAT_ST_MTIM
 599     st->st_atim.tv_nsec = st->st_mtim.tv_nsec = st->st_ctim.tv_nsec = 0;
 600 #endif
 601     st->st_mtime = tar_from_oct (1 + 12, header->header.mtime);
 602     st->st_atime = 0;
 603     st->st_ctime = 0;
 604     if (arch->type == TAR_GNU)
 605     {
 606         st->st_atime = tar_from_oct (1 + 12, header->oldgnu_header.atime);
 607         st->st_ctime = tar_from_oct (1 + 12, header->oldgnu_header.ctime);
 608     }
 609 
 610 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
 611     st->st_blksize = 8 * 1024;  /* FIXME */
 612 #endif
 613     vfs_adjust_stat (st);
 614 }
 615 
 616 /* --------------------------------------------------------------------------------------------- */
 617 /**
 618  * Return 1 for success, 0 if the checksum is bad, EOF on eof,
 619  * 2 for a block full of zeros (EOF marker).
 620  *
 621  */
 622 static ReadStatus
 623 tar_read_header (struct vfs_class *me, struct vfs_s_super *archive, int tard, size_t * h_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 624 {
 625     tar_super_t *arch = TAR_SUPER (archive);
 626     ReadStatus checksum_status;
 627     union block *header;
 628     static char *next_long_name = NULL, *next_long_link = NULL;
 629 
 630     while (TRUE)
 631     {
 632         header = tar_get_next_block (archive, tard);
 633         if (header == NULL)
 634             return STATUS_EOF;
 635 
 636         checksum_status = tar_checksum (header);
 637         if (checksum_status != STATUS_SUCCESS)
 638             return checksum_status;
 639 
 640         *h_size = tar_decode_header (header, arch);
 641 
 642         /* Skip over pax extended header and global extended header records. */
 643         if (header->header.typeflag == XHDTYPE || header->header.typeflag == XGLTYPE)
 644         {
 645             if (arch->type == TAR_UNKNOWN)
 646                 arch->type = TAR_POSIX;
 647             return STATUS_SUCCESS;
 648         }
 649 
 650         if (header->header.typeflag == GNUTYPE_LONGNAME
 651             || header->header.typeflag == GNUTYPE_LONGLINK)
 652         {
 653             char **longp;
 654             char *bp, *data;
 655             off_t size;
 656             size_t written;
 657 
 658             if (arch->type == TAR_UNKNOWN)
 659                 arch->type = TAR_GNU;
 660 
 661             if (*h_size > MC_MAXPATHLEN)
 662             {
 663                 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
 664                 return STATUS_BADCHECKSUM;
 665             }
 666 
 667             longp = header->header.typeflag == GNUTYPE_LONGNAME ? &next_long_name : &next_long_link;
 668 
 669             g_free (*longp);
 670             bp = *longp = g_malloc (*h_size + 1);
 671 
 672             for (size = *h_size; size > 0; size -= written)
 673             {
 674                 data = tar_get_next_block (archive, tard)->buffer;
 675                 if (data == NULL)
 676                 {
 677                     MC_PTR_FREE (*longp);
 678                     message (D_ERROR, MSG_ERROR, _("Unexpected EOF on archive file"));
 679                     return STATUS_BADCHECKSUM;
 680                 }
 681                 written = BLOCKSIZE;
 682                 if ((off_t) written > size)
 683                     written = (size_t) size;
 684 
 685                 memcpy (bp, data, written);
 686                 bp += written;
 687             }
 688 
 689             if (bp - *longp == MC_MAXPATHLEN && bp[-1] != '\0')
 690             {
 691                 MC_PTR_FREE (*longp);
 692                 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
 693                 return STATUS_BADCHECKSUM;
 694             }
 695 
 696             *bp = '\0';
 697         }
 698         else
 699             break;
 700     }
 701 
 702     {
 703         struct stat st;
 704         struct vfs_s_entry *entry;
 705         struct vfs_s_inode *inode = NULL, *parent;
 706         off_t data_position;
 707         char *p, *q;
 708         size_t len;
 709         char *current_file_name, *current_link_name;
 710 
 711         current_link_name =
 712             next_long_link != NULL ? next_long_link : g_strndup (header->header.linkname,
 713                                                                  sizeof (header->header.linkname));
 714         len = strlen (current_link_name);
 715         if (len > 1 && IS_PATH_SEP (current_link_name[len - 1]))
 716             current_link_name[len - 1] = '\0';
 717 
 718         current_file_name = NULL;
 719         switch (arch->type)
 720         {
 721         case TAR_USTAR:
 722         case TAR_POSIX:
 723             /* The ustar archive format supports pathnames of upto 256
 724              * characters in length. This is achieved by concatenating
 725              * the contents of the 'prefix' and 'name' fields like
 726              * this:
 727              *
 728              *   prefix + path_separator + name
 729              *
 730              * If the 'prefix' field contains an empty string i.e. its
 731              * first characters is '\0' the prefix field is ignored.
 732              */
 733             if (header->header.prefix[0] != '\0')
 734             {
 735                 char *temp_name, *temp_prefix;
 736 
 737                 temp_name = g_strndup (header->header.name, sizeof (header->header.name));
 738                 temp_prefix = g_strndup (header->header.prefix, sizeof (header->header.prefix));
 739                 current_file_name = g_strconcat (temp_prefix, PATH_SEP_STR,
 740                                                  temp_name, (char *) NULL);
 741                 g_free (temp_name);
 742                 g_free (temp_prefix);
 743             }
 744             break;
 745         case TAR_GNU:
 746             if (next_long_name != NULL)
 747                 current_file_name = next_long_name;
 748             break;
 749         default:
 750             break;
 751         }
 752 
 753         if (current_file_name == NULL)
 754         {
 755             if (next_long_name != NULL)
 756                 current_file_name = g_strdup (next_long_name);
 757             else
 758                 current_file_name = g_strndup (header->header.name, sizeof (header->header.name));
 759         }
 760 
 761         canonicalize_pathname (current_file_name);
 762         len = strlen (current_file_name);
 763 
 764         data_position = current_tar_position;
 765 
 766         p = strrchr (current_file_name, PATH_SEP);
 767         if (p == NULL)
 768         {
 769             p = current_file_name;
 770             q = current_file_name + len;        /* "" */
 771         }
 772         else
 773         {
 774             *(p++) = '\0';
 775             q = current_file_name;
 776         }
 777 
 778         parent = vfs_s_find_inode (me, archive, q, LINK_NO_FOLLOW, FL_MKDIR);
 779         if (parent == NULL)
 780         {
 781             message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
 782             return STATUS_BADCHECKSUM;
 783         }
 784 
 785         if (header->header.typeflag == LNKTYPE)
 786         {
 787             inode = vfs_s_find_inode (me, archive, current_link_name, LINK_NO_FOLLOW, FL_NONE);
 788             if (inode == NULL)
 789                 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
 790             else
 791             {
 792                 entry = vfs_s_new_entry (me, p, inode);
 793                 vfs_s_insert_entry (me, parent, entry);
 794                 g_free (current_link_name);
 795                 goto done;
 796             }
 797         }
 798 
 799         tar_fill_stat (archive, &st, header, *h_size);
 800         if (S_ISDIR (st.st_mode))
 801         {
 802             entry = VFS_SUBCLASS (me)->find_entry (me, parent, p, LINK_NO_FOLLOW, FL_NONE);
 803             if (entry != NULL)
 804                 goto done;
 805         }
 806 
 807         inode = vfs_s_new_inode (me, archive, &st);
 808         inode->data_offset = data_position;
 809 
 810         if (*current_link_name != '\0')
 811             inode->linkname = current_link_name;
 812         else if (current_link_name != next_long_link)
 813             g_free (current_link_name);
 814 
 815         entry = vfs_s_new_entry (me, p, inode);
 816         vfs_s_insert_entry (me, parent, entry);
 817         g_free (current_file_name);
 818 
 819       done:
 820         next_long_link = next_long_name = NULL;
 821 
 822         if (arch->type == TAR_GNU && header->oldgnu_header.isextended)
 823         {
 824             while (tar_get_next_block (archive, tard)->sparse_header.isextended != 0)
 825                 ;
 826 
 827             if (inode != NULL)
 828                 inode->data_offset = current_tar_position;
 829         }
 830         return STATUS_SUCCESS;
 831     }
 832 }
 833 
 834 /* --------------------------------------------------------------------------------------------- */
 835 /**
 836  * Main loop for reading an archive.
 837  * Returns 0 on success, -1 on error.
 838  */
 839 static int
 840 tar_open_archive (struct vfs_s_super *archive, const vfs_path_t * vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 841                   const vfs_path_element_t * vpath_element)
 842 {
 843     /* Initial status at start of archive */
 844     ReadStatus status = STATUS_EOFMARK;
 845     int tard;
 846 
 847     current_tar_position = 0;
 848     /* Open for reading */
 849     tard = tar_open_archive_int (vpath_element->class, vpath, archive);
 850     if (tard == -1)
 851         return -1;
 852 
 853     while (TRUE)
 854     {
 855         size_t h_size = 0;
 856         ReadStatus prev_status = status;
 857 
 858         status = tar_read_header (vpath_element->class, archive, tard, &h_size);
 859 
 860         switch (status)
 861         {
 862         case STATUS_SUCCESS:
 863             tar_skip_n_records (archive, tard, (h_size + BLOCKSIZE - 1) / BLOCKSIZE);
 864             continue;
 865 
 866             /*
 867              * Invalid header:
 868              *
 869              * If the previous header was good, tell them
 870              * that we are skipping bad ones.
 871              */
 872         case STATUS_BADCHECKSUM:
 873             switch (prev_status)
 874             {
 875                 /* Error on first block */
 876             case STATUS_EOFMARK:
 877                 {
 878                     message (D_ERROR, MSG_ERROR, _("%s\ndoesn't look like a tar archive."),
 879                              vfs_path_as_str (vpath));
 880                     MC_FALLTHROUGH;
 881 
 882                     /* Error after header rec */
 883                 }
 884             case STATUS_SUCCESS:
 885                 /* Error after error */
 886 
 887             case STATUS_BADCHECKSUM:
 888                 return -1;
 889 
 890             case STATUS_EOF:
 891                 return 0;
 892 
 893             default:
 894                 break;
 895             }
 896             MC_FALLTHROUGH;
 897 
 898             /* Record of zeroes */
 899         case STATUS_EOFMARK:   /* If error after 0's */
 900             MC_FALLTHROUGH;
 901             /* exit from loop */
 902         case STATUS_EOF:       /* End of archive */
 903             break;
 904         default:
 905             break;
 906         }
 907         break;
 908     }
 909     return 0;
 910 }
 911 
 912 /* --------------------------------------------------------------------------------------------- */
 913 
 914 static void *
 915 tar_super_check (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 916 {
 917     static struct stat stat_buf;
 918     int stat_result;
 919 
 920     stat_result = mc_stat (vpath, &stat_buf);
 921 
 922     return (stat_result != 0) ? NULL : &stat_buf;
 923 }
 924 
 925 /* --------------------------------------------------------------------------------------------- */
 926 
 927 static int
 928 tar_super_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *parc,
     /* [previous][next][first][last][top][bottom][index][help]  */
 929                 const vfs_path_t * vpath, void *cookie)
 930 {
 931     struct stat *archive_stat = cookie; /* stat of main archive */
 932 
 933     (void) vpath_element;
 934 
 935     if (strcmp (parc->name, vfs_path_as_str (vpath)) != 0)
 936         return 0;
 937 
 938     /* Has the cached archive been changed on the disk? */
 939     if (parc != NULL && TAR_SUPER (parc)->st.st_mtime < archive_stat->st_mtime)
 940     {
 941         /* Yes, reload! */
 942         vfs_tarfs_ops->free ((vfsid) parc);
 943         vfs_rmstamp (vfs_tarfs_ops, (vfsid) parc);
 944         return 2;
 945     }
 946     /* Hasn't been modified, give it a new timeout */
 947     vfs_stamp (vfs_tarfs_ops, (vfsid) parc);
 948     return 1;
 949 }
 950 
 951 /* --------------------------------------------------------------------------------------------- */
 952 
 953 static ssize_t
 954 tar_read (void *fh, char *buffer, size_t count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 955 {
 956     struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
 957     vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
 958     off_t begin = file->ino->data_offset;
 959     int fd = TAR_SUPER (VFS_FILE_HANDLER_SUPER (fh))->fd;
 960     ssize_t res;
 961 
 962     if (mc_lseek (fd, begin + file->pos, SEEK_SET) != begin + file->pos)
 963         ERRNOR (EIO, -1);
 964 
 965     count = MIN (count, (size_t) (file->ino->st.st_size - file->pos));
 966 
 967     res = mc_read (fd, buffer, count);
 968     if (res == -1)
 969         ERRNOR (errno, -1);
 970 
 971     file->pos += res;
 972     return res;
 973 }
 974 
 975 /* --------------------------------------------------------------------------------------------- */
 976 
 977 static int
 978 tar_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 979 {
 980     (void) fh;
 981     (void) mode;
 982 
 983     if ((flags & O_ACCMODE) != O_RDONLY)
 984         ERRNOR (EROFS, -1);
 985     return 0;
 986 }
 987 
 988 /* --------------------------------------------------------------------------------------------- */
 989 /*** public functions ****************************************************************************/
 990 /* --------------------------------------------------------------------------------------------- */
 991 
 992 void
 993 vfs_init_tarfs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 994 {
 995     /* FIXME: tarfs used own temp files */
 996     vfs_init_subclass (&tarfs_subclass, "tarfs", VFSF_READONLY, "utar");
 997     vfs_tarfs_ops->read = tar_read;
 998     vfs_tarfs_ops->setctl = NULL;
 999     tarfs_subclass.archive_check = tar_super_check;
1000     tarfs_subclass.archive_same = tar_super_same;
1001     tarfs_subclass.new_archive = tar_new_archive;
1002     tarfs_subclass.open_archive = tar_open_archive;
1003     tarfs_subclass.free_archive = tar_free_archive;
1004     tarfs_subclass.fh_open = tar_fh_open;
1005     vfs_register_class (vfs_tarfs_ops);
1006 }
1007 
1008 /* --------------------------------------------------------------------------------------------- */

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