Clarify usage of st_rdev. Use it if HAVE_STRUCT_STAT_ST_RDEV is defined.
[midnight-commander.git] / src / vfs / cpio / cpio.c
blob88068d2fd072fb53739646b55c33078100f83d72
1 /*
2 Virtual File System: GNU Tar file system.
4 Copyright (C) 2000-2016
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_POS(super) cpio_position
56 /* If some time reentrancy should be needed change it to */
57 /* #define CPIO_POS(super) (super)->u.arch.fd */
59 #define CPIO_SEEK_SET(super, where) \
60 mc_lseek (((cpio_super_data_t *)(super)->data)->fd, \
61 CPIO_POS(super) = (where), SEEK_SET)
62 #define CPIO_SEEK_CUR(super, where) \
63 mc_lseek (((cpio_super_data_t *)(super)->data)->fd, \
64 CPIO_POS(super) += (where), SEEK_SET)
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_data_t *)super->data)->type = (x))
69 #define TYPEIS(x) \
70 ((((cpio_super_data_t *)super->data)->type == CPIO_UNKNOWN) || \
71 (((cpio_super_data_t *)super->data)->type == (x)))
73 #define HEAD_LENGTH (26)
75 /*** file scope type declarations ****************************************************************/
77 enum
79 STATUS_START,
80 STATUS_OK,
81 STATUS_TRAIL,
82 STATUS_FAIL,
83 STATUS_EOF
86 enum
88 CPIO_UNKNOWN = 0, /* Not determined yet */
89 CPIO_BIN, /* Binary format */
90 CPIO_BINRE, /* Binary format, reverse endianity */
91 CPIO_OLDC, /* Old ASCII format */
92 CPIO_NEWC, /* New ASCII format */
93 CPIO_CRC /* New ASCII format + CRC */
96 struct old_cpio_header
98 unsigned short c_magic;
99 short c_dev;
100 unsigned short c_ino;
101 unsigned short c_mode;
102 unsigned short c_uid;
103 unsigned short c_gid;
104 unsigned short c_nlink;
105 short c_rdev;
106 unsigned short c_mtimes[2];
107 unsigned short c_namesize;
108 unsigned short c_filesizes[2];
111 struct new_cpio_header
113 unsigned short c_magic;
114 unsigned long c_ino;
115 unsigned long c_mode;
116 unsigned long c_uid;
117 unsigned long c_gid;
118 unsigned long c_nlink;
119 unsigned long c_mtime;
120 unsigned long c_filesize;
121 long c_dev;
122 long c_devmin;
123 long c_rdev;
124 long c_rdevmin;
125 unsigned long c_namesize;
126 unsigned long c_chksum;
129 typedef struct
131 unsigned long inumber;
132 dev_t device;
133 struct vfs_s_inode *inode;
134 } defer_inode;
136 typedef struct
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_data_t;
144 /*** file scope variables ************************************************************************/
146 static struct vfs_class vfs_cpiofs_ops;
148 static off_t cpio_position;
150 /*** file scope functions ************************************************************************/
151 /* --------------------------------------------------------------------------------------------- */
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);
159 /* --------------------------------------------------------------------------------------------- */
161 static int
162 cpio_defer_find (const void *a, const void *b)
164 const defer_inode *a1 = (const defer_inode *) a;
165 const defer_inode *b1 = (const defer_inode *) b;
167 return (a1->inumber == b1->inumber && a1->device == b1->device) ? 0 : 1;
170 /* --------------------------------------------------------------------------------------------- */
172 static ssize_t
173 cpio_skip_padding (struct vfs_s_super *super)
175 switch (((cpio_super_data_t *) super->data)->type)
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 :-) */
191 /* --------------------------------------------------------------------------------------------- */
193 static void
194 cpio_free_archive (struct vfs_class *me, struct vfs_s_super *super)
196 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
198 (void) me;
200 if (super->data == NULL)
201 return;
203 if (arch->fd != -1)
204 mc_close (arch->fd);
205 arch->fd = -1;
206 g_slist_free_full (arch->deferred, g_free);
207 arch->deferred = NULL;
208 MC_PTR_FREE (super->data);
211 /* --------------------------------------------------------------------------------------------- */
213 static int
214 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super, const vfs_path_t * vpath)
216 int fd, type;
217 cpio_super_data_t *arch;
218 mode_t mode;
219 struct vfs_s_inode *root;
221 fd = mc_open (vpath, O_RDONLY);
222 if (fd == -1)
224 message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), vfs_path_as_str (vpath));
225 return -1;
228 super->name = g_strdup (vfs_path_as_str (vpath));
229 super->data = g_new (cpio_super_data_t, 1);
230 arch = (cpio_super_data_t *) super->data;
231 arch->fd = -1; /* for now */
232 mc_stat (vpath, &arch->st);
233 arch->type = CPIO_UNKNOWN;
234 arch->deferred = NULL;
236 type = get_compression_type (fd, super->name);
237 if (type == COMPRESSION_NONE)
238 mc_lseek (fd, 0, SEEK_SET);
239 else
241 char *s;
242 vfs_path_t *tmp_vpath;
244 mc_close (fd);
245 s = g_strconcat (super->name, decompress_extension (type), (char *) NULL);
246 tmp_vpath = vfs_path_from_str_flags (s, VPF_NO_CANON);
247 fd = mc_open (tmp_vpath, O_RDONLY);
248 vfs_path_free (tmp_vpath);
249 if (fd == -1)
251 message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), s);
252 g_free (s);
253 MC_PTR_FREE (super->name);
254 return -1;
256 g_free (s);
259 arch->fd = fd;
260 mode = arch->st.st_mode & 07777;
261 mode |= (mode & 0444) >> 2; /* set eXec where Read is */
262 mode |= S_IFDIR;
264 root = vfs_s_new_inode (me, super, &arch->st);
265 root->st.st_mode = mode;
266 root->data_offset = -1;
267 root->st.st_nlink++;
268 root->st.st_dev = MEDATA->rdev++;
270 super->root = root;
272 CPIO_SEEK_SET (super, 0);
274 return fd;
277 /* --------------------------------------------------------------------------------------------- */
279 static ssize_t
280 cpio_read_head (struct vfs_class *me, struct vfs_s_super *super)
282 switch (cpio_find_head (me, super))
284 case CPIO_UNKNOWN:
285 return -1;
286 case CPIO_BIN:
287 case CPIO_BINRE:
288 return cpio_read_bin_head (me, super);
289 case CPIO_OLDC:
290 return cpio_read_oldc_head (me, super);
291 case CPIO_NEWC:
292 case CPIO_CRC:
293 return cpio_read_crc_head (me, super);
294 default:
295 g_assert_not_reached ();
296 return 42; /* & the compiler is happy :-) */
300 /* --------------------------------------------------------------------------------------------- */
302 static ssize_t
303 cpio_find_head (struct vfs_class *me, struct vfs_s_super *super)
305 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
306 char buf[BUF_SMALL * 2];
307 ssize_t ptr = 0;
308 ssize_t top;
309 ssize_t tmp;
311 top = mc_read (arch->fd, buf, sizeof (buf));
312 if (top > 0)
313 CPIO_POS (super) += top;
315 while (TRUE)
317 if (ptr + MAGIC_LENGTH >= top)
319 if (top > (ssize_t) (sizeof (buf) / 2))
321 memmove (buf, buf + top - sizeof (buf) / 2, sizeof (buf) / 2);
322 ptr -= top - sizeof (buf) / 2;
323 top = sizeof (buf) / 2;
325 tmp = mc_read (arch->fd, buf, top);
326 if (tmp == 0 || tmp == -1)
328 message (D_ERROR, MSG_ERROR, _("Premature end of cpio archive\n%s"), super->name);
329 cpio_free_archive (me, super);
330 return CPIO_UNKNOWN;
332 top += tmp;
334 if (TYPEIS (CPIO_BIN) && ((*(unsigned short *) (buf + ptr)) == 070707))
336 SEEKBACK;
337 RETURN (CPIO_BIN);
339 else if (TYPEIS (CPIO_BINRE)
340 && ((*(unsigned short *) (buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT (070707)))
342 SEEKBACK;
343 RETURN (CPIO_BINRE);
345 else if (TYPEIS (CPIO_OLDC) && (strncmp (buf + ptr, "070707", 6) == 0))
347 SEEKBACK;
348 RETURN (CPIO_OLDC);
350 else if (TYPEIS (CPIO_NEWC) && (strncmp (buf + ptr, "070701", 6) == 0))
352 SEEKBACK;
353 RETURN (CPIO_NEWC);
355 else if (TYPEIS (CPIO_CRC) && (strncmp (buf + ptr, "070702", 6) == 0))
357 SEEKBACK;
358 RETURN (CPIO_CRC);
360 ptr++;
364 /* --------------------------------------------------------------------------------------------- */
366 static int
367 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super, struct stat *st, char *name)
369 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
370 struct vfs_s_inode *inode = NULL;
371 struct vfs_s_inode *root = super->root;
372 struct vfs_s_entry *entry = NULL;
373 char *tn;
375 switch (st->st_mode & S_IFMT)
376 { /* For case of HP/UX archives */
377 case S_IFCHR:
378 case S_IFBLK:
379 #ifdef S_IFSOCK
380 /* cppcheck-suppress syntaxError */
381 case S_IFSOCK:
382 #endif
383 #ifdef S_IFIFO
384 /* cppcheck-suppress syntaxError */
385 case S_IFIFO:
386 #endif
387 #ifdef S_IFNAM
388 /* cppcheck-suppress syntaxError */
389 case S_IFNAM:
390 #endif
391 #ifdef HAVE_STRUCT_STAT_ST_RDEV
392 if ((st->st_size != 0) && (st->st_rdev == 0x0001))
394 /* FIXME: representation of major/minor differs between */
395 /* different operating systems. */
396 st->st_rdev = (unsigned) st->st_size;
397 st->st_size = 0;
399 #endif
400 break;
401 default:
402 break;
405 if ((st->st_nlink > 1) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
406 { /* For case of hardlinked files */
407 defer_inode i = { st->st_ino, st->st_dev, NULL };
408 GSList *l;
410 l = g_slist_find_custom (arch->deferred, &i, cpio_defer_find);
411 if (l != NULL)
413 inode = ((defer_inode *) l->data)->inode;
414 if (inode->st.st_size != 0 && st->st_size != 0 && (inode->st.st_size != st->st_size))
416 message (D_ERROR, MSG_ERROR,
417 _("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
418 name, super->name);
419 inode = NULL;
421 else if (inode->st.st_size == 0)
422 inode->st.st_size = st->st_size;
426 /* remove trailing slashes */
427 for (tn = name + strlen (name) - 1; tn >= name && IS_PATH_SEP (*tn); tn--)
428 *tn = '\0';
430 tn = strrchr (name, PATH_SEP);
431 if (tn == NULL)
432 tn = name;
433 else if (tn == name + 1)
435 /* started with "./" -- directory in the root of archive */
436 tn++;
438 else
440 *tn = '\0';
441 root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
442 *tn = PATH_SEP;
443 tn++;
446 entry = MEDATA->find_entry (me, root, tn, LINK_FOLLOW, FL_NONE); /* In case entry is already there */
448 if (entry != NULL)
450 /* This shouldn't happen! (well, it can happen if there is a record for a
451 file and than a record for a directory it is in; cpio would die with
452 'No such file or directory' is such case) */
454 if (!S_ISDIR (entry->ino->st.st_mode))
456 /* This can be considered archive inconsistency */
457 message (D_ERROR, MSG_ERROR,
458 _("%s contains duplicate entries! Skipping!"), super->name);
460 else
462 entry->ino->st.st_mode = st->st_mode;
463 entry->ino->st.st_uid = st->st_uid;
464 entry->ino->st.st_gid = st->st_gid;
465 entry->ino->st.st_atime = st->st_atime;
466 entry->ino->st.st_mtime = st->st_mtime;
467 entry->ino->st.st_ctime = st->st_ctime;
470 g_free (name);
472 else
473 { /* !entry */
474 /* root == NULL can be in the following case:
475 * a/b/c -> d
476 * where 'a/b' is the stale link and therefore root of 'c' cannot be found in the archive
478 if (root != NULL)
480 if (inode == NULL)
482 inode = vfs_s_new_inode (me, super, st);
483 if ((st->st_nlink > 0) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
485 /* For case of hardlinked files */
486 defer_inode *i;
488 i = g_new (defer_inode, 1);
489 i->inumber = st->st_ino;
490 i->device = st->st_dev;
491 i->inode = inode;
493 arch->deferred = g_slist_prepend (arch->deferred, i);
497 if (st->st_size != 0)
498 inode->data_offset = CPIO_POS (super);
500 entry = vfs_s_new_entry (me, tn, inode);
501 vfs_s_insert_entry (me, root, entry);
504 g_free (name);
506 if (!S_ISLNK (st->st_mode))
507 CPIO_SEEK_CUR (super, st->st_size);
508 else
510 if (inode != NULL)
512 /* FIXME: do we must read from arch->fd in case of inode != NULL only or in any case? */
514 inode->linkname = g_malloc (st->st_size + 1);
516 if (mc_read (arch->fd, inode->linkname, st->st_size) < st->st_size)
518 inode->linkname[0] = '\0';
519 return STATUS_EOF;
522 inode->linkname[st->st_size] = '\0'; /* Linkname stored without terminating \0 !!! */
525 CPIO_POS (super) += st->st_size;
526 cpio_skip_padding (super);
528 } /* !entry */
530 return STATUS_OK;
533 /* --------------------------------------------------------------------------------------------- */
535 static ssize_t
536 cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super)
538 union
540 struct old_cpio_header buf;
541 short shorts[HEAD_LENGTH >> 1];
542 } u;
544 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
545 ssize_t len;
546 char *name;
547 struct stat st;
549 len = mc_read (arch->fd, (char *) &u.buf, HEAD_LENGTH);
550 if (len < HEAD_LENGTH)
551 return STATUS_EOF;
552 CPIO_POS (super) += len;
553 if (arch->type == CPIO_BINRE)
555 int i;
556 for (i = 0; i < (HEAD_LENGTH >> 1); i++)
557 u.shorts[i] = GUINT16_SWAP_LE_BE_CONSTANT (u.shorts[i]);
560 if (u.buf.c_magic != 070707 || u.buf.c_namesize == 0 || u.buf.c_namesize > MC_MAXPATHLEN)
562 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
563 return STATUS_FAIL;
565 name = g_malloc (u.buf.c_namesize);
566 len = mc_read (arch->fd, name, u.buf.c_namesize);
567 if (len < u.buf.c_namesize)
569 g_free (name);
570 return STATUS_EOF;
572 name[u.buf.c_namesize - 1] = '\0';
573 CPIO_POS (super) += len;
574 cpio_skip_padding (super);
576 if (!strcmp ("TRAILER!!!", name))
577 { /* We got to the last record */
578 g_free (name);
579 return STATUS_TRAIL;
582 st.st_dev = u.buf.c_dev;
583 st.st_ino = u.buf.c_ino;
584 st.st_mode = u.buf.c_mode;
585 st.st_nlink = u.buf.c_nlink;
586 st.st_uid = u.buf.c_uid;
587 st.st_gid = u.buf.c_gid;
588 #ifdef HAVE_STRUCT_STAT_ST_RDEV
589 st.st_rdev = u.buf.c_rdev;
590 #endif
591 st.st_size = (u.buf.c_filesizes[0] << 16) | u.buf.c_filesizes[1];
592 st.st_atime = st.st_mtime = st.st_ctime = (u.buf.c_mtimes[0] << 16) | u.buf.c_mtimes[1];
594 return cpio_create_entry (me, super, &st, name);
597 /* --------------------------------------------------------------------------------------------- */
599 #undef HEAD_LENGTH
600 #define HEAD_LENGTH (76)
602 static ssize_t
603 cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super)
605 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
606 struct new_cpio_header hd;
607 union
609 struct stat st;
610 char buf[HEAD_LENGTH + 1];
611 } u;
612 ssize_t len;
613 char *name;
615 if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
616 return STATUS_EOF;
617 CPIO_POS (super) += HEAD_LENGTH;
618 u.buf[HEAD_LENGTH] = 0;
620 if (sscanf (u.buf, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
621 (unsigned long *) &hd.c_dev, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
622 &hd.c_nlink, (unsigned long *) &hd.c_rdev, &hd.c_mtime,
623 &hd.c_namesize, &hd.c_filesize) < 10)
625 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
626 return STATUS_FAIL;
629 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
631 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
632 return STATUS_FAIL;
634 name = g_malloc (hd.c_namesize);
635 len = mc_read (arch->fd, name, hd.c_namesize);
636 if ((len == -1) || ((unsigned long) len < hd.c_namesize))
638 g_free (name);
639 return STATUS_EOF;
641 name[hd.c_namesize - 1] = '\0';
642 CPIO_POS (super) += len;
643 cpio_skip_padding (super);
645 if (!strcmp ("TRAILER!!!", name))
646 { /* We got to the last record */
647 g_free (name);
648 return STATUS_TRAIL;
651 u.st.st_dev = hd.c_dev;
652 u.st.st_ino = hd.c_ino;
653 u.st.st_mode = hd.c_mode;
654 u.st.st_nlink = hd.c_nlink;
655 u.st.st_uid = hd.c_uid;
656 u.st.st_gid = hd.c_gid;
657 #ifdef HAVE_STRUCT_STAT_ST_RDEV
658 u.st.st_rdev = hd.c_rdev;
659 #endif
660 u.st.st_size = hd.c_filesize;
661 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
663 return cpio_create_entry (me, super, &u.st, name);
666 /* --------------------------------------------------------------------------------------------- */
668 #undef HEAD_LENGTH
669 #define HEAD_LENGTH (110)
671 static ssize_t
672 cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super)
674 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
675 struct new_cpio_header hd;
676 union
678 struct stat st;
679 char buf[HEAD_LENGTH + 1];
680 } u;
681 ssize_t len;
682 char *name;
684 if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
685 return STATUS_EOF;
687 CPIO_POS (super) += HEAD_LENGTH;
688 u.buf[HEAD_LENGTH] = '\0';
690 if (sscanf (u.buf, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
691 &hd.c_magic, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
692 &hd.c_nlink, &hd.c_mtime, &hd.c_filesize,
693 (unsigned long *) &hd.c_dev, (unsigned long *) &hd.c_devmin,
694 (unsigned long *) &hd.c_rdev, (unsigned long *) &hd.c_rdevmin,
695 &hd.c_namesize, &hd.c_chksum) < 14)
697 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
698 return STATUS_FAIL;
701 if ((arch->type == CPIO_NEWC && hd.c_magic != 070701) ||
702 (arch->type == CPIO_CRC && hd.c_magic != 070702))
703 return STATUS_FAIL;
705 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
707 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
708 return STATUS_FAIL;
711 name = g_malloc (hd.c_namesize);
712 len = mc_read (arch->fd, name, hd.c_namesize);
714 if ((len == -1) || ((unsigned long) len < hd.c_namesize))
716 g_free (name);
717 return STATUS_EOF;
719 name[hd.c_namesize - 1] = '\0';
720 CPIO_POS (super) += len;
721 cpio_skip_padding (super);
723 if (strcmp ("TRAILER!!!", name) == 0)
724 { /* We got to the last record */
725 g_free (name);
726 return STATUS_TRAIL;
729 u.st.st_dev = makedev (hd.c_dev, hd.c_devmin);
730 u.st.st_ino = hd.c_ino;
731 u.st.st_mode = hd.c_mode;
732 u.st.st_nlink = hd.c_nlink;
733 u.st.st_uid = hd.c_uid;
734 u.st.st_gid = hd.c_gid;
735 #ifdef HAVE_STRUCT_STAT_ST_RDEV
736 u.st.st_rdev = makedev (hd.c_rdev, hd.c_rdevmin);
737 #endif
738 u.st.st_size = hd.c_filesize;
739 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
741 return cpio_create_entry (me, super, &u.st, name);
744 /* --------------------------------------------------------------------------------------------- */
745 /** Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
747 static int
748 cpio_open_archive (struct vfs_s_super *super, const vfs_path_t * vpath,
749 const vfs_path_element_t * vpath_element)
751 (void) vpath_element;
753 if (cpio_open_cpio_file (vpath_element->class, super, vpath) == -1)
754 return -1;
756 while (TRUE)
758 ssize_t status;
760 status = cpio_read_head (vpath_element->class, super);
761 if (status < 0)
762 return (-1);
764 switch (status)
766 case STATUS_EOF:
768 message (D_ERROR, MSG_ERROR, _("Unexpected end of file\n%s"),
769 vfs_path_as_str (vpath));
770 return 0;
772 case STATUS_OK:
773 continue;
774 case STATUS_TRAIL:
775 break;
776 default:
777 break;
779 break;
782 return 0;
785 /* --------------------------------------------------------------------------------------------- */
786 /** Remaining functions are exactly same as for tarfs (and were in fact just copied) */
788 static void *
789 cpio_super_check (const vfs_path_t * vpath)
791 static struct stat sb;
792 int stat_result;
794 stat_result = mc_stat (vpath, &sb);
795 return (stat_result == 0 ? &sb : NULL);
798 /* --------------------------------------------------------------------------------------------- */
800 static int
801 cpio_super_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *parc,
802 const vfs_path_t * vpath, void *cookie)
804 struct stat *archive_stat = cookie; /* stat of main archive */
806 (void) vpath_element;
808 if (strcmp (parc->name, vfs_path_as_str (vpath)))
809 return 0;
811 /* Has the cached archive been changed on the disk? */
812 if (parc->data != NULL
813 && ((cpio_super_data_t *) parc->data)->st.st_mtime < archive_stat->st_mtime)
815 /* Yes, reload! */
816 (*vfs_cpiofs_ops.free) ((vfsid) parc);
817 vfs_rmstamp (&vfs_cpiofs_ops, (vfsid) parc);
818 return 2;
820 /* Hasn't been modified, give it a new timeout */
821 vfs_stamp (&vfs_cpiofs_ops, (vfsid) parc);
822 return 1;
825 /* --------------------------------------------------------------------------------------------- */
827 static ssize_t
828 cpio_read (void *fh, char *buffer, size_t count)
830 off_t begin = FH->ino->data_offset;
831 int fd = ((cpio_super_data_t *) FH_SUPER->data)->fd;
832 struct vfs_class *me = FH_SUPER->me;
833 ssize_t res;
835 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) != begin + FH->pos)
836 ERRNOR (EIO, -1);
838 count = MIN (count, (size_t) (FH->ino->st.st_size - FH->pos));
840 res = mc_read (fd, buffer, count);
841 if (res == -1)
842 ERRNOR (errno, -1);
844 FH->pos += res;
845 return res;
848 /* --------------------------------------------------------------------------------------------- */
850 static int
851 cpio_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
853 (void) mode;
855 fh->data = NULL;
857 if ((flags & O_ACCMODE) != O_RDONLY)
858 ERRNOR (EROFS, -1);
859 return 0;
862 /* --------------------------------------------------------------------------------------------- */
863 /*** public functions ****************************************************************************/
864 /* --------------------------------------------------------------------------------------------- */
866 void
867 init_cpiofs (void)
869 static struct vfs_s_subclass cpio_subclass;
871 cpio_subclass.flags = VFS_S_READONLY; /* FIXME: cpiofs used own temp files */
872 cpio_subclass.archive_check = cpio_super_check;
873 cpio_subclass.archive_same = cpio_super_same;
874 cpio_subclass.open_archive = cpio_open_archive;
875 cpio_subclass.free_archive = cpio_free_archive;
876 cpio_subclass.fh_open = cpio_fh_open;
878 vfs_s_init_class (&vfs_cpiofs_ops, &cpio_subclass);
879 vfs_cpiofs_ops.name = "cpiofs";
880 vfs_cpiofs_ops.prefix = "ucpio";
881 vfs_cpiofs_ops.read = cpio_read;
882 vfs_cpiofs_ops.setctl = NULL;
883 vfs_register_class (&vfs_cpiofs_ops);
886 /* --------------------------------------------------------------------------------------------- */