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
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 unsigned int i;
331 int unsigned_sum = 0;
332 int signed_sum = 0;
333 int recorded_sum;
334
335 for (i = 0; i < sizeof (*header); i++)
336 {
337 unsigned char uc = header->buffer[i];
338 signed char sc = header->buffer[i];
339
340 unsigned_sum += uc;
341 signed_sum += sc;
342 }
343
344 if (unsigned_sum == 0)
345 return HEADER_ZERO_BLOCK;
346
347
348 for (i = 0; i < sizeof (header->header.chksum); i++)
349 {
350 unsigned char uc = header->header.chksum[i];
351 signed char sc = header->header.chksum[i];
352
353 unsigned_sum -= uc;
354 signed_sum -= sc;
355 }
356
357 unsigned_sum += ' ' * sizeof (header->header.chksum);
358 signed_sum += ' ' * sizeof (header->header.chksum);
359
360 recorded_sum =
361 tar_from_header (header->header.chksum, sizeof (header->header.chksum), NULL, 0,
362 INT_MAX, TRUE);
363
364 if (recorded_sum < 0)
365 return HEADER_FAILURE;
366
367 if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
368 return HEADER_FAILURE;
369
370 return HEADER_SUCCESS;
371 }
372
373
374
375 static void
376 tar_decode_header (union block *header, tar_super_t *arch)
377 {
378 gboolean hbits = FALSE;
379
380 current_stat_info.stat.st_mode = MODE_FROM_HEADER (header->header.mode, &hbits);
381
382
383
384
385 if (arch->type == TAR_UNKNOWN)
386 {
387 if (strcmp (header->header.magic, TMAGIC) == 0)
388 {
389 if (header->star_header.prefix[130] == 0
390 && is_octal_digit (header->star_header.atime[0])
391 && header->star_header.atime[11] == ' '
392 && is_octal_digit (header->star_header.ctime[0])
393 && header->star_header.ctime[11] == ' ')
394 arch->type = TAR_STAR;
395 else if (current_stat_info.xhdr.buffer != NULL)
396 arch->type = TAR_POSIX;
397 else
398 arch->type = TAR_USTAR;
399 }
400 else if (strcmp (header->buffer + offsetof (struct posix_header, magic), OLDGNU_MAGIC) == 0)
401 arch->type = hbits ? TAR_OLDGNU : TAR_GNU;
402 else
403 arch->type = TAR_V7;
404 }
405
406
407
408
409 if (header->header.typeflag == '\000')
410 {
411 size_t len;
412
413 if (header->header.name[sizeof (header->header.name) - 1] != '\0')
414 len = sizeof (header->header.name);
415 else
416 len = strlen (header->header.name);
417
418 if (len != 0 && IS_PATH_SEP (header->header.name[len - 1]))
419 header->header.typeflag = DIRTYPE;
420 }
421
422 if (header->header.typeflag == GNUTYPE_DUMPDIR)
423 if (arch->type == TAR_UNKNOWN)
424 arch->type = TAR_GNU;
425 }
426
427
428
429 static void
430 tar_fill_stat (struct vfs_s_super *archive, union block *header)
431 {
432 tar_super_t *arch = TAR_SUPER (archive);
433
434
435
436
437
438
439 if (header->header.typeflag == DIRTYPE || header->header.typeflag == GNUTYPE_DUMPDIR)
440 current_stat_info.stat.st_mode |= S_IFDIR;
441 else if (header->header.typeflag == SYMTYPE)
442 current_stat_info.stat.st_mode |= S_IFLNK;
443 else if (header->header.typeflag == CHRTYPE)
444 current_stat_info.stat.st_mode |= S_IFCHR;
445 else if (header->header.typeflag == BLKTYPE)
446 current_stat_info.stat.st_mode |= S_IFBLK;
447 else if (header->header.typeflag == FIFOTYPE)
448 current_stat_info.stat.st_mode |= S_IFIFO;
449 else
450 current_stat_info.stat.st_mode |= S_IFREG;
451
452 current_stat_info.stat.st_dev = 0;
453 #ifdef HAVE_STRUCT_STAT_ST_RDEV
454 current_stat_info.stat.st_rdev = 0;
455 #endif
456
457 switch (arch->type)
458 {
459 case TAR_USTAR:
460 case TAR_POSIX:
461 case TAR_GNU:
462 case TAR_OLDGNU:
463
464 current_stat_info.stat.st_uid = *header->header.uname != '\0'
465 ? (uid_t) vfs_finduid (header->header.uname)
466 : UID_FROM_HEADER (header->header.uid);
467 current_stat_info.stat.st_gid = *header->header.gname != '\0'
468 ? (gid_t) vfs_findgid (header->header.gname)
469 : GID_FROM_HEADER (header->header.gid);
470
471
472 switch (header->header.typeflag)
473 {
474 case BLKTYPE:
475 case CHRTYPE:
476 #ifdef HAVE_STRUCT_STAT_ST_RDEV
477 current_stat_info.stat.st_rdev =
478 makedev (MAJOR_FROM_HEADER (header->header.devmajor),
479 MINOR_FROM_HEADER (header->header.devminor));
480 #endif
481 break;
482 default:
483 break;
484 }
485 break;
486
487 default:
488 current_stat_info.stat.st_uid = UID_FROM_HEADER (header->header.uid);
489 current_stat_info.stat.st_gid = GID_FROM_HEADER (header->header.gid);
490 break;
491 }
492
493 current_stat_info.atime.tv_nsec = 0;
494 current_stat_info.mtime.tv_nsec = 0;
495 current_stat_info.ctime.tv_nsec = 0;
496
497 current_stat_info.mtime.tv_sec = TIME_FROM_HEADER (header->header.mtime);
498 if (arch->type == TAR_GNU || arch->type == TAR_OLDGNU)
499 {
500 current_stat_info.atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
501 current_stat_info.ctime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.ctime);
502 }
503 else if (arch->type == TAR_STAR)
504 {
505 current_stat_info.atime.tv_sec = TIME_FROM_HEADER (header->star_header.atime);
506 current_stat_info.ctime.tv_sec = TIME_FROM_HEADER (header->star_header.ctime);
507 }
508 else
509 current_stat_info.atime = current_stat_info.ctime = start_time;
510
511 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
512 current_stat_info.stat.st_blksize = 8 * 1024;
513 #endif
514 vfs_adjust_stat (¤t_stat_info.stat);
515 }
516
517
518
519 static void
520 tar_free_inode (struct vfs_class *me, struct vfs_s_inode *ino)
521 {
522 (void) me;
523
524
525 if (ino->user_data != NULL)
526 g_array_free ((GArray *) ino->user_data, TRUE);
527 }
528
529
530
531 static read_header
532 tar_insert_entry (struct vfs_class *me, struct vfs_s_super *archive, union block *header,
533 struct vfs_s_inode **inode)
534 {
535 char *p, *q;
536 char *file_name = current_stat_info.file_name;
537 char *link_name = current_stat_info.link_name;
538 size_t len;
539 struct vfs_s_inode *parent;
540 struct vfs_s_entry *entry;
541
542 p = strrchr (file_name, PATH_SEP);
543 if (p == NULL)
544 {
545 len = strlen (file_name);
546 p = file_name;
547 q = file_name + len;
548 }
549 else
550 {
551 *(p++) = '\0';
552 q = file_name;
553 }
554
555 parent = vfs_s_find_inode (me, archive, q, LINK_NO_FOLLOW, FL_MKDIR);
556 if (parent == NULL)
557 return HEADER_FAILURE;
558
559 *inode = NULL;
560
561 if (header->header.typeflag == LNKTYPE)
562 {
563 if (*link_name != '\0')
564 {
565 len = strlen (link_name);
566 if (IS_PATH_SEP (link_name[len - 1]))
567 link_name[len - 1] = '\0';
568
569 *inode = vfs_s_find_inode (me, archive, link_name, LINK_NO_FOLLOW, FL_NONE);
570 }
571
572 if (*inode == NULL)
573 return HEADER_FAILURE;
574 }
575 else
576 {
577 if (S_ISDIR (current_stat_info.stat.st_mode))
578 {
579 entry = VFS_SUBCLASS (me)->find_entry (me, parent, p, LINK_NO_FOLLOW, FL_NONE);
580 if (entry != NULL)
581 return HEADER_SUCCESS;
582 }
583
584 *inode = vfs_s_new_inode (me, archive, ¤t_stat_info.stat);
585
586 (*inode)->st.st_mtime = current_stat_info.mtime.tv_sec;
587 (*inode)->st.st_atime = current_stat_info.atime.tv_sec;
588 (*inode)->st.st_ctime = current_stat_info.ctime.tv_sec;
589
590 if (link_name != NULL && *link_name != '\0')
591 (*inode)->linkname = g_strdup (link_name);
592 }
593
594 entry = vfs_s_new_entry (me, p, *inode);
595 vfs_s_insert_entry (me, parent, entry);
596
597 return HEADER_SUCCESS;
598 }
599
600
601
602 static read_header
603 tar_read_header (struct vfs_class *me, struct vfs_s_super *archive)
604 {
605 tar_super_t *arch = TAR_SUPER (archive);
606 union block *header;
607 union block *next_long_name = NULL, *next_long_link = NULL;
608 read_header status = HEADER_SUCCESS;
609
610 while (TRUE)
611 {
612 header = tar_find_next_block (arch);
613 current_header = header;
614 if (header == NULL)
615 {
616 status = HEADER_END_OF_FILE;
617 goto ret;
618 }
619
620 status = tar_checksum (header);
621 if (status != HEADER_SUCCESS)
622 goto ret;
623
624 if (header->header.typeflag == LNKTYPE || header->header.typeflag == DIRTYPE)
625 current_stat_info.stat.st_size = 0;
626 else
627 {
628 current_stat_info.stat.st_size = OFF_FROM_HEADER (header->header.size);
629 if (current_stat_info.stat.st_size < 0)
630 {
631 status = HEADER_FAILURE;
632 goto ret;
633 }
634 }
635
636 tar_decode_header (header, arch);
637 tar_fill_stat (archive, header);
638
639 if (header->header.typeflag == GNUTYPE_LONGNAME
640 || header->header.typeflag == GNUTYPE_LONGLINK)
641 {
642 off_t size;
643 union block *header_copy;
644 char *bp;
645 size_t written;
646
647 if (arch->type == TAR_UNKNOWN)
648 arch->type = TAR_GNU;
649
650 if (ckd_add (&size, current_stat_info.stat.st_size, 2 * BLOCKSIZE - 1))
651 {
652 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
653 status = HEADER_FAILURE;
654 goto ret;
655 }
656
657 size -= size % BLOCKSIZE;
658
659 header_copy = g_malloc (size + 1);
660
661 if (header->header.typeflag == GNUTYPE_LONGNAME)
662 {
663 g_free (next_long_name);
664 next_long_name = header_copy;
665 }
666 else
667 {
668 g_free (next_long_link);
669 next_long_link = header_copy;
670 }
671
672 tar_set_next_block_after (header);
673 *header_copy = *header;
674 bp = header_copy->buffer + BLOCKSIZE;
675
676 for (size -= BLOCKSIZE; size > 0; size -= written)
677 {
678 union block *data_block;
679
680 data_block = tar_find_next_block (arch);
681 if (data_block == NULL)
682 {
683 message (D_ERROR, MSG_ERROR, _("Unexpected EOF on archive file"));
684 status = HEADER_FAILURE;
685 goto ret;
686 }
687
688 written = tar_available_space_after (data_block);
689 if ((off_t) written > size)
690 written = (size_t) size;
691
692 memcpy (bp, data_block->buffer, written);
693 bp += written;
694 tar_set_next_block_after ((union block *) (data_block->buffer + written - 1));
695 }
696
697 *bp = '\0';
698 }
699 else if (header->header.typeflag == XHDTYPE || header->header.typeflag == SOLARIS_XHDTYPE)
700 {
701 if (arch->type == TAR_UNKNOWN)
702 arch->type = TAR_POSIX;
703 if (!tar_xheader_read
704 (arch, ¤t_stat_info.xhdr, header, OFF_FROM_HEADER (header->header.size)))
705 {
706 message (D_ERROR, MSG_ERROR, _("Unexpected EOF on archive file"));
707 status = HEADER_FAILURE;
708 goto ret;
709 }
710 }
711 else if (header->header.typeflag == XGLTYPE)
712 {
713 struct xheader xhdr;
714 gboolean ok;
715
716 if (arch->type == TAR_UNKNOWN)
717 arch->type = TAR_POSIX;
718
719 memset (&xhdr, 0, sizeof (xhdr));
720 tar_xheader_read (arch, &xhdr, header, OFF_FROM_HEADER (header->header.size));
721 ok = tar_xheader_decode_global (&xhdr);
722 tar_xheader_destroy (&xhdr);
723
724 if (!ok)
725 {
726 message (D_ERROR, MSG_ERROR, _("Inconsistent tar archive"));
727 status = HEADER_FAILURE;
728 goto ret;
729 }
730 }
731 else
732 break;
733 }
734
735 {
736 static union block *recent_long_name = NULL, *recent_long_link = NULL;
737 struct posix_header const *h = &header->header;
738 char *file_name = NULL;
739 char *link_name;
740 struct vfs_s_inode *inode = NULL;
741
742 g_free (recent_long_name);
743
744 if (next_long_name != NULL)
745 {
746 file_name = g_strdup (next_long_name->buffer + BLOCKSIZE);
747 recent_long_name = next_long_name;
748 }
749 else
750 {
751
752 char *s1 = NULL;
753 char *s2;
754
755
756 if (h->prefix[0] != '\0' && strcmp (h->magic, TMAGIC) == 0)
757 s1 = g_strndup (h->prefix, sizeof (h->prefix));
758
759 s2 = g_strndup (h->name, sizeof (h->name));
760
761 if (s1 == NULL)
762 file_name = s2;
763 else
764 {
765 file_name = g_strconcat (s1, PATH_SEP_STR, s2, (char *) NULL);
766 g_free (s1);
767 g_free (s2);
768 }
769
770 recent_long_name = NULL;
771 }
772
773 tar_assign_string_dup (¤t_stat_info.orig_file_name, file_name);
774 tar_assign_string (¤t_stat_info.file_name, file_name);
775
776 g_free (recent_long_link);
777
778 if (next_long_link != NULL)
779 {
780 link_name = g_strdup (next_long_link->buffer + BLOCKSIZE);
781 recent_long_link = next_long_link;
782 }
783 else
784 {
785 link_name = g_strndup (h->linkname, sizeof (h->linkname));
786 recent_long_link = NULL;
787 }
788
789 tar_assign_string (¤t_stat_info.link_name, link_name);
790
791 if (current_stat_info.xhdr.buffer != NULL && !tar_xheader_decode (¤t_stat_info))
792 {
793 status = HEADER_FAILURE;
794 goto ret;
795 }
796
797 if (tar_sparse_member_p (arch, ¤t_stat_info))
798 {
799 if (!tar_sparse_fixup_header (arch, ¤t_stat_info))
800 {
801 status = HEADER_FAILURE;
802 goto ret;
803 }
804
805 current_stat_info.is_sparse = TRUE;
806 }
807 else
808 {
809 current_stat_info.is_sparse = FALSE;
810
811 if (((arch->type == TAR_GNU || arch->type == TAR_OLDGNU)
812 && current_header->header.typeflag == GNUTYPE_DUMPDIR)
813 || current_stat_info.dumpdir != NULL)
814 current_stat_info.is_dumpdir = TRUE;
815 }
816
817
818 canonicalize_pathname (current_stat_info.file_name);
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
1294