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