This source file includes following definitions.
- tar_stat_destroy
- gid_from_header
- major_from_header
- minor_from_header
- mode_from_header
- time_from_header
- uid_from_header
- tar_calc_sparse_offsets
- tar_skip_member
- tar_available_space_after
- tar_checksum
- tar_decode_header
- tar_fill_stat
- tar_free_inode
- tar_insert_entry
- tar_read_header
- tar_new_archive
- tar_free_archive
- tar_open_archive_int
- tar_open_archive
- tar_super_check
- tar_super_same
- tar_get_sparse_chunk_idx
- tar_read_sparse
- tar_lseek_sparse
- tar_read
- tar_fh_open
- vfs_init_tarfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 #include <config.h>
37
38 #include <errno.h>
39 #include <string.h>
40
41 #ifdef hpux
42
43 # include <sys/mknod.h>
44 #endif
45
46 #include "lib/global.h"
47 #include "lib/util.h"
48 #include "lib/unixcompat.h"
49 #include "lib/widget.h"
50
51 #include "lib/vfs/vfs.h"
52 #include "lib/vfs/utilvfs.h"
53 #include "lib/vfs/gc.h"
54
55 #include "tar-internal.h"
56 #include "tar.h"
57
58
59
60
61
62 const idx_t blocking_factor = DEFAULT_BLOCKING;
63 const idx_t record_size = DEFAULT_BLOCKING * BLOCKSIZE;
64
65
66 union block *record_end;
67 union block *current_block;
68 off_t record_start_block;
69
70 union block *current_header;
71
72
73 gboolean hit_eof;
74
75 struct tar_stat_info current_stat_info;
76
77
78
79 #define TAR_SUPER(super) ((tar_super_t *) (super))
80
81
82
83
84 #define TMAGIC "ustar"
85
86 #define XHDTYPE 'x'
87 #define XGLTYPE 'g'
88
89
90 #define REGTYPE '0'
91 #define AREGTYPE '\0'
92 #define LNKTYPE '1'
93 #define SYMTYPE '2'
94 #define CHRTYPE '3'
95 #define BLKTYPE '4'
96 #define DIRTYPE '5'
97 #define FIFOTYPE '6'
98
99
100
101
102
103 #define OLDGNU_MAGIC "ustar "
104
105
106 #define TSUID 04000
107 #define TSGID 02000
108 #define TSVTX \
109 01000
110
111 #define TUREAD 00400
112 #define TUWRITE 00200
113 #define TUEXEC 00100
114 #define TGREAD 00040
115 #define TGWRITE 00020
116 #define TGEXEC 00010
117 #define TOREAD 00004
118 #define TOWRITE 00002
119 #define TOEXEC 00001
120
121 #define GID_FROM_HEADER(where) gid_from_header (where, sizeof (where))
122 #define MAJOR_FROM_HEADER(where) major_from_header (where, sizeof (where))
123 #define MINOR_FROM_HEADER(where) minor_from_header (where, sizeof (where))
124 #define MODE_FROM_HEADER(where, hbits) mode_from_header (where, sizeof (where), hbits)
125 #define TIME_FROM_HEADER(where) time_from_header (where, sizeof (where))
126 #define UID_FROM_HEADER(where) uid_from_header (where, sizeof (where))
127
128
129
130 typedef enum
131 {
132 HEADER_STILL_UNREAD,
133 HEADER_SUCCESS,
134 HEADER_ZERO_BLOCK,
135 HEADER_END_OF_FILE,
136 HEADER_FAILURE
137 } read_header;
138
139
140
141
142
143 static struct vfs_s_subclass tarfs_subclass;
144 static struct vfs_class *vfs_tarfs_ops = VFS_CLASS (&tarfs_subclass);
145
146 static struct timespec start_time;
147
148
149
150
151
152 static void
153 tar_stat_destroy (struct tar_stat_info *st)
154 {
155 g_free (st->orig_file_name);
156 g_free (st->file_name);
157 g_free (st->link_name);
158 #if 0
159 g_free (st->uname);
160 g_free (st->gname);
161 #endif
162 if (st->sparse_map != NULL)
163 {
164 g_array_free (st->sparse_map, TRUE);
165 st->sparse_map = NULL;
166 }
167 tar_xheader_destroy (&st->xhdr);
168 memset (st, 0, sizeof (*st));
169 }
170
171
172
173 static inline gid_t
174 gid_from_header (const char *p, size_t s)
175 {
176 return tar_from_header (p, s, "gid_t", TYPE_MINIMUM (gid_t), TYPE_MAXIMUM (gid_t), FALSE);
177 }
178
179
180
181 static inline major_t
182 major_from_header (const char *p, size_t s)
183 {
184 return tar_from_header (p, s, "major_t", TYPE_MINIMUM (major_t), TYPE_MAXIMUM (major_t), FALSE);
185 }
186
187
188
189 static inline minor_t
190 minor_from_header (const char *p, size_t s)
191 {
192 return tar_from_header (p, s, "minor_t", TYPE_MINIMUM (minor_t), TYPE_MAXIMUM (minor_t), FALSE);
193 }
194
195
196
197
198
199
200
201
202 static inline mode_t
203 mode_from_header (const char *p, size_t s, gboolean *hbits)
204 {
205 unsigned int u;
206 mode_t mode;
207
208
209 u = tar_from_header (p, s, "mode_t", INTMAX_MIN, UINTMAX_MAX, FALSE);
210
211 mode =
212 ((u & TSUID ? S_ISUID : 0) | (u & TSGID ? S_ISGID : 0) | (u & TSVTX ? S_ISVTX : 0)
213 | (u & TUREAD ? S_IRUSR : 0) | (u & TUWRITE ? S_IWUSR : 0) | (u & TUEXEC ? S_IXUSR : 0)
214 | (u & TGREAD ? S_IRGRP : 0) | (u & TGWRITE ? S_IWGRP : 0) | (u & TGEXEC ? S_IXGRP : 0)
215 | (u & TOREAD ? S_IROTH : 0) | (u & TOWRITE ? S_IWOTH : 0) | (u & TOEXEC ? S_IXOTH : 0));
216
217 if (hbits != NULL)
218 *hbits = (u & ~07777) != 0;
219
220 return mode;
221 }
222
223
224
225 static inline time_t
226 time_from_header (const char *p, size_t s)
227 {
228 return tar_from_header (p, s, "time_t", TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), FALSE);
229 }
230
231
232
233 static inline uid_t
234 uid_from_header (const char *p, size_t s)
235 {
236 return tar_from_header (p, s, "uid_t", TYPE_MINIMUM (uid_t), TYPE_MAXIMUM (uid_t), FALSE);
237 }
238
239
240
241 static void
242 tar_calc_sparse_offsets (struct vfs_s_inode *inode)
243 {
244 off_t begin = inode->data_offset;
245 GArray *sm = (GArray *) inode->user_data;
246 size_t i;
247
248 for (i = 0; i < sm->len; i++)
249 {
250 struct sp_array *sp;
251
252 sp = &g_array_index (sm, struct sp_array, i);
253 sp->arch_offset = begin;
254 begin += BLOCKSIZE * (sp->numbytes / BLOCKSIZE + sp->numbytes % BLOCKSIZE);
255 }
256 }
257
258
259
260 static gboolean
261 tar_skip_member (tar_super_t *archive, struct vfs_s_inode *inode)
262 {
263 char save_typeflag;
264
265 if (current_stat_info.skipped)
266 return TRUE;
267
268 save_typeflag = current_header->header.typeflag;
269
270 tar_set_next_block_after (current_header);
271
272 if (current_stat_info.is_sparse)
273 {
274 if (inode != NULL)
275 inode->data_offset = BLOCKSIZE * tar_current_block_ordinal (archive);
276
277 (void) tar_sparse_skip_file (archive, ¤t_stat_info);
278
279 if (inode != NULL)
280 {
281
282 inode->user_data = current_stat_info.sparse_map;
283 current_stat_info.sparse_map = NULL;
284
285 tar_calc_sparse_offsets (inode);
286 }
287 }
288 else if (save_typeflag != DIRTYPE)
289 {
290 if (inode != NULL && (save_typeflag == REGTYPE || save_typeflag == AREGTYPE))
291 inode->data_offset = BLOCKSIZE * tar_current_block_ordinal (archive);
292
293 return tar_skip_file (archive, current_stat_info.stat.st_size);
294 }
295
296 return TRUE;
297 }
298
299
300
301
302
303
304
305
306
307 static inline size_t
308 tar_available_space_after (const union block *pointer)
309 {
310 return record_end->buffer - pointer->buffer;
311 }
312
313
314
315
316
317 static read_header
318 tar_checksum (const union block *header)
319 {
320 unsigned int i;
321 int unsigned_sum = 0;
322 int signed_sum = 0;
323 int recorded_sum;
324
325 for (i = 0; i < sizeof (*header); i++)
326 {
327 unsigned char uc = header->buffer[i];
328 signed char sc = header->buffer[i];
329
330 unsigned_sum += uc;
331 signed_sum += sc;
332 }
333
334 if (unsigned_sum == 0)
335 return HEADER_ZERO_BLOCK;
336
337
338 for (i = 0; i < sizeof (header->header.chksum); i++)
339 {
340 unsigned char uc = header->header.chksum[i];
341 signed char sc = header->header.chksum[i];
342
343 unsigned_sum -= uc;
344 signed_sum -= sc;
345 }
346
347 unsigned_sum += ' ' * sizeof (header->header.chksum);
348 signed_sum += ' ' * sizeof (header->header.chksum);
349
350 recorded_sum = tar_from_header (header->header.chksum, sizeof (header->header.chksum), NULL, 0,
351 INT_MAX, TRUE);
352
353 if (recorded_sum < 0)
354 return HEADER_FAILURE;
355
356 if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
357 return HEADER_FAILURE;
358
359 return HEADER_SUCCESS;
360 }
361
362
363
364 static void
365 tar_decode_header (union block *header, tar_super_t *arch)
366 {
367 gboolean hbits = FALSE;
368
369 current_stat_info.stat.st_mode = MODE_FROM_HEADER (header->header.mode, &hbits);
370
371
372
373
374 if (arch->type == TAR_UNKNOWN)
375 {
376 if (strcmp (header->header.magic, TMAGIC) == 0)
377 {
378 if (header->star_header.prefix[130] == 0
379 && is_octal_digit (header->star_header.atime[0])
380 && header->star_header.atime[11] == ' '
381 && is_octal_digit (header->star_header.ctime[0])
382 && header->star_header.ctime[11] == ' ')
383 arch->type = TAR_STAR;
384 else if (current_stat_info.xhdr.buffer != NULL)
385 arch->type = TAR_POSIX;
386 else
387 arch->type = TAR_USTAR;
388 }
389 else if (strcmp (header->buffer + offsetof (struct posix_header, magic), OLDGNU_MAGIC) == 0)
390 arch->type = hbits ? TAR_OLDGNU : TAR_GNU;
391 else
392 arch->type = TAR_V7;
393 }
394
395
396
397
398 if (header->header.typeflag == '\000')
399 {
400 size_t len;
401
402 if (header->header.name[sizeof (header->header.name) - 1] != '\0')
403 len = sizeof (header->header.name);
404 else
405 len = strlen (header->header.name);
406
407 if (len != 0 && IS_PATH_SEP (header->header.name[len - 1]))
408 header->header.typeflag = DIRTYPE;
409 }
410
411 if (header->header.typeflag == GNUTYPE_DUMPDIR)
412 if (arch->type == TAR_UNKNOWN)
413 arch->type = TAR_GNU;
414 }
415
416
417
418 static void
419 tar_fill_stat (struct vfs_s_super *archive, union block *header)
420 {
421 tar_super_t *arch = TAR_SUPER (archive);
422
423
424
425
426
427
428 if (header->header.typeflag == DIRTYPE || header->header.typeflag == GNUTYPE_DUMPDIR)
429 current_stat_info.stat.st_mode |= S_IFDIR;
430 else if (header->header.typeflag == SYMTYPE)
431 current_stat_info.stat.st_mode |= S_IFLNK;
432 else if (header->header.typeflag == CHRTYPE)
433 current_stat_info.stat.st_mode |= S_IFCHR;
434 else if (header->header.typeflag == BLKTYPE)
435 current_stat_info.stat.st_mode |= S_IFBLK;
436 else if (header->header.typeflag == FIFOTYPE)
437 current_stat_info.stat.st_mode |= S_IFIFO;
438 else
439 current_stat_info.stat.st_mode |= S_IFREG;
440
441 current_stat_info.stat.st_dev = 0;
442 #ifdef HAVE_STRUCT_STAT_ST_RDEV
443 current_stat_info.stat.st_rdev = 0;
444 #endif
445
446 switch (arch->type)
447 {
448 case TAR_USTAR:
449 case TAR_POSIX:
450 case TAR_GNU:
451 case TAR_OLDGNU:
452 current_stat_info.stat.st_uid = *header->header.uname != '\0'
453 ? (uid_t) vfs_finduid (header->header.uname)
454 : UID_FROM_HEADER (header->header.uid);
455 current_stat_info.stat.st_gid = *header->header.gname != '\0'
456 ? (gid_t) vfs_findgid (header->header.gname)
457 : GID_FROM_HEADER (header->header.gid);
458
459 switch (header->header.typeflag)
460 {
461 case BLKTYPE:
462 case CHRTYPE:
463 #ifdef HAVE_STRUCT_STAT_ST_RDEV
464 current_stat_info.stat.st_rdev = makedev (MAJOR_FROM_HEADER (header->header.devmajor),
465 MINOR_FROM_HEADER (header->header.devminor));
466 #endif
467 break;
468 default:
469 break;
470 }
471 break;
472
473 default:
474 current_stat_info.stat.st_uid = UID_FROM_HEADER (header->header.uid);
475 current_stat_info.stat.st_gid = GID_FROM_HEADER (header->header.gid);
476 break;
477 }
478
479 current_stat_info.atime.tv_nsec = 0;
480 current_stat_info.mtime.tv_nsec = 0;
481 current_stat_info.ctime.tv_nsec = 0;
482
483 current_stat_info.mtime.tv_sec = TIME_FROM_HEADER (header->header.mtime);
484 if (arch->type == TAR_GNU || arch->type == TAR_OLDGNU)
485 {
486 current_stat_info.atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
487 current_stat_info.ctime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.ctime);
488 }
489 else if (arch->type == TAR_STAR)
490 {
491 current_stat_info.atime.tv_sec = TIME_FROM_HEADER (header->star_header.atime);
492 current_stat_info.ctime.tv_sec = TIME_FROM_HEADER (header->star_header.ctime);
493 }
494 else
495 current_stat_info.atime = current_stat_info.ctime = start_time;
496
497 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
498 current_stat_info.stat.st_blksize = 8 * 1024;
499 #endif
500 vfs_adjust_stat (¤t_stat_info.stat);
501 }
502
503
504
505 static void
506 tar_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
507 {
508 (void) me;
509
510
511 if (ino->user_data != NULL)
512 g_array_free ((GArray *) ino->user_data, TRUE);
513 }
514
515
516
517 static read_header
518 tar_insert_entry (struct vfs_class *me, struct vfs_s_super *archive, union block *header,
519 struct vfs_s_inode **inode)
520 {
521 char *p, *q;
522 char *file_name = current_stat_info.file_name;
523 char *link_name = current_stat_info.link_name;
524 size_t len;
525 struct vfs_s_inode *parent;
526 struct vfs_s_entry *entry;
527
528 p = strrchr (file_name, PATH_SEP);
529 if (p == NULL)
530 {
531 len = strlen (file_name);
532 p = file_name;
533 q = file_name + len;
534 }
535 else
536 {
537 *(p++) = '\0';
538 q = file_name;
539 }
540
541 parent = vfs_s_find_inode (me, archive, q, LINK_NO_FOLLOW, FL_MKDIR);
542 if (parent == NULL)
543 return HEADER_FAILURE;
544
545 *inode = NULL;
546
547 if (header->header.typeflag == LNKTYPE)
548 {
549 if (*link_name != '\0')
550 {
551 len = strlen (link_name);
552 if (IS_PATH_SEP (link_name[len - 1]))
553 link_name[len - 1] = '\0';
554
555 *inode = vfs_s_find_inode (me, archive, link_name, LINK_NO_FOLLOW, FL_NONE);
556 }
557
558 if (*inode == NULL)
559 return HEADER_FAILURE;
560 }
561 else
562 {
563 if (S_ISDIR (current_stat_info.stat.st_mode))
564 {
565 entry = VFS_SUBCLASS (me)->find_entry (me, parent, p, LINK_NO_FOLLOW, FL_NONE);
566 if (entry != NULL)
567 return HEADER_SUCCESS;
568 }
569
570 *inode = vfs_s_new_inode (me, archive, ¤t_stat_info.stat);
571
572 (*inode)->st.st_mtime = current_stat_info.mtime.tv_sec;
573 (*inode)->st.st_atime = current_stat_info.atime.tv_sec;
574 (*inode)->st.st_ctime = current_stat_info.ctime.tv_sec;
575
576 if (link_name != NULL && *link_name != '\0')
577 (*inode)->linkname = g_strdup (link_name);
578 }
579
580 entry = vfs_s_new_entry (me, p, *inode);
581 vfs_s_insert_entry (me, parent, entry);
582
583 return HEADER_SUCCESS;
584 }
585
586
587
588 static read_header
589 tar_read_header (struct vfs_class *me, struct vfs_s_super *archive)
590 {
591 tar_super_t *arch = TAR_SUPER (archive);
592 union block *header;
593 union block *next_long_name = NULL, *next_long_link = NULL;
594 read_header status = HEADER_SUCCESS;
595
596 while (TRUE)
597 {
598 header = tar_find_next_block (arch);
599 current_header = header;
600 if (header == NULL)
601 {
602 status = HEADER_END_OF_FILE;
603 goto ret;
604 }
605
606 status = tar_checksum (header);
607 if (status != HEADER_SUCCESS)
608 goto ret;
609
610 if (header->header.typeflag == LNKTYPE || header->header.typeflag == DIRTYPE)
611 current_stat_info.stat.st_size = 0;
612 else
613 {
614 current_stat_info.stat.st_size = OFF_FROM_HEADER (header->header.size);
615 if (current_stat_info.stat.st_size < 0)
616 {
617 status = HEADER_FAILURE;
618 goto ret;
619 }
620 }
621
622 tar_decode_header (header, arch);
623 tar_fill_stat (archive, header);
624
625 if (header->header.typeflag == GNUTYPE_LONGNAME
626 || header->header.typeflag == GNUTYPE_LONGLINK)
627 {
628 off_t size;
629 union block *header_copy;
630 char *bp;
631 size_t written;
632
633 if (arch->type == TAR_UNKNOWN)
634 arch->type = TAR_GNU;
635
636 if (ckd_add (&size, current_stat_info.stat.st_size, 2 * BLOCKSIZE - 1))
637 {
638 message (D_ERROR, MSG_ERROR, _ ("Inconsistent tar archive"));
639 status = HEADER_FAILURE;
640 goto ret;
641 }
642
643 size -= size % BLOCKSIZE;
644
645 header_copy = g_malloc (size + 1);
646
647 if (header->header.typeflag == GNUTYPE_LONGNAME)
648 {
649 g_free (next_long_name);
650 next_long_name = header_copy;
651 }
652 else
653 {
654 g_free (next_long_link);
655 next_long_link = header_copy;
656 }
657
658 tar_set_next_block_after (header);
659 *header_copy = *header;
660 bp = header_copy->buffer + BLOCKSIZE;
661
662 for (size -= BLOCKSIZE; size > 0; size -= written)
663 {
664 union block *data_block;
665
666 data_block = tar_find_next_block (arch);
667 if (data_block == NULL)
668 {
669 message (D_ERROR, MSG_ERROR, _ ("Unexpected EOF on archive file"));
670 status = HEADER_FAILURE;
671 goto ret;
672 }
673
674 written = tar_available_space_after (data_block);
675 if ((off_t) written > size)
676 written = (size_t) size;
677
678 memcpy (bp, data_block->buffer, written);
679 bp += written;
680 tar_set_next_block_after ((union block *) (data_block->buffer + written - 1));
681 }
682
683 *bp = '\0';
684 }
685 else if (header->header.typeflag == XHDTYPE || header->header.typeflag == SOLARIS_XHDTYPE)
686 {
687 if (arch->type == TAR_UNKNOWN)
688 arch->type = TAR_POSIX;
689 if (!tar_xheader_read (arch, ¤t_stat_info.xhdr, header,
690 OFF_FROM_HEADER (header->header.size)))
691 {
692 message (D_ERROR, MSG_ERROR, _ ("Unexpected EOF on archive file"));
693 status = HEADER_FAILURE;
694 goto ret;
695 }
696 }
697 else if (header->header.typeflag == XGLTYPE)
698 {
699 struct xheader xhdr;
700 gboolean ok;
701
702 if (arch->type == TAR_UNKNOWN)
703 arch->type = TAR_POSIX;
704
705 memset (&xhdr, 0, sizeof (xhdr));
706 tar_xheader_read (arch, &xhdr, header, OFF_FROM_HEADER (header->header.size));
707 ok = tar_xheader_decode_global (&xhdr);
708 tar_xheader_destroy (&xhdr);
709
710 if (!ok)
711 {
712 message (D_ERROR, MSG_ERROR, _ ("Inconsistent tar archive"));
713 status = HEADER_FAILURE;
714 goto ret;
715 }
716 }
717 else
718 break;
719 }
720
721 {
722 static union block *recent_long_name = NULL, *recent_long_link = NULL;
723 struct posix_header const *h = &header->header;
724 char *file_name = NULL;
725 char *link_name;
726 struct vfs_s_inode *inode = NULL;
727
728 g_free (recent_long_name);
729
730 if (next_long_name != NULL)
731 {
732 file_name = g_strdup (next_long_name->buffer + BLOCKSIZE);
733 recent_long_name = next_long_name;
734 }
735 else
736 {
737
738 char *s1 = NULL;
739 char *s2;
740
741
742 if (h->prefix[0] != '\0' && strcmp (h->magic, TMAGIC) == 0)
743 s1 = g_strndup (h->prefix, sizeof (h->prefix));
744
745 s2 = g_strndup (h->name, sizeof (h->name));
746
747 if (s1 == NULL)
748 file_name = s2;
749 else
750 {
751 file_name = g_strconcat (s1, PATH_SEP_STR, s2, (char *) NULL);
752 g_free (s1);
753 g_free (s2);
754 }
755
756 recent_long_name = NULL;
757 }
758
759 tar_assign_string_dup (¤t_stat_info.orig_file_name, file_name);
760 tar_assign_string (¤t_stat_info.file_name, file_name);
761
762 g_free (recent_long_link);
763
764 if (next_long_link != NULL)
765 {
766 link_name = g_strdup (next_long_link->buffer + BLOCKSIZE);
767 recent_long_link = next_long_link;
768 }
769 else
770 {
771 link_name = g_strndup (h->linkname, sizeof (h->linkname));
772 recent_long_link = NULL;
773 }
774
775 tar_assign_string (¤t_stat_info.link_name, link_name);
776
777 if (current_stat_info.xhdr.buffer != NULL && !tar_xheader_decode (¤t_stat_info))
778 {
779 status = HEADER_FAILURE;
780 goto ret;
781 }
782
783 if (tar_sparse_member_p (arch, ¤t_stat_info))
784 {
785 if (!tar_sparse_fixup_header (arch, ¤t_stat_info))
786 {
787 status = HEADER_FAILURE;
788 goto ret;
789 }
790
791 current_stat_info.is_sparse = TRUE;
792 }
793 else
794 {
795 current_stat_info.is_sparse = FALSE;
796
797 if (((arch->type == TAR_GNU || arch->type == TAR_OLDGNU)
798 && current_header->header.typeflag == GNUTYPE_DUMPDIR)
799 || current_stat_info.dumpdir != NULL)
800 current_stat_info.is_dumpdir = TRUE;
801 }
802
803
804 canonicalize_pathname (current_stat_info.file_name);
805
806 status = tar_insert_entry (me, archive, header, &inode);
807 if (status != HEADER_SUCCESS)
808 {
809 message (D_ERROR, MSG_ERROR, _ ("Inconsistent tar archive"));
810 goto ret;
811 }
812
813 if (recent_long_name == next_long_name)
814 recent_long_name = NULL;
815
816 if (recent_long_link == next_long_link)
817 recent_long_link = NULL;
818
819 if (tar_skip_member (arch, inode))
820 status = HEADER_SUCCESS;
821 else if (hit_eof)
822 status = HEADER_END_OF_FILE;
823 else
824 status = HEADER_FAILURE;
825 }
826
827 ret:
828 g_free (next_long_name);
829 g_free (next_long_link);
830
831 return status;
832 }
833
834
835
836 static struct vfs_s_super *
837 tar_new_archive (struct vfs_class *me)
838 {
839 tar_super_t *arch;
840 gint64 usec;
841
842 arch = g_new0 (tar_super_t, 1);
843 arch->base.me = me;
844 arch->fd = -1;
845 arch->type = TAR_UNKNOWN;
846
847
848 record_start_block = 0;
849 arch->record_start = g_malloc (record_size);
850 record_end = arch->record_start;
851 current_block = arch->record_start;
852 hit_eof = FALSE;
853
854
855 usec = g_get_real_time ();
856
857 start_time.tv_sec = usec / G_USEC_PER_SEC;
858 start_time.tv_nsec = (usec % G_USEC_PER_SEC) * 1000;
859
860 return VFS_SUPER (arch);
861 }
862
863
864
865 static void
866 tar_free_archive (struct vfs_class *me, struct vfs_s_super *archive)
867 {
868 tar_super_t *arch = TAR_SUPER (archive);
869
870 (void) me;
871
872 if (arch->fd != -1)
873 {
874 mc_close (arch->fd);
875 arch->fd = -1;
876 }
877
878 g_free (arch->record_start);
879 tar_stat_destroy (¤t_stat_info);
880 }
881
882
883
884
885 static gboolean
886 tar_open_archive_int (struct vfs_class *me, const vfs_path_t *vpath, struct vfs_s_super *archive)
887 {
888 tar_super_t *arch = TAR_SUPER (archive);
889 int result, type;
890 mode_t mode;
891 struct vfs_s_inode *root;
892
893 result = mc_open (vpath, O_RDONLY);
894 if (result == -1)
895 {
896 message (D_ERROR, MSG_ERROR, _ ("Cannot open tar archive\n%s"), vfs_path_as_str (vpath));
897 ERRNOR (ENOENT, FALSE);
898 }
899
900 archive->name = g_strdup (vfs_path_as_str (vpath));
901 mc_stat (vpath, &arch->st);
902
903
904 type = get_compression_type (result, archive->name);
905 if (type == COMPRESSION_NONE)
906 mc_lseek (result, 0, SEEK_SET);
907 else
908 {
909 char *s;
910 vfs_path_t *tmp_vpath;
911
912 mc_close (result);
913 s = g_strconcat (archive->name, decompress_extension (type), (char *) NULL);
914 tmp_vpath = vfs_path_from_str_flags (s, VPF_NO_CANON);
915 result = mc_open (tmp_vpath, O_RDONLY);
916 vfs_path_free (tmp_vpath, TRUE);
917 if (result == -1)
918 message (D_ERROR, MSG_ERROR, _ ("Cannot open tar archive\n%s"), s);
919 g_free (s);
920 if (result == -1)
921 {
922 MC_PTR_FREE (archive->name);
923 ERRNOR (ENOENT, FALSE);
924 }
925 }
926
927 arch->fd = result;
928 mode = arch->st.st_mode & 07777;
929 if (mode & 0400)
930 mode |= 0100;
931 if (mode & 0040)
932 mode |= 0010;
933 if (mode & 0004)
934 mode |= 0001;
935 mode |= S_IFDIR;
936
937 root = vfs_s_new_inode (me, archive, &arch->st);
938 root->st.st_mode = mode;
939 root->data_offset = -1;
940 root->st.st_nlink++;
941 root->st.st_dev = VFS_SUBCLASS (me)->rdev++;
942
943 archive->root = root;
944
945 return TRUE;
946 }
947
948
949
950
951
952
953 static int
954 tar_open_archive (struct vfs_s_super *archive, const vfs_path_t *vpath,
955 const vfs_path_element_t *vpath_element)
956 {
957 tar_super_t *arch = TAR_SUPER (archive);
958
959 read_header status = HEADER_STILL_UNREAD;
960
961
962 if (!tar_open_archive_int (vpath_element->class, vpath, archive))
963 return -1;
964
965 tar_find_next_block (arch);
966
967 while (TRUE)
968 {
969 read_header prev_status;
970
971 prev_status = status;
972 tar_stat_destroy (¤t_stat_info);
973 status = tar_read_header (vpath_element->class, archive);
974
975 switch (status)
976 {
977 case HEADER_STILL_UNREAD:
978 message (D_ERROR, MSG_ERROR, _ ("%s\ndoesn't look like a tar archive"),
979 vfs_path_as_str (vpath));
980 return -1;
981
982 case HEADER_SUCCESS:
983 continue;
984
985
986 case HEADER_ZERO_BLOCK:
987 tar_set_next_block_after (current_header);
988 (void) tar_read_header (vpath_element->class, archive);
989 status = prev_status;
990 continue;
991
992 case HEADER_END_OF_FILE:
993 break;
994
995
996
997 case HEADER_FAILURE:
998 tar_set_next_block_after (current_header);
999
1000 switch (prev_status)
1001 {
1002 case HEADER_STILL_UNREAD:
1003 message (D_ERROR, MSG_ERROR, _ ("%s\ndoesn't look like a tar archive"),
1004 vfs_path_as_str (vpath));
1005 return -1;
1006
1007 case HEADER_ZERO_BLOCK:
1008 case HEADER_SUCCESS:
1009
1010 break;
1011
1012 case HEADER_END_OF_FILE:
1013 case HEADER_FAILURE:
1014
1015
1016 return -1;
1017
1018 default:
1019 break;
1020 }
1021 continue;
1022
1023 default:
1024 break;
1025 }
1026 break;
1027 }
1028
1029 return 0;
1030 }
1031
1032
1033
1034 static void *
1035 tar_super_check (const vfs_path_t *vpath)
1036 {
1037 static struct stat stat_buf;
1038 int stat_result;
1039
1040 stat_result = mc_stat (vpath, &stat_buf);
1041
1042 return (stat_result != 0) ? NULL : &stat_buf;
1043 }
1044
1045
1046
1047 static int
1048 tar_super_same (const vfs_path_element_t *vpath_element, struct vfs_s_super *parc,
1049 const vfs_path_t *vpath, void *cookie)
1050 {
1051 struct stat *archive_stat = cookie;
1052
1053 (void) vpath_element;
1054
1055 if (strcmp (parc->name, vfs_path_as_str (vpath)) != 0)
1056 return 0;
1057
1058
1059 if (parc != NULL && TAR_SUPER (parc)->st.st_mtime < archive_stat->st_mtime)
1060 {
1061
1062 vfs_tarfs_ops->free ((vfsid) parc);
1063 vfs_rmstamp (vfs_tarfs_ops, (vfsid) parc);
1064 return 2;
1065 }
1066
1067 vfs_stamp (vfs_tarfs_ops, (vfsid) parc);
1068 return 1;
1069 }
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088 static ssize_t
1089 tar_get_sparse_chunk_idx (const GArray *sparse_map, off_t offset)
1090 {
1091 size_t k;
1092
1093 for (k = 1; k <= sparse_map->len; k++)
1094 {
1095 const struct sp_array *chunk;
1096
1097 chunk = &g_array_index (sparse_map, struct sp_array, k - 1);
1098
1099
1100 if (offset >= chunk->offset && offset < chunk->offset + chunk->numbytes)
1101 return k;
1102
1103
1104 if (offset < chunk->offset)
1105 return -k;
1106 }
1107
1108
1109 return 0;
1110 }
1111
1112
1113
1114 static ssize_t
1115 tar_read_sparse (vfs_file_handler_t *fh, char *buffer, size_t count)
1116 {
1117 int fd = TAR_SUPER (fh->ino->super)->fd;
1118 const GArray *sm = (const GArray *) fh->ino->user_data;
1119 ssize_t chunk_idx;
1120 const struct sp_array *chunk;
1121 off_t remain;
1122 ssize_t res;
1123
1124 chunk_idx = tar_get_sparse_chunk_idx (sm, fh->pos);
1125 if (chunk_idx > 0)
1126 {
1127
1128 chunk = &g_array_index (sm, struct sp_array, chunk_idx - 1);
1129 remain = MIN ((off_t) count, chunk->offset + chunk->numbytes - fh->pos);
1130 res = mc_read (fd, buffer, (size_t) remain);
1131 }
1132 else
1133 {
1134 if (chunk_idx == 0)
1135 {
1136
1137 remain = MIN ((off_t) count, fh->ino->st.st_size - fh->pos);
1138
1139 remain = MAX (remain, 0);
1140 }
1141 else
1142 {
1143
1144 chunk = &g_array_index (sm, struct sp_array, -chunk_idx - 1);
1145 remain = MIN ((off_t) count, chunk->offset - fh->pos);
1146 }
1147
1148 memset (buffer, 0, (size_t) remain);
1149 res = (ssize_t) remain;
1150 }
1151
1152 return res;
1153 }
1154
1155
1156
1157 static off_t
1158 tar_lseek_sparse (vfs_file_handler_t *fh, off_t offset)
1159 {
1160 off_t saved_offset = offset;
1161 int fd = TAR_SUPER (fh->ino->super)->fd;
1162 const GArray *sm = (const GArray *) fh->ino->user_data;
1163 ssize_t chunk_idx;
1164 const struct sp_array *chunk;
1165 off_t res;
1166
1167 chunk_idx = tar_get_sparse_chunk_idx (sm, offset);
1168 if (chunk_idx > 0)
1169 {
1170
1171
1172 chunk = &g_array_index (sm, struct sp_array, chunk_idx - 1);
1173
1174 offset -= chunk->offset;
1175
1176 offset += chunk->arch_offset;
1177 }
1178 else
1179 {
1180
1181
1182
1183 switch (chunk_idx)
1184 {
1185 case -1:
1186 offset = fh->ino->data_offset;
1187 break;
1188
1189 case 0:
1190 chunk = &g_array_index (sm, struct sp_array, sm->len - 1);
1191
1192 offset = chunk->arch_offset + chunk->numbytes;
1193 break;
1194
1195 default:
1196 chunk = &g_array_index (sm, struct sp_array, -chunk_idx - 1);
1197 offset = chunk->arch_offset + chunk->numbytes;
1198 break;
1199 }
1200 }
1201
1202 res = mc_lseek (fd, offset, SEEK_SET);
1203
1204 if (res == offset)
1205 res = saved_offset;
1206
1207 return res;
1208 }
1209
1210
1211
1212 static ssize_t
1213 tar_read (void *fh, char *buffer, size_t count)
1214 {
1215 struct vfs_class *me = VFS_FILE_HANDLER_SUPER (fh)->me;
1216 vfs_file_handler_t *file = VFS_FILE_HANDLER (fh);
1217 int fd = TAR_SUPER (VFS_FILE_HANDLER_SUPER (fh))->fd;
1218 off_t begin = file->pos;
1219 ssize_t res;
1220
1221 if (file->ino->user_data != NULL)
1222 {
1223 if (tar_lseek_sparse (file, begin) != begin)
1224 ERRNOR (EIO, -1);
1225
1226 res = tar_read_sparse (file, buffer, count);
1227 }
1228 else
1229 {
1230 begin += file->ino->data_offset;
1231
1232 if (mc_lseek (fd, begin, SEEK_SET) != begin)
1233 ERRNOR (EIO, -1);
1234
1235 count = (size_t) MIN ((off_t) count, file->ino->st.st_size - file->pos);
1236 res = mc_read (fd, buffer, count);
1237 }
1238
1239 if (res == -1)
1240 ERRNOR (errno, -1);
1241
1242 file->pos += res;
1243 return res;
1244 }
1245
1246
1247
1248 static int
1249 tar_fh_open (struct vfs_class *me, vfs_file_handler_t *fh, int flags, mode_t mode)
1250 {
1251 (void) fh;
1252 (void) mode;
1253
1254 if ((flags & O_ACCMODE) != O_RDONLY)
1255 ERRNOR (EROFS, -1);
1256 return 0;
1257 }
1258
1259
1260
1261
1262
1263 void
1264 vfs_init_tarfs (void)
1265 {
1266
1267 vfs_init_subclass (&tarfs_subclass, "tarfs", VFSF_READONLY, "utar");
1268 vfs_tarfs_ops->read = tar_read;
1269 vfs_tarfs_ops->setctl = NULL;
1270 tarfs_subclass.archive_check = tar_super_check;
1271 tarfs_subclass.archive_same = tar_super_same;
1272 tarfs_subclass.new_archive = tar_new_archive;
1273 tarfs_subclass.open_archive = tar_open_archive;
1274 tarfs_subclass.free_archive = tar_free_archive;
1275 tarfs_subclass.free_inode = tar_free_inode;
1276 tarfs_subclass.fh_open = tar_fh_open;
1277 vfs_register_class (vfs_tarfs_ops);
1278 }
1279
1280