2 Virtual File System: GNU Tar file system.
4 Copyright (C) 2000-2024
5 Free Software Foundation, Inc.
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/>.
28 * \brief Source: Virtual File System: GNU Tar file system.
36 #include <sys/types.h>
39 #include "lib/global.h"
40 #include "lib/unixcompat.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 */
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 ****************************************************************/
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
;
97 unsigned short c_mode
;
100 unsigned short c_nlink
;
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
;
111 unsigned long c_mode
;
114 unsigned long c_nlink
;
115 unsigned long c_mtime
;
116 unsigned long c_filesize
;
121 unsigned long c_namesize
;
122 unsigned long c_chksum
;
127 unsigned long inumber
;
129 struct vfs_s_inode
*inode
;
134 struct vfs_s_super base
; /* base class */
138 int type
; /* Type of the archive */
139 GSList
*deferred
; /* List of inodes for which another entries may appear */
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 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */
172 cpio_skip_padding (struct vfs_s_super
*super
)
174 switch (CPIO_SUPER (super
)->type
)
178 return CPIO_SEEK_CUR (super
, (2 - (CPIO_POS (super
) % 2)) % 2);
181 return CPIO_SEEK_CUR (super
, (4 - (CPIO_POS (super
) % 4)) % 4);
183 return CPIO_POS (super
);
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
)
197 arch
= g_new0 (cpio_super_t
, 1);
199 arch
->fd
= -1; /* for now */
200 arch
->type
= CPIO_UNKNOWN
;
202 return VFS_SUPER (arch
);
205 /* --------------------------------------------------------------------------------------------- */
208 cpio_free_archive (struct vfs_class
*me
, struct vfs_s_super
*super
)
210 cpio_super_t
*arch
= CPIO_SUPER (super
);
220 g_clear_slist (&arch
->deferred
, g_free
);
223 /* --------------------------------------------------------------------------------------------- */
226 cpio_open_cpio_file (struct vfs_class
*me
, struct vfs_s_super
*super
, const vfs_path_t
*vpath
)
231 struct vfs_s_inode
*root
;
233 fd
= mc_open (vpath
, O_RDONLY
);
236 message (D_ERROR
, MSG_ERROR
, _("Cannot open cpio archive\n%s"), vfs_path_as_str (vpath
));
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
);
250 vfs_path_t
*tmp_vpath
;
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
);
259 message (D_ERROR
, MSG_ERROR
, _("Cannot open cpio archive\n%s"), s
);
261 MC_PTR_FREE (super
->name
);
268 mode
= arch
->st
.st_mode
& 07777;
269 mode
|= (mode
& 0444) >> 2; /* set eXec where Read is */
272 root
= vfs_s_new_inode (me
, super
, &arch
->st
);
273 root
->st
.st_mode
= mode
;
274 root
->data_offset
= -1;
276 root
->st
.st_dev
= VFS_SUBCLASS (me
)->rdev
++;
280 CPIO_SEEK_SET (super
, 0);
285 /* --------------------------------------------------------------------------------------------- */
288 cpio_read_head (struct vfs_class
*me
, struct vfs_s_super
*super
)
290 switch (cpio_find_head (me
, super
))
296 return cpio_read_bin_head (me
, super
);
298 return cpio_read_oldc_head (me
, super
);
301 return cpio_read_crc_head (me
, super
);
303 g_assert_not_reached ();
304 return 42; /* & the compiler is happy :-) */
308 /* --------------------------------------------------------------------------------------------- */
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];
319 top
= mc_read (arch
->fd
, buf
, sizeof (buf
));
321 CPIO_POS (super
) += top
;
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
);
342 if (TYPEIS (CPIO_BIN
) && ((*(unsigned short *) (buf
+ ptr
)) == 070707))
347 else if (TYPEIS (CPIO_BINRE
)
348 && ((*(unsigned short *) (buf
+ ptr
)) == GUINT16_SWAP_LE_BE_CONSTANT (070707)))
353 else if (TYPEIS (CPIO_OLDC
) && (strncmp (buf
+ ptr
, "070707", 6) == 0))
358 else if (TYPEIS (CPIO_NEWC
) && (strncmp (buf
+ ptr
, "070701", 6) == 0))
363 else if (TYPEIS (CPIO_CRC
) && (strncmp (buf
+ ptr
, "070702", 6) == 0))
372 /* --------------------------------------------------------------------------------------------- */
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
;
383 switch (st
->st_mode
& S_IFMT
)
384 { /* For case of HP/UX archives */
388 /* cppcheck-suppress syntaxError */
392 /* cppcheck-suppress syntaxError */
396 /* cppcheck-suppress syntaxError */
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
;
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
};
418 l
= g_slist_find_custom (arch
->deferred
, &i
, cpio_defer_find
);
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"),
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
--)
438 tn
= strrchr (name
, PATH_SEP
);
441 else if (tn
== name
+ 1)
443 /* started with "./" -- directory in the root of archive */
449 root
= vfs_s_find_inode (me
, super
, name
, LINK_FOLLOW
, FL_MKDIR
);
454 entry
= VFS_SUBCLASS (me
)->find_entry (me
, root
, tn
, LINK_FOLLOW
, FL_NONE
); /* In case entry is already there */
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
);
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
;
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
;
488 /* root == NULL can be in the following case:
490 * where 'a/b' is the stale link and therefore root of 'c' cannot be found in the archive
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 */
502 i
= g_new (defer_inode
, 1);
503 i
->inumber
= st
->st_ino
;
504 i
->device
= st
->st_dev
;
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
);
520 if (!S_ISLNK (st
->st_mode
))
521 CPIO_SEEK_CUR (super
, st
->st_size
);
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';
536 inode
->linkname
[st
->st_size
] = '\0'; /* Linkname stored without terminating \0 !!! */
539 CPIO_POS (super
) += st
->st_size
;
540 cpio_skip_padding (super
);
547 /* --------------------------------------------------------------------------------------------- */
550 cpio_read_bin_head (struct vfs_class
*me
, struct vfs_s_super
*super
)
554 struct old_cpio_header buf
;
555 short shorts
[HEAD_LENGTH
>> 1];
558 cpio_super_t
*arch
= CPIO_SUPER (super
);
563 len
= mc_read (arch
->fd
, (char *) &u
.buf
, HEAD_LENGTH
);
564 if (len
< HEAD_LENGTH
)
566 CPIO_POS (super
) += len
;
567 if (arch
->type
== CPIO_BINRE
)
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
);
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
)
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 */
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
;
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;
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 /* --------------------------------------------------------------------------------------------- */
618 #define HEAD_LENGTH (76)
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
;
628 char buf
[HEAD_LENGTH
+ 1];
633 if (mc_read (arch
->fd
, u
.buf
, HEAD_LENGTH
) != HEAD_LENGTH
)
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
);
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
);
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
))
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 */
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
;
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;
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 /* --------------------------------------------------------------------------------------------- */
690 #define HEAD_LENGTH (110)
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
;
700 char buf
[HEAD_LENGTH
+ 1];
705 if (mc_read (arch
->fd
, u
.buf
, HEAD_LENGTH
) != HEAD_LENGTH
)
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
);
722 if ((arch
->type
== CPIO_NEWC
&& hd
.c_magic
!= 070701) ||
723 (arch
->type
== CPIO_CRC
&& hd
.c_magic
!= 070702))
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
);
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
))
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 */
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
);
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;
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!!!! */
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)
784 status
= cpio_read_head (vpath_element
->class, super
);
792 message (D_ERROR
, MSG_ERROR
, _("Unexpected end of file\n%s"),
793 vfs_path_as_str (vpath
));
809 /* --------------------------------------------------------------------------------------------- */
810 /** Remaining functions are exactly same as for tarfs (and were in fact just copied) */
813 cpio_super_check (const vfs_path_t
*vpath
)
815 static struct stat sb
;
818 stat_result
= mc_stat (vpath
, &sb
);
819 return (stat_result
== 0 ? &sb
: NULL
);
822 /* --------------------------------------------------------------------------------------------- */
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
)))
835 /* Has the cached archive been changed on the disk? */
836 if (parc
!= NULL
&& CPIO_SUPER (parc
)->st
.st_mtime
< archive_stat
->st_mtime
)
839 vfs_cpiofs_ops
->free ((vfsid
) parc
);
840 vfs_rmstamp (vfs_cpiofs_ops
, (vfsid
) parc
);
843 /* Hasn't been modified, give it a new timeout */
844 vfs_stamp (vfs_cpiofs_ops
, (vfsid
) parc
);
848 /* --------------------------------------------------------------------------------------------- */
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
;
859 if (mc_lseek (fd
, begin
+ file
->pos
, SEEK_SET
) != begin
+ file
->pos
)
862 count
= MIN (count
, (size_t) (file
->ino
->st
.st_size
- file
->pos
));
864 res
= mc_read (fd
, buffer
, count
);
872 /* --------------------------------------------------------------------------------------------- */
875 cpio_fh_open (struct vfs_class
*me
, vfs_file_handler_t
*fh
, int flags
, mode_t mode
)
880 if ((flags
& O_ACCMODE
) != O_RDONLY
)
885 /* --------------------------------------------------------------------------------------------- */
886 /*** public functions ****************************************************************************/
887 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */