* syntax.c(this_try_alloc_color_pair): Use g_strlcpy instead
[midnight-commander.git] / vfs / cpio.c
blob6537e2e2cb42d61cab540f5ea7ba4de6923c6460
1 /* Virtual File System: GNU Tar file system.
2 Copyright (C) 2000 The Free Software Foundation
4 Written by: 2000 Jan Hudec
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License
8 as published by the Free Software Foundation; either version 2 of
9 the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #include <config.h>
21 #include <errno.h>
22 #include "utilvfs.h"
23 #include "vfs-impl.h"
24 #include "gc.h" /* vfs_rmstamp */
25 #include "xdirentry.h"
27 enum {
28 STATUS_START,
29 STATUS_OK,
30 STATUS_TRAIL,
31 STATUS_FAIL,
32 STATUS_EOF
35 enum {
36 CPIO_UNKNOWN = 0, /* Not determined yet */
37 CPIO_BIN, /* Binary format */
38 CPIO_BINRE, /* Binary format, reverse endianity */
39 CPIO_OLDC, /* Old ASCII format */
40 CPIO_NEWC, /* New ASCII format */
41 CPIO_CRC /* New ASCII format + CRC */
44 static struct vfs_class vfs_cpiofs_ops;
46 struct old_cpio_header
48 unsigned short c_magic;
49 short c_dev;
50 unsigned short c_ino;
51 unsigned short c_mode;
52 unsigned short c_uid;
53 unsigned short c_gid;
54 unsigned short c_nlink;
55 short c_rdev;
56 unsigned short c_mtimes[2];
57 unsigned short c_namesize;
58 unsigned short c_filesizes[2];
61 struct new_cpio_header
63 unsigned short c_magic;
64 unsigned long c_ino;
65 unsigned long c_mode;
66 unsigned long c_uid;
67 unsigned long c_gid;
68 unsigned long c_nlink;
69 unsigned long c_mtime;
70 unsigned long c_filesize;
71 long c_dev;
72 long c_devmin;
73 long c_rdev;
74 long c_rdevmin;
75 unsigned long c_namesize;
76 unsigned long c_chksum;
79 struct defer_inode {
80 struct defer_inode *next;
81 unsigned long inumber;
82 unsigned short device;
83 struct vfs_s_inode *inode;
86 static int cpio_position;
88 static int cpio_find_head(struct vfs_class *me, struct vfs_s_super *super);
89 static int cpio_read_bin_head(struct vfs_class *me, struct vfs_s_super *super);
90 static int cpio_read_oldc_head(struct vfs_class *me, struct vfs_s_super *super);
91 static int cpio_read_crc_head(struct vfs_class *me, struct vfs_s_super *super);
92 static int cpio_create_entry(struct vfs_class *me, struct vfs_s_super *super, struct stat *, char *name);
93 static int cpio_read(void *fh, char *buffer, int count);
95 #define CPIO_POS(super) cpio_position
96 /* If some time reentrancy should be needed change it to */
97 /* #define CPIO_POS(super) (super)->u.arch.fd */
99 #define CPIO_SEEK_SET(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) = (where), SEEK_SET)
100 #define CPIO_SEEK_CUR(super, where) mc_lseek((super)->u.arch.fd, CPIO_POS(super) += (where), SEEK_SET)
102 static struct defer_inode *
103 cpio_defer_find (struct defer_inode *l, struct defer_inode *i)
105 if (!l)
106 return NULL;
107 return l->inumber == i->inumber
108 && l->device == i->device ? l : cpio_defer_find (l->next, i);
111 static int cpio_skip_padding(struct vfs_s_super *super)
113 switch(super->u.arch.type) {
114 case CPIO_BIN:
115 case CPIO_BINRE:
116 return CPIO_SEEK_CUR(super, (2 - (CPIO_POS(super) % 2)) % 2);
117 case CPIO_NEWC:
118 case CPIO_CRC:
119 return CPIO_SEEK_CUR(super, (4 - (CPIO_POS(super) % 4)) % 4);
120 case CPIO_OLDC:
121 return CPIO_POS(super);
122 default:
123 g_assert_not_reached();
124 return 42; /* & the compiler is happy :-) */
128 static void cpio_free_archive(struct vfs_class *me, struct vfs_s_super *super)
130 if(super->u.arch.fd != -1)
131 mc_close(super->u.arch.fd);
134 static int
135 cpio_open_cpio_file (struct vfs_class *me, struct vfs_s_super *super,
136 const char *name)
138 int fd, type;
139 mode_t mode;
140 struct vfs_s_inode *root;
142 if ((fd = mc_open (name, O_RDONLY)) == -1) {
143 message (1, MSG_ERROR, _("Cannot open cpio archive\n%s"), name);
144 return -1;
147 super->name = g_strdup (name);
148 super->u.arch.fd = -1; /* for now */
149 mc_stat (name, &(super->u.arch.st));
150 super->u.arch.type = CPIO_UNKNOWN;
152 type = get_compression_type (fd);
153 if (type != COMPRESSION_NONE) {
154 char *s;
156 mc_close (fd);
157 s = g_strconcat (name, decompress_extension (type), NULL);
158 if ((fd = mc_open (s, O_RDONLY)) == -1) {
159 message (1, MSG_ERROR, _("Cannot open cpio archive\n%s"), s);
160 g_free (s);
161 return -1;
163 g_free (s);
166 super->u.arch.fd = fd;
167 mode = super->u.arch.st.st_mode & 07777;
168 mode |= (mode & 0444) >> 2; /* set eXec where Read is */
169 mode |= S_IFDIR;
171 root = vfs_s_new_inode (me, super, &(super->u.arch.st));
172 root->st.st_mode = mode;
173 root->data_offset = -1;
174 root->st.st_nlink++;
175 root->st.st_dev = MEDATA->rdev++;
177 super->root = root;
179 CPIO_SEEK_SET (super, 0);
181 return fd;
184 static int cpio_read_head(struct vfs_class *me, struct vfs_s_super *super)
186 switch(cpio_find_head(me, super)) {
187 case CPIO_UNKNOWN:
188 return -1;
189 case CPIO_BIN:
190 case CPIO_BINRE:
191 return cpio_read_bin_head(me, super);
192 case CPIO_OLDC:
193 return cpio_read_oldc_head(me, super);
194 case CPIO_NEWC:
195 case CPIO_CRC:
196 return cpio_read_crc_head(me, super);
197 default:
198 g_assert_not_reached();
199 return 42; /* & the compiler is happy :-) */
203 #define MAGIC_LENGTH (6) /* How many bytes we have to read ahead */
204 #define SEEKBACK CPIO_SEEK_CUR(super, ptr - top)
205 #define RETURN(x) return(super->u.arch.type = (x))
206 #define TYPEIS(x) ((super->u.arch.type == CPIO_UNKNOWN) || (super->u.arch.type == (x)))
207 static int cpio_find_head(struct vfs_class *me, struct vfs_s_super *super)
209 char buf[256];
210 int ptr = 0;
211 int top = 0;
212 int tmp;
214 top = mc_read(super->u.arch.fd, buf, 256);
215 CPIO_POS(super) += top;
216 for(;;) {
217 if(ptr + MAGIC_LENGTH >= top) {
218 if(top > 128) {
219 memmove(buf, buf + top - 128, 128);
220 top = 128;
221 ptr -= top - 128;
223 if((tmp = mc_read(super->u.arch.fd, buf, top)) == 0 || tmp == -1) {
224 message (1, MSG_ERROR, _("Premature end of cpio archive\n%s"), super->name);
225 cpio_free_archive(me, super);
226 return CPIO_UNKNOWN;
228 top += tmp;
230 if(TYPEIS(CPIO_BIN) && ((*(unsigned short *)(buf + ptr)) == 070707)) {
231 SEEKBACK; RETURN(CPIO_BIN);
232 } else if(TYPEIS(CPIO_BINRE) && ((*(unsigned short *)(buf + ptr)) == GUINT16_SWAP_LE_BE_CONSTANT(070707))) {
233 SEEKBACK; RETURN(CPIO_BINRE);
234 } else if(TYPEIS(CPIO_OLDC) && (!strncmp(buf + ptr, "070707", 6))) {
235 SEEKBACK; RETURN(CPIO_OLDC);
236 } else if(TYPEIS(CPIO_NEWC) && (!strncmp(buf + ptr, "070701", 6))) {
237 SEEKBACK; RETURN(CPIO_NEWC);
238 } else if(TYPEIS(CPIO_CRC) && (!strncmp(buf + ptr, "070702", 6))) {
239 SEEKBACK; RETURN(CPIO_CRC);
241 ptr++;
244 #undef RETURN
245 #undef SEEKBACK
247 #define HEAD_LENGTH (26)
248 static int cpio_read_bin_head(struct vfs_class *me, struct vfs_s_super *super)
250 struct old_cpio_header buf;
251 int len;
252 char *name;
253 struct stat st;
255 if((len = mc_read(super->u.arch.fd, (char *)&buf, HEAD_LENGTH)) < HEAD_LENGTH)
256 return STATUS_EOF;
257 CPIO_POS(super) += len;
258 if(super->u.arch.type == CPIO_BINRE) {
259 int i;
260 for(i = 0; i < (HEAD_LENGTH >> 1); i++)
261 ((short *)&buf)[i] = GUINT16_SWAP_LE_BE(((short *)&buf)[i]);
263 g_assert(buf.c_magic == 070707);
265 name = g_malloc(buf.c_namesize);
266 if((len = mc_read(super->u.arch.fd, name, buf.c_namesize)) < buf.c_namesize) {
267 g_free(name);
268 return STATUS_EOF;
270 CPIO_POS(super) += len;
271 cpio_skip_padding(super);
273 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
274 g_free(name);
275 return STATUS_TRAIL;
278 st.st_dev = buf.c_dev;
279 st.st_ino = buf.c_ino;
280 st.st_mode = buf.c_mode;
281 st.st_nlink = buf.c_nlink;
282 st.st_uid = buf.c_uid;
283 st.st_gid = buf.c_gid;
284 st.st_rdev = buf.c_rdev;
285 st.st_size = (buf.c_filesizes[0] << 16) | buf.c_filesizes[1];
286 st.st_atime = st.st_mtime = st.st_ctime = (buf.c_mtimes[0] << 16) | buf.c_mtimes[1];
288 return cpio_create_entry(me, super, &st, name);
290 #undef HEAD_LENGTH
292 #define HEAD_LENGTH (76)
293 static int cpio_read_oldc_head(struct vfs_class *me, struct vfs_s_super *super)
295 struct new_cpio_header hd;
296 struct stat st;
297 char buf[HEAD_LENGTH + 1];
298 int len;
299 char *name;
301 if((len = mc_read(super->u.arch.fd, buf, HEAD_LENGTH)) < HEAD_LENGTH)
302 return STATUS_EOF;
303 CPIO_POS(super) += len;
304 buf[HEAD_LENGTH] = 0;
306 if(sscanf(buf, "070707%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo",
307 &hd.c_dev, &hd.c_ino, &hd.c_mode, &hd.c_uid, &hd.c_gid,
308 &hd.c_nlink, &hd.c_rdev, &hd.c_mtime,
309 &hd.c_namesize, &hd.c_filesize) < 10) {
310 message (1, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"), super->name);
311 return STATUS_FAIL;
314 name = g_malloc(hd.c_namesize);
315 if((len = mc_read(super->u.arch.fd, name, hd.c_namesize)) == -1 ||
316 (unsigned long) len < hd.c_namesize) {
317 g_free (name);
318 return STATUS_EOF;
320 CPIO_POS(super) += len;
321 cpio_skip_padding(super);
323 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
324 g_free(name);
325 return STATUS_TRAIL;
328 st.st_dev = hd.c_dev;
329 st.st_ino = hd.c_ino;
330 st.st_mode = hd.c_mode;
331 st.st_nlink = hd.c_nlink;
332 st.st_uid = hd.c_uid;
333 st.st_gid = hd.c_gid;
334 st.st_rdev = hd.c_rdev;
335 st.st_size = hd.c_filesize;
336 st.st_atime = st.st_mtime = st.st_ctime = hd.c_mtime;
338 return cpio_create_entry(me, super, &st, name);
340 #undef HEAD_LENGTH
342 #define HEAD_LENGTH (110)
343 static int cpio_read_crc_head(struct vfs_class *me, struct vfs_s_super *super)
345 struct new_cpio_header hd;
346 struct stat st;
347 char buf[HEAD_LENGTH + 1];
348 int len;
349 char *name;
351 if((len = mc_read(super->u.arch.fd, buf, HEAD_LENGTH)) < HEAD_LENGTH)
352 return STATUS_EOF;
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 (1, MSG_ERROR, _("Corrupted cpio header encountered in\n%s"),
362 super->name);
363 return STATUS_FAIL;
366 if((super->u.arch.type == CPIO_NEWC && hd.c_magic != 070701) ||
367 (super->u.arch.type == CPIO_CRC && hd.c_magic != 070702))
368 return STATUS_FAIL;
370 name = g_malloc(hd.c_namesize);
371 if((len = mc_read(super->u.arch.fd, name, hd.c_namesize)) != -1 &&
372 (unsigned long) len < hd.c_namesize) {
373 g_free (name);
374 return STATUS_EOF;
376 CPIO_POS(super) += len;
377 cpio_skip_padding(super);
379 if(!strcmp("TRAILER!!!", name)) { /* We got to the last record */
380 g_free(name);
381 return STATUS_TRAIL;
384 st.st_dev = (hd.c_dev << 8) + hd.c_devmin;
385 st.st_ino = hd.c_ino;
386 st.st_mode = hd.c_mode;
387 st.st_nlink = hd.c_nlink;
388 st.st_uid = hd.c_uid;
389 st.st_gid = hd.c_gid;
390 st.st_rdev = (hd.c_rdev << 8) + hd.c_rdevmin;
391 st.st_size = hd.c_filesize;
392 st.st_atime = st.st_mtime = st.st_ctime = hd.c_mtime;
394 return cpio_create_entry(me, super, &st, name);
397 static int
398 cpio_create_entry (struct vfs_class *me, struct vfs_s_super *super,
399 struct stat *st, char *name)
401 struct vfs_s_inode *inode = NULL;
402 struct vfs_s_inode *root = super->root;
403 struct vfs_s_entry *entry = NULL;
404 char *tn;
406 switch (st->st_mode & S_IFMT) { /* For case of HP/UX archives */
407 case S_IFCHR:
408 case S_IFBLK:
409 #ifdef S_IFSOCK
410 case S_IFSOCK:
411 #endif
412 #ifdef S_IFIFO
413 case S_IFIFO:
414 #endif
415 if ((st->st_size != 0) && (st->st_rdev == 0x0001)) {
416 st->st_rdev = (unsigned) st->st_size;
417 st->st_size = 0;
419 break;
420 default:
421 break;
424 if ((st->st_nlink > 1) && (super->u.arch.type == CPIO_NEWC || super->u.arch.type == CPIO_CRC)) { /* For case of hardlinked files */
425 struct defer_inode i, *l;
426 i.inumber = st->st_ino;
427 i.device = st->st_dev;
428 i.inode = NULL;
429 if ((l = cpio_defer_find (super->u.arch.deferred, &i)) != NULL) {
430 inode = l->inode;
431 if (inode->st.st_size && st->st_size
432 && (inode->st.st_size != st->st_size)) {
433 message (1, MSG_ERROR,
435 ("Inconsistent hardlinks of\n%s\nin cpio archive\n%s"),
436 name, super->name);
437 inode = NULL;
442 for (tn = name + strlen (name) - 1; tn >= name && *tn == PATH_SEP; tn--)
443 *tn = 0;
444 if ((tn = strrchr (name, PATH_SEP))) {
445 *tn = 0;
446 root = vfs_s_find_inode (me, super, name, LINK_FOLLOW, FL_MKDIR);
447 *tn = PATH_SEP;
448 tn++;
449 } else
450 tn = name;
452 entry = MEDATA->find_entry (me, root, tn, LINK_FOLLOW, FL_NONE); /* In case entry is already there */
454 if (entry) { /* This shouldn't happen! (well, it can happen if there is a record for a
455 file and than a record for a directory it is in; cpio would die with
456 'No such file or directory' is such case) */
458 if (!S_ISDIR (entry->ino->st.st_mode)) { /* This can be considered archive inconsistency */
459 message (1, MSG_ERROR,
460 _("%s contains duplicate entries! Skipping!"),
461 super->name);
462 } else {
463 entry->ino->st.st_mode = st->st_mode;
464 entry->ino->st.st_uid = st->st_uid;
465 entry->ino->st.st_gid = st->st_gid;
466 entry->ino->st.st_atime = st->st_atime;
467 entry->ino->st.st_mtime = st->st_mtime;
468 entry->ino->st.st_ctime = st->st_ctime;
471 } else { /* !entry */
473 if (!inode) {
474 inode = vfs_s_new_inode (me, super, st);
475 if ((st->st_nlink > 0) && (super->u.arch.type == CPIO_NEWC || super->u.arch.type == CPIO_CRC)) { /* For case of hardlinked files */
476 struct defer_inode *i;
477 i = g_new (struct defer_inode, 1);
478 i->inumber = st->st_ino;
479 i->device = st->st_dev;
480 i->inode = inode;
481 i->next = super->u.arch.deferred;
482 super->u.arch.deferred = i;
486 if (st->st_size)
487 inode->data_offset = CPIO_POS (super);
489 entry = vfs_s_new_entry (me, tn, inode);
490 vfs_s_insert_entry (me, root, entry);
492 if (S_ISLNK (st->st_mode)) {
493 inode->linkname = g_malloc (st->st_size + 1);
494 if (mc_read (super->u.arch.fd, inode->linkname, st->st_size)
495 < st->st_size) {
496 inode->linkname[0] = 0;
497 g_free (name);
498 return STATUS_EOF;
500 inode->linkname[st->st_size] = 0; /* Linkname stored without terminating \0 !!! */
501 CPIO_POS (super) += st->st_size;
502 cpio_skip_padding (super);
503 } else {
504 CPIO_SEEK_CUR (super, st->st_size);
507 } /* !entry */
509 g_free (name);
510 return STATUS_OK;
513 /* Need to CPIO_SEEK_CUR to skip the file at the end of add entry!!!! */
515 static int
516 cpio_open_archive (struct vfs_class *me, struct vfs_s_super *super,
517 const char *name, char *op)
519 int status = STATUS_START;
521 if (cpio_open_cpio_file (me, super, name) == -1)
522 return -1;
524 for (;;) {
525 status = cpio_read_head (me, super);
527 switch (status) {
528 case STATUS_EOF:
529 message (1, MSG_ERROR, _("Unexpected end of file\n%s"), name);
530 return 0;
531 case STATUS_OK:
532 continue;
533 case STATUS_TRAIL:
534 break;
536 break;
539 return 0;
542 /* Remaining functions are exactly same as for tarfs (and were in fact just copied) */
543 static void *
544 cpio_super_check (struct vfs_class *me, const char *archive_name, char *op)
546 static struct stat sb;
547 if (mc_stat (archive_name, &sb))
548 return NULL;
549 return &sb;
552 static int
553 cpio_super_same (struct vfs_class *me, struct vfs_s_super *parc,
554 const char *archive_name, char *op, void *cookie)
556 struct stat *archive_stat = cookie; /* stat of main archive */
558 if (strcmp (parc->name, archive_name))
559 return 0;
561 /* Has the cached archive been changed on the disk? */
562 if (parc->u.arch.st.st_mtime < archive_stat->st_mtime) {
563 /* Yes, reload! */
564 (*vfs_cpiofs_ops.free) ((vfsid) parc);
565 vfs_rmstamp (&vfs_cpiofs_ops, (vfsid) parc);
566 return 2;
568 /* Hasn't been modified, give it a new timeout */
569 vfs_stamp (&vfs_cpiofs_ops, (vfsid) parc);
570 return 1;
573 static int cpio_read(void *fh, char *buffer, int count)
575 off_t begin = FH->ino->data_offset;
576 int fd = FH_SUPER->u.arch.fd;
577 struct vfs_class *me = FH_SUPER->me;
579 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) !=
580 begin + FH->pos) ERRNOR (EIO, -1);
582 count = MIN(count, FH->ino->st.st_size - FH->pos);
584 if ((count = mc_read (fd, buffer, count)) == -1) ERRNOR (errno, -1);
586 FH->pos += count;
587 return count;
590 static int cpio_fh_open(struct vfs_class *me, struct vfs_s_fh *fh, int flags, int mode)
592 if ((flags & O_ACCMODE) != O_RDONLY) ERRNOR (EROFS, -1);
593 return 0;
596 void
597 init_cpiofs (void)
599 static struct vfs_s_subclass cpio_subclass;
601 cpio_subclass.flags = VFS_S_READONLY;
602 cpio_subclass.archive_check = cpio_super_check;
603 cpio_subclass.archive_same = cpio_super_same;
604 cpio_subclass.open_archive = cpio_open_archive;
605 cpio_subclass.free_archive = cpio_free_archive;
606 cpio_subclass.fh_open = cpio_fh_open;
608 vfs_s_init_class (&vfs_cpiofs_ops, &cpio_subclass);
609 vfs_cpiofs_ops.name = "cpiofs";
610 vfs_cpiofs_ops.prefix = "ucpio";
611 vfs_cpiofs_ops.read = cpio_read;
612 vfs_cpiofs_ops.setctl = NULL;
613 vfs_register_class (&vfs_cpiofs_ops);