Changed interface of function mc_open() for handle vfs_path_t object as parameter
[midnight-commander.git] / src / vfs / tar / tar.c
blob76e7dadf5c9fd8f3ef3f86959d78ac763d460bee
1 /*
2 Virtual File System: GNU Tar file system.
4 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
5 2006, 2007, 2011
6 The Free Software Foundation, Inc.
8 Written by:
9 Jakub Jelinek, 1995
10 Pavel Machek, 1998
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 /**
29 * \file
30 * \brief Source: Virtual File System: GNU Tar file system
31 * \author Jakub Jelinek
32 * \author Pavel Machek
33 * \date 1995, 1998
35 * Namespace: init_tarfs
38 #include <config.h>
39 #include <sys/types.h>
40 #include <errno.h>
41 #include <ctype.h>
42 #include <fcntl.h>
44 #ifdef hpux
45 /* major() and minor() macros (among other things) defined here for hpux */
46 #include <sys/mknod.h>
47 #endif
49 #include "lib/global.h"
50 #include "lib/util.h"
51 #include "lib/widget.h" /* message() */
53 #include "lib/vfs/vfs.h"
54 #include "lib/vfs/utilvfs.h"
55 #include "lib/vfs/xdirentry.h"
56 #include "lib/vfs/gc.h" /* vfs_rmstamp */
58 #include "tar.h"
60 /*** global variables ****************************************************************************/
62 /*** file scope macro definitions ****************************************************************/
65 * Header block on tape.
67 * I'm going to use traditional DP naming conventions here.
68 * A "block" is a big chunk of stuff that we do I/O on.
69 * A "record" is a piece of info that we care about.
70 * Typically many "record"s fit into a "block".
72 #define RECORDSIZE 512
73 #define NAMSIZ 100
74 #define PREFIX_SIZE 155
75 #define TUNMLEN 32
76 #define TGNMLEN 32
77 #define SPARSE_EXT_HDR 21
78 #define SPARSE_IN_HDR 4
80 /* The checksum field is filled with this while the checksum is computed. */
81 #define CHKBLANKS " " /* 8 blanks, no null */
83 /* The magic field is filled with this if uname and gname are valid. */
84 #define TMAGIC "ustar" /* ustar and a null */
85 #define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
87 /* The linkflag defines the type of file */
88 #define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */
89 #define LF_NORMAL '0' /* Normal disk file */
90 #define LF_LINK '1' /* Link to previously dumped file */
91 #define LF_SYMLINK '2' /* Symbolic link */
92 #define LF_CHR '3' /* Character special file */
93 #define LF_BLK '4' /* Block special file */
94 #define LF_DIR '5' /* Directory */
95 #define LF_FIFO '6' /* FIFO special file */
96 #define LF_CONTIG '7' /* Contiguous file */
97 #define LF_EXTHDR 'x' /* pax Extended Header */
98 #define LF_GLOBAL_EXTHDR 'g' /* pax Global Extended Header */
99 /* Further link types may be defined later. */
101 /* Note that the standards committee allows only capital A through
102 capital Z for user-defined expansion. This means that defining something
103 as, say '8' is a *bad* idea. */
104 #define LF_DUMPDIR 'D' /* This is a dir entry that contains
105 the names of files that were in
106 the dir at the time the dump
107 was made */
108 #define LF_LONGLINK 'K' /* Identifies the NEXT file on the tape
109 as having a long linkname */
110 #define LF_LONGNAME 'L' /* Identifies the NEXT file on the tape
111 as having a long name. */
112 #define LF_MULTIVOL 'M' /* This is the continuation
113 of a file that began on another
114 volume */
115 #define LF_NAMES 'N' /* For storing filenames that didn't
116 fit in 100 characters */
117 #define LF_SPARSE 'S' /* This is for sparse files */
118 #define LF_VOLHDR 'V' /* This file is a tape/volume header */
119 /* Ignore it on extraction */
122 * Exit codes from the "tar" program
124 #define EX_SUCCESS 0 /* success! */
125 #define EX_ARGSBAD 1 /* invalid args */
126 #define EX_BADFILE 2 /* invalid filename */
127 #define EX_BADARCH 3 /* bad archive */
128 #define EX_SYSTEM 4 /* system gave unexpected error */
129 #define EX_BADVOL 5 /* Special error code means
130 Tape volume doesn't match the one
131 specified on the command line */
133 #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
135 /*** file scope type declarations ****************************************************************/
137 enum
139 TAR_UNKNOWN = 0,
140 TAR_V7,
141 TAR_USTAR,
142 TAR_POSIX,
143 TAR_GNU
146 struct sparse
148 char offset[12];
149 char numbytes[12];
152 struct sp_array
154 int offset;
155 int numbytes;
158 union record
160 char charptr[RECORDSIZE];
161 struct header
163 char arch_name[NAMSIZ];
164 char mode[8];
165 char uid[8];
166 char gid[8];
167 char size[12];
168 char mtime[12];
169 char chksum[8];
170 char linkflag;
171 char arch_linkname[NAMSIZ];
172 char magic[8];
173 char uname[TUNMLEN];
174 char gname[TGNMLEN];
175 char devmajor[8];
176 char devminor[8];
177 /* The following bytes of the tar header record were originally unused.
179 Archives following the ustar specification use almost all of those
180 bytes to support pathnames of 256 characters in length.
182 GNU tar archives use the "unused" space to support incremental
183 archives and sparse files. */
184 union unused
186 char prefix[PREFIX_SIZE];
187 /* GNU extensions to the ustar (POSIX.1-1988) archive format. */
188 struct oldgnu
190 char atime[12];
191 char ctime[12];
192 char offset[12];
193 char longnames[4];
194 char pad;
195 struct sparse sp[SPARSE_IN_HDR];
196 char isextended;
197 char realsize[12]; /* true size of the sparse file */
198 } oldgnu;
199 } unused;
200 } header;
201 struct extended_header
203 struct sparse sp[21];
204 char isextended;
205 } ext_hdr;
208 typedef enum
210 STATUS_BADCHECKSUM,
211 STATUS_SUCCESS,
212 STATUS_EOFMARK,
213 STATUS_EOF
214 } ReadStatus;
216 typedef struct
218 int fd;
219 struct stat st;
220 int type; /* Type of the archive */
221 } tar_super_data_t;
223 /*** file scope variables ************************************************************************/
225 static struct vfs_class vfs_tarfs_ops;
227 /* As we open one archive at a time, it is safe to have this static */
228 static int current_tar_position = 0;
230 static union record rec_buf;
232 /*** file scope functions ************************************************************************/
233 /* --------------------------------------------------------------------------------------------- */
235 * Quick and dirty octal conversion.
237 * Result is -1 if the field is invalid (all blank, or nonoctal).
239 static long
240 tar_from_oct (int digs, char *where)
242 register long value;
244 while (isspace ((unsigned char) *where))
245 { /* Skip spaces */
246 where++;
247 if (--digs <= 0)
248 return -1; /* All blank field */
250 value = 0;
251 while (digs > 0 && isodigit (*where))
252 { /* Scan till nonoctal */
253 value = (value << 3) | (*where++ - '0');
254 --digs;
257 if (digs > 0 && *where && !isspace ((unsigned char) *where))
258 return -1; /* Ended on non-space/nul */
260 return value;
263 /* --------------------------------------------------------------------------------------------- */
265 static void
266 tar_free_archive (struct vfs_class *me, struct vfs_s_super *archive)
268 (void) me;
270 if (archive->data != NULL)
272 tar_super_data_t *arch = (tar_super_data_t *) archive->data;
274 if (arch->fd != -1)
275 mc_close (arch->fd);
276 g_free (archive->data);
280 /* --------------------------------------------------------------------------------------------- */
282 /* Returns fd of the open tar file */
283 static int
284 tar_open_archive_int (struct vfs_class *me, const vfs_path_t * vpath, struct vfs_s_super *archive)
286 int result, type;
287 tar_super_data_t *arch;
288 mode_t mode;
289 struct vfs_s_inode *root;
291 result = mc_open (vpath, O_RDONLY);
292 if (result == -1)
294 char *name;
296 name = vfs_path_to_str (vpath);
297 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), name);
298 g_free (name);
299 ERRNOR (ENOENT, -1);
302 archive->name = vfs_path_to_str (vpath);
303 archive->data = g_new (tar_super_data_t, 1);
304 arch = (tar_super_data_t *) archive->data;
305 mc_stat (vpath, &arch->st);
306 arch->fd = -1;
307 arch->type = TAR_UNKNOWN;
309 /* Find out the method to handle this tar file */
310 type = get_compression_type (result, archive->name);
311 mc_lseek (result, 0, SEEK_SET);
312 if (type != COMPRESSION_NONE)
314 char *s;
315 vfs_path_t *tmp_vpath;
317 mc_close (result);
318 s = g_strconcat (archive->name, decompress_extension (type), (char *) NULL);
319 tmp_vpath = vfs_path_from_str (s);
320 result = mc_open (tmp_vpath, O_RDONLY);
321 vfs_path_free (tmp_vpath);
322 if (result == -1)
323 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), s);
324 g_free (s);
325 if (result == -1)
327 g_free (archive->name);
328 ERRNOR (ENOENT, -1);
332 arch->fd = result;
333 mode = arch->st.st_mode & 07777;
334 if (mode & 0400)
335 mode |= 0100;
336 if (mode & 0040)
337 mode |= 0010;
338 if (mode & 0004)
339 mode |= 0001;
340 mode |= S_IFDIR;
342 root = vfs_s_new_inode (me, archive, &arch->st);
343 root->st.st_mode = mode;
344 root->data_offset = -1;
345 root->st.st_nlink++;
346 root->st.st_dev = MEDATA->rdev++;
348 archive->root = root;
350 return result;
353 /* --------------------------------------------------------------------------------------------- */
355 static union record *
356 tar_get_next_record (struct vfs_s_super *archive, int tard)
358 int n;
360 (void) archive;
362 n = mc_read (tard, rec_buf.charptr, RECORDSIZE);
363 if (n != RECORDSIZE)
364 return NULL; /* An error has occurred */
365 current_tar_position += RECORDSIZE;
366 return &rec_buf;
369 /* --------------------------------------------------------------------------------------------- */
371 static void
372 tar_skip_n_records (struct vfs_s_super *archive, int tard, int n)
374 (void) archive;
376 mc_lseek (tard, n * RECORDSIZE, SEEK_CUR);
377 current_tar_position += n * RECORDSIZE;
380 /* --------------------------------------------------------------------------------------------- */
382 static void
383 tar_fill_stat (struct vfs_s_super *archive, struct stat *st, union record *header, size_t h_size)
385 tar_super_data_t *arch = (tar_super_data_t *) archive->data;
387 st->st_mode = tar_from_oct (8, header->header.mode);
389 /* Adjust st->st_mode because there are tar-files with
390 * linkflag==LF_SYMLINK and S_ISLNK(mod)==0. I don't
391 * know about the other modes but I think I cause no new
392 * problem when I adjust them, too. -- Norbert.
394 if (header->header.linkflag == LF_DIR)
395 st->st_mode |= S_IFDIR;
396 else if (header->header.linkflag == LF_SYMLINK)
397 st->st_mode |= S_IFLNK;
398 else if (header->header.linkflag == LF_CHR)
399 st->st_mode |= S_IFCHR;
400 else if (header->header.linkflag == LF_BLK)
401 st->st_mode |= S_IFBLK;
402 else if (header->header.linkflag == LF_FIFO)
403 st->st_mode |= S_IFIFO;
404 else
405 st->st_mode |= S_IFREG;
407 st->st_rdev = 0;
408 switch (arch->type)
410 case TAR_USTAR:
411 case TAR_POSIX:
412 case TAR_GNU:
413 /* *INDENT-OFF* */
414 st->st_uid = *header->header.uname
415 ? vfs_finduid (header->header.uname)
416 : tar_from_oct (8, header->header.uid);
417 st->st_gid = *header->header.gname
418 ? vfs_findgid (header->header.gname)
419 : tar_from_oct (8,header->header.gid);
420 /* *INDENT-ON* */
422 switch (header->header.linkflag)
424 case LF_BLK:
425 case LF_CHR:
426 st->st_rdev =
427 (tar_from_oct (8, header->header.devmajor) << 8) |
428 tar_from_oct (8, header->header.devminor);
430 default:
431 st->st_uid = tar_from_oct (8, header->header.uid);
432 st->st_gid = tar_from_oct (8, header->header.gid);
434 st->st_size = h_size;
435 st->st_mtime = tar_from_oct (1 + 12, header->header.mtime);
436 st->st_atime = 0;
437 st->st_ctime = 0;
438 if (arch->type == TAR_GNU)
440 st->st_atime = tar_from_oct (1 + 12, header->header.unused.oldgnu.atime);
441 st->st_ctime = tar_from_oct (1 + 12, header->header.unused.oldgnu.ctime);
445 /* --------------------------------------------------------------------------------------------- */
447 * Return 1 for success, 0 if the checksum is bad, EOF on eof,
448 * 2 for a record full of zeros (EOF marker).
451 static ReadStatus
452 tar_read_header (struct vfs_class *me, struct vfs_s_super *archive, int tard, size_t * h_size)
454 tar_super_data_t *arch = (tar_super_data_t *) archive->data;
456 register int i;
457 register long sum, signed_sum, recsum;
458 register char *p;
459 register union record *header;
460 static char *next_long_name = NULL, *next_long_link = NULL;
462 recurse:
464 header = tar_get_next_record (archive, tard);
465 if (NULL == header)
466 return STATUS_EOF;
468 recsum = tar_from_oct (8, header->header.chksum);
470 sum = 0;
471 signed_sum = 0;
472 p = header->charptr;
473 for (i = sizeof (*header); --i >= 0;)
476 * We can't use unsigned char here because of old compilers,
477 * e.g. V7.
479 signed_sum += *p;
480 sum += 0xFF & *p++;
483 /* Adjust checksum to count the "chksum" field as blanks. */
484 for (i = sizeof (header->header.chksum); --i >= 0;)
486 sum -= 0xFF & header->header.chksum[i];
487 signed_sum -= (char) header->header.chksum[i];
489 sum += ' ' * sizeof header->header.chksum;
490 signed_sum += ' ' * sizeof header->header.chksum;
493 * This is a zeroed record...whole record is 0's except
494 * for the 8 blanks we faked for the checksum field.
496 if (sum == 8 * ' ')
497 return STATUS_EOFMARK;
499 if (sum != recsum && signed_sum != recsum)
500 return STATUS_BADCHECKSUM;
503 * Try to determine the archive format.
505 if (arch->type == TAR_UNKNOWN)
507 if (strcmp (header->header.magic, TMAGIC) == 0)
509 if (header->header.linkflag == LF_GLOBAL_EXTHDR)
510 arch->type = TAR_POSIX;
511 else
512 arch->type = TAR_USTAR;
514 else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
515 arch->type = TAR_GNU;
519 * linkflag on BSDI tar (pax) always '\000'
521 if (header->header.linkflag == '\000')
523 size_t len;
525 if (header->header.arch_name[NAMSIZ - 1] != '\0')
526 len = NAMSIZ;
527 else
528 len = strlen (header->header.arch_name);
530 if (len != 0 && header->header.arch_name[len - 1] == '/')
531 header->header.linkflag = LF_DIR;
535 * Good record. Decode file size and return.
537 if (header->header.linkflag == LF_LINK || header->header.linkflag == LF_DIR)
538 *h_size = 0; /* Links 0 size on tape */
539 else
540 *h_size = tar_from_oct (1 + 12, header->header.size);
543 * Skip over directory snapshot info records that
544 * are stored in incremental tar archives.
546 if (header->header.linkflag == LF_DUMPDIR)
548 if (arch->type == TAR_UNKNOWN)
549 arch->type = TAR_GNU;
550 return STATUS_SUCCESS;
554 * Skip over pax extended header and global extended
555 * header records.
557 if (header->header.linkflag == LF_EXTHDR || header->header.linkflag == LF_GLOBAL_EXTHDR)
559 if (arch->type == TAR_UNKNOWN)
560 arch->type = TAR_POSIX;
561 return STATUS_SUCCESS;
564 if (header->header.linkflag == LF_LONGNAME || header->header.linkflag == LF_LONGLINK)
566 char **longp;
567 char *bp, *data;
568 int size, written;
570 if (arch->type == TAR_UNKNOWN)
571 arch->type = TAR_GNU;
573 if (*h_size > MC_MAXPATHLEN)
575 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
576 return STATUS_BADCHECKSUM;
579 longp = ((header->header.linkflag == LF_LONGNAME) ? &next_long_name : &next_long_link);
581 g_free (*longp);
582 bp = *longp = g_malloc (*h_size + 1);
584 for (size = *h_size; size > 0; size -= written)
586 data = tar_get_next_record (archive, tard)->charptr;
587 if (data == NULL)
589 g_free (*longp);
590 *longp = NULL;
591 message (D_ERROR, MSG_ERROR, _("Unexpected EOF on archive file"));
592 return STATUS_BADCHECKSUM;
594 written = RECORDSIZE;
595 if (written > size)
596 written = size;
598 memcpy (bp, data, written);
599 bp += written;
602 if (bp - *longp == MC_MAXPATHLEN && bp[-1] != '\0')
604 g_free (*longp);
605 *longp = NULL;
606 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
607 return STATUS_BADCHECKSUM;
609 *bp = 0;
610 goto recurse;
612 else
614 struct stat st;
615 struct vfs_s_entry *entry;
616 struct vfs_s_inode *inode = NULL, *parent;
617 long data_position;
618 char *q;
619 int len;
620 char *current_file_name, *current_link_name;
622 current_link_name =
623 (next_long_link ? next_long_link : g_strndup (header->header.arch_linkname, NAMSIZ));
624 len = strlen (current_link_name);
625 if (len > 1 && current_link_name[len - 1] == '/')
626 current_link_name[len - 1] = 0;
628 current_file_name = NULL;
629 switch (arch->type)
631 case TAR_USTAR:
632 case TAR_POSIX:
633 /* The ustar archive format supports pathnames of upto 256
634 * characters in length. This is achieved by concatenating
635 * the contents of the `prefix' and `arch_name' fields like
636 * this:
638 * prefix + path_separator + arch_name
640 * If the `prefix' field contains an empty string i.e. its
641 * first characters is '\0' the prefix field is ignored.
643 if (header->header.unused.prefix[0] != '\0')
645 char *temp_name, *temp_prefix;
647 temp_name = g_strndup (header->header.arch_name, NAMSIZ);
648 temp_prefix = g_strndup (header->header.unused.prefix, PREFIX_SIZE);
649 current_file_name = g_strconcat (temp_prefix, PATH_SEP_STR,
650 temp_name, (char *) NULL);
651 g_free (temp_name);
652 g_free (temp_prefix);
654 break;
655 case TAR_GNU:
656 if (next_long_name != NULL)
657 current_file_name = next_long_name;
658 break;
659 default:
660 break;
663 if (current_file_name == NULL)
665 if (next_long_name != NULL)
666 current_file_name = g_strdup (next_long_name);
667 else
668 current_file_name = g_strndup (header->header.arch_name, NAMSIZ);
671 canonicalize_pathname (current_file_name);
672 len = strlen (current_file_name);
674 data_position = current_tar_position;
676 p = strrchr (current_file_name, '/');
677 if (p == NULL)
679 p = current_file_name;
680 q = current_file_name + len; /* "" */
682 else
684 *(p++) = 0;
685 q = current_file_name;
688 parent = vfs_s_find_inode (me, archive, q, LINK_NO_FOLLOW, FL_MKDIR);
689 if (parent == NULL)
691 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
692 return STATUS_BADCHECKSUM;
695 if (header->header.linkflag == LF_LINK)
697 inode = vfs_s_find_inode (me, archive, current_link_name, LINK_NO_FOLLOW, 0);
698 if (inode == NULL)
700 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
702 else
704 entry = vfs_s_new_entry (me, p, inode);
705 vfs_s_insert_entry (me, parent, entry);
706 g_free (current_link_name);
707 goto done;
711 tar_fill_stat (archive, &st, header, *h_size);
712 if (S_ISDIR (st.st_mode))
714 entry = MEDATA->find_entry (me, parent, p, LINK_NO_FOLLOW, FL_NONE);
715 if (entry)
716 goto done;
718 inode = vfs_s_new_inode (me, archive, &st);
720 inode->data_offset = data_position;
721 if (*current_link_name)
723 inode->linkname = current_link_name;
725 else if (current_link_name != next_long_link)
727 g_free (current_link_name);
729 entry = vfs_s_new_entry (me, p, inode);
731 vfs_s_insert_entry (me, parent, entry);
732 g_free (current_file_name);
734 done:
735 next_long_link = next_long_name = NULL;
737 if (arch->type == TAR_GNU && header->header.unused.oldgnu.isextended)
739 while (tar_get_next_record (archive, tard)->ext_hdr.isextended != 0)
741 inode->data_offset = current_tar_position;
743 return STATUS_SUCCESS;
747 /* --------------------------------------------------------------------------------------------- */
749 * Main loop for reading an archive.
750 * Returns 0 on success, -1 on error.
752 static int
753 tar_open_archive (struct vfs_s_super *archive, const vfs_path_t * vpath,
754 const vfs_path_element_t * vpath_element)
756 /* Initial status at start of archive */
757 ReadStatus status = STATUS_EOFMARK;
758 ReadStatus prev_status;
759 int tard;
761 current_tar_position = 0;
762 /* Open for reading */
763 tard = tar_open_archive_int (vpath_element->class, vpath, archive);
764 if (tard == -1)
765 return -1;
767 for (;;)
769 size_t h_size;
771 prev_status = status;
772 status = tar_read_header (vpath_element->class, archive, tard, &h_size);
774 switch (status)
777 case STATUS_SUCCESS:
778 tar_skip_n_records (archive, tard, (h_size + RECORDSIZE - 1) / RECORDSIZE);
779 continue;
782 * Invalid header:
784 * If the previous header was good, tell them
785 * that we are skipping bad ones.
787 case STATUS_BADCHECKSUM:
788 switch (prev_status)
791 /* Error on first record */
792 case STATUS_EOFMARK:
794 char *archive_name = vfs_path_to_str (vpath);
795 message (D_ERROR, MSG_ERROR, _("%s\ndoesn't look like a tar archive."),
796 archive_name);
797 g_free (archive_name);
798 /* FALL THRU */
800 /* Error after header rec */
802 case STATUS_SUCCESS:
803 /* Error after error */
805 case STATUS_BADCHECKSUM:
806 return -1;
808 case STATUS_EOF:
809 return 0;
812 /* Record of zeroes */
813 case STATUS_EOFMARK:
814 status = prev_status; /* If error after 0's */
815 /* FALL THRU */
817 case STATUS_EOF: /* End of archive */
818 break;
820 break;
822 return 0;
825 /* --------------------------------------------------------------------------------------------- */
827 static void *
828 tar_super_check (const vfs_path_t * vpath)
830 static struct stat stat_buf;
831 int stat_result;
833 stat_result = mc_stat (vpath, &stat_buf);
835 return (stat_result != 0) ? NULL : &stat_buf;
838 /* --------------------------------------------------------------------------------------------- */
840 static int
841 tar_super_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *parc,
842 const vfs_path_t * vpath, void *cookie)
844 struct stat *archive_stat = cookie; /* stat of main archive */
845 char *archive_name = vfs_path_to_str (vpath);
847 (void) vpath_element;
849 if (strcmp (parc->name, archive_name) != 0)
851 g_free (archive_name);
852 return 0;
854 g_free (archive_name);
856 /* Has the cached archive been changed on the disk? */
857 if (((tar_super_data_t *) parc->data)->st.st_mtime < archive_stat->st_mtime)
859 /* Yes, reload! */
860 (*vfs_tarfs_ops.free) ((vfsid) parc);
861 vfs_rmstamp (&vfs_tarfs_ops, (vfsid) parc);
862 return 2;
864 /* Hasn't been modified, give it a new timeout */
865 vfs_stamp (&vfs_tarfs_ops, (vfsid) parc);
866 return 1;
869 /* --------------------------------------------------------------------------------------------- */
871 static ssize_t
872 tar_read (void *fh, char *buffer, size_t count)
874 off_t begin = FH->ino->data_offset;
875 int fd = ((tar_super_data_t *) FH_SUPER->data)->fd;
876 struct vfs_class *me = FH_SUPER->me;
877 ssize_t res;
879 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) != begin + FH->pos)
880 ERRNOR (EIO, -1);
882 count = MIN (count, (size_t) (FH->ino->st.st_size - FH->pos));
884 res = mc_read (fd, buffer, count);
885 if (res == -1)
886 ERRNOR (errno, -1);
888 FH->pos += res;
889 return res;
892 /* --------------------------------------------------------------------------------------------- */
894 static int
895 tar_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
897 (void) fh;
898 (void) mode;
900 if ((flags & O_ACCMODE) != O_RDONLY)
901 ERRNOR (EROFS, -1);
902 return 0;
905 /* --------------------------------------------------------------------------------------------- */
906 /*** public functions ****************************************************************************/
907 /* --------------------------------------------------------------------------------------------- */
909 void
910 init_tarfs (void)
912 static struct vfs_s_subclass tarfs_subclass;
914 tarfs_subclass.flags = VFS_S_READONLY; /* FIXME: tarfs used own temp files */
915 tarfs_subclass.archive_check = tar_super_check;
916 tarfs_subclass.archive_same = tar_super_same;
917 tarfs_subclass.open_archive = tar_open_archive;
918 tarfs_subclass.free_archive = tar_free_archive;
919 tarfs_subclass.fh_open = tar_fh_open;
921 vfs_s_init_class (&vfs_tarfs_ops, &tarfs_subclass);
922 vfs_tarfs_ops.name = "tarfs";
923 vfs_tarfs_ops.prefix = "utar";
924 vfs_tarfs_ops.read = tar_read;
925 vfs_tarfs_ops.setctl = NULL;
926 vfs_register_class (&vfs_tarfs_ops);
929 /* --------------------------------------------------------------------------------------------- */