2 ** Copyright 1998-2003 University of Illinois Board of Trustees
3 ** Copyright 1998-2003 Mark D. Roth
4 ** All rights reserved.
6 ** block.c - libtar code to handle tar archive header blocks
8 ** Mark D. Roth <roth@uiuc.edu>
9 ** Campus Information Technologies and Educational Services
10 ** University of Illinois at Urbana-Champaign
23 #define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
26 /* read a header block */
27 /* FIXME: the return value of this function should match the return value
28 of tar_block_read(), which is a macro which references a prototype
29 that returns a ssize_t. So far, this is safe, since tar_block_read()
30 only ever reads 512 (T_BLOCKSIZE) bytes at a time, so any difference
31 in size of ssize_t and int is of negligible risk. BUT, if
32 T_BLOCKSIZE ever changes, or ever becomes a variable parameter
33 controllable by the user, all the code that calls it,
34 including this function and all code that calls it, should be
35 fixed for security reasons.
36 Thanks to Chris Palmer for the critique.
39 th_read_internal(TAR
*t
)
42 int num_zero_blocks
= 0;
45 printf("==> th_read_internal(TAR=\"%s\")\n", t
->pathname
);
48 while ((i
= tar_block_read(t
, &(t
->th_buf
))) == T_BLOCKSIZE
)
50 /* two all-zero blocks mark EOF */
51 if (t
->th_buf
.name
[0] == '\0')
54 if (!BIT_ISSET(t
->options
, TAR_IGNORE_EOT
)
55 && num_zero_blocks
>= 2)
61 /* verify magic and version */
62 if (BIT_ISSET(t
->options
, TAR_CHECK_MAGIC
)
63 && strncmp(t
->th_buf
.magic
, TMAGIC
, TMAGLEN
- 1) != 0)
66 puts("!!! unknown magic value in tar header");
71 if (BIT_ISSET(t
->options
, TAR_CHECK_VERSION
)
72 && strncmp(t
->th_buf
.version
, TVERSION
, TVERSLEN
) != 0)
75 puts("!!! unknown version value in tar header");
81 if (!BIT_ISSET(t
->options
, TAR_IGNORE_CRC
)
85 puts("!!! tar header checksum error");
94 printf("<== th_read_internal(): returning %d\n", i
);
100 /* wrapper function for th_read_internal() to handle GNU extensions */
105 size_t sz
, j
, blocks
;
109 printf("==> th_read(t=0x%lx)\n", t
);
112 if (t
->th_buf
.gnu_longname
!= NULL
)
113 free(t
->th_buf
.gnu_longname
);
114 if (t
->th_buf
.gnu_longlink
!= NULL
)
115 free(t
->th_buf
.gnu_longlink
);
116 memset(&(t
->th_buf
), 0, sizeof(struct tar_header
));
118 i
= th_read_internal(t
);
121 else if (i
!= T_BLOCKSIZE
)
128 /* check for GNU long link extention */
129 if (TH_ISLONGLINK(t
))
132 blocks
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0);
133 if (blocks
> ((size_t)-1 / T_BLOCKSIZE
))
139 printf(" th_read(): GNU long linkname detected "
140 "(%ld bytes, %d blocks)\n", sz
, blocks
);
142 t
->th_buf
.gnu_longlink
= (char *)malloc(blocks
* T_BLOCKSIZE
);
143 if (t
->th_buf
.gnu_longlink
== NULL
)
146 for (j
= 0, ptr
= t
->th_buf
.gnu_longlink
; j
< blocks
;
147 j
++, ptr
+= T_BLOCKSIZE
)
150 printf(" th_read(): reading long linkname "
151 "(%d blocks left, ptr == %ld)\n", blocks
-j
, ptr
);
153 i
= tar_block_read(t
, ptr
);
154 if (i
!= T_BLOCKSIZE
)
161 printf(" th_read(): read block == \"%s\"\n", ptr
);
165 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
166 t
->th_buf
.gnu_longlink
);
169 i
= th_read_internal(t
);
170 if (i
!= T_BLOCKSIZE
)
178 /* check for GNU long name extention */
179 if (TH_ISLONGNAME(t
))
182 blocks
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0);
183 if (blocks
> ((size_t)-1 / T_BLOCKSIZE
))
189 printf(" th_read(): GNU long filename detected "
190 "(%ld bytes, %d blocks)\n", sz
, blocks
);
192 t
->th_buf
.gnu_longname
= (char *)malloc(blocks
* T_BLOCKSIZE
);
193 if (t
->th_buf
.gnu_longname
== NULL
)
196 for (j
= 0, ptr
= t
->th_buf
.gnu_longname
; j
< blocks
;
197 j
++, ptr
+= T_BLOCKSIZE
)
200 printf(" th_read(): reading long filename "
201 "(%d blocks left, ptr == %ld)\n", blocks
-j
, ptr
);
203 i
= tar_block_read(t
, ptr
);
204 if (i
!= T_BLOCKSIZE
)
211 printf(" th_read(): read block == \"%s\"\n", ptr
);
215 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
216 t
->th_buf
.gnu_longname
);
219 i
= th_read_internal(t
);
220 if (i
!= T_BLOCKSIZE
)
230 ** work-around for old archive files with broken typeflag fields
231 ** NOTE: I fixed this in the TH_IS*() macros instead
235 ** (directories are signified with a trailing '/')
237 if (t
->th_buf
.typeflag
== AREGTYPE
238 && t
->th_buf
.name
[strlen(t
->th_buf
.name
) - 1] == '/')
239 t
->th_buf
.typeflag
= DIRTYPE
;
242 ** fallback to using mode bits
244 if (t
->th_buf
.typeflag
== AREGTYPE
)
246 mode
= (mode_t
)oct_to_int(t
->th_buf
.mode
);
249 t
->th_buf
.typeflag
= REGTYPE
;
250 else if (S_ISDIR(mode
))
251 t
->th_buf
.typeflag
= DIRTYPE
;
252 else if (S_ISFIFO(mode
))
253 t
->th_buf
.typeflag
= FIFOTYPE
;
254 else if (S_ISCHR(mode
))
255 t
->th_buf
.typeflag
= CHRTYPE
;
256 else if (S_ISBLK(mode
))
257 t
->th_buf
.typeflag
= BLKTYPE
;
258 else if (S_ISLNK(mode
))
259 t
->th_buf
.typeflag
= SYMTYPE
;
267 /* write a header block */
275 char buf
[T_BLOCKSIZE
];
278 printf("==> th_write(TAR=\"%s\")\n", t
->pathname
);
282 if ((t
->options
& TAR_GNU
) && t
->th_buf
.gnu_longlink
!= NULL
)
285 printf("th_write(): using gnu_longlink (\"%s\")\n",
286 t
->th_buf
.gnu_longlink
);
288 /* save old size and type */
289 type2
= t
->th_buf
.typeflag
;
290 sz2
= th_get_size(t
);
292 /* write out initial header block with fake size and type */
293 t
->th_buf
.typeflag
= GNU_LONGLINK_TYPE
;
294 sz
= strlen(t
->th_buf
.gnu_longlink
);
297 i
= tar_block_write(t
, &(t
->th_buf
));
298 if (i
!= T_BLOCKSIZE
)
305 /* write out extra blocks containing long name */
306 for (j
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0),
307 ptr
= t
->th_buf
.gnu_longlink
; j
> 1;
308 j
--, ptr
+= T_BLOCKSIZE
)
310 i
= tar_block_write(t
, ptr
);
311 if (i
!= T_BLOCKSIZE
)
318 memset(buf
, 0, T_BLOCKSIZE
);
319 strncpy(buf
, ptr
, T_BLOCKSIZE
);
320 i
= tar_block_write(t
, &buf
);
321 if (i
!= T_BLOCKSIZE
)
328 /* reset type and size to original values */
329 t
->th_buf
.typeflag
= type2
;
333 if ((t
->options
& TAR_GNU
) && t
->th_buf
.gnu_longname
!= NULL
)
336 printf("th_write(): using gnu_longname (\"%s\")\n",
337 t
->th_buf
.gnu_longname
);
339 /* save old size and type */
340 type2
= t
->th_buf
.typeflag
;
341 sz2
= th_get_size(t
);
343 /* write out initial header block with fake size and type */
344 t
->th_buf
.typeflag
= GNU_LONGNAME_TYPE
;
345 sz
= strlen(t
->th_buf
.gnu_longname
);
348 i
= tar_block_write(t
, &(t
->th_buf
));
349 if (i
!= T_BLOCKSIZE
)
356 /* write out extra blocks containing long name */
357 for (j
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0),
358 ptr
= t
->th_buf
.gnu_longname
; j
> 1;
359 j
--, ptr
+= T_BLOCKSIZE
)
361 i
= tar_block_write(t
, ptr
);
362 if (i
!= T_BLOCKSIZE
)
369 memset(buf
, 0, T_BLOCKSIZE
);
370 strncpy(buf
, ptr
, T_BLOCKSIZE
);
371 i
= tar_block_write(t
, &buf
);
372 if (i
!= T_BLOCKSIZE
)
379 /* reset type and size to original values */
380 t
->th_buf
.typeflag
= type2
;
387 /* print tar header */
391 i
= tar_block_write(t
, &(t
->th_buf
));
392 if (i
!= T_BLOCKSIZE
)
400 puts("th_write(): returning 0");