Ticket #2775: segfault after open incorrect archive
[midnight-commander.git] / src / vfs / cpio / cpio.c
blobcf43749727f145520c2fdef33d4f042e1f14b471
1 /*
2 Virtual File System: GNU Tar file system.
4 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2011
5 The Free Software Foundation, Inc.
7 Written by:
8 Jan Hudec, 2000
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /** \file
27 * \brief Source: Virtual File System: GNU Tar file system.
28 * \author Jan Hudec
29 * \date 2000
32 #include <config.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
40 #include "lib/global.h"
41 #include "lib/unixcompat.h"
42 #include "lib/util.h"
43 #include "lib/widget.h" /* message() */
45 #include "lib/vfs/vfs.h"
46 #include "lib/vfs/utilvfs.h"
47 #include "lib/vfs/xdirentry.h"
48 #include "lib/vfs/gc.h" /* vfs_rmstamp */
50 #include "cpio.h"
52 /*** global variables ****************************************************************************/
54 /*** file scope macro definitions ****************************************************************/
56 #define CPIO_POS(super) cpio_position
57 /* If some time reentrancy should be needed change it to */
58 /* #define CPIO_POS(super) (super)->u.arch.fd */
60 #define CPIO_SEEK_SET(super, where) \
61 mc_lseek (((cpio_super_data_t *)(super)->data)->fd, \
62 CPIO_POS(super) = (where), SEEK_SET)
63 #define CPIO_SEEK_CUR(super, where) \
64 mc_lseek (((cpio_super_data_t *)(super)->data)->fd, \
65 CPIO_POS(super) += (where), SEEK_SET)
67 #define MAGIC_LENGTH (6) /* How many bytes we have to read ahead */
68 #define SEEKBACK CPIO_SEEK_CUR(super, ptr - top)
69 #define RETURN(x) return (((cpio_super_data_t *)super->data)->type = (x))
70 #define TYPEIS(x) \
71 ((((cpio_super_data_t *)super->data)->type == CPIO_UNKNOWN) || \
72 (((cpio_super_data_t *)super->data)->type == (x)))
74 #define HEAD_LENGTH (26)
76 /*** file scope type declarations ****************************************************************/
78 enum
80 STATUS_START,
81 STATUS_OK,
82 STATUS_TRAIL,
83 STATUS_FAIL,
84 STATUS_EOF
87 enum
89 CPIO_UNKNOWN = 0, /* Not determined yet */
90 CPIO_BIN, /* Binary format */
91 CPIO_BINRE, /* Binary format, reverse endianity */
92 CPIO_OLDC, /* Old ASCII format */
93 CPIO_NEWC, /* New ASCII format */
94 CPIO_CRC /* New ASCII format + CRC */
97 struct old_cpio_header
99 unsigned short c_magic;
100 short c_dev;
101 unsigned short c_ino;
102 unsigned short c_mode;
103 unsigned short c_uid;
104 unsigned short c_gid;
105 unsigned short c_nlink;
106 short c_rdev;
107 unsigned short c_mtimes[2];
108 unsigned short c_namesize;
109 unsigned short c_filesizes[2];
112 struct new_cpio_header
114 unsigned short c_magic;
115 unsigned long c_ino;
116 unsigned long c_mode;
117 unsigned long c_uid;
118 unsigned long c_gid;
119 unsigned long c_nlink;
120 unsigned long c_mtime;
121 unsigned long c_filesize;
122 long c_dev;
123 long c_devmin;
124 long c_rdev;
125 long c_rdevmin;
126 unsigned long c_namesize;
127 unsigned long c_chksum;
130 typedef struct
132 unsigned long inumber;
133 unsigned short device;
134 struct vfs_s_inode *inode;
135 } defer_inode;
137 typedef struct
139 int fd;
140 struct stat st;
141 int type; /* Type of the archive */
142 GSList *deferred; /* List of inodes for which another entries may appear */
143 } cpio_super_data_t;
145 /*** file scope variables ************************************************************************/
147 static struct vfs_class vfs_cpiofs_ops;
149 /* FIXME: should be off_t instead of int. */
150 static int cpio_position;
152 /*** file scope functions ************************************************************************/
153 /* --------------------------------------------------------------------------------------------- */
155 static int cpio_find_head (struct vfs_class *me, struct vfs_s_super *super);
156 static ssize_t cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super);
157 static ssize_t cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super);
158 static ssize_t cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super);
159 static ssize_t cpio_read (void *fh, char *buffer, size_t count);
161 /* --------------------------------------------------------------------------------------------- */
163 static int
164 cpio_defer_find (const void *a, const void *b)
166 const defer_inode *a1 = (const defer_inode *) a;
167 const defer_inode *b1 = (const defer_inode *) b;
169 return (a1->inumber == b1->inumber && a1->device == b1->device) ? 0 : 1;
172 /* --------------------------------------------------------------------------------------------- */
174 static int
175 cpio_skip_padding (struct vfs_s_super *super)
177 switch (((cpio_super_data_t *) super->data)->type)
179 case CPIO_BIN:
180 case CPIO_BINRE:
181 return CPIO_SEEK_CUR (super, (2 - (CPIO_POS (super) % 2)) % 2);
182 case CPIO_NEWC:
183 case CPIO_CRC:
184 return CPIO_SEEK_CUR (super, (4 - (CPIO_POS (super) % 4)) % 4);
185 case CPIO_OLDC:
186 return CPIO_POS (super);
187 default:
188 g_assert_not_reached ();
189 return 42; /* & the compiler is happy :-) */
193 /* --------------------------------------------------------------------------------------------- */
195 static void
196 cpio_free_archive (struct vfs_class *me, struct vfs_s_super *super)
198 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
200 (void) me;
202 if (super->data == NULL)
203 return;
205 if (arch->fd != -1)
206 mc_close (arch->fd);
207 arch->fd = -1;
208 g_slist_foreach (arch->deferred, (GFunc) g_free, NULL);
209 g_slist_free (arch->deferred);
210 arch->deferred = NULL;
211 g_free (super->data);
212 super->data = NULL;
215 /* --------------------------------------------------------------------------------------------- */
217 static int
218 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super, const vfs_path_t * vpath)
220 int fd, type;
221 cpio_super_data_t *arch;
222 mode_t mode;
223 struct vfs_s_inode *root;
225 fd = mc_open (vpath, O_RDONLY);
226 if (fd == -1)
228 char *name;
230 name = vfs_path_to_str (vpath);
231 message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), name);
232 g_free (name);
233 return -1;
236 super->name = vfs_path_to_str (vpath);
237 super->data = g_new (cpio_super_data_t, 1);
238 arch = (cpio_super_data_t *) super->data;
239 arch->fd = -1; /* for now */
240 mc_stat (vpath, &arch->st);
241 arch->type = CPIO_UNKNOWN;
242 arch->deferred = NULL;
244 type = get_compression_type (fd, super->name);
245 if (type != COMPRESSION_NONE)
247 char *s;
248 vfs_path_t *tmp_vpath;
250 mc_close (fd);
251 s = g_strconcat (super->name, decompress_extension (type), (char *) NULL);
252 tmp_vpath = vfs_path_from_str (s);
253 fd = mc_open (tmp_vpath, O_RDONLY);
254 vfs_path_free (tmp_vpath);
255 if (fd == -1)
257 message (D_ERROR, MSG_ERROR, _("Cannot open cpio archive\n%s"), s);
258 g_free (s);
259 g_free (super->name);
260 super->name = NULL;
261 return -1;
263 g_free (s);
266 arch->fd = fd;
267 mode = arch->st.st_mode & 07777;
268 mode |= (mode & 0444) >> 2; /* set eXec where Read is */
269 mode |= S_IFDIR;
271 root = vfs_s_new_inode (me, super, &arch->st);
272 root->st.st_mode = mode;
273 root->data_offset = -1;
274 root->st.st_nlink++;
275 root->st.st_dev = MEDATA->rdev++;
277 super->root = root;
279 CPIO_SEEK_SET (super, 0);
281 return fd;
284 /* --------------------------------------------------------------------------------------------- */
286 static ssize_t
287 cpio_read_head (struct vfs_class *me, struct vfs_s_super *super)
289 switch (cpio_find_head (me, super))
291 case CPIO_UNKNOWN:
292 return -1;
293 case CPIO_BIN:
294 case CPIO_BINRE:
295 return cpio_read_bin_head (me, super);
296 case CPIO_OLDC:
297 return cpio_read_oldc_head (me, super);
298 case CPIO_NEWC:
299 case CPIO_CRC:
300 return cpio_read_crc_head (me, super);
301 default:
302 g_assert_not_reached ();
303 return 42; /* & the compiler is happy :-) */
307 /* --------------------------------------------------------------------------------------------- */
309 static int
310 cpio_find_head (struct vfs_class *me, struct vfs_s_super *super)
312 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
313 char buf[BUF_SMALL * 2];
314 int ptr = 0;
315 ssize_t top;
316 ssize_t tmp;
318 top = mc_read (arch->fd, buf, sizeof (buf));
319 if (top > 0)
320 CPIO_POS (super) += top;
322 while (TRUE)
324 if (ptr + MAGIC_LENGTH >= top)
326 if (top > (ssize_t) (sizeof (buf) / 2))
328 memmove (buf, buf + top - sizeof (buf) / 2, sizeof (buf) / 2);
329 ptr -= top - sizeof (buf) / 2;
330 top = sizeof (buf) / 2;
332 tmp = mc_read (arch->fd, buf, top);
333 if (tmp == 0 || tmp == -1)
335 message (D_ERROR, MSG_ERROR, _("Premature end of cpio archive\n%s"), super->name);
336 cpio_free_archive (me, super);
337 return CPIO_UNKNOWN;
339 top += tmp;
341 if (TYPEIS (CPIO_BIN) && ((*(unsigned short *) (buf + ptr)) == 070707))
343 SEEKBACK;
344 RETURN (CPIO_BIN);
346 else if (TYPEIS (CPIO_BINRE)
347 && ((*(unsigned short *) (buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT (070707)))
349 SEEKBACK;
350 RETURN (CPIO_BINRE);
352 else if (TYPEIS (CPIO_OLDC) && (strncmp (buf + ptr, "070707", 6) == 0))
354 SEEKBACK;
355 RETURN (CPIO_OLDC);
357 else if (TYPEIS (CPIO_NEWC) && (strncmp (buf + ptr, "070701", 6) == 0))
359 SEEKBACK;
360 RETURN (CPIO_NEWC);
362 else if (TYPEIS (CPIO_CRC) && (strncmp (buf + ptr, "070702", 6) == 0))
364 SEEKBACK;
365 RETURN (CPIO_CRC);
367 ptr++;
371 /* --------------------------------------------------------------------------------------------- */
373 static int
374 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super, struct stat *st, char *name)
376 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
377 struct vfs_s_inode *inode = NULL;
378 struct vfs_s_inode *root = super->root;
379 struct vfs_s_entry *entry = NULL;
380 char *tn;
382 switch (st->st_mode & S_IFMT)
383 { /* For case of HP/UX archives */
384 case S_IFCHR:
385 case S_IFBLK:
386 #ifdef S_IFSOCK
387 case S_IFSOCK:
388 #endif
389 #ifdef S_IFIFO
390 case S_IFIFO:
391 #endif
392 #ifdef S_IFNAM
393 case S_IFNAM:
394 #endif
395 if ((st->st_size != 0) && (st->st_rdev == 0x0001))
397 /* FIXME: representation of major/minor differs between */
398 /* different operating systems. */
399 st->st_rdev = (unsigned) st->st_size;
400 st->st_size = 0;
402 break;
403 default:
404 break;
407 if ((st->st_nlink > 1) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
408 { /* For case of hardlinked files */
409 defer_inode i = { st->st_ino, st->st_dev, NULL };
410 GSList *l;
412 l = g_slist_find_custom (arch->deferred, &i, cpio_defer_find);
413 if (l != NULL)
415 inode = ((defer_inode *) l->data)->inode;
416 if (inode->st.st_size != 0 && st->st_size != 0 && (inode->st.st_size != st->st_size))
418 message (D_ERROR, MSG_ERROR,
419 _("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
420 name, super->name);
421 inode = NULL;
423 else if (inode->st.st_size == 0)
424 inode->st.st_size = st->st_size;
428 /* remove trailing slashes */
429 for (tn = name + strlen (name) - 1; tn >= name && *tn == PATH_SEP; tn--)
430 *tn = '\0';
432 tn = strrchr (name, PATH_SEP);
433 if (tn == NULL)
434 tn = name;
435 else if (tn == name + 1)
437 /* started with "./" -- directory in the root of archive */
438 tn++;
440 else
442 *tn = '\0';
443 root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
444 *tn = PATH_SEP;
445 tn++;
448 entry = MEDATA->find_entry (me, root, tn, LINK_FOLLOW, FL_NONE); /* In case entry is already there */
450 if (entry != NULL)
452 /* This shouldn't happen! (well, it can happen if there is a record for a
453 file and than a record for a directory it is in; cpio would die with
454 'No such file or directory' is such case) */
456 if (!S_ISDIR (entry->ino->st.st_mode))
458 /* This can be considered archive inconsistency */
459 message (D_ERROR, MSG_ERROR,
460 _("%s contains duplicate entries! Skipping!"), super->name);
462 else
464 entry->ino->st.st_mode = st->st_mode;
465 entry->ino->st.st_uid = st->st_uid;
466 entry->ino->st.st_gid = st->st_gid;
467 entry->ino->st.st_atime = st->st_atime;
468 entry->ino->st.st_mtime = st->st_mtime;
469 entry->ino->st.st_ctime = st->st_ctime;
472 g_free (name);
474 else
475 { /* !entry */
476 if (inode == NULL)
478 inode = vfs_s_new_inode (me, super, st);
479 if ((st->st_nlink > 0) && ((arch->type == CPIO_NEWC) || (arch->type == CPIO_CRC)))
481 /* For case of hardlinked files */
482 defer_inode *i;
484 i = g_new (defer_inode, 1);
485 i->inumber = st->st_ino;
486 i->device = st->st_dev;
487 i->inode = inode;
489 arch->deferred = g_slist_prepend (arch->deferred, i);
493 if (st->st_size != 0)
494 inode->data_offset = CPIO_POS (super);
496 entry = vfs_s_new_entry (me, tn, inode);
497 vfs_s_insert_entry (me, root, entry);
499 g_free (name);
501 if (!S_ISLNK (st->st_mode))
502 CPIO_SEEK_CUR (super, st->st_size);
503 else
505 inode->linkname = g_malloc (st->st_size + 1);
507 if (mc_read (arch->fd, inode->linkname, st->st_size) < st->st_size)
509 inode->linkname[0] = '\0';
510 return STATUS_EOF;
513 inode->linkname[st->st_size] = '\0'; /* Linkname stored without terminating \0 !!! */
514 CPIO_POS (super) += st->st_size;
515 cpio_skip_padding (super);
517 } /* !entry */
519 return STATUS_OK;
522 /* --------------------------------------------------------------------------------------------- */
524 static ssize_t
525 cpio_read_bin_head (struct vfs_class *me, struct vfs_s_super *super)
527 union
529 struct old_cpio_header buf;
530 short shorts[HEAD_LENGTH >> 1];
531 } u;
533 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
534 ssize_t len;
535 char *name;
536 struct stat st;
538 len = mc_read (arch->fd, (char *) &u.buf, HEAD_LENGTH);
539 if (len < HEAD_LENGTH)
540 return STATUS_EOF;
541 CPIO_POS (super) += len;
542 if (arch->type == CPIO_BINRE)
544 int i;
545 for (i = 0; i < (HEAD_LENGTH >> 1); i++)
546 u.shorts[i] = GUINT16_SWAP_LE_BE_CONSTANT (u.shorts[i]);
549 if (u.buf.c_magic != 070707 || u.buf.c_namesize == 0 || u.buf.c_namesize > MC_MAXPATHLEN)
551 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
552 return STATUS_FAIL;
554 name = g_malloc (u.buf.c_namesize);
555 len = mc_read (arch->fd, name, u.buf.c_namesize);
556 if (len < u.buf.c_namesize)
558 g_free (name);
559 return STATUS_EOF;
561 name[u.buf.c_namesize - 1] = '\0';
562 CPIO_POS (super) += len;
563 cpio_skip_padding (super);
565 if (!strcmp ("TRAILER!!!", name))
566 { /* We got to the last record */
567 g_free (name);
568 return STATUS_TRAIL;
571 st.st_dev = u.buf.c_dev;
572 st.st_ino = u.buf.c_ino;
573 st.st_mode = u.buf.c_mode;
574 st.st_nlink = u.buf.c_nlink;
575 st.st_uid = u.buf.c_uid;
576 st.st_gid = u.buf.c_gid;
577 st.st_rdev = u.buf.c_rdev;
578 st.st_size = (u.buf.c_filesizes[0] << 16) | u.buf.c_filesizes[1];
579 st.st_atime = st.st_mtime = st.st_ctime = (u.buf.c_mtimes[0] << 16) | u.buf.c_mtimes[1];
581 return cpio_create_entry (me, super, &st, name);
584 /* --------------------------------------------------------------------------------------------- */
586 #undef HEAD_LENGTH
587 #define HEAD_LENGTH (76)
589 static ssize_t
590 cpio_read_oldc_head (struct vfs_class *me, struct vfs_s_super *super)
592 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
593 struct new_cpio_header hd;
594 union
596 struct stat st;
597 char buf[HEAD_LENGTH + 1];
598 } u;
599 ssize_t len;
600 char *name;
602 if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
603 return STATUS_EOF;
604 CPIO_POS (super) += HEAD_LENGTH;
605 u.buf[HEAD_LENGTH] = 0;
607 if (sscanf (u.buf, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
608 (unsigned long *) &hd.c_dev, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
609 &hd.c_nlink, (unsigned long *) &hd.c_rdev, &hd.c_mtime,
610 &hd.c_namesize, &hd.c_filesize) < 10)
612 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
613 return STATUS_FAIL;
616 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
618 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
619 return STATUS_FAIL;
621 name = g_malloc (hd.c_namesize);
622 len = mc_read (arch->fd, name, hd.c_namesize);
623 if ((len == -1) || ((unsigned long) len < hd.c_namesize))
625 g_free (name);
626 return STATUS_EOF;
628 name[hd.c_namesize - 1] = '\0';
629 CPIO_POS (super) += len;
630 cpio_skip_padding (super);
632 if (!strcmp ("TRAILER!!!", name))
633 { /* We got to the last record */
634 g_free (name);
635 return STATUS_TRAIL;
638 u.st.st_dev = hd.c_dev;
639 u.st.st_ino = hd.c_ino;
640 u.st.st_mode = hd.c_mode;
641 u.st.st_nlink = hd.c_nlink;
642 u.st.st_uid = hd.c_uid;
643 u.st.st_gid = hd.c_gid;
644 u.st.st_rdev = hd.c_rdev;
645 u.st.st_size = hd.c_filesize;
646 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
648 return cpio_create_entry (me, super, &u.st, name);
651 /* --------------------------------------------------------------------------------------------- */
653 #undef HEAD_LENGTH
654 #define HEAD_LENGTH (110)
656 static ssize_t
657 cpio_read_crc_head (struct vfs_class *me, struct vfs_s_super *super)
659 cpio_super_data_t *arch = (cpio_super_data_t *) super->data;
660 struct new_cpio_header hd;
661 union
663 struct stat st;
664 char buf[HEAD_LENGTH + 1];
665 } u;
666 ssize_t len;
667 char *name;
669 if (mc_read (arch->fd, u.buf, HEAD_LENGTH) != HEAD_LENGTH)
670 return STATUS_EOF;
672 CPIO_POS (super) += HEAD_LENGTH;
673 u.buf[HEAD_LENGTH] = '\0';
675 if (sscanf (u.buf, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
676 &hd.c_magic, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
677 &hd.c_nlink, &hd.c_mtime, &hd.c_filesize,
678 (unsigned long *) &hd.c_dev, (unsigned long *) &hd.c_devmin,
679 (unsigned long *) &hd.c_rdev, (unsigned long *) &hd.c_rdevmin,
680 &hd.c_namesize, &hd.c_chksum) < 14)
682 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
683 return STATUS_FAIL;
686 if ((arch->type == CPIO_NEWC && hd.c_magic != 070701) ||
687 (arch->type == CPIO_CRC && hd.c_magic != 070702))
688 return STATUS_FAIL;
690 if (hd.c_namesize == 0 || hd.c_namesize > MC_MAXPATHLEN)
692 message (D_ERROR, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
693 return STATUS_FAIL;
696 name = g_malloc (hd.c_namesize);
697 len = mc_read (arch->fd, name, hd.c_namesize);
699 if ((len == -1) || ((unsigned long) len < hd.c_namesize))
701 g_free (name);
702 return STATUS_EOF;
704 name[hd.c_namesize - 1] = '\0';
705 CPIO_POS (super) += len;
706 cpio_skip_padding (super);
708 if (strcmp ("TRAILER!!!", name) == 0)
709 { /* We got to the last record */
710 g_free (name);
711 return STATUS_TRAIL;
714 u.st.st_dev = makedev (hd.c_dev, hd.c_devmin);
715 u.st.st_ino = hd.c_ino;
716 u.st.st_mode = hd.c_mode;
717 u.st.st_nlink = hd.c_nlink;
718 u.st.st_uid = hd.c_uid;
719 u.st.st_gid = hd.c_gid;
720 u.st.st_rdev = makedev (hd.c_rdev, hd.c_rdevmin);
721 u.st.st_size = hd.c_filesize;
722 u.st.st_atime = u.st.st_mtime = u.st.st_ctime = hd.c_mtime;
724 return cpio_create_entry (me, super, &u.st, name);
727 /* --------------------------------------------------------------------------------------------- */
728 /** Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
730 static int
731 cpio_open_archive (struct vfs_s_super *super, const vfs_path_t * vpath,
732 const vfs_path_element_t * vpath_element)
734 int status = STATUS_START;
736 (void) vpath_element;
738 if (cpio_open_cpio_file (vpath_element->class, super, vpath) == -1)
739 return -1;
741 while (TRUE)
743 status = cpio_read_head (vpath_element->class, super);
745 switch (status)
747 case STATUS_EOF:
749 char *archive_name;
751 archive_name = vfs_path_to_str (vpath);
752 message (D_ERROR, MSG_ERROR, _("Unexpected end of file\n%s"), archive_name);
753 g_free (archive_name);
754 return 0;
756 case STATUS_OK:
757 continue;
758 case STATUS_TRAIL:
759 break;
761 break;
764 return 0;
767 /* --------------------------------------------------------------------------------------------- */
768 /** Remaining functions are exactly same as for tarfs (and were in fact just copied) */
770 static void *
771 cpio_super_check (const vfs_path_t * vpath)
773 static struct stat sb;
774 int stat_result;
776 stat_result = mc_stat (vpath, &sb);
777 return (stat_result == 0 ? &sb : NULL);
780 /* --------------------------------------------------------------------------------------------- */
782 static int
783 cpio_super_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *parc,
784 const vfs_path_t * vpath, void *cookie)
786 struct stat *archive_stat = cookie; /* stat of main archive */
787 char *archive_name = vfs_path_to_str (vpath);
789 (void) vpath_element;
791 if (strcmp (parc->name, archive_name))
793 g_free (archive_name);
794 return 0;
796 g_free (archive_name);
798 /* Has the cached archive been changed on the disk? */
799 if (((cpio_super_data_t *) parc->data)->st.st_mtime < archive_stat->st_mtime)
801 /* Yes, reload! */
802 (*vfs_cpiofs_ops.free) ((vfsid) parc);
803 vfs_rmstamp (&vfs_cpiofs_ops, (vfsid) parc);
804 return 2;
806 /* Hasn't been modified, give it a new timeout */
807 vfs_stamp (&vfs_cpiofs_ops, (vfsid) parc);
808 return 1;
811 /* --------------------------------------------------------------------------------------------- */
813 static ssize_t
814 cpio_read (void *fh, char *buffer, size_t count)
816 off_t begin = FH->ino->data_offset;
817 int fd = ((cpio_super_data_t *) FH_SUPER->data)->fd;
818 struct vfs_class *me = FH_SUPER->me;
819 ssize_t res;
821 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) != begin + FH->pos)
822 ERRNOR (EIO, -1);
824 count = MIN (count, (size_t) (FH->ino->st.st_size - FH->pos));
826 res = mc_read (fd, buffer, count);
827 if (res == -1)
828 ERRNOR (errno, -1);
830 FH->pos += res;
831 return res;
834 /* --------------------------------------------------------------------------------------------- */
836 static int
837 cpio_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
839 (void) mode;
841 fh->data = NULL;
843 if ((flags & O_ACCMODE) != O_RDONLY)
844 ERRNOR (EROFS, -1);
845 return 0;
848 /* --------------------------------------------------------------------------------------------- */
849 /*** public functions ****************************************************************************/
850 /* --------------------------------------------------------------------------------------------- */
852 void
853 init_cpiofs (void)
855 static struct vfs_s_subclass cpio_subclass;
857 cpio_subclass.flags = VFS_S_READONLY; /* FIXME: cpiofs used own temp files */
858 cpio_subclass.archive_check = cpio_super_check;
859 cpio_subclass.archive_same = cpio_super_same;
860 cpio_subclass.open_archive = cpio_open_archive;
861 cpio_subclass.free_archive = cpio_free_archive;
862 cpio_subclass.fh_open = cpio_fh_open;
864 vfs_s_init_class (&vfs_cpiofs_ops, &cpio_subclass);
865 vfs_cpiofs_ops.name = "cpiofs";
866 vfs_cpiofs_ops.prefix = "ucpio";
867 vfs_cpiofs_ops.read = cpio_read;
868 vfs_cpiofs_ops.setctl = NULL;
869 vfs_register_class (&vfs_cpiofs_ops);
872 /* --------------------------------------------------------------------------------------------- */