root/src/vfs/cpio/cpio.c

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

DEFINITIONS

This source file includes following definitions.
  1. cpio_defer_find
  2. cpio_skip_padding
  3. cpio_new_archive
  4. cpio_free_archive
  5. cpio_open_cpio_file
  6. cpio_read_head
  7. cpio_find_head
  8. cpio_create_entry
  9. cpio_read_bin_head
  10. cpio_read_oldc_head
  11. cpio_read_crc_head
  12. cpio_open_archive
  13. cpio_super_check
  14. cpio_super_same
  15. cpio_read
  16. cpio_fh_open
  17. vfs_init_cpiofs

   1 /*
   2    Virtual File System: GNU Tar file system.
   3 
   4    Copyright (C) 2000-2019
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Jan Hudec, 2000
   9    Slava Zanko <slavazanko@gmail.com>, 2013
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 /** \file
  28  *  \brief Source: Virtual File System: GNU Tar file system.
  29  *  \author Jan Hudec
  30  *  \date 2000
  31  */
  32 
  33 #include <config.h>
  34 
  35 #include <errno.h>
  36 #include <sys/types.h>
  37 #include <sys/stat.h>
  38 
  39 #include "lib/global.h"
  40 #include "lib/unixcompat.h"
  41 #include "lib/util.h"
  42 #include "lib/widget.h"         /* message() */
  43 
  44 #include "lib/vfs/vfs.h"
  45 #include "lib/vfs/utilvfs.h"
  46 #include "lib/vfs/xdirentry.h"
  47 #include "lib/vfs/gc.h"         /* vfs_rmstamp */
  48 
  49 #include "cpio.h"
  50 
  51 /*** global variables ****************************************************************************/
  52 
  53 /*** file scope macro definitions ****************************************************************/
  54 
  55 #define CPIO_SUPER(super) ((cpio_super_t *) (super))
  56 
  57 #define CPIO_POS(super) cpio_position
  58 /* If some time reentrancy should be needed change it to */
  59 /* #define CPIO_POS(super) (super)->u.arch.fd */
  60 
  61 #define CPIO_SEEK_SET(super, where) mc_lseek (CPIO_SUPER(super)->fd, CPIO_POS(super) = (where), SEEK_SET)
  62 #define CPIO_SEEK_CUR(super, where) mc_lseek (CPIO_SUPER(super)->fd, CPIO_POS(super) += (where), SEEK_SET)
  63 
  64 #define MAGIC_LENGTH (6)        /* How many bytes we have to read ahead */
  65 #define SEEKBACK CPIO_SEEK_CUR(super, ptr - top)
  66 #define RETURN(x) return (CPIO_SUPER(super)->type = (x))
  67 #define TYPEIS(x) ((CPIO_SUPER(super)->type == CPIO_UNKNOWN) || (CPIO_SUPER(super)->type == (x)))
  68 
  69 #define HEAD_LENGTH (26)
  70 
  71 /*** file scope type declarations ****************************************************************/
  72 
  73 enum
  74 {
  75     STATUS_START,
  76     STATUS_OK,
  77     STATUS_TRAIL,
  78     STATUS_FAIL,
  79     STATUS_EOF
  80 };
  81 
  82 enum
  83 {
  84     CPIO_UNKNOWN = 0,           /* Not determined yet */
  85     CPIO_BIN,                   /* Binary format */
  86     CPIO_BINRE,                 /* Binary format, reverse endianity */
  87     CPIO_OLDC,                  /* Old ASCII format */
  88     CPIO_NEWC,                  /* New ASCII format */
  89     CPIO_CRC                    /* New ASCII format + CRC */
  90 };
  91 
  92 struct old_cpio_header
  93 {
  94     unsigned short c_magic;
  95     short c_dev;
  96     unsigned short c_ino;
  97     unsigned short c_mode;
  98     unsigned short c_uid;
  99     unsigned short c_gid;
 100     unsigned short c_nlink;
 101     short c_rdev;
 102     unsigned short c_mtimes[2];
 103     unsigned short c_namesize;
 104     unsigned short c_filesizes[2];
 105 };
 106 
 107 struct new_cpio_header
 108 {
 109     unsigned short c_magic;
 110     unsigned long c_ino;
 111     unsigned long c_mode;
 112     unsigned long c_uid;
 113     unsigned long c_gid;
 114     unsigned long c_nlink;
 115     unsigned long c_mtime;
 116     unsigned long c_filesize;
 117     long c_dev;
 118     long c_devmin;
 119     long c_rdev;
 120     long c_rdevmin;
 121     unsigned long c_namesize;
 122     unsigned long c_chksum;
 123 };
 124 
 125 typedef struct
 126 {
 127     unsigned long inumber;
 128     dev_t device;
 129     struct vfs_s_inode *inode;
 130 } defer_inode;
 131 
 132 typedef struct
 133 {
 134     struct vfs_s_super base;    /* base class */
 135 
 136     int fd;
 137     struct stat st;
 138     int type;                   /* Type of the archive */
 139     GSList *deferred;           /* List of inodes for which another entries may appear */
 140 } cpio_super_t;
 141 
 142 /*** file scope variables ************************************************************************/
 143 
 144 static struct vfs_s_subclass cpio_subclass;
 145 static struct vfs_class *vfs_cpiofs_ops = VFS_CLASS (&cpio_subclass);
 146 
 147 static off_t cpio_position;
 148 
 149 /* --------------------------------------------------------------------------------------------- */
 150 /*** file scope functions ************************************************************************/
 151 /* --------------------------------------------------------------------------------------------- */
 152 
 153 static ssize_t cpio_find_head (struct vfs_class *me, struct vfs_s_super *super);
 154 static ssize_t cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super);
 155 static ssize_t cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super);
 156 static ssize_t cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super);
 157 static ssize_t cpio_read (void *fh, char *buffer, size_t count);
 158 
 159 /* --------------------------------------------------------------------------------------------- */
 160 
 161 static int
 162 cpio_defer_find (const void *a, const void *b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 163 {
 164     const defer_inode *a1 = (const defer_inode *) a;
 165     const defer_inode *b1 = (const defer_inode *) b;
 166 
 167     return (a1->inumber == b1->inumber && a1->device == b1->device) ? 0 : 1;
 168 }
 169 
 170 /* --------------------------------------------------------------------------------------------- */
 171 
 172 static ssize_t
 173 cpio_skip_padding (struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 174 {
 175     switch (CPIO_SUPER (super)->type)
 176     {
 177     case CPIO_BIN:
 178     case CPIO_BINRE:
 179         return CPIO_SEEK_CUR (super, (2 - (CPIO_POS (super) % 2)) % 2);
 180     case CPIO_NEWC:
 181     case CPIO_CRC:
 182         return CPIO_SEEK_CUR (super, (4 - (CPIO_POS (super) % 4)) % 4);
 183     case CPIO_OLDC:
 184         return CPIO_POS (super);
 185     default:
 186         g_assert_not_reached ();
 187         return 42;              /* & the compiler is happy :-) */
 188     }
 189 }
 190 
 191 /* --------------------------------------------------------------------------------------------- */
 192 
 193 static struct vfs_s_super *
 194 cpio_new_archive (struct vfs_class *me)
     /* [previous][next][first][last][top][bottom][index][help]  */
 195 {
 196     cpio_super_t *arch;
 197 
 198     arch = g_new0 (cpio_super_t, 1);
 199     arch->base.me = me;
 200     arch->fd = -1;              /* for now */
 201     arch->type = CPIO_UNKNOWN;
 202 
 203     return VFS_SUPER (arch);
 204 }
 205 
 206 /* --------------------------------------------------------------------------------------------- */
 207 
 208 static void
 209 cpio_free_archive (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 210 {
 211     cpio_super_t *arch = CPIO_SUPER (super);
 212 
 213     (void) me;
 214 
 215     if (arch->fd != -1)
 216     {
 217         mc_close (arch->fd);
 218         arch->fd = -1;
 219     }
 220     g_slist_free_full (arch->deferred, g_free);
 221     arch->deferred = NULL;
 222 }
 223 
 224 /* --------------------------------------------------------------------------------------------- */
 225 
 226 static int
 227 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super, const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 228 {
 229     int fd, type;
 230     cpio_super_t *arch;
 231     mode_t mode;
 232     struct vfs_s_inode *root;
 233 
 234     fd = mc_open (vpath, O_RDONLY);
 235     if (fd == -1)
 236     {
 237         message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), vfs_path_as_str (vpath));
 238         return -1;
 239     }
 240 
 241     super->name = g_strdup (vfs_path_as_str (vpath));
 242     arch = CPIO_SUPER (super);
 243     mc_stat (vpath, &arch->st);
 244 
 245     type = get_compression_type (fd, super->name);
 246     if (type == COMPRESSION_NONE)
 247         mc_lseek (fd, 0, SEEK_SET);
 248     else
 249     {
 250         char *s;
 251         vfs_path_t *tmp_vpath;
 252 
 253         mc_close (fd);
 254         s = g_strconcat (super->name, decompress_extension (type), (char *) NULL);
 255         tmp_vpath = vfs_path_from_str_flags (s, VPF_NO_CANON);
 256         fd = mc_open (tmp_vpath, O_RDONLY);
 257         vfs_path_free (tmp_vpath);
 258         if (fd == -1)
 259         {
 260             message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), s);
 261             g_free (s);
 262             MC_PTR_FREE (super->name);
 263             return -1;
 264         }
 265         g_free (s);
 266     }
 267 
 268     arch->fd = fd;
 269     mode = arch->st.st_mode & 07777;
 270     mode |= (mode & 0444) >> 2; /* set eXec where Read is */
 271     mode |= S_IFDIR;
 272 
 273     root = vfs_s_new_inode (me, super, &arch->st);
 274     root->st.st_mode = mode;
 275     root->data_offset = -1;
 276     root->st.st_nlink++;
 277     root->st.st_dev = VFS_SUBCLASS (me)->rdev++;
 278 
 279     super->root = root;
 280 
 281     CPIO_SEEK_SET (super, 0);
 282 
 283     return fd;
 284 }
 285 
 286 /* --------------------------------------------------------------------------------------------- */
 287 
 288 static ssize_t
 289 cpio_read_head (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 290 {
 291     switch (cpio_find_head (me, super))
 292     {
 293     case CPIO_UNKNOWN:
 294         return -1;
 295     case CPIO_BIN:
 296     case CPIO_BINRE:
 297         return cpio_read_bin_head (me, super);
 298     case CPIO_OLDC:
 299         return cpio_read_oldc_head (me, super);
 300     case CPIO_NEWC:
 301     case CPIO_CRC:
 302         return cpio_read_crc_head (me, super);
 303     default:
 304         g_assert_not_reached ();
 305         return 42;              /* & the compiler is happy :-) */
 306     }
 307 }
 308 
 309 /* --------------------------------------------------------------------------------------------- */
 310 
 311 static ssize_t
 312 cpio_find_head (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 313 {
 314     cpio_super_t *arch = CPIO_SUPER (super);
 315     char buf[BUF_SMALL * 2];
 316     ssize_t ptr = 0;
 317     ssize_t top;
 318     ssize_t tmp;
 319 
 320     top = mc_read (arch->fd, buf, sizeof (buf));
 321     if (top > 0)
 322         CPIO_POS (super) += top;
 323 
 324     while (TRUE)
 325     {
 326         if (ptr + MAGIC_LENGTH >= top)
 327         {
 328             if (top > (ssize_t) (sizeof (buf) / 2))
 329             {
 330                 memmove (buf, buf + top - sizeof (buf) / 2, sizeof (buf) / 2);
 331                 ptr -= top - sizeof (buf) / 2;
 332                 top = sizeof (buf) / 2;
 333             }
 334             tmp = mc_read (arch->fd, buf, top);
 335             if (tmp == 0 || tmp == -1)
 336             {
 337                 message (D_ERROR, MSG_ERROR, _("Premature end of cpio archive\n%s"), super->name);
 338                 cpio_free_archive (me, super);
 339                 return CPIO_UNKNOWN;
 340             }
 341             top += tmp;
 342         }
 343         if (TYPEIS (CPIO_BIN) && ((*(unsigned short *) (buf + ptr)) == 070707))
 344         {
 345             SEEKBACK;
 346             RETURN (CPIO_BIN);
 347         }
 348         else if (TYPEIS (CPIO_BINRE)
 349                  && ((*(unsigned short *) (buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT (070707)))
 350         {
 351             SEEKBACK;
 352             RETURN (CPIO_BINRE);
 353         }
 354         else if (TYPEIS (CPIO_OLDC) && (strncmp (buf + ptr, "070707", 6) == 0))
 355         {
 356             SEEKBACK;
 357             RETURN (CPIO_OLDC);
 358         }
 359         else if (TYPEIS (CPIO_NEWC) && (strncmp (buf + ptr, "070701", 6) == 0))
 360         {
 361             SEEKBACK;
 362             RETURN (CPIO_NEWC);
 363         }
 364         else if (TYPEIS (CPIO_CRC) && (strncmp (buf + ptr, "070702", 6) == 0))
 365         {
 366             SEEKBACK;
 367             RETURN (CPIO_CRC);
 368         };
 369         ptr++;
 370     }
 371 }
 372 
 373 /* --------------------------------------------------------------------------------------------- */
 374 
 375 static int
 376 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super, struct stat *st, char *name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 377 {
 378     cpio_super_t *arch = CPIO_SUPER (super);
 379     struct vfs_s_inode *inode = NULL;
 380     struct vfs_s_inode *root = super->root;
 381     struct vfs_s_entry *entry = NULL;
 382     char *tn;
 383 
 384     switch (st->st_mode & S_IFMT)
 385     {                           /* For case of HP/UX archives */
 386     case S_IFCHR:
 387     case S_IFBLK:
 388 #ifdef S_IFSOCK
 389         /* cppcheck-suppress syntaxError */
 390     case S_IFSOCK:
 391 #endif
 392 #ifdef S_IFIFO
 393         /* cppcheck-suppress syntaxError */
 394     case S_IFIFO:
 395 #endif
 396 #ifdef S_IFNAM
 397         /* cppcheck-suppress syntaxError */
 398     case S_IFNAM:
 399 #endif
 400 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 401         if ((st->st_size != 0) && (st->st_rdev == 0x0001))
 402         {
 403             /* FIXME: representation of major/minor differs between */
 404             /* different operating systems. */
 405             st->st_rdev = (unsigned) st->st_size;
 406             st->st_size = 0;
 407         }
 408 #endif
 409         break;
 410     default:
 411         break;
 412     }
 413 
 414     if ((st->st_nlink > 1) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
 415     {                           /* For case of hardlinked files */
 416         defer_inode i = { st->st_ino, st->st_dev, NULL };
 417         GSList *l;
 418 
 419         l = g_slist_find_custom (arch->deferred, &i, cpio_defer_find);
 420         if (l != NULL)
 421         {
 422             inode = ((defer_inode *) l->data)->inode;
 423             if (inode->st.st_size != 0 && st->st_size != 0 && (inode->st.st_size != st->st_size))
 424             {
 425                 message (D_ERROR, MSG_ERROR,
 426                          _("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
 427                          name, super->name);
 428                 inode = NULL;
 429             }
 430             else if (inode->st.st_size == 0)
 431                 inode->st.st_size = st->st_size;
 432         }
 433     }
 434 
 435     /* remove trailing slashes */
 436     for (tn = name + strlen (name) - 1; tn >= name && IS_PATH_SEP (*tn); tn--)
 437         *tn = '\0';
 438 
 439     tn = strrchr (name, PATH_SEP);
 440     if (tn == NULL)
 441         tn = name;
 442     else if (tn == name + 1)
 443     {
 444         /* started with "./" -- directory in the root of archive */
 445         tn++;
 446     }
 447     else
 448     {
 449         *tn = '\0';
 450         root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
 451         *tn = PATH_SEP;
 452         tn++;
 453     }
 454 
 455     entry = VFS_SUBCLASS (me)->find_entry (me, root, tn, LINK_FOLLOW, FL_NONE); /* In case entry is already there */
 456 
 457     if (entry != NULL)
 458     {
 459         /* This shouldn't happen! (well, it can happen if there is a record for a
 460            file and than a record for a directory it is in; cpio would die with
 461            'No such file or directory' is such case) */
 462 
 463         if (!S_ISDIR (entry->ino->st.st_mode))
 464         {
 465             /* This can be considered archive inconsistency */
 466             message (D_ERROR, MSG_ERROR,
 467                      _("%s contains duplicate entries! Skipping!"), super->name);
 468         }
 469         else
 470         {
 471             entry->ino->st.st_mode = st->st_mode;
 472             entry->ino->st.st_uid = st->st_uid;
 473             entry->ino->st.st_gid = st->st_gid;
 474 #ifdef HAVE_STRUCT_STAT_ST_MTIM
 475             entry->ino->st.st_atim = st->st_atim;
 476             entry->ino->st.st_mtim = st->st_mtim;
 477             entry->ino->st.st_ctim = st->st_ctim;
 478 #else
 479             entry->ino->st.st_atime = st->st_atime;
 480             entry->ino->st.st_mtime = st->st_mtime;
 481             entry->ino->st.st_ctime = st->st_ctime;
 482 #endif
 483         }
 484 
 485         g_free (name);
 486     }
 487     else
 488     {                           /* !entry */
 489         /* root == NULL can be in the following case:
 490          * a/b/c -> d
 491          * where 'a/b' is the stale link and therefore root of 'c' cannot be found in the archive
 492          */
 493         if (root != NULL)
 494         {
 495             if (inode == NULL)
 496             {
 497                 inode = vfs_s_new_inode (me, super, st);
 498                 if ((st->st_nlink > 0) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
 499                 {
 500                     /* For case of hardlinked files */
 501                     defer_inode *i;
 502 
 503                     i = g_new (defer_inode, 1);
 504                     i->inumber = st->st_ino;
 505                     i->device = st->st_dev;
 506                     i->inode = inode;
 507 
 508                     arch->deferred = g_slist_prepend (arch->deferred, i);
 509                 }
 510             }
 511 
 512             if (st->st_size != 0)
 513                 inode->data_offset = CPIO_POS (super);
 514 
 515             entry = vfs_s_new_entry (me, tn, inode);
 516             vfs_s_insert_entry (me, root, entry);
 517         }
 518 
 519         g_free (name);
 520 
 521         if (!S_ISLNK (st->st_mode))
 522             CPIO_SEEK_CUR (super, st->st_size);
 523         else
 524         {
 525             if (inode != NULL)
 526             {
 527                 /* FIXME: do we must read from arch->fd in case of inode != NULL only or in any case? */
 528 
 529                 inode->linkname = g_malloc (st->st_size + 1);
 530 
 531                 if (mc_read (arch->fd, inode->linkname, st->st_size) < st->st_size)
 532                 {
 533                     inode->linkname[0] = '\0';
 534                     return STATUS_EOF;
 535                 }
 536 
 537                 inode->linkname[st->st_size] = '\0';    /* Linkname stored without terminating \0 !!! */
 538             }
 539 
 540             CPIO_POS (super) += st->st_size;
 541             cpio_skip_padding (super);
 542         }
 543     }                           /* !entry */
 544 
 545     return STATUS_OK;
 546 }
 547 
 548 /* --------------------------------------------------------------------------------------------- */
 549 
 550 static ssize_t
 551 cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 552 {
 553     union
 554     {
 555         struct old_cpio_header buf;
 556         short shorts[HEAD_LENGTH >> 1];
 557     } u;
 558 
 559     cpio_super_t *arch = CPIO_SUPER (super);
 560     ssize_t len;
 561     char *name;
 562     struct stat st;
 563 
 564     len = mc_read (arch->fd, (char *) &u.buf, HEAD_LENGTH);
 565     if (len < HEAD_LENGTH)
 566         return STATUS_EOF;
 567     CPIO_POS (super) += len;
 568     if (arch->type == CPIO_BINRE)
 569     {
 570         int i;
 571         for (i = 0; i < (HEAD_LENGTH >> 1); i++)
 572             u.shorts[i] = GUINT16_SWAP_LE_BE_CONSTANT (u.shorts[i]);
 573     }
 574 
 575     if (u.buf.c_magic != 070707 || u.buf.c_namesize == 0 || u.buf.c_namesize > MC_MAXPATHLEN)
 576     {
 577         message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
 578         return STATUS_FAIL;
 579     }
 580     name = g_malloc (u.buf.c_namesize);
 581     len = mc_read (arch->fd, name, u.buf.c_namesize);
 582     if (len < u.buf.c_namesize)
 583     {
 584         g_free (name);
 585         return STATUS_EOF;
 586     }
 587     name[u.buf.c_namesize - 1] = '\0';
 588     CPIO_POS (super) += len;
 589     cpio_skip_padding (super);
 590 
 591     if (!strcmp ("TRAILER!!!", name))
 592     {                           /* We got to the last record */
 593         g_free (name);
 594         return STATUS_TRAIL;
 595     }
 596 
 597     st.st_dev = u.buf.c_dev;
 598     st.st_ino = u.buf.c_ino;
 599     st.st_mode = u.buf.c_mode;
 600     st.st_nlink = u.buf.c_nlink;
 601     st.st_uid = u.buf.c_uid;
 602     st.st_gid = u.buf.c_gid;
 603 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 604     st.st_rdev = u.buf.c_rdev;
 605 #endif
 606     st.st_size = (u.buf.c_filesizes[0] << 16) | u.buf.c_filesizes[1];
 607 #ifdef HAVE_STRUCT_STAT_ST_MTIM
 608     st.st_atim.tv_nsec = st.st_mtim.tv_nsec = st.st_ctim.tv_nsec = 0;
 609 #endif
 610     st.st_atime = st.st_mtime = st.st_ctime = (u.buf.c_mtimes[0] << 16) | u.buf.c_mtimes[1];
 611 
 612     return cpio_create_entry (me, super, &st, name);
 613 }
 614 
 615 /* --------------------------------------------------------------------------------------------- */
 616 
 617 #undef HEAD_LENGTH
 618 #define HEAD_LENGTH (76)
 619 
 620 static ssize_t
 621 cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 622 {
 623     cpio_super_t *arch = CPIO_SUPER (super);
 624     struct new_cpio_header hd;
 625     union
 626     {
 627         struct stat st;
 628         char buf[HEAD_LENGTH + 1];
 629     } u;
 630     ssize_t len;
 631     char *name;
 632 
 633     if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
 634         return STATUS_EOF;
 635     CPIO_POS (super) += HEAD_LENGTH;
 636     u.buf[HEAD_LENGTH] = 0;
 637 
 638     if (sscanf (u.buf, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
 639                 (unsigned long *) &hd.c_dev, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
 640                 &hd.c_nlink, (unsigned long *) &hd.c_rdev, &hd.c_mtime,
 641                 &hd.c_namesize, &hd.c_filesize) < 10)
 642     {
 643         message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
 644         return STATUS_FAIL;
 645     }
 646 
 647     if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
 648     {
 649         message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
 650         return STATUS_FAIL;
 651     }
 652     name = g_malloc (hd.c_namesize);
 653     len = mc_read (arch->fd, name, hd.c_namesize);
 654     if ((len == -1) || ((unsigned long) len < hd.c_namesize))
 655     {
 656         g_free (name);
 657         return STATUS_EOF;
 658     }
 659     name[hd.c_namesize - 1] = '\0';
 660     CPIO_POS (super) += len;
 661     cpio_skip_padding (super);
 662 
 663     if (!strcmp ("TRAILER!!!", name))
 664     {                           /* We got to the last record */
 665         g_free (name);
 666         return STATUS_TRAIL;
 667     }
 668 
 669     u.st.st_dev = hd.c_dev;
 670     u.st.st_ino = hd.c_ino;
 671     u.st.st_mode = hd.c_mode;
 672     u.st.st_nlink = hd.c_nlink;
 673     u.st.st_uid = hd.c_uid;
 674     u.st.st_gid = hd.c_gid;
 675 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 676     u.st.st_rdev = hd.c_rdev;
 677 #endif
 678     u.st.st_size = hd.c_filesize;
 679 #ifdef HAVE_STRUCT_STAT_ST_MTIM
 680     u.st.st_atim.tv_nsec = u.st.st_mtim.tv_nsec = u.st.st_ctim.tv_nsec = 0;
 681 #endif
 682     u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
 683 
 684     return cpio_create_entry (me, super, &u.st, name);
 685 }
 686 
 687 /* --------------------------------------------------------------------------------------------- */
 688 
 689 #undef HEAD_LENGTH
 690 #define HEAD_LENGTH (110)
 691 
 692 static ssize_t
 693 cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super)
     /* [previous][next][first][last][top][bottom][index][help]  */
 694 {
 695     cpio_super_t *arch = CPIO_SUPER (super);
 696     struct new_cpio_header hd;
 697     union
 698     {
 699         struct stat st;
 700         char buf[HEAD_LENGTH + 1];
 701     } u;
 702     ssize_t len;
 703     char *name;
 704 
 705     if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
 706         return STATUS_EOF;
 707 
 708     CPIO_POS (super) += HEAD_LENGTH;
 709     u.buf[HEAD_LENGTH] = '\0';
 710 
 711     if (sscanf (u.buf, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
 712                 &hd.c_magic, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
 713                 &hd.c_nlink, &hd.c_mtime, &hd.c_filesize,
 714                 (unsigned long *) &hd.c_dev, (unsigned long *) &hd.c_devmin,
 715                 (unsigned long *) &hd.c_rdev, (unsigned long *) &hd.c_rdevmin,
 716                 &hd.c_namesize, &hd.c_chksum) < 14)
 717     {
 718         message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
 719         return STATUS_FAIL;
 720     }
 721 
 722     if ((arch->type == CPIO_NEWC && hd.c_magic != 070701) ||
 723         (arch->type == CPIO_CRC && hd.c_magic != 070702))
 724         return STATUS_FAIL;
 725 
 726     if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
 727     {
 728         message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
 729         return STATUS_FAIL;
 730     }
 731 
 732     name = g_malloc (hd.c_namesize);
 733     len = mc_read (arch->fd, name, hd.c_namesize);
 734 
 735     if ((len == -1) || ((unsigned long) len < hd.c_namesize))
 736     {
 737         g_free (name);
 738         return STATUS_EOF;
 739     }
 740     name[hd.c_namesize - 1] = '\0';
 741     CPIO_POS (super) += len;
 742     cpio_skip_padding (super);
 743 
 744     if (strcmp ("TRAILER!!!", name) == 0)
 745     {                           /* We got to the last record */
 746         g_free (name);
 747         return STATUS_TRAIL;
 748     }
 749 
 750     u.st.st_dev = makedev (hd.c_dev, hd.c_devmin);
 751     u.st.st_ino = hd.c_ino;
 752     u.st.st_mode = hd.c_mode;
 753     u.st.st_nlink = hd.c_nlink;
 754     u.st.st_uid = hd.c_uid;
 755     u.st.st_gid = hd.c_gid;
 756 #ifdef HAVE_STRUCT_STAT_ST_RDEV
 757     u.st.st_rdev = makedev (hd.c_rdev, hd.c_rdevmin);
 758 #endif
 759     u.st.st_size = hd.c_filesize;
 760 #ifdef HAVE_STRUCT_STAT_ST_MTIM
 761     u.st.st_atim.tv_nsec = u.st.st_mtim.tv_nsec = u.st.st_ctim.tv_nsec = 0;
 762 #endif
 763     u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
 764 
 765     return cpio_create_entry (me, super, &u.st, name);
 766 }
 767 
 768 /* --------------------------------------------------------------------------------------------- */
 769 /** Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
 770 
 771 static int
 772 cpio_open_archive (struct vfs_s_super *super, const vfs_path_t * vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 773                    const vfs_path_element_t * vpath_element)
 774 {
 775     (void) vpath_element;
 776 
 777     if (cpio_open_cpio_file (vpath_element->class, super, vpath) == -1)
 778         return -1;
 779 
 780     while (TRUE)
 781     {
 782         ssize_t status;
 783 
 784         status = cpio_read_head (vpath_element->class, super);
 785         if (status < 0)
 786             return (-1);
 787 
 788         switch (status)
 789         {
 790         case STATUS_EOF:
 791             {
 792                 message (D_ERROR, MSG_ERROR, _("Unexpected end of file\n%s"),
 793                          vfs_path_as_str (vpath));
 794                 return 0;
 795             }
 796         case STATUS_OK:
 797             continue;
 798         case STATUS_TRAIL:
 799             break;
 800         default:
 801             break;
 802         }
 803         break;
 804     }
 805 
 806     return 0;
 807 }
 808 
 809 /* --------------------------------------------------------------------------------------------- */
 810 /** Remaining functions are exactly same as for tarfs (and were in fact just copied) */
 811 
 812 static void *
 813 cpio_super_check (const vfs_path_t * vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 814 {
 815     static struct stat sb;
 816     int stat_result;
 817 
 818     stat_result = mc_stat (vpath, &sb);
 819     return (stat_result == 0 ? &sb : NULL);
 820 }
 821 
 822 /* --------------------------------------------------------------------------------------------- */
 823 
 824 static int
 825 cpio_super_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *parc,
     /* [previous][next][first][last][top][bottom][index][help]  */
 826                  const vfs_path_t * vpath, void *cookie)
 827 {
 828     struct stat *archive_stat = cookie; /* stat of main archive */
 829 
 830     (void) vpath_element;
 831 
 832     if (strcmp (parc->name, vfs_path_as_str (vpath)))
 833         return 0;
 834 
 835     /* Has the cached archive been changed on the disk? */
 836     if (parc != NULL && CPIO_SUPER (parc)->st.st_mtime < archive_stat->st_mtime)
 837     {
 838         /* Yes, reload! */
 839         vfs_cpiofs_ops->free ((vfsid) parc);
 840         vfs_rmstamp (vfs_cpiofs_ops, (vfsid) parc);
 841         return 2;
 842     }
 843     /* Hasn't been modified, give it a new timeout */
 844     vfs_stamp (vfs_cpiofs_ops, (vfsid) parc);
 845     return 1;
 846 }
 847 
 848 /* --------------------------------------------------------------------------------------------- */
 849 
 850 static ssize_t
 851 cpio_read (void *fh, char *buffer, size_t count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 852 {
 853     vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
 854     struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
 855     int fd = CPIO_SUPER (VFS_FILE_HANDLER_SUPER (fh))->fd;
 856     off_t begin = file->ino->data_offset;
 857     ssize_t res;
 858 
 859     if (mc_lseek (fd, begin + file->pos, SEEK_SET) != begin + file->pos)
 860         ERRNOR (EIO, -1);
 861 
 862     count = MIN (count, (size_t) (file->ino->st.st_size - file->pos));
 863 
 864     res = mc_read (fd, buffer, count);
 865     if (res == -1)
 866         ERRNOR (errno, -1);
 867 
 868     file->pos += res;
 869     return res;
 870 }
 871 
 872 /* --------------------------------------------------------------------------------------------- */
 873 
 874 static int
 875 cpio_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 876 {
 877     (void) fh;
 878     (void) mode;
 879 
 880     if ((flags & O_ACCMODE) != O_RDONLY)
 881         ERRNOR (EROFS, -1);
 882     return 0;
 883 }
 884 
 885 /* --------------------------------------------------------------------------------------------- */
 886 /*** public functions ****************************************************************************/
 887 /* --------------------------------------------------------------------------------------------- */
 888 
 889 void
 890 vfs_init_cpiofs (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 891 {
 892     /* FIXME: cpiofs used own temp files */
 893     vfs_init_subclass (&cpio_subclass, "cpiofs", VFS_READONLY, "ucpio");
 894     vfs_cpiofs_ops->read = cpio_read;
 895     vfs_cpiofs_ops->setctl = NULL;
 896     cpio_subclass.archive_check = cpio_super_check;
 897     cpio_subclass.archive_same = cpio_super_same;
 898     cpio_subclass.new_archive = cpio_new_archive;
 899     cpio_subclass.open_archive = cpio_open_archive;
 900     cpio_subclass.free_archive = cpio_free_archive;
 901     cpio_subclass.fh_open = cpio_fh_open;
 902     vfs_register_class (vfs_cpiofs_ops);
 903 }
 904 
 905 /* --------------------------------------------------------------------------------------------- */

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