1 /*
2 Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <ctype.h>
23 #ifndef NO_STRING_H
24 #include <string.h>
25 #else
26 #include <strings.h>
27 #endif
28 #include "libarc/mblock.h"
29 #include "zip.h"
30 #include "libarc/arc.h"
31
32 #define TARBLKSIZ 512
33 #define TARHDRSIZ 512
34
35 static long octal_value(char *s, int len);
36 static int tar_checksum(char *hdr);
37
next_tar_entry(void)38 ArchiveEntryNode *next_tar_entry(void)
39 {
40 char hdr[TARHDRSIZ];
41 long size, sizeb;
42 ArchiveEntryNode *entry;
43 URL url;
44 int flen;
45 int macbin_check;
46
47 url = arc_handler.url;
48 macbin_check = (arc_handler.counter == 0);
49
50 retry_read:
51 if(!macbin_check)
52 {
53 if(url_read(url, hdr, TARHDRSIZ) != TARHDRSIZ)
54 return NULL;
55 }
56 else
57 {
58 int c = url_getc(url);
59 if(c == 0)
60 {
61 url_skip(url, 127);
62 if(arc_handler.isfile)
63 arc_handler.pos += 128;
64 if(url_read(url, hdr, TARHDRSIZ) != TARHDRSIZ)
65 return NULL;
66 }
67 else
68 {
69 hdr[0] = c;
70 if(url_read(url, hdr+1, TARHDRSIZ-1) != TARHDRSIZ-1)
71 return NULL;
72 }
73 }
74
75 macbin_check = 0;
76
77 if(hdr[0] == '\0')
78 return NULL;
79 if(!tar_checksum(hdr))
80 return NULL;
81 size = octal_value(hdr + 124, 12);
82 flen = strlen(hdr);
83 if(size == 0 && flen > 0 && hdr[flen - 1] == '/')
84 {
85 if(arc_handler.isfile)
86 arc_handler.pos += TARHDRSIZ;
87 goto retry_read;
88 }
89
90 entry = new_entry_node(hdr, flen);
91 if(entry == NULL)
92 return NULL;
93 sizeb = (((size) + (TARBLKSIZ-1)) & ~(TARBLKSIZ-1));
94
95 if(arc_handler.isfile)
96 {
97 arc_handler.pos += TARHDRSIZ;
98 entry->comptype = ARCHIVEC_STORED;
99 entry->compsize = entry->origsize = size;
100 entry->start = arc_handler.pos;
101 url_skip(url, sizeb);
102 arc_handler.pos += sizeb;
103 }
104 else
105 {
106 void *data;
107 long n;
108
109 data = url_dump(url, size, &n);
110 if(size != n)
111 {
112 if(data != NULL)
113 free(data);
114 free_entry_node(entry);
115 return NULL;
116 }
117 entry->cache = arc_compress(data, size, ARC_DEFLATE_LEVEL,
118 &entry->compsize);
119 free(data);
120 entry->comptype = ARCHIVEC_DEFLATED;
121 entry->origsize = size;
122 entry->start = 0;
123 url_skip(url, sizeb - size);
124 }
125
126 return entry;
127 }
128
octal_value(char * s,int len)129 static long octal_value(char *s, int len)
130 {
131 long val;
132
133 while(len > 0 && !isdigit((int)(unsigned char)*s))
134 {
135 s++;
136 len--;
137 }
138
139 val = 0;
140 while(len > 0 && isdigit((int)(unsigned char)*s))
141 {
142 val = ((val<<3) | (*s - '0'));
143 s++;
144 len--;
145 }
146 return val;
147 }
148
tar_checksum(char * hdr)149 static int tar_checksum(char *hdr)
150 {
151 int i;
152
153 long recorded_sum;
154 long unsigned_sum; /* the POSIX one :-) */
155 long signed_sum; /* the Sun one :-( */
156
157 recorded_sum = octal_value(hdr + 148, 8);
158 unsigned_sum = 0;
159 signed_sum = 0;
160 for(i = 0; i < TARBLKSIZ; i++)
161 {
162 unsigned_sum += 0xFF & hdr[i];
163 signed_sum += hdr[i];
164 }
165
166 /* Adjust checksum to count the "chksum" field as blanks. */
167 for(i = 0; i < 8; i++)
168 {
169 unsigned_sum -= 0xFF & hdr[148 + i];
170 signed_sum -= hdr[i];
171 }
172 unsigned_sum += ' ' * 8;
173 signed_sum += ' ' * 8;
174
175 return unsigned_sum == recorded_sum || signed_sum == recorded_sum;
176 }
177