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

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