Manual pages: mc • mcdiff • mcedit • mcview

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

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