blob: 89e5e3d70c6ad4acc9a97863f46ef505b9c59106 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2** Copyright 1998-2003 University of Illinois Board of Trustees
3** Copyright 1998-2003 Mark D. Roth
4** All rights reserved.
5**
6** block.c - libtar code to handle tar archive header blocks
7**
8** Mark D. Roth <roth@uiuc.edu>
9** Campus Information Technologies and Educational Services
10** University of Illinois at Urbana-Champaign
11*/
12
13#include <internal.h>
14
15#include <errno.h>
16
17#ifdef STDC_HEADERS
18# include <string.h>
19# include <stdlib.h>
20#endif
21
22#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
23
24
25/* read a header block */
26int
27th_read_internal(TAR *t)
28{
29 int i;
30 int num_zero_blocks = 0;
31
32#ifdef DEBUG
33 printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
34#endif
35
36 while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE)
37 {
38 /* two all-zero blocks mark EOF */
39 if (t->th_buf.name[0] == '\0')
40 {
41 num_zero_blocks++;
42 if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
43 && num_zero_blocks >= 2)
44 return 0; /* EOF */
45 else
46 continue;
47 }
48
49 /* verify magic and version */
50 if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
51 && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
52 {
53#ifdef DEBUG
54 puts("!!! unknown magic value in tar header");
55#endif
56 return -2;
57 }
58
59 if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
60 && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
61 {
62#ifdef DEBUG
63 puts("!!! unknown version value in tar header");
64#endif
65 return -2;
66 }
67
68 /* check chksum */
69 if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
70 && !th_crc_ok(t))
71 {
72#ifdef DEBUG
73 puts("!!! tar header checksum error");
74#endif
75 return -2;
76 }
77
78 break;
79 }
80
81#ifdef DEBUG
82 printf("<== th_read_internal(): returning %d\n", i);
83#endif
84 return i;
85}
86
87
88/* wrapper function for th_read_internal() to handle GNU extensions */
89int
90th_read(TAR *t)
91{
92 int i, j;
93 size_t sz;
94 char *ptr;
95
96#ifdef DEBUG
97 printf("==> th_read(t=0x%lx)\n", t);
98#endif
99
100 if (t->th_buf.gnu_longname != NULL)
101 free(t->th_buf.gnu_longname);
102 if (t->th_buf.gnu_longlink != NULL)
103 free(t->th_buf.gnu_longlink);
104 memset(&(t->th_buf), 0, sizeof(struct tar_header));
105
106 i = th_read_internal(t);
107 if (i == 0)
108 return 1;
109 else if (i != T_BLOCKSIZE)
110 {
111 if (i != -1)
112 errno = EINVAL;
113 return -1;
114 }
115
116 /* check for GNU long link extention */
117 if (TH_ISLONGLINK(t))
118 {
119 sz = th_get_size(t);
120 j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
121#ifdef DEBUG
122 printf(" th_read(): GNU long linkname detected "
123 "(%ld bytes, %d blocks)\n", sz, j);
124#endif
125 t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
126 if (t->th_buf.gnu_longlink == NULL)
127 return -1;
128
129 for (ptr = t->th_buf.gnu_longlink; j > 0;
130 j--, ptr += T_BLOCKSIZE)
131 {
132#ifdef DEBUG
133 printf(" th_read(): reading long linkname "
134 "(%d blocks left, ptr == %ld)\n", j, ptr);
135#endif
136 i = tar_block_read(t, ptr);
137 if (i != T_BLOCKSIZE)
138 {
139 if (i != -1)
140 errno = EINVAL;
141 return -1;
142 }
143#ifdef DEBUG
144 printf(" th_read(): read block == \"%s\"\n", ptr);
145#endif
146 }
147#ifdef DEBUG
148 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
149 t->th_buf.gnu_longlink);
150#endif
151
152 i = th_read_internal(t);
153 if (i != T_BLOCKSIZE)
154 {
155 if (i != -1)
156 errno = EINVAL;
157 return -1;
158 }
159 }
160
161 /* check for GNU long name extention */
162 if (TH_ISLONGNAME(t))
163 {
164 sz = th_get_size(t);
165 j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
166#ifdef DEBUG
167 printf(" th_read(): GNU long filename detected "
168 "(%ld bytes, %d blocks)\n", sz, j);
169#endif
170 t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
171 if (t->th_buf.gnu_longname == NULL)
172 return -1;
173
174 for (ptr = t->th_buf.gnu_longname; j > 0;
175 j--, ptr += T_BLOCKSIZE)
176 {
177#ifdef DEBUG
178 printf(" th_read(): reading long filename "
179 "(%d blocks left, ptr == %ld)\n", j, ptr);
180#endif
181 i = tar_block_read(t, ptr);
182 if (i != T_BLOCKSIZE)
183 {
184 if (i != -1)
185 errno = EINVAL;
186 return -1;
187 }
188#ifdef DEBUG
189 printf(" th_read(): read block == \"%s\"\n", ptr);
190#endif
191 }
192#ifdef DEBUG
193 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
194 t->th_buf.gnu_longname);
195#endif
196
197 i = th_read_internal(t);
198 if (i != T_BLOCKSIZE)
199 {
200 if (i != -1)
201 errno = EINVAL;
202 return -1;
203 }
204 }
205
206#if 0
207 /*
208 ** work-around for old archive files with broken typeflag fields
209 ** NOTE: I fixed this in the TH_IS*() macros instead
210 */
211
212 /*
213 ** (directories are signified with a trailing '/')
214 */
215 if (t->th_buf.typeflag == AREGTYPE
216 && t->th_buf.name[strlen(t->th_buf.name) - 1] == '/')
217 t->th_buf.typeflag = DIRTYPE;
218
219 /*
220 ** fallback to using mode bits
221 */
222 if (t->th_buf.typeflag == AREGTYPE)
223 {
224 mode = (mode_t)oct_to_int(t->th_buf.mode);
225
226 if (S_ISREG(mode))
227 t->th_buf.typeflag = REGTYPE;
228 else if (S_ISDIR(mode))
229 t->th_buf.typeflag = DIRTYPE;
230 else if (S_ISFIFO(mode))
231 t->th_buf.typeflag = FIFOTYPE;
232 else if (S_ISCHR(mode))
233 t->th_buf.typeflag = CHRTYPE;
234 else if (S_ISBLK(mode))
235 t->th_buf.typeflag = BLKTYPE;
236 else if (S_ISLNK(mode))
237 t->th_buf.typeflag = SYMTYPE;
238 }
239#endif
240
241 return 0;
242}
243
244
245/* write a header block */
246int
247th_write(TAR *t)
248{
249 int i, j;
250 char type2;
251 size_t sz, sz2;
252 char *ptr;
253 char buf[T_BLOCKSIZE];
254
255#ifdef DEBUG
256 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
257 th_print(t);
258#endif
259
260 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
261 {
262#ifdef DEBUG
263 printf("th_write(): using gnu_longlink (\"%s\")\n",
264 t->th_buf.gnu_longlink);
265#endif
266 /* save old size and type */
267 type2 = t->th_buf.typeflag;
268 sz2 = th_get_size(t);
269
270 /* write out initial header block with fake size and type */
271 t->th_buf.typeflag = GNU_LONGLINK_TYPE;
272 sz = strlen(t->th_buf.gnu_longlink);
273 th_set_size(t, sz);
274 th_finish(t);
275 i = tar_block_write(t, &(t->th_buf));
276 if (i != T_BLOCKSIZE)
277 {
278 if (i != -1)
279 errno = EINVAL;
280 return -1;
281 }
282
283 /* write out extra blocks containing long name */
284 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
285 ptr = t->th_buf.gnu_longlink; j > 1;
286 j--, ptr += T_BLOCKSIZE)
287 {
288 i = tar_block_write(t, ptr);
289 if (i != T_BLOCKSIZE)
290 {
291 if (i != -1)
292 errno = EINVAL;
293 return -1;
294 }
295 }
296 memset(buf, 0, T_BLOCKSIZE);
297 strncpy(buf, ptr, T_BLOCKSIZE);
298 i = tar_block_write(t, &buf);
299 if (i != T_BLOCKSIZE)
300 {
301 if (i != -1)
302 errno = EINVAL;
303 return -1;
304 }
305
306 /* reset type and size to original values */
307 t->th_buf.typeflag = type2;
308 th_set_size(t, sz2);
309 }
310
311 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
312 {
313#ifdef DEBUG
314 printf("th_write(): using gnu_longname (\"%s\")\n",
315 t->th_buf.gnu_longname);
316#endif
317 /* save old size and type */
318 type2 = t->th_buf.typeflag;
319 sz2 = th_get_size(t);
320
321 /* write out initial header block with fake size and type */
322 t->th_buf.typeflag = GNU_LONGNAME_TYPE;
323 sz = strlen(t->th_buf.gnu_longname);
324 th_set_size(t, sz);
325 th_finish(t);
326 i = tar_block_write(t, &(t->th_buf));
327 if (i != T_BLOCKSIZE)
328 {
329 if (i != -1)
330 errno = EINVAL;
331 return -1;
332 }
333
334 /* write out extra blocks containing long name */
335 for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0),
336 ptr = t->th_buf.gnu_longname; j > 1;
337 j--, ptr += T_BLOCKSIZE)
338 {
339 i = tar_block_write(t, ptr);
340 if (i != T_BLOCKSIZE)
341 {
342 if (i != -1)
343 errno = EINVAL;
344 return -1;
345 }
346 }
347 memset(buf, 0, T_BLOCKSIZE);
348 strncpy(buf, ptr, T_BLOCKSIZE);
349 i = tar_block_write(t, &buf);
350 if (i != T_BLOCKSIZE)
351 {
352 if (i != -1)
353 errno = EINVAL;
354 return -1;
355 }
356
357 /* reset type and size to original values */
358 t->th_buf.typeflag = type2;
359 th_set_size(t, sz2);
360 }
361
362 th_finish(t);
363
364#ifdef DEBUG
365 /* print tar header */
366 th_print(t);
367#endif
368
369 i = tar_block_write(t, &(t->th_buf));
370 if (i != T_BLOCKSIZE)
371 {
372 if (i != -1)
373 errno = EINVAL;
374 return -1;
375 }
376
377#ifdef DEBUG
378 puts("th_write(): returning 0");
379#endif
380 return 0;
381}
382
383