maint: fix typos in the code
[midnight-commander.git] / src / vfs / cpio / cpio.c
blobf14443f36a0154673f5bddcd30d7984066052684
1 /*
2 Virtual File System: GNU Tar file system.
4 Copyright (C) 2000-2024
5 Free Software Foundation, Inc.
7 Written by:
8 Jan Hudec, 2000
9 Slava Zanko <slavazanko@gmail.com>, 2013
11 This file is part of the Midnight Commander.
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.
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.
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/>.
27 /** \file
28 * \brief Source: Virtual File System: GNU Tar file system.
29 * \author Jan Hudec
30 * \date 2000
33 #include <config.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
39 #include "lib/global.h"
40 #include "lib/unixcompat.h"
41 #include "lib/util.h"
42 #include "lib/widget.h" /* message() */
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 */
49 #include "cpio.h"
51 /*** global variables ****************************************************************************/
53 /*** file scope macro definitions ****************************************************************/
55 #define CPIO_SUPER(super) ((cpio_super_t *) (super))
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 */
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)
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)))
69 #define HEAD_LENGTH (26)
71 /*** file scope type declarations ****************************************************************/
73 enum
75 STATUS_START,
76 STATUS_OK,
77 STATUS_TRAIL,
78 STATUS_FAIL,
79 STATUS_EOF
82 enum
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 */
92 struct old_cpio_header
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];
107 struct new_cpio_header
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;
125 typedef struct
127 unsigned long inumber;
128 dev_t device;
129 struct vfs_s_inode *inode;
130 } defer_inode;
132 typedef struct
134 struct vfs_s_super base; /* base class */
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;
142 /*** forward declarations (file scope functions) *************************************************/
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);
149 /*** file scope variables ************************************************************************/
151 static struct vfs_s_subclass cpio_subclass;
152 static struct vfs_class *vfs_cpiofs_ops = VFS_CLASS (&cpio_subclass);
154 static off_t cpio_position;
156 /* --------------------------------------------------------------------------------------------- */
157 /*** file scope functions ************************************************************************/
158 /* --------------------------------------------------------------------------------------------- */
160 static int
161 cpio_defer_find (const void *a, const void *b)
163 const defer_inode *a1 = (const defer_inode *) a;
164 const defer_inode *b1 = (const defer_inode *) b;
166 return (a1->inumber == b1->inumber && a1->device == b1->device) ? 0 : 1;
169 /* --------------------------------------------------------------------------------------------- */
171 static ssize_t
172 cpio_skip_padding (struct vfs_s_super *super)
174 switch (CPIO_SUPER (super)->type)
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 :-) */
190 /* --------------------------------------------------------------------------------------------- */
192 static struct vfs_s_super *
193 cpio_new_archive (struct vfs_class *me)
195 cpio_super_t *arch;
197 arch = g_new0 (cpio_super_t, 1);
198 arch->base.me = me;
199 arch->fd = -1; /* for now */
200 arch->type = CPIO_UNKNOWN;
202 return VFS_SUPER (arch);
205 /* --------------------------------------------------------------------------------------------- */
207 static void
208 cpio_free_archive (struct vfs_class *me, struct vfs_s_super *super)
210 cpio_super_t *arch = CPIO_SUPER (super);
212 (void) me;
214 if (arch->fd != -1)
216 mc_close (arch->fd);
217 arch->fd = -1;
220 g_clear_slist (&arch->deferred, g_free);
223 /* --------------------------------------------------------------------------------------------- */
225 static int
226 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super, const vfs_path_t *vpath)
228 int fd, type;
229 cpio_super_t *arch;
230 mode_t mode;
231 struct vfs_s_inode *root;
233 fd = mc_open (vpath, O_RDONLY);
234 if (fd == -1)
236 message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), vfs_path_as_str (vpath));
237 return -1;
240 super->name = g_strdup (vfs_path_as_str (vpath));
241 arch = CPIO_SUPER (super);
242 mc_stat (vpath, &arch->st);
244 type = get_compression_type (fd, super->name);
245 if (type == COMPRESSION_NONE)
246 mc_lseek (fd, 0, SEEK_SET);
247 else
249 char *s;
250 vfs_path_t *tmp_vpath;
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)
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;
264 g_free (s);
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;
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++;
278 super->root = root;
280 CPIO_SEEK_SET (super, 0);
282 return fd;
285 /* --------------------------------------------------------------------------------------------- */
287 static ssize_t
288 cpio_read_head (struct vfs_class *me, struct vfs_s_super *super)
290 switch (cpio_find_head (me, super))
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 :-) */
308 /* --------------------------------------------------------------------------------------------- */
310 static ssize_t
311 cpio_find_head (struct vfs_class *me, struct vfs_s_super *super)
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;
319 top = mc_read (arch->fd, buf, sizeof (buf));
320 if (top > 0)
321 CPIO_POS (super) += top;
323 while (TRUE)
325 if (ptr + MAGIC_LENGTH >= top)
327 if (top > (ssize_t) (sizeof (buf) / 2))
329 memmove (buf, buf + top - sizeof (buf) / 2, sizeof (buf) / 2);
330 ptr -= top - sizeof (buf) / 2;
331 top = sizeof (buf) / 2;
333 tmp = mc_read (arch->fd, buf, top);
334 if (tmp == 0 || tmp == -1)
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;
340 top += tmp;
342 if (TYPEIS (CPIO_BIN) && ((*(unsigned short *) (buf + ptr)) == 070707))
344 SEEKBACK;
345 RETURN (CPIO_BIN);
347 else if (TYPEIS (CPIO_BINRE)
348 && ((*(unsigned short *) (buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT (070707)))
350 SEEKBACK;
351 RETURN (CPIO_BINRE);
353 else if (TYPEIS (CPIO_OLDC) && (strncmp (buf + ptr, "070707", 6) == 0))
355 SEEKBACK;
356 RETURN (CPIO_OLDC);
358 else if (TYPEIS (CPIO_NEWC) && (strncmp (buf + ptr, "070701", 6) == 0))
360 SEEKBACK;
361 RETURN (CPIO_NEWC);
363 else if (TYPEIS (CPIO_CRC) && (strncmp (buf + ptr, "070702", 6) == 0))
365 SEEKBACK;
366 RETURN (CPIO_CRC);
368 ptr++;
372 /* --------------------------------------------------------------------------------------------- */
374 static int
375 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super, struct stat *st, char *name)
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;
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))
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;
407 #endif
408 break;
409 default:
410 break;
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;
418 l = g_slist_find_custom (arch->deferred, &i, cpio_defer_find);
419 if (l != NULL)
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))
424 message (D_ERROR, MSG_ERROR,
425 _("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
426 name, super->name);
427 inode = NULL;
429 else if (inode->st.st_size == 0)
430 inode->st.st_size = st->st_size;
434 /* remove trailing slashes */
435 for (tn = name + strlen (name) - 1; tn >= name && IS_PATH_SEP (*tn); tn--)
436 *tn = '\0';
438 tn = strrchr (name, PATH_SEP);
439 if (tn == NULL)
440 tn = name;
441 else if (tn == name + 1)
443 /* started with "./" -- directory in the root of archive */
444 tn++;
446 else
448 *tn = '\0';
449 root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
450 *tn = PATH_SEP;
451 tn++;
454 entry = VFS_SUBCLASS (me)->find_entry (me, root, tn, LINK_FOLLOW, FL_NONE); /* In case entry is already there */
456 if (entry != NULL)
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) */
462 if (!S_ISDIR (entry->ino->st.st_mode))
464 /* This can be considered archive inconsistency */
465 message (D_ERROR, MSG_ERROR,
466 _("%s contains duplicate entries! Skipping!"), super->name);
468 else
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 #ifdef HAVE_STRUCT_STAT_ST_MTIM
474 entry->ino->st.st_atim = st->st_atim;
475 entry->ino->st.st_mtim = st->st_mtim;
476 entry->ino->st.st_ctim = st->st_ctim;
477 #else
478 entry->ino->st.st_atime = st->st_atime;
479 entry->ino->st.st_mtime = st->st_mtime;
480 entry->ino->st.st_ctime = st->st_ctime;
481 #endif
484 g_free (name);
486 else
487 { /* !entry */
488 /* root == NULL can be in the following case:
489 * a/b/c -> d
490 * where 'a/b' is the stale link and therefore root of 'c' cannot be found in the archive
492 if (root != NULL)
494 if (inode == NULL)
496 inode = vfs_s_new_inode (me, super, st);
497 if ((st->st_nlink > 0) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
499 /* For case of hardlinked files */
500 defer_inode *i;
502 i = g_new (defer_inode, 1);
503 i->inumber = st->st_ino;
504 i->device = st->st_dev;
505 i->inode = inode;
507 arch->deferred = g_slist_prepend (arch->deferred, i);
511 if (st->st_size != 0)
512 inode->data_offset = CPIO_POS (super);
514 entry = vfs_s_new_entry (me, tn, inode);
515 vfs_s_insert_entry (me, root, entry);
518 g_free (name);
520 if (!S_ISLNK (st->st_mode))
521 CPIO_SEEK_CUR (super, st->st_size);
522 else
524 if (inode != NULL)
526 /* FIXME: do we must read from arch->fd in case of inode != NULL only or in any case? */
528 inode->linkname = g_malloc (st->st_size + 1);
530 if (mc_read (arch->fd, inode->linkname, st->st_size) < st->st_size)
532 inode->linkname[0] = '\0';
533 return STATUS_EOF;
536 inode->linkname[st->st_size] = '\0'; /* Linkname stored without terminating \0 !!! */
539 CPIO_POS (super) += st->st_size;
540 cpio_skip_padding (super);
542 } /* !entry */
544 return STATUS_OK;
547 /* --------------------------------------------------------------------------------------------- */
549 static ssize_t
550 cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super)
552 union
554 struct old_cpio_header buf;
555 short shorts[HEAD_LENGTH >> 1];
556 } u;
558 cpio_super_t *arch = CPIO_SUPER (super);
559 ssize_t len;
560 char *name;
561 struct stat st;
563 len = mc_read (arch->fd, (char *) &u.buf, HEAD_LENGTH);
564 if (len < HEAD_LENGTH)
565 return STATUS_EOF;
566 CPIO_POS (super) += len;
567 if (arch->type == CPIO_BINRE)
569 int i;
570 for (i = 0; i < (HEAD_LENGTH >> 1); i++)
571 u.shorts[i] = GUINT16_SWAP_LE_BE_CONSTANT (u.shorts[i]);
574 if (u.buf.c_magic != 070707 || u.buf.c_namesize == 0 || u.buf.c_namesize > MC_MAXPATHLEN)
576 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
577 return STATUS_FAIL;
579 name = g_malloc (u.buf.c_namesize);
580 len = mc_read (arch->fd, name, u.buf.c_namesize);
581 if (len < u.buf.c_namesize)
583 g_free (name);
584 return STATUS_EOF;
586 name[u.buf.c_namesize - 1] = '\0';
587 CPIO_POS (super) += len;
588 cpio_skip_padding (super);
590 if (!strcmp ("TRAILER!!!", name))
591 { /* We got to the last record */
592 g_free (name);
593 return STATUS_TRAIL;
596 st.st_dev = u.buf.c_dev;
597 st.st_ino = u.buf.c_ino;
598 st.st_mode = u.buf.c_mode;
599 st.st_nlink = u.buf.c_nlink;
600 st.st_uid = u.buf.c_uid;
601 st.st_gid = u.buf.c_gid;
602 #ifdef HAVE_STRUCT_STAT_ST_RDEV
603 st.st_rdev = u.buf.c_rdev;
604 #endif
605 st.st_size = ((off_t) u.buf.c_filesizes[0] << 16) | u.buf.c_filesizes[1];
606 #ifdef HAVE_STRUCT_STAT_ST_MTIM
607 st.st_atim.tv_nsec = st.st_mtim.tv_nsec = st.st_ctim.tv_nsec = 0;
608 #endif
609 st.st_atime = st.st_mtime = st.st_ctime =
610 ((time_t) u.buf.c_mtimes[0] << 16) | u.buf.c_mtimes[1];
612 return cpio_create_entry (me, super, &st, name);
615 /* --------------------------------------------------------------------------------------------- */
617 #undef HEAD_LENGTH
618 #define HEAD_LENGTH (76)
620 static ssize_t
621 cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super)
623 cpio_super_t *arch = CPIO_SUPER (super);
624 struct new_cpio_header hd;
625 union
627 struct stat st;
628 char buf[HEAD_LENGTH + 1];
629 } u;
630 ssize_t len;
631 char *name;
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;
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)
643 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
644 return STATUS_FAIL;
647 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
649 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
650 return STATUS_FAIL;
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))
656 g_free (name);
657 return STATUS_EOF;
659 name[hd.c_namesize - 1] = '\0';
660 CPIO_POS (super) += len;
661 cpio_skip_padding (super);
663 if (!strcmp ("TRAILER!!!", name))
664 { /* We got to the last record */
665 g_free (name);
666 return STATUS_TRAIL;
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;
684 return cpio_create_entry (me, super, &u.st, name);
687 /* --------------------------------------------------------------------------------------------- */
689 #undef HEAD_LENGTH
690 #define HEAD_LENGTH (110)
692 static ssize_t
693 cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super)
695 cpio_super_t *arch = CPIO_SUPER (super);
696 struct new_cpio_header hd;
697 union
699 struct stat st;
700 char buf[HEAD_LENGTH + 1];
701 } u;
702 ssize_t len;
703 char *name;
705 if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
706 return STATUS_EOF;
708 CPIO_POS (super) += HEAD_LENGTH;
709 u.buf[HEAD_LENGTH] = '\0';
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)
718 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
719 return STATUS_FAIL;
722 if ((arch->type == CPIO_NEWC && hd.c_magic != 070701) ||
723 (arch->type == CPIO_CRC && hd.c_magic != 070702))
724 return STATUS_FAIL;
726 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
728 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
729 return STATUS_FAIL;
732 name = g_malloc (hd.c_namesize);
733 len = mc_read (arch->fd, name, hd.c_namesize);
735 if ((len == -1) || ((unsigned long) len < hd.c_namesize))
737 g_free (name);
738 return STATUS_EOF;
740 name[hd.c_namesize - 1] = '\0';
741 CPIO_POS (super) += len;
742 cpio_skip_padding (super);
744 if (strcmp ("TRAILER!!!", name) == 0)
745 { /* We got to the last record */
746 g_free (name);
747 return STATUS_TRAIL;
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;
765 return cpio_create_entry (me, super, &u.st, name);
768 /* --------------------------------------------------------------------------------------------- */
769 /** Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
771 static int
772 cpio_open_archive (struct vfs_s_super *super, const vfs_path_t *vpath,
773 const vfs_path_element_t *vpath_element)
775 (void) vpath_element;
777 if (cpio_open_cpio_file (vpath_element->class, super, vpath) == -1)
778 return -1;
780 while (TRUE)
782 ssize_t status;
784 status = cpio_read_head (vpath_element->class, super);
785 if (status < 0)
786 return (-1);
788 switch (status)
790 case STATUS_EOF:
792 message (D_ERROR, MSG_ERROR, _("Unexpected end of file\n%s"),
793 vfs_path_as_str (vpath));
794 return 0;
796 case STATUS_OK:
797 continue;
798 case STATUS_TRAIL:
799 break;
800 default:
801 break;
803 break;
806 return 0;
809 /* --------------------------------------------------------------------------------------------- */
810 /** Remaining functions are exactly same as for tarfs (and were in fact just copied) */
812 static void *
813 cpio_super_check (const vfs_path_t *vpath)
815 static struct stat sb;
816 int stat_result;
818 stat_result = mc_stat (vpath, &sb);
819 return (stat_result == 0 ? &sb : NULL);
822 /* --------------------------------------------------------------------------------------------- */
824 static int
825 cpio_super_same (const vfs_path_element_t *vpath_element, struct vfs_s_super *parc,
826 const vfs_path_t *vpath, void *cookie)
828 struct stat *archive_stat = cookie; /* stat of main archive */
830 (void) vpath_element;
832 if (strcmp (parc->name, vfs_path_as_str (vpath)))
833 return 0;
835 /* Has the cached archive been changed on the disk? */
836 if (parc != NULL && CPIO_SUPER (parc)->st.st_mtime < archive_stat->st_mtime)
838 /* Yes, reload! */
839 vfs_cpiofs_ops->free ((vfsid) parc);
840 vfs_rmstamp (vfs_cpiofs_ops, (vfsid) parc);
841 return 2;
843 /* Hasn't been modified, give it a new timeout */
844 vfs_stamp (vfs_cpiofs_ops, (vfsid) parc);
845 return 1;
848 /* --------------------------------------------------------------------------------------------- */
850 static ssize_t
851 cpio_read (void *fh, char *buffer, size_t count)
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;
859 if (mc_lseek (fd, begin + file->pos, SEEK_SET) != begin + file->pos)
860 ERRNOR (EIO, -1);
862 count = MIN (count, (size_t) (file->ino->st.st_size - file->pos));
864 res = mc_read (fd, buffer, count);
865 if (res == -1)
866 ERRNOR (errno, -1);
868 file->pos += res;
869 return res;
872 /* --------------------------------------------------------------------------------------------- */
874 static int
875 cpio_fh_open (struct vfs_class *me, vfs_file_handler_t *fh, int flags, mode_t mode)
877 (void) fh;
878 (void) mode;
880 if ((flags & O_ACCMODE) != O_RDONLY)
881 ERRNOR (EROFS, -1);
882 return 0;
885 /* --------------------------------------------------------------------------------------------- */
886 /*** public functions ****************************************************************************/
887 /* --------------------------------------------------------------------------------------------- */
889 void
890 vfs_init_cpiofs (void)
892 /* FIXME: cpiofs used own temp files */
893 vfs_init_subclass (&cpio_subclass, "cpiofs", VFSF_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);
905 /* --------------------------------------------------------------------------------------------- */