Updated Russian translation.
[midnight-commander.git] / lib / vfs / mc-vfs / tar.c
blob88930f1fa3afb81d8dcc129818c2cbcf0dd6f208
1 /* Virtual File System: GNU Tar file system.
2 Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
5 Written by: 1995 Jakub Jelinek
6 Rewritten by: 1998 Pavel Machek
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
22 /**
23 * \file
24 * \brief Source: Virtual File System: GNU Tar file system
25 * \author Jakub Jelinek
26 * \author Pavel Machek
27 * \date 1995, 1998
29 * Namespace: init_tarfs
32 #include <config.h>
33 #include <sys/types.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <fcntl.h>
38 #ifdef hpux
39 /* major() and minor() macros (among other things) defined here for hpux */
40 #include <sys/mknod.h>
41 #endif
43 #include "lib/global.h"
44 #include "lib/util.h"
45 #include "lib/widget.h" /* message() */
47 #include "vfs-impl.h"
48 #include "utilvfs.h"
49 #include "xdirentry.h"
50 #include "gc.h" /* vfs_rmstamp */
52 /*** global variables ****************************************************************************/
54 /*** file scope macro definitions ****************************************************************/
57 * Header block on tape.
59 * I'm going to use traditional DP naming conventions here.
60 * A "block" is a big chunk of stuff that we do I/O on.
61 * A "record" is a piece of info that we care about.
62 * Typically many "record"s fit into a "block".
64 #define RECORDSIZE 512
65 #define NAMSIZ 100
66 #define PREFIX_SIZE 155
67 #define TUNMLEN 32
68 #define TGNMLEN 32
69 #define SPARSE_EXT_HDR 21
70 #define SPARSE_IN_HDR 4
72 /* The checksum field is filled with this while the checksum is computed. */
73 #define CHKBLANKS " " /* 8 blanks, no null */
75 /* The magic field is filled with this if uname and gname are valid. */
76 #define TMAGIC "ustar" /* ustar and a null */
77 #define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
79 /* The linkflag defines the type of file */
80 #define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */
81 #define LF_NORMAL '0' /* Normal disk file */
82 #define LF_LINK '1' /* Link to previously dumped file */
83 #define LF_SYMLINK '2' /* Symbolic link */
84 #define LF_CHR '3' /* Character special file */
85 #define LF_BLK '4' /* Block special file */
86 #define LF_DIR '5' /* Directory */
87 #define LF_FIFO '6' /* FIFO special file */
88 #define LF_CONTIG '7' /* Contiguous file */
89 #define LF_EXTHDR 'x' /* pax Extended Header */
90 #define LF_GLOBAL_EXTHDR 'g' /* pax Global Extended Header */
91 /* Further link types may be defined later. */
93 /* Note that the standards committee allows only capital A through
94 capital Z for user-defined expansion. This means that defining something
95 as, say '8' is a *bad* idea. */
96 #define LF_DUMPDIR 'D' /* This is a dir entry that contains
97 the names of files that were in
98 the dir at the time the dump
99 was made */
100 #define LF_LONGLINK 'K' /* Identifies the NEXT file on the tape
101 as having a long linkname */
102 #define LF_LONGNAME 'L' /* Identifies the NEXT file on the tape
103 as having a long name. */
104 #define LF_MULTIVOL 'M' /* This is the continuation
105 of a file that began on another
106 volume */
107 #define LF_NAMES 'N' /* For storing filenames that didn't
108 fit in 100 characters */
109 #define LF_SPARSE 'S' /* This is for sparse files */
110 #define LF_VOLHDR 'V' /* This file is a tape/volume header */
111 /* Ignore it on extraction */
114 * Exit codes from the "tar" program
116 #define EX_SUCCESS 0 /* success! */
117 #define EX_ARGSBAD 1 /* invalid args */
118 #define EX_BADFILE 2 /* invalid filename */
119 #define EX_BADARCH 3 /* bad archive */
120 #define EX_SYSTEM 4 /* system gave unexpected error */
121 #define EX_BADVOL 5 /* Special error code means
122 Tape volume doesn't match the one
123 specified on the command line */
125 #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
127 /*** file scope type declarations ****************************************************************/
129 enum
131 TAR_UNKNOWN = 0,
132 TAR_V7,
133 TAR_USTAR,
134 TAR_POSIX,
135 TAR_GNU
138 struct sparse
140 char offset[12];
141 char numbytes[12];
144 struct sp_array
146 int offset;
147 int numbytes;
150 union record
152 char charptr[RECORDSIZE];
153 struct header
155 char arch_name[NAMSIZ];
156 char mode[8];
157 char uid[8];
158 char gid[8];
159 char size[12];
160 char mtime[12];
161 char chksum[8];
162 char linkflag;
163 char arch_linkname[NAMSIZ];
164 char magic[8];
165 char uname[TUNMLEN];
166 char gname[TGNMLEN];
167 char devmajor[8];
168 char devminor[8];
169 /* The following bytes of the tar header record were originally unused.
171 Archives following the ustar specification use almost all of those
172 bytes to support pathnames of 256 characters in length.
174 GNU tar archives use the "unused" space to support incremental
175 archives and sparse files. */
176 union unused
178 char prefix[PREFIX_SIZE];
179 /* GNU extensions to the ustar (POSIX.1-1988) archive format. */
180 struct oldgnu
182 char atime[12];
183 char ctime[12];
184 char offset[12];
185 char longnames[4];
186 char pad;
187 struct sparse sp[SPARSE_IN_HDR];
188 char isextended;
189 char realsize[12]; /* true size of the sparse file */
190 } oldgnu;
191 } unused;
192 } header;
193 struct extended_header
195 struct sparse sp[21];
196 char isextended;
197 } ext_hdr;
200 typedef enum
202 STATUS_BADCHECKSUM,
203 STATUS_SUCCESS,
204 STATUS_EOFMARK,
205 STATUS_EOF
206 } ReadStatus;
208 /*** file scope variables ************************************************************************/
210 static struct vfs_class vfs_tarfs_ops;
212 /* As we open one archive at a time, it is safe to have this static */
213 static int current_tar_position = 0;
215 static union record rec_buf;
217 /*** file scope functions ************************************************************************/
218 /* --------------------------------------------------------------------------------------------- */
220 * Quick and dirty octal conversion.
222 * Result is -1 if the field is invalid (all blank, or nonoctal).
224 static long
225 tar_from_oct (int digs, char *where)
227 register long value;
229 while (isspace ((unsigned char) *where))
230 { /* Skip spaces */
231 where++;
232 if (--digs <= 0)
233 return -1; /* All blank field */
235 value = 0;
236 while (digs > 0 && isodigit (*where))
237 { /* Scan till nonoctal */
238 value = (value << 3) | (*where++ - '0');
239 --digs;
242 if (digs > 0 && *where && !isspace ((unsigned char) *where))
243 return -1; /* Ended on non-space/nul */
245 return value;
248 /* --------------------------------------------------------------------------------------------- */
250 static void
251 tar_free_archive (struct vfs_class *me, struct vfs_s_super *archive)
253 (void) me;
255 if (archive->u.arch.fd != -1)
256 mc_close (archive->u.arch.fd);
259 /* --------------------------------------------------------------------------------------------- */
261 /* Returns fd of the open tar file */
262 static int
263 tar_open_archive_int (struct vfs_class *me, const char *name, struct vfs_s_super *archive)
265 int result, type;
266 mode_t mode;
267 struct vfs_s_inode *root;
269 result = mc_open (name, O_RDONLY);
270 if (result == -1)
272 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), name);
273 ERRNOR (ENOENT, -1);
276 archive->name = g_strdup (name);
277 mc_stat (name, &(archive->u.arch.st));
278 archive->u.arch.fd = -1;
279 archive->u.arch.type = TAR_UNKNOWN;
281 /* Find out the method to handle this tar file */
282 type = get_compression_type (result, name);
283 mc_lseek (result, 0, SEEK_SET);
284 if (type != COMPRESSION_NONE)
286 char *s;
287 mc_close (result);
288 s = g_strconcat (archive->name, decompress_extension (type), (char *) NULL);
289 result = mc_open (s, O_RDONLY);
290 if (result == -1)
291 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), s);
292 g_free (s);
293 if (result == -1)
294 ERRNOR (ENOENT, -1);
297 archive->u.arch.fd = result;
298 mode = archive->u.arch.st.st_mode & 07777;
299 if (mode & 0400)
300 mode |= 0100;
301 if (mode & 0040)
302 mode |= 0010;
303 if (mode & 0004)
304 mode |= 0001;
305 mode |= S_IFDIR;
307 root = vfs_s_new_inode (me, archive, &archive->u.arch.st);
308 root->st.st_mode = mode;
309 root->data_offset = -1;
310 root->st.st_nlink++;
311 root->st.st_dev = MEDATA->rdev++;
313 archive->root = root;
315 return result;
318 /* --------------------------------------------------------------------------------------------- */
320 static union record *
321 tar_get_next_record (struct vfs_s_super *archive, int tard)
323 int n;
325 (void) archive;
327 n = mc_read (tard, rec_buf.charptr, RECORDSIZE);
328 if (n != RECORDSIZE)
329 return NULL; /* An error has occurred */
330 current_tar_position += RECORDSIZE;
331 return &rec_buf;
334 /* --------------------------------------------------------------------------------------------- */
336 static void
337 tar_skip_n_records (struct vfs_s_super *archive, int tard, int n)
339 (void) archive;
341 mc_lseek (tard, n * RECORDSIZE, SEEK_CUR);
342 current_tar_position += n * RECORDSIZE;
345 /* --------------------------------------------------------------------------------------------- */
347 static void
348 tar_fill_stat (struct vfs_s_super *archive, struct stat *st, union record *header, size_t h_size)
350 st->st_mode = tar_from_oct (8, header->header.mode);
352 /* Adjust st->st_mode because there are tar-files with
353 * linkflag==LF_SYMLINK and S_ISLNK(mod)==0. I don't
354 * know about the other modes but I think I cause no new
355 * problem when I adjust them, too. -- Norbert.
357 if (header->header.linkflag == LF_DIR)
359 st->st_mode |= S_IFDIR;
361 else if (header->header.linkflag == LF_SYMLINK)
363 st->st_mode |= S_IFLNK;
365 else if (header->header.linkflag == LF_CHR)
367 st->st_mode |= S_IFCHR;
369 else if (header->header.linkflag == LF_BLK)
371 st->st_mode |= S_IFBLK;
373 else if (header->header.linkflag == LF_FIFO)
375 st->st_mode |= S_IFIFO;
377 else
378 st->st_mode |= S_IFREG;
380 st->st_rdev = 0;
381 switch (archive->u.arch.type)
383 case TAR_USTAR:
384 case TAR_POSIX:
385 case TAR_GNU:
386 st->st_uid =
387 *header->header.uname ? vfs_finduid (header->header.uname) : tar_from_oct (8,
388 header->
389 header.uid);
390 st->st_gid =
391 *header->header.gname ? vfs_findgid (header->header.gname) : tar_from_oct (8,
392 header->
393 header.gid);
394 switch (header->header.linkflag)
396 case LF_BLK:
397 case LF_CHR:
398 st->st_rdev =
399 (tar_from_oct (8, header->header.devmajor) << 8) |
400 tar_from_oct (8, header->header.devminor);
402 default:
403 st->st_uid = tar_from_oct (8, header->header.uid);
404 st->st_gid = tar_from_oct (8, header->header.gid);
406 st->st_size = h_size;
407 st->st_mtime = tar_from_oct (1 + 12, header->header.mtime);
408 st->st_atime = 0;
409 st->st_ctime = 0;
410 if (archive->u.arch.type == TAR_GNU)
412 st->st_atime = tar_from_oct (1 + 12, header->header.unused.oldgnu.atime);
413 st->st_ctime = tar_from_oct (1 + 12, header->header.unused.oldgnu.ctime);
417 /* --------------------------------------------------------------------------------------------- */
419 * Return 1 for success, 0 if the checksum is bad, EOF on eof,
420 * 2 for a record full of zeros (EOF marker).
423 static ReadStatus
424 tar_read_header (struct vfs_class *me, struct vfs_s_super *archive, int tard, size_t * h_size)
426 register int i;
427 register long sum, signed_sum, recsum;
428 register char *p;
429 register union record *header;
430 static char *next_long_name = NULL, *next_long_link = NULL;
432 recurse:
434 header = tar_get_next_record (archive, tard);
435 if (NULL == header)
436 return STATUS_EOF;
438 recsum = tar_from_oct (8, header->header.chksum);
440 sum = 0;
441 signed_sum = 0;
442 p = header->charptr;
443 for (i = sizeof (*header); --i >= 0;)
446 * We can't use unsigned char here because of old compilers,
447 * e.g. V7.
449 signed_sum += *p;
450 sum += 0xFF & *p++;
453 /* Adjust checksum to count the "chksum" field as blanks. */
454 for (i = sizeof (header->header.chksum); --i >= 0;)
456 sum -= 0xFF & header->header.chksum[i];
457 signed_sum -= (char) header->header.chksum[i];
459 sum += ' ' * sizeof header->header.chksum;
460 signed_sum += ' ' * sizeof header->header.chksum;
463 * This is a zeroed record...whole record is 0's except
464 * for the 8 blanks we faked for the checksum field.
466 if (sum == 8 * ' ')
467 return STATUS_EOFMARK;
469 if (sum != recsum && signed_sum != recsum)
470 return STATUS_BADCHECKSUM;
473 * Try to determine the archive format.
475 if (archive->u.arch.type == TAR_UNKNOWN)
477 if (!strcmp (header->header.magic, TMAGIC))
479 if (header->header.linkflag == LF_GLOBAL_EXTHDR)
480 archive->u.arch.type = TAR_POSIX;
481 else
482 archive->u.arch.type = TAR_USTAR;
484 else if (!strcmp (header->header.magic, OLDGNU_MAGIC))
486 archive->u.arch.type = TAR_GNU;
491 * linkflag on BSDI tar (pax) always '\000'
493 if (header->header.linkflag == '\000')
495 if (header->header.arch_name[NAMSIZ - 1] != '\0')
496 i = NAMSIZ;
497 else
498 i = strlen (header->header.arch_name);
500 if (i && header->header.arch_name[i - 1] == '/')
501 header->header.linkflag = LF_DIR;
505 * Good record. Decode file size and return.
507 if (header->header.linkflag == LF_LINK || header->header.linkflag == LF_DIR)
508 *h_size = 0; /* Links 0 size on tape */
509 else
510 *h_size = tar_from_oct (1 + 12, header->header.size);
513 * Skip over directory snapshot info records that
514 * are stored in incremental tar archives.
516 if (header->header.linkflag == LF_DUMPDIR)
518 if (archive->u.arch.type == TAR_UNKNOWN)
519 archive->u.arch.type = TAR_GNU;
520 return STATUS_SUCCESS;
524 * Skip over pax extended header and global extended
525 * header records.
527 if (header->header.linkflag == LF_EXTHDR || header->header.linkflag == LF_GLOBAL_EXTHDR)
529 if (archive->u.arch.type == TAR_UNKNOWN)
530 archive->u.arch.type = TAR_POSIX;
531 return STATUS_SUCCESS;
534 if (header->header.linkflag == LF_LONGNAME || header->header.linkflag == LF_LONGLINK)
536 char **longp;
537 char *bp, *data;
538 int size, written;
540 if (archive->u.arch.type == TAR_UNKNOWN)
541 archive->u.arch.type = TAR_GNU;
543 if (*h_size > MC_MAXPATHLEN)
545 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
546 return STATUS_BADCHECKSUM;
549 longp = ((header->header.linkflag == LF_LONGNAME) ? &next_long_name : &next_long_link);
551 g_free (*longp);
552 bp = *longp = g_malloc (*h_size + 1);
554 for (size = *h_size; size > 0; size -= written)
556 data = tar_get_next_record (archive, tard)->charptr;
557 if (data == NULL)
559 g_free (*longp);
560 *longp = NULL;
561 message (D_ERROR, MSG_ERROR, _("Unexpected EOF on archive file"));
562 return STATUS_BADCHECKSUM;
564 written = RECORDSIZE;
565 if (written > size)
566 written = size;
568 memcpy (bp, data, written);
569 bp += written;
572 if (bp - *longp == MC_MAXPATHLEN && bp[-1] != '\0')
574 g_free (*longp);
575 *longp = NULL;
576 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
577 return STATUS_BADCHECKSUM;
579 *bp = 0;
580 goto recurse;
582 else
584 struct stat st;
585 struct vfs_s_entry *entry;
586 struct vfs_s_inode *inode = NULL, *parent;
587 long data_position;
588 char *q;
589 int len;
590 char *current_file_name, *current_link_name;
592 current_link_name =
593 (next_long_link ? next_long_link : g_strndup (header->header.arch_linkname, NAMSIZ));
594 len = strlen (current_link_name);
595 if (len > 1 && current_link_name[len - 1] == '/')
596 current_link_name[len - 1] = 0;
598 current_file_name = NULL;
599 switch (archive->u.arch.type)
601 case TAR_USTAR:
602 case TAR_POSIX:
603 /* The ustar archive format supports pathnames of upto 256
604 * characters in length. This is achieved by concatenating
605 * the contents of the `prefix' and `arch_name' fields like
606 * this:
608 * prefix + path_separator + arch_name
610 * If the `prefix' field contains an empty string i.e. its
611 * first characters is '\0' the prefix field is ignored.
613 if (header->header.unused.prefix[0] != '\0')
615 char *temp_name, *temp_prefix;
617 temp_name = g_strndup (header->header.arch_name, NAMSIZ);
618 temp_prefix = g_strndup (header->header.unused.prefix, PREFIX_SIZE);
619 current_file_name = g_strconcat (temp_prefix, PATH_SEP_STR,
620 temp_name, (char *) NULL);
621 g_free (temp_name);
622 g_free (temp_prefix);
624 break;
625 case TAR_GNU:
626 if (next_long_name != NULL)
627 current_file_name = next_long_name;
628 break;
629 default:
630 break;
633 if (current_file_name == NULL)
635 if (next_long_name != NULL)
636 current_file_name = g_strdup (next_long_name);
637 else
638 current_file_name = g_strndup (header->header.arch_name, NAMSIZ);
641 canonicalize_pathname (current_file_name);
642 len = strlen (current_file_name);
644 data_position = current_tar_position;
646 p = strrchr (current_file_name, '/');
647 if (p == NULL)
649 p = current_file_name;
650 q = current_file_name + len; /* "" */
652 else
654 *(p++) = 0;
655 q = current_file_name;
658 parent = vfs_s_find_inode (me, archive, q, LINK_NO_FOLLOW, FL_MKDIR);
659 if (parent == NULL)
661 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
662 return STATUS_BADCHECKSUM;
665 if (header->header.linkflag == LF_LINK)
667 inode = vfs_s_find_inode (me, archive, current_link_name, LINK_NO_FOLLOW, 0);
668 if (inode == NULL)
670 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
672 else
674 entry = vfs_s_new_entry (me, p, inode);
675 vfs_s_insert_entry (me, parent, entry);
676 g_free (current_link_name);
677 goto done;
681 tar_fill_stat (archive, &st, header, *h_size);
682 if (S_ISDIR (st.st_mode))
684 entry = MEDATA->find_entry (me, parent, p, LINK_NO_FOLLOW, FL_NONE);
685 if (entry)
686 goto done;
688 inode = vfs_s_new_inode (me, archive, &st);
690 inode->data_offset = data_position;
691 if (*current_link_name)
693 inode->linkname = current_link_name;
695 else if (current_link_name != next_long_link)
697 g_free (current_link_name);
699 entry = vfs_s_new_entry (me, p, inode);
701 vfs_s_insert_entry (me, parent, entry);
702 g_free (current_file_name);
704 done:
705 next_long_link = next_long_name = NULL;
707 if (archive->u.arch.type == TAR_GNU && header->header.unused.oldgnu.isextended)
709 while (tar_get_next_record (archive, tard)->ext_hdr.isextended);
710 inode->data_offset = current_tar_position;
712 return STATUS_SUCCESS;
716 /* --------------------------------------------------------------------------------------------- */
718 * Main loop for reading an archive.
719 * Returns 0 on success, -1 on error.
721 static int
722 tar_open_archive (struct vfs_class *me, struct vfs_s_super *archive, const char *name, char *op)
724 /* Initial status at start of archive */
725 ReadStatus status = STATUS_EOFMARK;
726 ReadStatus prev_status;
727 int tard;
729 (void) op;
731 current_tar_position = 0;
732 /* Open for reading */
733 tard = tar_open_archive_int (me, name, archive);
734 if (tard == -1)
735 return -1;
737 for (;;)
739 size_t h_size;
741 prev_status = status;
742 status = tar_read_header (me, archive, tard, &h_size);
744 switch (status)
747 case STATUS_SUCCESS:
748 tar_skip_n_records (archive, tard, (h_size + RECORDSIZE - 1) / RECORDSIZE);
749 continue;
752 * Invalid header:
754 * If the previous header was good, tell them
755 * that we are skipping bad ones.
757 case STATUS_BADCHECKSUM:
758 switch (prev_status)
761 /* Error on first record */
762 case STATUS_EOFMARK:
763 message (D_ERROR, MSG_ERROR, _("%s\ndoesn't look like a tar archive."), name);
764 /* FALL THRU */
766 /* Error after header rec */
767 case STATUS_SUCCESS:
768 /* Error after error */
770 case STATUS_BADCHECKSUM:
771 return -1;
773 case STATUS_EOF:
774 return 0;
777 /* Record of zeroes */
778 case STATUS_EOFMARK:
779 status = prev_status; /* If error after 0's */
780 /* FALL THRU */
782 case STATUS_EOF: /* End of archive */
783 break;
785 break;
787 return 0;
790 /* --------------------------------------------------------------------------------------------- */
792 static void *
793 tar_super_check (struct vfs_class *me, const char *archive_name, char *op)
795 static struct stat stat_buf;
797 (void) me;
798 (void) op;
800 if (mc_stat (archive_name, &stat_buf))
801 return NULL;
802 return &stat_buf;
805 /* --------------------------------------------------------------------------------------------- */
807 static int
808 tar_super_same (struct vfs_class *me, struct vfs_s_super *parc,
809 const char *archive_name, char *op, void *cookie)
811 struct stat *archive_stat = cookie; /* stat of main archive */
813 (void) me;
814 (void) op;
816 if (strcmp (parc->name, archive_name))
817 return 0;
819 /* Has the cached archive been changed on the disk? */
820 if (parc->u.arch.st.st_mtime < archive_stat->st_mtime)
822 /* Yes, reload! */
823 (*vfs_tarfs_ops.free) ((vfsid) parc);
824 vfs_rmstamp (&vfs_tarfs_ops, (vfsid) parc);
825 return 2;
827 /* Hasn't been modified, give it a new timeout */
828 vfs_stamp (&vfs_tarfs_ops, (vfsid) parc);
829 return 1;
832 /* --------------------------------------------------------------------------------------------- */
834 static ssize_t
835 tar_read (void *fh, char *buffer, size_t count)
837 off_t begin = FH->ino->data_offset;
838 int fd = FH_SUPER->u.arch.fd;
839 struct vfs_class *me = FH_SUPER->me;
840 ssize_t res;
842 if (mc_lseek (fd, begin + FH->pos, SEEK_SET) != begin + FH->pos)
843 ERRNOR (EIO, -1);
845 count = MIN (count, (size_t) (FH->ino->st.st_size - FH->pos));
847 res = mc_read (fd, buffer, count);
848 if (res == -1)
849 ERRNOR (errno, -1);
851 FH->pos += res;
852 return res;
855 /* --------------------------------------------------------------------------------------------- */
857 static int
858 tar_fh_open (struct vfs_class *me, struct vfs_s_fh *fh, int flags, mode_t mode)
860 (void) fh;
861 (void) mode;
863 if ((flags & O_ACCMODE) != O_RDONLY)
864 ERRNOR (EROFS, -1);
865 return 0;
868 /* --------------------------------------------------------------------------------------------- */
869 /*** public functions ****************************************************************************/
870 /* --------------------------------------------------------------------------------------------- */
872 void
873 init_tarfs (void)
875 static struct vfs_s_subclass tarfs_subclass;
877 tarfs_subclass.flags = VFS_S_READONLY;
878 tarfs_subclass.archive_check = tar_super_check;
879 tarfs_subclass.archive_same = tar_super_same;
880 tarfs_subclass.open_archive = tar_open_archive;
881 tarfs_subclass.free_archive = tar_free_archive;
882 tarfs_subclass.fh_open = tar_fh_open;
884 vfs_s_init_class (&vfs_tarfs_ops, &tarfs_subclass);
885 vfs_tarfs_ops.name = "tarfs";
886 vfs_tarfs_ops.prefix = "utar";
887 vfs_tarfs_ops.read = tar_read;
888 vfs_tarfs_ops.setctl = NULL;
889 vfs_register_class (&vfs_tarfs_ops);
892 /* --------------------------------------------------------------------------------------------- */