1 /*
2 Virtual File System: GNU Tar file system.
3
4 Copyright (C) 1995-2021
5 Free Software Foundation, Inc.
6
7 Written by:
8 Jakub Jelinek, 1995
9 Pavel Machek, 1998
10 Slava Zanko <slavazanko@gmail.com>, 2013
11
12 This file is part of the Midnight Commander.
13
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.
18
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.
23
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/>.
26 */
27
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
34 *
35 * Namespace: init_tarfs
36 */
37
38 #include <config.h>
39 #include <sys/types.h>
40 #include <errno.h>
41 #include <ctype.h>
42
43 #ifdef hpux
44 /* major() and minor() macros (among other things) defined here for hpux */
45 #include <sys/mknod.h>
46 #endif
47
48 #include "lib/global.h"
49 #include "lib/util.h"
50 #include "lib/unixcompat.h" /* makedev() */
51 #include "lib/widget.h" /* message() */
52
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 */
57
58 #include "tar.h"
59
60 /*** global variables ****************************************************************************/
61
62 /*** file scope macro definitions ****************************************************************/
63
64 #define TAR_SUPER(super) ((tar_super_t *) (super))
65
66
67 /* tar Header Block, from POSIX 1003.1-1990. */
68
69 /* The magic field is filled with this if uname and gname are valid. */
70 #define TMAGIC "ustar" /* ustar and a null */
71
72 #define XHDTYPE 'x' /* Extended header referring to the next file in the archive */
73 #define XGLTYPE 'g' /* Global extended header */
74
75 /* Values used in typeflag field. */
76 #define LNKTYPE '1' /* link */
77 #define SYMTYPE '2' /* symbolic link */
78 #define CHRTYPE '3' /* character special */
79 #define BLKTYPE '4' /* block special */
80 #define DIRTYPE '5' /* directory */
81 #define FIFOTYPE '6' /* FIFO special */
82
83
84 /* tar Header Block, GNU extensions. */
85
86 /* *BEWARE* *BEWARE* *BEWARE* that the following information is still
87 boiling, and may change. Even if the OLDGNU format description should be
88 accurate, the so-called GNU format is not yet fully decided. It is
89 surely meant to use only extensions allowed by POSIX, but the sketch
90 below repeats some ugliness from the OLDGNU format, which should rather
91 go away. Sparse files should be saved in such a way that they do *not*
92 require two passes at archive creation time. Huge files get some POSIX
93 fields to overflow, alternate solutions have to be sought for this. */
94
95
96 /* Sparse files are not supported in POSIX ustar format. For sparse files
97 with a POSIX header, a GNU extra header is provided which holds overall
98 sparse information and a few sparse descriptors. When an old GNU header
99 replaces both the POSIX header and the GNU extra header, it holds some
100 sparse descriptors too. Whether POSIX or not, if more sparse descriptors
101 are still needed, they are put into as many successive sparse headers as
102 necessary. The following constants tell how many sparse descriptors fit
103 in each kind of header able to hold them. */
104
105 #define SPARSES_IN_EXTRA_HEADER 16
106 #define SPARSES_IN_OLDGNU_HEADER 4
107 #define SPARSES_IN_SPARSE_HEADER 21
108
109 /* OLDGNU_MAGIC uses both magic and version fields, which are contiguous.
110 Found in an archive, it indicates an old GNU header format, which will be
111 hopefully become obsolescent. With OLDGNU_MAGIC, uname and gname are
112 valid, though the header is not truly POSIX conforming. */
113 #define OLDGNU_MAGIC "ustar " /* 7 chars and a null */
114
115 /* The standards committee allows only capital A through capital Z for user-defined expansion. */
116
117 /* This is a dir entry that contains the names of files that were in the
118 dir at the time the dump was made. */
119 #define GNUTYPE_DUMPDIR 'D'
120
121 /* Identifies the *next* file on the tape as having a long linkname. */
122 #define GNUTYPE_LONGLINK 'K'
123
124 /* Identifies the *next* file on the tape as having a long name. */
125 #define GNUTYPE_LONGNAME 'L'
126
127
128 /* tar Header Block, overall structure. */
129
130 /* tar files are made in basic blocks of this size. */
131 #define BLOCKSIZE 512
132
133
134 #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
135
136 /*** file scope type declarations ****************************************************************/
137
138 /* *INDENT-OFF* */
139
140 /* POSIX header */
141 struct posix_header
142 { /* byte offset */
143 char name[100]; /* 0 */
144 char mode[8]; /* 100 */
145 char uid[8]; /* 108 */
146 char gid[8]; /* 116 */
147 char size[12]; /* 124 */
148 char mtime[12]; /* 136 */
149 char chksum[8]; /* 148 */
150 char typeflag; /* 156 */
151 char linkname[100]; /* 157 */
152 char magic[6]; /* 257 */
153 char version[2]; /* 263 */
154 char uname[32]; /* 265 */
155 char gname[32]; /* 297 */
156 char devmajor[8]; /* 329 */
157 char devminor[8]; /* 337 */
158 char prefix[155]; /* 345 */
159 /* 500 */
160 };
161
162 /* Descriptor for a single file hole */
163 struct sparse
164 { /* byte offset */
165 /* cppcheck-suppress unusedStructMember */
166 char offset[12]; /* 0 */
167 /* cppcheck-suppress unusedStructMember */
168 char numbytes[12]; /* 12 */
169 /* 24 */
170 };
171
172 /* The GNU extra header contains some information GNU tar needs, but not
173 foreseen in POSIX header format. It is only used after a POSIX header
174 (and never with old GNU headers), and immediately follows this POSIX
175 header, when typeflag is a letter rather than a digit, so signaling a GNU
176 extension. */
177 struct extra_header
178 { /* byte offset */
179 char atime[12]; /* 0 */
180 char ctime[12]; /* 12 */
181 char offset[12]; /* 24 */
182 char realsize[12]; /* 36 */
183 char longnames[4]; /* 48 */
184 char unused_pad1[68]; /* 52 */
185 struct sparse sp[SPARSES_IN_EXTRA_HEADER];
186 /* 120 */
187 char isextended; /* 504 */
188 /* 505 */
189 };
190
191 /* Extension header for sparse files, used immediately after the GNU extra
192 header, and used only if all sparse information cannot fit into that
193 extra header. There might even be many such extension headers, one after
194 the other, until all sparse information has been recorded. */
195 struct sparse_header
196 { /* byte offset */
197 struct sparse sp[SPARSES_IN_SPARSE_HEADER];
198 /* 0 */
199 char isextended; /* 504 */
200 /* 505 */
201 };
202
203 /* The old GNU format header conflicts with POSIX format in such a way that
204 POSIX archives may fool old GNU tar's, and POSIX tar's might well be
205 fooled by old GNU tar archives. An old GNU format header uses the space
206 used by the prefix field in a POSIX header, and cumulates information
207 normally found in a GNU extra header. With an old GNU tar header, we
208 never see any POSIX header nor GNU extra header. Supplementary sparse
209 headers are allowed, however. */
210 struct oldgnu_header
211 { /* byte offset */
212 char unused_pad1[345]; /* 0 */
213 char atime[12]; /* 345 */
214 char ctime[12]; /* 357 */
215 char offset[12]; /* 369 */
216 char longnames[4]; /* 381 */
217 char unused_pad2; /* 385 */
218 struct sparse sp[SPARSES_IN_OLDGNU_HEADER];
219 /* 386 */
220 char isextended; /* 482 */
221 char realsize[12]; /* 483 */
222 /* 495 */
223 };
224
225 /* *INDENT-ON* */
226
227 /* tar Header Block, overall structure */
228 union block
229 {
230 char buffer[BLOCKSIZE];
231 struct posix_header header;
232 struct extra_header extra_header;
233 struct oldgnu_header oldgnu_header;
234 struct sparse_header sparse_header;
235 };
236
237 enum archive_format
238 {
239 TAR_UNKNOWN = 0,
240 TAR_V7,
241 TAR_USTAR,
242 TAR_POSIX,
243 TAR_GNU
244 };
245
246 typedef enum
247 {
248 STATUS_BADCHECKSUM,
249 STATUS_SUCCESS,
250 STATUS_EOFMARK,
251 STATUS_EOF
252 } ReadStatus;
253
254 typedef struct
255 {
256 struct vfs_s_super base; /* base class */
257
258 int fd;
259 struct stat st;
260 enum archive_format type; /* Type of the archive */
261 } tar_super_t;
262
263 /*** file scope variables ************************************************************************/
264
265 static struct vfs_s_subclass tarfs_subclass;
266 static struct vfs_class *vfs_tarfs_ops = VFS_CLASS (&tarfs_subclass);
267
268 /* As we open one archive at a time, it is safe to have this static */
269 static off_t current_tar_position = 0;
270
271 static union block block_buf;
272
273 /* --------------------------------------------------------------------------------------------- */
274 /*** file scope functions ************************************************************************/
275 /* --------------------------------------------------------------------------------------------- */
276 /**
277 * Quick and dirty octal conversion.
278 *
279 * Result is -1 if the field is invalid (all blank, or nonoctal).
280 */
281 static long
tar_from_oct(int digs,const char * where)282 tar_from_oct (int digs, const char *where)
283 {
284 long value;
285
286 while (isspace ((unsigned char) *where))
287 { /* Skip spaces */
288 where++;
289 if (--digs <= 0)
290 return -1; /* All blank field */
291 }
292 value = 0;
293 while (digs > 0 && isodigit (*where))
294 { /* Scan till nonoctal */
295 value = (value << 3) | (*where++ - '0');
296 --digs;
297 }
298
299 if (digs > 0 && *where && !isspace ((unsigned char) *where))
300 return -1; /* Ended on non-space/nul */
301
302 return value;
303 }
304
305 /* --------------------------------------------------------------------------------------------- */
306
307 static struct vfs_s_super *
tar_new_archive(struct vfs_class * me)308 tar_new_archive (struct vfs_class *me)
309 {
310 tar_super_t *arch;
311
312 arch = g_new0 (tar_super_t, 1);
313 arch->base.me = me;
314 arch->fd = -1;
315 arch->type = TAR_UNKNOWN;
316
317 return VFS_SUPER (arch);
318 }
319
320 /* --------------------------------------------------------------------------------------------- */
321
322 static void
tar_free_archive(struct vfs_class * me,struct vfs_s_super * archive)323 tar_free_archive (struct vfs_class *me, struct vfs_s_super *archive)
324 {
325 tar_super_t *arch = TAR_SUPER (archive);
326
327 (void) me;
328
329 if (arch->fd != -1)
330 {
331 mc_close (arch->fd);
332 arch->fd = -1;
333 }
334 }
335
336 /* --------------------------------------------------------------------------------------------- */
337
338 /* Returns fd of the open tar file */
339 static int
tar_open_archive_int(struct vfs_class * me,const vfs_path_t * vpath,struct vfs_s_super * archive)340 tar_open_archive_int (struct vfs_class *me, const vfs_path_t * vpath, struct vfs_s_super *archive)
341 {
342 int result, type;
343 tar_super_t *arch;
344 mode_t mode;
345 struct vfs_s_inode *root;
346
347 result = mc_open (vpath, O_RDONLY);
348 if (result == -1)
349 {
350 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), vfs_path_as_str (vpath));
351 ERRNOR (ENOENT, -1);
352 }
353
354 archive->name = g_strdup (vfs_path_as_str (vpath));
355 arch = TAR_SUPER (archive);
356 mc_stat (vpath, &arch->st);
357
358 /* Find out the method to handle this tar file */
359 type = get_compression_type (result, archive->name);
360 if (type == COMPRESSION_NONE)
361 mc_lseek (result, 0, SEEK_SET);
362 else
363 {
364 char *s;
365 vfs_path_t *tmp_vpath;
366
367 mc_close (result);
368 s = g_strconcat (archive->name, decompress_extension (type), (char *) NULL);
369 tmp_vpath = vfs_path_from_str_flags (s, VPF_NO_CANON);
370 result = mc_open (tmp_vpath, O_RDONLY);
371 vfs_path_free (tmp_vpath, TRUE);
372 if (result == -1)
373 message (D_ERROR, MSG_ERROR, _("Cannot open tar archive\n%s"), s);
374 g_free (s);
375 if (result == -1)
376 {
377 MC_PTR_FREE (archive->name);
378 ERRNOR (ENOENT, -1);
379 }
380 }
381
382 arch->fd = result;
383 mode = arch->st.st_mode & 07777;
384 if (mode & 0400)
385 mode |= 0100;
386 if (mode & 0040)
387 mode |= 0010;
388 if (mode & 0004)
389 mode |= 0001;
390 mode |= S_IFDIR;
391
392 root = vfs_s_new_inode (me, archive, &arch->st);
393 root->st.st_mode = mode;
394 root->data_offset = -1;
395 root->st.st_nlink++;
396 root->st.st_dev = VFS_SUBCLASS (me)->rdev++;
397
398 archive->root = root;
399
400 return result;
401 }
402
403 /* --------------------------------------------------------------------------------------------- */
404
405 static union block *
tar_get_next_block(struct vfs_s_super * archive,int tard)406 tar_get_next_block (struct vfs_s_super *archive, int tard)
407 {
408 int n;
409
410 (void) archive;
411
412 n = mc_read (tard, block_buf.buffer, sizeof (block_buf.buffer));
413 if (n != sizeof (block_buf.buffer))
414 return NULL; /* An error has occurred */
415 current_tar_position += sizeof (block_buf.buffer);
416 return &block_buf;
417 }
418
419 /* --------------------------------------------------------------------------------------------- */
420
421 static void
tar_skip_n_records(struct vfs_s_super * archive,int tard,size_t n)422 tar_skip_n_records (struct vfs_s_super *archive, int tard, size_t n)
423 {
424 (void) archive;
425
426 mc_lseek (tard, n * sizeof (block_buf.buffer), SEEK_CUR);
427 current_tar_position += n * sizeof (block_buf.buffer);
428 }
429
430 /* --------------------------------------------------------------------------------------------- */
431
432 static ReadStatus
tar_checksum(const union block * header)433 tar_checksum (const union block *header)
434 {
435 long recsum;
436 long signed_sum = 0;
437 long sum = 0;
438 int i;
439 const char *p = header->buffer;
440
441 recsum = tar_from_oct (8, header->header.chksum);
442
443 for (i = sizeof (*header); --i >= 0;)
444 {
445 /*
446 * We can't use unsigned char here because of old compilers,
447 * e.g. V7.
448 */
449 signed_sum += *p;
450 sum += 0xFF & *p++;
451 }
452
453 /* Adjust checksum to count the "chksum" field as blanks. */
454 for (i = sizeof (header->header.chksum); --i >= 0;)
455 {
456 sum -= 0xFF & header->header.chksum[i];
457 signed_sum -= (char) header->header.chksum[i];
458 }
459
460 sum += ' ' * sizeof (header->header.chksum);
461 signed_sum += ' ' * sizeof (header->header.chksum);
462
463 /*
464 * This is a zeroed block... whole block is 0's except
465 * for the 8 blanks we faked for the checksum field.
466 */
467 if (sum == 8 * ' ')
468 return STATUS_EOFMARK;
469
470 if (sum != recsum && signed_sum != recsum)
471 return STATUS_BADCHECKSUM;
472
473 return STATUS_SUCCESS;
474 }
475
476 /* --------------------------------------------------------------------------------------------- */
477
478 static size_t
tar_decode_header(union block * header,tar_super_t * arch)479 tar_decode_header (union block *header, tar_super_t * arch)
480 {
481 size_t size;
482
483 /*
484 * Try to determine the archive format.
485 */
486 if (arch->type == TAR_UNKNOWN)
487 {
488 if (strcmp (header->header.magic, TMAGIC) == 0)
489 {
490 if (header->header.typeflag == XGLTYPE)
491 arch->type = TAR_POSIX;
492 else
493 arch->type = TAR_USTAR;
494 }
495 else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
496 arch->type = TAR_GNU;
497 }
498
499 /*
500 * typeflag on BSDI tar (pax) always '\000'
501 */
502 if (header->header.typeflag == '\000')
503 {
504 size_t len;
505
506 if (header->header.name[sizeof (header->header.name) - 1] != '\0')
507 len = sizeof (header->header.name);
508 else
509 len = strlen (header->header.name);
510
511 if (len != 0 && IS_PATH_SEP (header->header.name[len - 1]))
512 header->header.typeflag = DIRTYPE;
513 }
514
515 /*
516 * Good block. Decode file size and return.
517 */
518 if (header->header.typeflag == LNKTYPE || header->header.typeflag == DIRTYPE)
519 size = 0; /* Links 0 size on tape */
520 else
521 size = tar_from_oct (1 + 12, header->header.size);
522
523 if (header->header.typeflag == GNUTYPE_DUMPDIR)
524 if (arch->type == TAR_UNKNOWN)
525 arch->type = TAR_GNU;
526
527 return size;
528 }
529
530 /* --------------------------------------------------------------------------------------------- */
531
532 static void
tar_fill_stat(struct vfs_s_super * archive,struct stat * st,union block * header,size_t h_size)533 tar_fill_stat (struct vfs_s_super *archive, struct stat *st, union block *header, size_t h_size)
534 {
535 tar_super_t *arch = TAR_SUPER (archive);
536
537 st->st_mode = tar_from_oct (8, header->header.mode);
538
539 /* Adjust st->st_mode because there are tar-files with
540 * typeflag==SYMTYPE and S_ISLNK(mod)==0. I don't
541 * know about the other modes but I think I cause no new
542 * problem when I adjust them, too. -- Norbert.
543 */
544 if (header->header.typeflag == DIRTYPE || header->header.typeflag == GNUTYPE_DUMPDIR)
545 st->st_mode |= S_IFDIR;
546 else if (header->header.typeflag == SYMTYPE)
547 st->st_mode |= S_IFLNK;
548 else if (header->header.typeflag == CHRTYPE)
549 st->st_mode |= S_IFCHR;
550 else if (header->header.typeflag == BLKTYPE)
551 st->st_mode |= S_IFBLK;
552 else if (header->header.typeflag == FIFOTYPE)
553 st->st_mode |= S_IFIFO;
554 else
555 st->st_mode |= S_IFREG;
556
557 st->st_dev = 0;
558 #ifdef HAVE_STRUCT_STAT_ST_RDEV
559 st->st_rdev = 0;
560 #endif
561
562 switch (arch->type)
563 {
564 case TAR_USTAR:
565 case TAR_POSIX:
566 case TAR_GNU:
567 /* *INDENT-OFF* */
568 st->st_uid = *header->header.uname != '\0'
569 ? (uid_t) vfs_finduid (header->header.uname)
570 : tar_from_oct (8, header->header.uid);
571 st->st_gid = *header->header.gname != '\0'
572 ? (gid_t) vfs_findgid (header->header.gname)
573 : tar_from_oct (8,header->header.gid);
574 /* *INDENT-ON* */
575
576 switch (header->header.typeflag)
577 {
578 case BLKTYPE:
579 case CHRTYPE:
580 #ifdef HAVE_STRUCT_STAT_ST_RDEV
581 st->st_rdev =
582 makedev (tar_from_oct (8, header->header.devmajor),
583 tar_from_oct (8, header->header.devminor));
584 #endif
585 break;
586 default:
587 break;
588 }
589 break;
590
591 default:
592 st->st_uid = tar_from_oct (8, header->header.uid);
593 st->st_gid = tar_from_oct (8, header->header.gid);
594 break;
595 }
596
597 st->st_size = h_size;
598 #ifdef HAVE_STRUCT_STAT_ST_MTIM
599 st->st_atim.tv_nsec = st->st_mtim.tv_nsec = st->st_ctim.tv_nsec = 0;
600 #endif
601 st->st_mtime = tar_from_oct (1 + 12, header->header.mtime);
602 st->st_atime = 0;
603 st->st_ctime = 0;
604 if (arch->type == TAR_GNU)
605 {
606 st->st_atime = tar_from_oct (1 + 12, header->oldgnu_header.atime);
607 st->st_ctime = tar_from_oct (1 + 12, header->oldgnu_header.ctime);
608 }
609
610 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
611 st->st_blksize = 8 * 1024; /* FIXME */
612 #endif
613 vfs_adjust_stat (st);
614 }
615
616 /* --------------------------------------------------------------------------------------------- */
617 /**
618 * Return 1 for success, 0 if the checksum is bad, EOF on eof,
619 * 2 for a block full of zeros (EOF marker).
620 *
621 */
622 static ReadStatus
tar_read_header(struct vfs_class * me,struct vfs_s_super * archive,int tard,size_t * h_size)623 tar_read_header (struct vfs_class *me, struct vfs_s_super *archive, int tard, size_t * h_size)
624 {
625 tar_super_t *arch = TAR_SUPER (archive);
626 ReadStatus checksum_status;
627 union block *header;
628 static char *next_long_name = NULL, *next_long_link = NULL;
629
630 while (TRUE)
631 {
632 header = tar_get_next_block (archive, tard);
633 if (header == NULL)
634 return STATUS_EOF;
635
636 checksum_status = tar_checksum (header);
637 if (checksum_status != STATUS_SUCCESS)
638 return checksum_status;
639
640 *h_size = tar_decode_header (header, arch);
641
642 /* Skip over pax extended header and global extended header records. */
643 if (header->header.typeflag == XHDTYPE || header->header.typeflag == XGLTYPE)
644 {
645 if (arch->type == TAR_UNKNOWN)
646 arch->type = TAR_POSIX;
647 return STATUS_SUCCESS;
648 }
649
650 if (header->header.typeflag == GNUTYPE_LONGNAME
651 || header->header.typeflag == GNUTYPE_LONGLINK)
652 {
653 char **longp;
654 char *bp, *data;
655 off_t size;
656 size_t written;
657
658 if (arch->type == TAR_UNKNOWN)
659 arch->type = TAR_GNU;
660
661 if (*h_size > MC_MAXPATHLEN)
662 {
663 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
664 return STATUS_BADCHECKSUM;
665 }
666
667 longp = header->header.typeflag == GNUTYPE_LONGNAME ? &next_long_name : &next_long_link;
668
669 g_free (*longp);
670 bp = *longp = g_malloc (*h_size + 1);
671
672 for (size = *h_size; size > 0; size -= written)
673 {
674 data = tar_get_next_block (archive, tard)->buffer;
675 if (data == NULL)
676 {
677 MC_PTR_FREE (*longp);
678 message (D_ERROR, MSG_ERROR, _("Unexpected EOF on archive file"));
679 return STATUS_BADCHECKSUM;
680 }
681 written = BLOCKSIZE;
682 if ((off_t) written > size)
683 written = (size_t) size;
684
685 memcpy (bp, data, written);
686 bp += written;
687 }
688
689 if (bp - *longp == MC_MAXPATHLEN && bp[-1] != '\0')
690 {
691 MC_PTR_FREE (*longp);
692 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
693 return STATUS_BADCHECKSUM;
694 }
695
696 *bp = '\0';
697 }
698 else
699 break;
700 }
701
702 {
703 struct stat st;
704 struct vfs_s_entry *entry;
705 struct vfs_s_inode *inode = NULL, *parent;
706 off_t data_position;
707 char *p, *q;
708 size_t len;
709 char *current_file_name, *current_link_name;
710
711 current_link_name =
712 next_long_link != NULL ? next_long_link : g_strndup (header->header.linkname,
713 sizeof (header->header.linkname));
714 len = strlen (current_link_name);
715 if (len > 1 && IS_PATH_SEP (current_link_name[len - 1]))
716 current_link_name[len - 1] = '\0';
717
718 current_file_name = NULL;
719 switch (arch->type)
720 {
721 case TAR_USTAR:
722 case TAR_POSIX:
723 /* The ustar archive format supports pathnames of upto 256
724 * characters in length. This is achieved by concatenating
725 * the contents of the 'prefix' and 'name' fields like
726 * this:
727 *
728 * prefix + path_separator + name
729 *
730 * If the 'prefix' field contains an empty string i.e. its
731 * first characters is '\0' the prefix field is ignored.
732 */
733 if (header->header.prefix[0] != '\0')
734 {
735 char *temp_name, *temp_prefix;
736
737 temp_name = g_strndup (header->header.name, sizeof (header->header.name));
738 temp_prefix = g_strndup (header->header.prefix, sizeof (header->header.prefix));
739 current_file_name = g_strconcat (temp_prefix, PATH_SEP_STR,
740 temp_name, (char *) NULL);
741 g_free (temp_name);
742 g_free (temp_prefix);
743 }
744 break;
745 case TAR_GNU:
746 if (next_long_name != NULL)
747 current_file_name = next_long_name;
748 break;
749 default:
750 break;
751 }
752
753 if (current_file_name == NULL)
754 {
755 if (next_long_name != NULL)
756 current_file_name = g_strdup (next_long_name);
757 else
758 current_file_name = g_strndup (header->header.name, sizeof (header->header.name));
759 }
760
761 canonicalize_pathname (current_file_name);
762 len = strlen (current_file_name);
763
764 data_position = current_tar_position;
765
766 p = strrchr (current_file_name, PATH_SEP);
767 if (p == NULL)
768 {
769 p = current_file_name;
770 q = current_file_name + len; /* "" */
771 }
772 else
773 {
774 *(p++) = '\0';
775 q = current_file_name;
776 }
777
778 parent = vfs_s_find_inode (me, archive, q, LINK_NO_FOLLOW, FL_MKDIR);
779 if (parent == NULL)
780 {
781 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
782 return STATUS_BADCHECKSUM;
783 }
784
785 if (header->header.typeflag == LNKTYPE)
786 {
787 inode = vfs_s_find_inode (me, archive, current_link_name, LINK_NO_FOLLOW, FL_NONE);
788 if (inode == NULL)
789 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
790 else
791 {
792 entry = vfs_s_new_entry (me, p, inode);
793 vfs_s_insert_entry (me, parent, entry);
794 g_free (current_link_name);
795 goto done;
796 }
797 }
798
799 memset (&st, 0, sizeof (st));
800 tar_fill_stat (archive, &st, header, *h_size);
801
802 if (S_ISDIR (st.st_mode))
803 {
804 entry = VFS_SUBCLASS (me)->find_entry (me, parent, p, LINK_NO_FOLLOW, FL_NONE);
805 if (entry != NULL)
806 goto done;
807 }
808
809 inode = vfs_s_new_inode (me, archive, &st);
810 inode->data_offset = data_position;
811
812 if (*current_link_name != '\0')
813 inode->linkname = current_link_name;
814 else if (current_link_name != next_long_link)
815 g_free (current_link_name);
816
817 entry = vfs_s_new_entry (me, p, inode);
818 vfs_s_insert_entry (me, parent, entry);
819 g_free (current_file_name);
820
821 done:
822 next_long_link = next_long_name = NULL;
823
824 if (arch->type == TAR_GNU && header->oldgnu_header.isextended)
825 {
826 while (tar_get_next_block (archive, tard)->sparse_header.isextended != 0)
827 ;
828
829 if (inode != NULL)
830 inode->data_offset = current_tar_position;
831 }
832 return STATUS_SUCCESS;
833 }
834 }
835
836 /* --------------------------------------------------------------------------------------------- */
837 /**
838 * Main loop for reading an archive.
839 * Returns 0 on success, -1 on error.
840 */
841 static int
tar_open_archive(struct vfs_s_super * archive,const vfs_path_t * vpath,const vfs_path_element_t * vpath_element)842 tar_open_archive (struct vfs_s_super *archive, const vfs_path_t * vpath,
843 const vfs_path_element_t * vpath_element)
844 {
845 /* Initial status at start of archive */
846 ReadStatus status = STATUS_EOFMARK;
847 int tard;
848
849 current_tar_position = 0;
850 /* Open for reading */
851 tard = tar_open_archive_int (vpath_element->class, vpath, archive);
852 if (tard == -1)
853 return -1;
854
855 while (TRUE)
856 {
857 size_t h_size = 0;
858 ReadStatus prev_status = status;
859
860 status = tar_read_header (vpath_element->class, archive, tard, &h_size);
861
862 switch (status)
863 {
864 case STATUS_SUCCESS:
865 tar_skip_n_records (archive, tard, (h_size + BLOCKSIZE - 1) / BLOCKSIZE);
866 continue;
867
868 /*
869 * Invalid header:
870 *
871 * If the previous header was good, tell them
872 * that we are skipping bad ones.
873 */
874 case STATUS_BADCHECKSUM:
875 switch (prev_status)
876 {
877 /* Error on first block */
878 case STATUS_EOFMARK:
879 {
880 message (D_ERROR, MSG_ERROR, _("%s\ndoesn't look like a tar archive."),
881 vfs_path_as_str (vpath));
882 MC_FALLTHROUGH;
883
884 /* Error after header rec */
885 }
886 case STATUS_SUCCESS:
887 /* Error after error */
888
889 case STATUS_BADCHECKSUM:
890 return -1;
891
892 case STATUS_EOF:
893 return 0;
894
895 default:
896 break;
897 }
898 MC_FALLTHROUGH;
899
900 /* Record of zeroes */
901 case STATUS_EOFMARK: /* If error after 0's */
902 MC_FALLTHROUGH;
903 /* exit from loop */
904 case STATUS_EOF: /* End of archive */
905 break;
906 default:
907 break;
908 }
909 break;
910 }
911 return 0;
912 }
913
914 /* --------------------------------------------------------------------------------------------- */
915
916 static void *
tar_super_check(const vfs_path_t * vpath)917 tar_super_check (const vfs_path_t * vpath)
918 {
919 static struct stat stat_buf;
920 int stat_result;
921
922 stat_result = mc_stat (vpath, &stat_buf);
923
924 return (stat_result != 0) ? NULL : &stat_buf;
925 }
926
927 /* --------------------------------------------------------------------------------------------- */
928
929 static int
tar_super_same(const vfs_path_element_t * vpath_element,struct vfs_s_super * parc,const vfs_path_t * vpath,void * cookie)930 tar_super_same (const vfs_path_element_t * vpath_element, struct vfs_s_super *parc,
931 const vfs_path_t * vpath, void *cookie)
932 {
933 struct stat *archive_stat = cookie; /* stat of main archive */
934
935 (void) vpath_element;
936
937 if (strcmp (parc->name, vfs_path_as_str (vpath)) != 0)
938 return 0;
939
940 /* Has the cached archive been changed on the disk? */
941 if (parc != NULL && TAR_SUPER (parc)->st.st_mtime < archive_stat->st_mtime)
942 {
943 /* Yes, reload! */
944 vfs_tarfs_ops->free ((vfsid) parc);
945 vfs_rmstamp (vfs_tarfs_ops, (vfsid) parc);
946 return 2;
947 }
948 /* Hasn't been modified, give it a new timeout */
949 vfs_stamp (vfs_tarfs_ops, (vfsid) parc);
950 return 1;
951 }
952
953 /* --------------------------------------------------------------------------------------------- */
954
955 static ssize_t
tar_read(void * fh,char * buffer,size_t count)956 tar_read (void *fh, char *buffer, size_t count)
957 {
958 struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
959 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
960 off_t begin = file->ino->data_offset;
961 int fd = TAR_SUPER (VFS_FILE_HANDLER_SUPER (fh))->fd;
962 ssize_t res;
963
964 if (mc_lseek (fd, begin + file->pos, SEEK_SET) != begin + file->pos)
965 ERRNOR (EIO, -1);
966
967 count = MIN (count, (size_t) (file->ino->st.st_size - file->pos));
968
969 res = mc_read (fd, buffer, count);
970 if (res == -1)
971 ERRNOR (errno, -1);
972
973 file->pos += res;
974 return res;
975 }
976
977 /* --------------------------------------------------------------------------------------------- */
978
979 static int
tar_fh_open(struct vfs_class * me,vfs_file_handler_t * fh,int flags,mode_t mode)980 tar_fh_open (struct vfs_class *me, vfs_file_handler_t * fh, int flags, mode_t mode)
981 {
982 (void) fh;
983 (void) mode;
984
985 if ((flags & O_ACCMODE) != O_RDONLY)
986 ERRNOR (EROFS, -1);
987 return 0;
988 }
989
990 /* --------------------------------------------------------------------------------------------- */
991 /*** public functions ****************************************************************************/
992 /* --------------------------------------------------------------------------------------------- */
993
994 void
vfs_init_tarfs(void)995 vfs_init_tarfs (void)
996 {
997 /* FIXME: tarfs used own temp files */
998 vfs_init_subclass (&tarfs_subclass, "tarfs", VFSF_READONLY, "utar");
999 vfs_tarfs_ops->read = tar_read;
1000 vfs_tarfs_ops->setctl = NULL;
1001 tarfs_subclass.archive_check = tar_super_check;
1002 tarfs_subclass.archive_same = tar_super_same;
1003 tarfs_subclass.new_archive = tar_new_archive;
1004 tarfs_subclass.open_archive = tar_open_archive;
1005 tarfs_subclass.free_archive = tar_free_archive;
1006 tarfs_subclass.fh_open = tar_fh_open;
1007 vfs_register_class (vfs_tarfs_ops);
1008 }
1009
1010 /* --------------------------------------------------------------------------------------------- */
1011