1 /* Virtual File System: GNU Tar file system.
2 Copyright (C) 2000 The Free Software Foundation
4 Written by: 2000 Jan Hudec
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public License
10 as published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public
19 License along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25 #include "xdirentry.h"
27 /* #include "utilvfs.h" */
29 #include "../src/dialog.h"
30 /* #include "cpio.h" */
42 CPIO_UNKNOWN
= 0, /* Not determined yet */
43 CPIO_BIN
, /* Binary format */
44 CPIO_BINRE
, /* Binary format, reverse endianity */
45 CPIO_OLDC
, /* Old ASCII format */
46 CPIO_NEWC
, /* New ASCII format */
47 CPIO_CRC
/* New ASCII format + CRC */
50 struct old_cpio_header
52 unsigned short c_magic
;
55 unsigned short c_mode
;
58 unsigned short c_nlink
;
60 unsigned short c_mtimes
[2];
61 unsigned short c_namesize
;
62 unsigned short c_filesizes
[2];
65 struct new_cpio_header
67 unsigned short c_magic
;
72 unsigned long c_nlink
;
73 unsigned long c_mtime
;
74 unsigned long c_filesize
;
79 unsigned long c_namesize
;
80 unsigned long c_chksum
;
84 struct defer_inode
*next
;
85 unsigned long inumber
;
86 unsigned short device
;
90 static int cpio_position
;
92 static int cpio_find_head(vfs
*me
, vfs_s_super
*super
);
93 static int cpio_read_bin_head(vfs
*me
, vfs_s_super
*super
);
94 static int cpio_read_oldc_head(vfs
*me
, vfs_s_super
*super
);
95 static int cpio_read_crc_head(vfs
*me
, vfs_s_super
*super
);
96 static int cpio_create_entry(vfs
*me
, vfs_s_super
*super
, struct stat
*stat
, char *name
);
97 static int cpio_read(void *fh
, char *buffer
, int count
);
99 #define CPIO_POS(super) cpio_position
100 /* If some time reentrancy should be needed change it to */
101 /* #define CPIO_POS(super) (super)->u.cpio.fd */
103 #define CPIO_SEEK_SET(super, where) mc_lseek((super)->u.cpio.fd, CPIO_POS(super) = (where), SEEK_SET)
104 #define CPIO_SEEK_CUR(super, where) mc_lseek((super)->u.cpio.fd, CPIO_POS(super) += (where), SEEK_SET)
106 static struct defer_inode
* defer_find(struct defer_inode
*l
, struct defer_inode
*i
)
109 return l
->inumber
== i
->inumber
&& l
->device
== i
->device
? l
:
110 defer_find(l
->next
, i
);
113 static int cpio_skip_padding(vfs_s_super
*super
)
115 switch(super
->u
.cpio
.type
) {
118 return CPIO_SEEK_CUR(super
, (2 - (CPIO_POS(super
) % 2)) % 2);
121 return CPIO_SEEK_CUR(super
, (4 - (CPIO_POS(super
) % 4)) % 4);
123 return CPIO_POS(super
);
125 g_assert_not_reached();
126 return 42; /* & the compiler is happy :-) */
130 static void cpio_free_archive(vfs
*me
, vfs_s_super
*super
)
132 if(super
->u
.cpio
.fd
!= -1)
133 mc_close(super
->u
.cpio
.fd
);
136 static int cpio_open_cpio_file(vfs
*me
, vfs_s_super
*super
, char *name
)
142 if((fd
= mc_open(name
, O_RDONLY
)) == -1) {
143 message_2s(1, MSG_ERROR
, _("Couldn't open cpio archive\n%s"), name
);
147 super
->name
= g_strdup(name
);
148 super
->u
.cpio
.fd
= -1; /* for now */
149 mc_stat(name
, &(super
->u
.cpio
.stat
));
150 super
->u
.cpio
.type
= CPIO_UNKNOWN
;
152 type
= get_compression_type(fd
);
153 if (type
!= COMPRESSION_NONE
) {
157 s
= g_strconcat(name
, decompress_extension(type
), NULL
);
158 if((fd
= mc_open(s
, O_RDONLY
)) == -1) {
159 message_2s(1, MSG_ERROR
, _("Couldn't open cpio archive\n%s"), s
);
166 super
->u
.cpio
.fd
= fd
;
167 mode
= super
->u
.cpio
.stat
.st_mode
& 07777;
168 mode
|= (mode
& 0444) >> 2; /* set eXec where Read is */
171 root
= vfs_s_new_inode(me
, super
, &(super
->u
.cpio
.stat
));
172 root
->st
.st_mode
= mode
;
173 root
->u
.cpio
.offset
= -1;
175 root
->st
.st_dev
= MEDATA
->rdev
++;
177 vfs_s_add_dots(me
, root
, NULL
);
180 CPIO_SEEK_SET(super
, 0);
185 static int cpio_read_head(vfs
*me
, vfs_s_super
*super
)
187 switch(cpio_find_head(me
, super
)) {
192 return cpio_read_bin_head(me
, super
);
194 return cpio_read_oldc_head(me
, super
);
197 return cpio_read_crc_head(me
, super
);
199 g_assert_not_reached();
200 return 42; /* & the compiler is happy :-) */
204 #define MAGIC_LENGTH (6) /* How many bytes we have to read ahead */
205 #define SEEKBACK CPIO_SEEK_CUR(super, ptr - top)
206 #define RETURN(x) return(super->u.cpio.type = (x))
207 #define TYPEIS(x) ((super->u.cpio.type == CPIO_UNKNOWN) || (super->u.cpio.type == (x)))
208 static int cpio_find_head(vfs
*me
, vfs_s_super
*super
)
215 top
= mc_read(super
->u
.cpio
.fd
, buf
, 256);
216 CPIO_POS(super
) += top
;
218 if(ptr
+ MAGIC_LENGTH
>= top
) {
220 memmove(buf
, buf
+ top
- 128, 128);
224 if((tmp
= mc_read(super
->u
.cpio
.fd
, buf
, top
)) == 0 || tmp
== -1) {
225 message_2s(1, MSG_ERROR
, _("Premature end of cpio archive\n%s"), super
->name
);
226 cpio_free_archive(me
, super
);
231 if(TYPEIS(CPIO_BIN
) && ((*(unsigned short *)(buf
+ ptr
)) == 070707)) {
232 SEEKBACK
; RETURN(CPIO_BIN
);
233 } else if(TYPEIS(CPIO_BINRE
) && ((*(unsigned short *)(buf
+ ptr
)) == GUINT16_SWAP_LE_BE_CONSTANT(070707))) {
234 SEEKBACK
; RETURN(CPIO_BINRE
);
235 } else if(TYPEIS(CPIO_OLDC
) && (!strncmp(buf
+ ptr
, "070707", 6))) {
236 SEEKBACK
; RETURN(CPIO_OLDC
);
237 } else if(TYPEIS(CPIO_NEWC
) && (!strncmp(buf
+ ptr
, "070701", 6))) {
238 SEEKBACK
; RETURN(CPIO_NEWC
);
239 } else if(TYPEIS(CPIO_CRC
) && (!strncmp(buf
+ ptr
, "070702", 6))) {
240 SEEKBACK
; RETURN(CPIO_CRC
);
248 #define HEAD_LENGTH (26)
249 static int cpio_read_bin_head(vfs
*me
, vfs_s_super
*super
)
251 struct old_cpio_header buf
;
256 if((len
= mc_read(super
->u
.cpio
.fd
, (char *)&buf
, HEAD_LENGTH
)) < HEAD_LENGTH
)
258 CPIO_POS(super
) += len
;
259 if(super
->u
.cpio
.type
== CPIO_BINRE
) {
261 for(i
= 0; i
< (HEAD_LENGTH
>> 1); i
++)
262 ((short *)&buf
)[i
] = GUINT16_SWAP_LE_BE(((short *)&buf
)[i
]);
264 g_assert(buf
.c_magic
== 070707);
266 name
= g_malloc(buf
.c_namesize
);
267 if((len
= mc_read(super
->u
.cpio
.fd
, name
, buf
.c_namesize
)) < buf
.c_namesize
){
271 CPIO_POS(super
) += len
;
272 cpio_skip_padding(super
);
274 if(!strcmp("TRAILER!!!", name
)) { /* We got to the last record */
279 stat
.st_dev
= buf
.c_dev
;
280 stat
.st_ino
= buf
.c_ino
;
281 stat
.st_mode
= buf
.c_mode
;
282 stat
.st_nlink
= buf
.c_nlink
;
283 stat
.st_uid
= buf
.c_uid
;
284 stat
.st_gid
= buf
.c_gid
;
285 stat
.st_rdev
= buf
.c_rdev
;
286 stat
.st_size
= (buf
.c_filesizes
[0] << 16) | buf
.c_filesizes
[1];
287 stat
.st_atime
= stat
.st_mtime
= stat
.st_ctime
= (buf
.c_mtimes
[0] << 16) | buf
.c_mtimes
[1];
289 return cpio_create_entry(me
, super
, &stat
, name
);
293 #define HEAD_LENGTH (76)
294 static int cpio_read_oldc_head(vfs
*me
, vfs_s_super
*super
)
296 struct new_cpio_header hd
;
298 char buf
[HEAD_LENGTH
+ 1];
302 if((len
= mc_read(super
->u
.cpio
.fd
, buf
, HEAD_LENGTH
)) < HEAD_LENGTH
)
304 CPIO_POS(super
) += len
;
305 buf
[HEAD_LENGTH
] = 0;
307 if(sscanf(buf
, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
308 &hd
.c_dev
, &hd
.c_ino
, &hd
.c_mode
, &hd
.c_uid
, &hd
.c_gid
,
309 &hd
.c_nlink
, &hd
.c_rdev
, &hd
.c_mtime
,
310 &hd
.c_namesize
, &hd
.c_filesize
) < 10) {
311 message_2s(1, MSG_ERROR
, _("Corrupted cpio header encountered in\n%s"), super
->name
);
315 name
= g_malloc(hd
.c_namesize
);
316 if((len
= mc_read(super
->u
.cpio
.fd
, name
, hd
.c_namesize
)) < hd
.c_namesize
) {
320 CPIO_POS(super
) += len
;
321 cpio_skip_padding(super
);
323 if(!strcmp("TRAILER!!!", name
)) { /* We got to the last record */
328 stat
.st_dev
= hd
.c_dev
;
329 stat
.st_ino
= hd
.c_ino
;
330 stat
.st_mode
= hd
.c_mode
;
331 stat
.st_nlink
= hd
.c_nlink
;
332 stat
.st_uid
= hd
.c_uid
;
333 stat
.st_gid
= hd
.c_gid
;
334 stat
.st_rdev
= hd
.c_rdev
;
335 stat
.st_size
= hd
.c_filesize
;
336 stat
.st_atime
= stat
.st_mtime
= stat
.st_ctime
= hd
.c_mtime
;
338 return cpio_create_entry(me
, super
, &stat
, name
);
342 #define HEAD_LENGTH (110)
343 static int cpio_read_crc_head(vfs
*me
, vfs_s_super
*super
)
345 struct new_cpio_header hd
;
347 char buf
[HEAD_LENGTH
+ 1];
351 if((len
= mc_read(super
->u
.cpio
.fd
, buf
, HEAD_LENGTH
)) < HEAD_LENGTH
)
353 CPIO_POS(super
) += len
;
354 buf
[HEAD_LENGTH
] = 0;
356 if(sscanf(buf
, "%6ho%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx",
357 &hd
.c_magic
, &hd
.c_ino
, &hd
.c_mode
, &hd
.c_uid
, &hd
.c_gid
,
358 &hd
.c_nlink
, &hd
.c_mtime
, &hd
.c_filesize
,
359 &hd
.c_dev
, &hd
.c_devmin
, &hd
.c_rdev
, &hd
.c_rdevmin
,
360 &hd
.c_namesize
, &hd
.c_chksum
) < 14) {
361 message_2s(1, MSG_ERROR
, _("Corrupted cpio header encountered in\n%s"),
366 if((super
->u
.cpio
.type
== CPIO_NEWC
&& hd
.c_magic
!= 070701) ||
367 (super
->u
.cpio
.type
== CPIO_CRC
&& hd
.c_magic
!= 070702))
370 name
= g_malloc(hd
.c_namesize
);
371 if((len
= mc_read(super
->u
.cpio
.fd
, name
, hd
.c_namesize
)) < hd
.c_namesize
){
375 CPIO_POS(super
) += len
;
376 cpio_skip_padding(super
);
378 if(!strcmp("TRAILER!!!", name
)) { /* We got to the last record */
383 stat
.st_dev
= (hd
.c_dev
<< 8) + hd
.c_devmin
;
384 stat
.st_ino
= hd
.c_ino
;
385 stat
.st_mode
= hd
.c_mode
;
386 stat
.st_nlink
= hd
.c_nlink
;
387 stat
.st_uid
= hd
.c_uid
;
388 stat
.st_gid
= hd
.c_gid
;
389 stat
.st_rdev
= (hd
.c_rdev
<< 8) + hd
.c_rdevmin
;
390 stat
.st_size
= hd
.c_filesize
;
391 stat
.st_atime
= stat
.st_mtime
= stat
.st_ctime
= hd
.c_mtime
;
393 return cpio_create_entry(me
, super
, &stat
, name
);
396 static int cpio_create_entry(vfs
*me
, vfs_s_super
*super
, struct stat
*stat
, char *name
)
398 vfs_s_inode
*inode
= NULL
;
399 vfs_s_inode
*root
= super
->root
;
400 vfs_s_entry
*entry
= NULL
;
403 switch (stat
->st_mode
& S_IFMT
) { /* For case of HP/UX archives */
412 if((stat
->st_size
!= 0) &&
413 (stat
->st_rdev
== 0x0001)) {
414 stat
->st_rdev
= (unsigned) stat
->st_size
;
422 if((stat
->st_nlink
> 1) &&
423 (super
->u
.cpio
.type
== CPIO_NEWC
||
424 super
->u
.cpio
.type
== CPIO_CRC
)) { /* For case of harlinked files */
425 struct defer_inode i
, *l
;
426 i
.inumber
= stat
->st_ino
;
427 i
.device
= stat
->st_dev
;
429 if((l
= defer_find(super
->u
.cpio
.defered
, &i
)) != NULL
) {
431 if(inode
->st
.st_size
&& stat
->st_size
&& (inode
->st
.st_size
!= stat
->st_size
)) {
432 message_3s(1, MSG_ERROR
, _("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
439 while(name
[strlen(name
)-1] == PATH_SEP
) name
[strlen(name
)-1] = 0;
440 if((tn
= strrchr(name
, PATH_SEP
))) {
442 root
= vfs_s_find_inode(me
, root
, name
, LINK_FOLLOW
, FL_MKDIR
); /* CHECKME! What function here? */
448 entry
= vfs_s_find_entry_tree(me
, root
, tn
, LINK_FOLLOW
, FL_NONE
); /* In case entry is already there */
450 if(entry
) { /* 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
)) { /* This can be considered archive inconsistency */
455 message_2s(1, MSG_ERROR
, _("%s contains duplicit entries! Skipping!"), super
->name
);
457 entry
->ino
->st
.st_mode
= stat
->st_mode
;
458 entry
->ino
->st
.st_uid
= stat
->st_uid
;
459 entry
->ino
->st
.st_gid
= stat
->st_gid
;
460 entry
->ino
->st
.st_atime
= stat
->st_atime
;
461 entry
->ino
->st
.st_mtime
= stat
->st_mtime
;
462 entry
->ino
->st
.st_ctime
= stat
->st_ctime
;
465 } else { /* !entry */
468 inode
= vfs_s_new_inode(me
, super
, stat
);
469 if((stat
->st_nlink
> 0) &&
470 (super
->u
.cpio
.type
== CPIO_NEWC
||
471 super
->u
.cpio
.type
== CPIO_CRC
)) { /* For case of hardlinked files */
472 struct defer_inode
*i
;
473 i
= g_new(struct defer_inode
, 1);
474 i
->inumber
= stat
->st_ino
;
475 i
->device
= stat
->st_dev
;
477 i
->next
= super
->u
.cpio
.defered
;
478 super
->u
.cpio
.defered
= i
;
483 inode
->u
.cpio
.offset
= CPIO_POS(super
);
485 entry
= vfs_s_new_entry(me
, tn
, inode
);
486 vfs_s_insert_entry(me
, root
, entry
);
488 if(S_ISDIR(stat
->st_mode
))
489 vfs_s_add_dots(me
, inode
, root
);
491 if(S_ISLNK(stat
->st_mode
)) {
492 inode
->linkname
= g_malloc(stat
->st_size
+ 1);
493 if(mc_read(super
->u
.cpio
.fd
, inode
->linkname
, stat
->st_size
) < stat
->st_size
) {
494 inode
->linkname
[0] = 0;
497 inode
->linkname
[stat
->st_size
] = 0; /* Linkname stored without terminating \0 !!! */
498 CPIO_POS(super
) += stat
->st_size
;
499 cpio_skip_padding(super
);
501 CPIO_SEEK_CUR(super
, stat
->st_size
);
510 /* Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
512 static int cpio_open_archive(vfs
*me
, vfs_s_super
*super
, char *name
, char *op
)
514 int status
= STATUS_START
;
516 if(cpio_open_cpio_file(me
, super
, name
) == -1)
520 status
= cpio_read_head(me
, super
);
524 message_2s(1, MSG_ERROR
, _("Unexpected end of file\n%s"), name
);
537 /* Remaining functions are exactly same as for tarfs (and were in fact just copied) */
538 static void *cpio_super_check(vfs
*me
, char *archive_name
, char *op
)
540 static struct stat sb
;
541 if(mc_stat(archive_name
, &sb
))
546 static int cpio_super_same(vfs
*me
, struct vfs_s_super
*parc
, char *archive_name
, char *op
, void *cookie
)
548 struct stat
*archive_stat
= cookie
; /* stat of main archive */
550 if(strcmp(parc
->name
, archive_name
)) return 0;
552 if(vfs_uid
&& (!(archive_stat
->st_mode
& 0004)))
553 if((archive_stat
->st_gid
!= vfs_gid
) || !(archive_stat
->st_mode
& 0040))
554 if((archive_stat
->st_uid
!= vfs_uid
) || !(archive_stat
->st_mode
& 0400))
556 /* Has the cached archive been changed on the disk? */
557 if(parc
->u
.cpio
.stat
.st_mtime
< archive_stat
->st_mtime
) { /* Yes, reload! */
558 (*vfs_cpiofs_ops
.free
) ((vfsid
) parc
);
559 vfs_rmstamp (&vfs_cpiofs_ops
, (vfsid
) parc
, 0);
562 /* Hasn't been modified, give it a new timeout */
563 vfs_stamp (&vfs_cpiofs_ops
, (vfsid
) parc
);
567 static int cpio_read(void *fh
, char *buffer
, int count
)
569 off_t begin
= FH
->ino
->u
.tar
.data_offset
;
570 int fd
= FH_SUPER
->u
.tar
.fd
;
571 vfs
*me
= FH_SUPER
->me
;
573 if (mc_lseek (fd
, begin
+ FH
->pos
, SEEK_SET
) !=
574 begin
+ FH
->pos
) ERRNOR (EIO
, -1);
576 count
= MIN(count
, FH
->ino
->st
.st_size
- FH
->pos
);
578 if ((count
= mc_read (fd
, buffer
, count
)) == -1) ERRNOR (errno
, -1);
584 static int cpio_ungetlocalcopy(vfs
*me
, char *path
, char *local
, int has_changed
)
586 /* We do just nothing. (We are read only and do not need to free local,
587 since it will be freed when tar archive will be freed */
591 static int cpio_fh_open(vfs
*me
, vfs_s_fh
*fh
, int flags
, int mode
)
593 if ((flags
& O_ACCMODE
) != O_RDONLY
) ERRNOR (EROFS
, -1);
597 static struct vfs_s_data cpiofs_data
= {
603 NULL
, /* init inode */
604 NULL
, /* free inode */
605 NULL
, /* init entry */
615 vfs_s_find_entry_tree
,
621 vfs vfs_cpiofs_ops
= {
622 NULL
, /* next pointer */
625 "ucpio", /* prefix */
626 &cpiofs_data
, /* vfs_s_data */