1 /* Virtual File System: GNU Tar file system.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
3 Free Software Foundation, Inc.
5 Written by: 2000 Jan Hudec
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License
9 as published by the Free Software Foundation; either version 2 of
10 the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 * \brief Source: Virtual File System: GNU Tar file system.
32 #include "../src/global.h"
34 #include "../src/wtools.h" /* message() */
35 #include "../src/main.h" /* print_vfs_message */
36 #include "../src/unixcompat.h"
40 #include "gc.h" /* vfs_rmstamp */
41 #include "xdirentry.h"
52 CPIO_UNKNOWN
= 0, /* Not determined yet */
53 CPIO_BIN
, /* Binary format */
54 CPIO_BINRE
, /* Binary format, reverse endianity */
55 CPIO_OLDC
, /* Old ASCII format */
56 CPIO_NEWC
, /* New ASCII format */
57 CPIO_CRC
/* New ASCII format + CRC */
60 static struct vfs_class vfs_cpiofs_ops
;
62 struct old_cpio_header
64 unsigned short c_magic
;
67 unsigned short c_mode
;
70 unsigned short c_nlink
;
72 unsigned short c_mtimes
[2];
73 unsigned short c_namesize
;
74 unsigned short c_filesizes
[2];
77 struct new_cpio_header
79 unsigned short c_magic
;
84 unsigned long c_nlink
;
85 unsigned long c_mtime
;
86 unsigned long c_filesize
;
91 unsigned long c_namesize
;
92 unsigned long c_chksum
;
96 struct defer_inode
*next
;
97 unsigned long inumber
;
98 unsigned short device
;
99 struct vfs_s_inode
*inode
;
102 /* FIXME: should be off_t instead of int. */
103 static int cpio_position
;
105 static int cpio_find_head(struct vfs_class
*me
, struct vfs_s_super
*super
);
106 static ssize_t
cpio_read_bin_head(struct vfs_class
*me
, struct vfs_s_super
*super
);
107 static ssize_t
cpio_read_oldc_head(struct vfs_class
*me
, struct vfs_s_super
*super
);
108 static ssize_t
cpio_read_crc_head(struct vfs_class
*me
, struct vfs_s_super
*super
);
109 static ssize_t
cpio_read(void *fh
, char *buffer
, int count
);
111 #define CPIO_POS(super) cpio_position
112 /* If some time reentrancy should be needed change it to */
113 /* #define CPIO_POS(super) (super)->u.arch.fd */
115 #define CPIO_SEEK_SET(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) = (where), SEEK_SET)
116 #define CPIO_SEEK_CUR(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) += (where), SEEK_SET)
118 static struct defer_inode
*
119 cpio_defer_find (struct defer_inode
*l
, struct defer_inode
*i
)
121 while (l
&& (l
->inumber
!= i
->inumber
|| l
->device
!= i
->device
))
126 static int cpio_skip_padding(struct vfs_s_super
*super
)
128 switch(super
->u
.arch
.type
) {
131 return CPIO_SEEK_CUR(super
, (2 - (CPIO_POS(super
) % 2)) % 2);
134 return CPIO_SEEK_CUR(super
, (4 - (CPIO_POS(super
) % 4)) % 4);
136 return CPIO_POS(super
);
138 g_assert_not_reached();
139 return 42; /* & the compiler is happy :-) */
143 static void cpio_free_archive(struct vfs_class
*me
, struct vfs_s_super
*super
)
145 struct defer_inode
*l
, *lnext
;
149 if(super
->u
.arch
.fd
!= -1)
150 mc_close(super
->u
.arch
.fd
);
151 super
->u
.arch
.fd
= -1;
152 for (l
= super
->u
.arch
.deferred
; l
; l
= lnext
) {
156 super
->u
.arch
.deferred
= NULL
;
160 cpio_open_cpio_file (struct vfs_class
*me
, struct vfs_s_super
*super
,
165 struct vfs_s_inode
*root
;
167 if ((fd
= mc_open (name
, O_RDONLY
)) == -1) {
168 message (D_ERROR
, MSG_ERROR
, _("Cannot open cpio archive\n%s"), name
);
172 super
->name
= g_strdup (name
);
173 super
->u
.arch
.fd
= -1; /* for now */
174 mc_stat (name
, &(super
->u
.arch
.st
));
175 super
->u
.arch
.type
= CPIO_UNKNOWN
;
177 type
= get_compression_type (fd
, name
);
178 if (type
!= COMPRESSION_NONE
) {
182 s
= g_strconcat (name
, decompress_extension (type
), (char *) NULL
);
183 if ((fd
= mc_open (s
, O_RDONLY
)) == -1) {
184 message (D_ERROR
, MSG_ERROR
, _("Cannot open cpio archive\n%s"), s
);
191 super
->u
.arch
.fd
= fd
;
192 mode
= super
->u
.arch
.st
.st_mode
& 07777;
193 mode
|= (mode
& 0444) >> 2; /* set eXec where Read is */
196 root
= vfs_s_new_inode (me
, super
, &(super
->u
.arch
.st
));
197 root
->st
.st_mode
= mode
;
198 root
->data_offset
= -1;
200 root
->st
.st_dev
= MEDATA
->rdev
++;
204 CPIO_SEEK_SET (super
, 0);
209 static ssize_t
cpio_read_head(struct vfs_class
*me
, struct vfs_s_super
*super
)
211 switch(cpio_find_head(me
, super
)) {
216 return cpio_read_bin_head(me
, super
);
218 return cpio_read_oldc_head(me
, super
);
221 return cpio_read_crc_head(me
, super
);
223 g_assert_not_reached();
224 return 42; /* & the compiler is happy :-) */
228 #define MAGIC_LENGTH (6) /* How many bytes we have to read ahead */
229 #define SEEKBACK CPIO_SEEK_CUR(super, ptr - top)
230 #define RETURN(x) return(super->u.arch.type = (x))
231 #define TYPEIS(x) ((super->u.arch.type == CPIO_UNKNOWN) || (super->u.arch.type == (x)))
232 static int cpio_find_head(struct vfs_class
*me
, struct vfs_s_super
*super
)
239 top
= mc_read (super
->u
.arch
.fd
, buf
, 256);
241 CPIO_POS (super
) += top
;
243 if(ptr
+ MAGIC_LENGTH
>= top
) {
245 memmove(buf
, buf
+ top
- 128, 128);
249 if((tmp
= mc_read(super
->u
.arch
.fd
, buf
, top
)) == 0 || tmp
== -1) {
250 message (D_ERROR
, MSG_ERROR
, _("Premature end of cpio archive\n%s"), super
->name
);
251 cpio_free_archive(me
, super
);
256 if(TYPEIS(CPIO_BIN
) && ((*(unsigned short *)(buf
+ ptr
)) == 070707)) {
257 SEEKBACK
; RETURN(CPIO_BIN
);
258 } else if(TYPEIS(CPIO_BINRE
) && ((*(unsigned short *)(buf
+ ptr
)) == GUINT16_SWAP_LE_BE_CONSTANT(070707))) {
259 SEEKBACK
; RETURN(CPIO_BINRE
);
260 } else if(TYPEIS(CPIO_OLDC
) && (!strncmp(buf
+ ptr
, "070707", 6))) {
261 SEEKBACK
; RETURN(CPIO_OLDC
);
262 } else if(TYPEIS(CPIO_NEWC
) && (!strncmp(buf
+ ptr
, "070701", 6))) {
263 SEEKBACK
; RETURN(CPIO_NEWC
);
264 } else if(TYPEIS(CPIO_CRC
) && (!strncmp(buf
+ ptr
, "070702", 6))) {
265 SEEKBACK
; RETURN(CPIO_CRC
);
274 cpio_create_entry (struct vfs_class
*me
, struct vfs_s_super
*super
,
275 struct stat
*st
, char *name
)
277 struct vfs_s_inode
*inode
= NULL
;
278 struct vfs_s_inode
*root
= super
->root
;
279 struct vfs_s_entry
*entry
= NULL
;
282 switch (st
->st_mode
& S_IFMT
) { /* For case of HP/UX archives */
294 if ((st
->st_size
!= 0) && (st
->st_rdev
== 0x0001)) {
295 /* FIXME: representation of major/minor differs between */
296 /* different operating systems. */
297 st
->st_rdev
= (unsigned) st
->st_size
;
305 if ((st
->st_nlink
> 1)
306 && ((super
->u
.arch
.type
== CPIO_NEWC
)
307 || (super
->u
.arch
.type
== CPIO_CRC
))) { /* For case of hardlinked files */
308 struct defer_inode i
, *l
;
309 i
.inumber
= st
->st_ino
;
310 i
.device
= st
->st_dev
;
313 l
= cpio_defer_find (super
->u
.arch
.deferred
, &i
);
316 if (inode
->st
.st_size
!= 0 && st
->st_size
!= 0
317 && (inode
->st
.st_size
!= st
->st_size
)) {
318 message (D_ERROR
, MSG_ERROR
,
319 _("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
322 } else if (inode
->st
.st_size
== 0)
323 inode
->st
.st_size
= st
->st_size
;
327 /* remove trailing slashes */
328 for (tn
= name
+ strlen (name
) - 1; tn
>= name
&& *tn
== PATH_SEP
; tn
--)
331 tn
= strrchr (name
, PATH_SEP
);
334 else if (tn
== name
+ 1) {
335 /* started with "./" -- directory in the root of archive */
339 root
= vfs_s_find_inode (me
, super
, name
, LINK_FOLLOW
, FL_MKDIR
);
344 entry
= MEDATA
->find_entry (me
, root
, tn
, LINK_FOLLOW
, FL_NONE
); /* In case entry is already there */
347 /* This shouldn't happen! (well, it can happen if there is a record for a
348 file and than a record for a directory it is in; cpio would die with
349 'No such file or directory' is such case) */
351 if (!S_ISDIR (entry
->ino
->st
.st_mode
)) {
352 /* This can be considered archive inconsistency */
353 message (D_ERROR
, MSG_ERROR
,
354 _("%s contains duplicate entries! Skipping!"),
357 entry
->ino
->st
.st_mode
= st
->st_mode
;
358 entry
->ino
->st
.st_uid
= st
->st_uid
;
359 entry
->ino
->st
.st_gid
= st
->st_gid
;
360 entry
->ino
->st
.st_atime
= st
->st_atime
;
361 entry
->ino
->st
.st_mtime
= st
->st_mtime
;
362 entry
->ino
->st
.st_ctime
= st
->st_ctime
;
366 } else { /* !entry */
368 inode
= vfs_s_new_inode (me
, super
, st
);
369 if ((st
->st_nlink
> 0)
370 && ((super
->u
.arch
.type
== CPIO_NEWC
)
371 || (super
->u
.arch
.type
== CPIO_CRC
))) {
372 /* For case of hardlinked files */
373 struct defer_inode
*i
;
374 i
= g_new (struct defer_inode
, 1);
375 i
->inumber
= st
->st_ino
;
376 i
->device
= st
->st_dev
;
378 i
->next
= super
->u
.arch
.deferred
;
379 super
->u
.arch
.deferred
= i
;
383 if (st
->st_size
!= 0)
384 inode
->data_offset
= CPIO_POS (super
);
386 entry
= vfs_s_new_entry (me
, tn
, inode
);
387 vfs_s_insert_entry (me
, root
, entry
);
391 if (!S_ISLNK (st
->st_mode
))
392 CPIO_SEEK_CUR (super
, st
->st_size
);
394 inode
->linkname
= g_malloc (st
->st_size
+ 1);
396 if (mc_read (super
->u
.arch
.fd
, inode
->linkname
, st
->st_size
) < st
->st_size
) {
397 inode
->linkname
[0] = '\0';
401 inode
->linkname
[st
->st_size
] = '\0'; /* Linkname stored without terminating \0 !!! */
402 CPIO_POS (super
) += st
->st_size
;
403 cpio_skip_padding (super
);
410 #define HEAD_LENGTH (26)
411 static ssize_t
cpio_read_bin_head(struct vfs_class
*me
, struct vfs_s_super
*super
)
414 struct old_cpio_header buf
;
415 short shorts
[HEAD_LENGTH
>> 1];
421 if((len
= mc_read(super
->u
.arch
.fd
, (char *)&u
.buf
, HEAD_LENGTH
)) < HEAD_LENGTH
)
423 CPIO_POS(super
) += len
;
424 if(super
->u
.arch
.type
== CPIO_BINRE
) {
426 for(i
= 0; i
< (HEAD_LENGTH
>> 1); i
++)
427 u
.shorts
[i
] = GUINT16_SWAP_LE_BE_CONSTANT(u
.shorts
[i
]);
430 if (u
.buf
.c_magic
!= 070707 ||
431 u
.buf
.c_namesize
== 0 || u
.buf
.c_namesize
> MC_MAXPATHLEN
) {
432 message (D_ERROR
, MSG_ERROR
, _("Corrupted cpio header encountered in\n%s"),
436 name
= g_malloc(u
.buf
.c_namesize
);
437 if((len
= mc_read(super
->u
.arch
.fd
, name
, u
.buf
.c_namesize
)) < u
.buf
.c_namesize
) {
441 name
[u
.buf
.c_namesize
- 1] = '\0';
442 CPIO_POS(super
) += len
;
443 cpio_skip_padding(super
);
445 if(!strcmp("TRAILER!!!", name
)) { /* We got to the last record */
450 st
.st_dev
= u
.buf
.c_dev
;
451 st
.st_ino
= u
.buf
.c_ino
;
452 st
.st_mode
= u
.buf
.c_mode
;
453 st
.st_nlink
= u
.buf
.c_nlink
;
454 st
.st_uid
= u
.buf
.c_uid
;
455 st
.st_gid
= u
.buf
.c_gid
;
456 st
.st_rdev
= u
.buf
.c_rdev
;
457 st
.st_size
= (u
.buf
.c_filesizes
[0] << 16) | u
.buf
.c_filesizes
[1];
458 st
.st_atime
= st
.st_mtime
= st
.st_ctime
= (u
.buf
.c_mtimes
[0] << 16) | u
.buf
.c_mtimes
[1];
460 return cpio_create_entry(me
, super
, &st
, name
);
464 #define HEAD_LENGTH (76)
465 static ssize_t
cpio_read_oldc_head(struct vfs_class
*me
, struct vfs_s_super
*super
)
467 struct new_cpio_header hd
;
470 char buf
[HEAD_LENGTH
+ 1];
475 if (mc_read (super
->u
.arch
.fd
, u
.buf
, HEAD_LENGTH
) != HEAD_LENGTH
)
477 CPIO_POS (super
) += HEAD_LENGTH
;
478 u
.buf
[HEAD_LENGTH
] = 0;
480 if (sscanf (u
.buf
, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
481 (unsigned long *)&hd
.c_dev
, &hd
.c_ino
, &hd
.c_mode
, &hd
.c_uid
, &hd
.c_gid
,
482 &hd
.c_nlink
, (unsigned long *)&hd
.c_rdev
, &hd
.c_mtime
,
483 &hd
.c_namesize
, &hd
.c_filesize
) < 10) {
484 message (D_ERROR
, MSG_ERROR
, _("Corrupted cpio header encountered in\n%s"),
489 if (hd
.c_namesize
== 0 || hd
.c_namesize
> MC_MAXPATHLEN
) {
490 message (D_ERROR
, MSG_ERROR
, _("Corrupted cpio header encountered in\n%s"),
494 name
= g_malloc(hd
.c_namesize
);
495 if((len
= mc_read(super
->u
.arch
.fd
, name
, hd
.c_namesize
)) == -1 ||
496 (unsigned long) len
< hd
.c_namesize
) {
500 name
[hd
.c_namesize
- 1] = '\0';
501 CPIO_POS(super
) += len
;
502 cpio_skip_padding(super
);
504 if(!strcmp("TRAILER!!!", name
)) { /* We got to the last record */
509 u
.st
.st_dev
= hd
.c_dev
;
510 u
.st
.st_ino
= hd
.c_ino
;
511 u
.st
.st_mode
= hd
.c_mode
;
512 u
.st
.st_nlink
= hd
.c_nlink
;
513 u
.st
.st_uid
= hd
.c_uid
;
514 u
.st
.st_gid
= hd
.c_gid
;
515 u
.st
.st_rdev
= hd
.c_rdev
;
516 u
.st
.st_size
= hd
.c_filesize
;
517 u
.st
.st_atime
= u
.st
.st_mtime
= u
.st
.st_ctime
= hd
.c_mtime
;
519 return cpio_create_entry (me
, super
, &u
.st
, name
);
523 #define HEAD_LENGTH (110)
525 cpio_read_crc_head (struct vfs_class
*me
, struct vfs_s_super
*super
)
527 struct new_cpio_header hd
;
530 char buf
[HEAD_LENGTH
+ 1];
535 if (mc_read (super
->u
.arch
.fd
, u
.buf
, HEAD_LENGTH
) != HEAD_LENGTH
)
538 CPIO_POS (super
) += HEAD_LENGTH
;
539 u
.buf
[HEAD_LENGTH
] = '\0';
541 if (sscanf (u
.buf
, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
542 &hd
.c_magic
, &hd
.c_ino
, &hd
.c_mode
, &hd
.c_uid
, &hd
.c_gid
,
543 &hd
.c_nlink
, &hd
.c_mtime
, &hd
.c_filesize
,
544 (unsigned long *)&hd
.c_dev
, (unsigned long *)&hd
.c_devmin
,
545 (unsigned long *)&hd
.c_rdev
, (unsigned long *)&hd
.c_rdevmin
,
546 &hd
.c_namesize
, &hd
.c_chksum
) < 14) {
547 message (D_ERROR
, MSG_ERROR
, _("Corrupted cpio header encountered in\n%s"),
552 if((super
->u
.arch
.type
== CPIO_NEWC
&& hd
.c_magic
!= 070701) ||
553 (super
->u
.arch
.type
== CPIO_CRC
&& hd
.c_magic
!= 070702))
556 if (hd
.c_namesize
== 0 || hd
.c_namesize
> MC_MAXPATHLEN
) {
557 message (D_ERROR
, MSG_ERROR
, _("Corrupted cpio header encountered in\n%s"),
562 name
= g_malloc(hd
.c_namesize
);
563 len
= mc_read (super
->u
.arch
.fd
, name
, hd
.c_namesize
);
565 if ((len
== -1) || ((unsigned long) len
< hd
.c_namesize
)) {
569 name
[hd
.c_namesize
- 1] = '\0';
570 CPIO_POS(super
) += len
;
571 cpio_skip_padding(super
);
573 if (strcmp ("TRAILER!!!", name
) == 0) { /* We got to the last record */
578 u
.st
.st_dev
= makedev (hd
.c_dev
, hd
.c_devmin
);
579 u
.st
.st_ino
= hd
.c_ino
;
580 u
.st
.st_mode
= hd
.c_mode
;
581 u
.st
.st_nlink
= hd
.c_nlink
;
582 u
.st
.st_uid
= hd
.c_uid
;
583 u
.st
.st_gid
= hd
.c_gid
;
584 u
.st
.st_rdev
= makedev (hd
.c_rdev
, hd
.c_rdevmin
);
585 u
.st
.st_size
= hd
.c_filesize
;
586 u
.st
.st_atime
= u
.st
.st_mtime
= u
.st
.st_ctime
= hd
.c_mtime
;
588 return cpio_create_entry (me
, super
, &u
.st
, name
);
591 /* Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
594 cpio_open_archive (struct vfs_class
*me
, struct vfs_s_super
*super
,
595 const char *name
, char *op
)
597 int status
= STATUS_START
;
601 if (cpio_open_cpio_file (me
, super
, name
) == -1)
605 status
= cpio_read_head (me
, super
);
609 message (D_ERROR
, MSG_ERROR
, _("Unexpected end of file\n%s"), name
);
622 /* Remaining functions are exactly same as for tarfs (and were in fact just copied) */
624 cpio_super_check (struct vfs_class
*me
, const char *archive_name
, char *op
)
626 static struct stat sb
;
631 if (mc_stat (archive_name
, &sb
))
637 cpio_super_same (struct vfs_class
*me
, struct vfs_s_super
*parc
,
638 const char *archive_name
, char *op
, void *cookie
)
640 struct stat
*archive_stat
= cookie
; /* stat of main archive */
645 if (strcmp (parc
->name
, archive_name
))
648 /* Has the cached archive been changed on the disk? */
649 if (parc
->u
.arch
.st
.st_mtime
< archive_stat
->st_mtime
) {
651 (*vfs_cpiofs_ops
.free
) ((vfsid
) parc
);
652 vfs_rmstamp (&vfs_cpiofs_ops
, (vfsid
) parc
);
655 /* Hasn't been modified, give it a new timeout */
656 vfs_stamp (&vfs_cpiofs_ops
, (vfsid
) parc
);
660 static ssize_t
cpio_read(void *fh
, char *buffer
, int count
)
662 off_t begin
= FH
->ino
->data_offset
;
663 int fd
= FH_SUPER
->u
.arch
.fd
;
664 struct vfs_class
*me
= FH_SUPER
->me
;
666 if (mc_lseek (fd
, begin
+ FH
->pos
, SEEK_SET
) !=
667 begin
+ FH
->pos
) ERRNOR (EIO
, -1);
669 count
= MIN(count
, FH
->ino
->st
.st_size
- FH
->pos
);
671 if ((count
= mc_read (fd
, buffer
, count
)) == -1) ERRNOR (errno
, -1);
677 static int cpio_fh_open(struct vfs_class
*me
, struct vfs_s_fh
*fh
, int flags
, int mode
)
682 if ((flags
& O_ACCMODE
) != O_RDONLY
) ERRNOR (EROFS
, -1);
689 static struct vfs_s_subclass cpio_subclass
;
691 cpio_subclass
.flags
= VFS_S_READONLY
;
692 cpio_subclass
.archive_check
= cpio_super_check
;
693 cpio_subclass
.archive_same
= cpio_super_same
;
694 cpio_subclass
.open_archive
= cpio_open_archive
;
695 cpio_subclass
.free_archive
= cpio_free_archive
;
696 cpio_subclass
.fh_open
= cpio_fh_open
;
698 vfs_s_init_class (&vfs_cpiofs_ops
, &cpio_subclass
);
699 vfs_cpiofs_ops
.name
= "cpiofs";
700 vfs_cpiofs_ops
.prefix
= "ucpio";
701 vfs_cpiofs_ops
.read
= cpio_read
;
702 vfs_cpiofs_ops
.setctl
= NULL
;
703 vfs_register_class (&vfs_cpiofs_ops
);