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
13 #include <libtarint/internal.h>
23 #define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
26 /* read a header block */
28 th_read_internal(TAR
*t
)
31 int num_zero_blocks
= 0;
34 printf("==> th_read_internal(TAR=\"%s\")\n", t
->pathname
);
37 while ((i
= tar_block_read(t
, &(t
->th_buf
))) == T_BLOCKSIZE
)
39 /* two all-zero blocks mark EOF */
40 if (t
->th_buf
.name
[0] == '\0')
43 if (!BIT_ISSET(t
->options
, TAR_IGNORE_EOT
)
44 && num_zero_blocks
>= 2)
50 /* verify magic and version */
51 if (BIT_ISSET(t
->options
, TAR_CHECK_MAGIC
)
52 && strncmp(t
->th_buf
.magic
, TMAGIC
, TMAGLEN
- 1) != 0)
55 puts("!!! unknown magic value in tar header");
60 if (BIT_ISSET(t
->options
, TAR_CHECK_VERSION
)
61 && strncmp(t
->th_buf
.version
, TVERSION
, TVERSLEN
) != 0)
64 puts("!!! unknown version value in tar header");
70 if (!BIT_ISSET(t
->options
, TAR_IGNORE_CRC
)
74 puts("!!! tar header checksum error");
83 printf("<== th_read_internal(): returning %d\n", i
);
89 /* wrapper function for th_read_internal() to handle GNU extensions */
98 printf("==> th_read(t=0x%lx)\n", t
);
101 if (t
->th_buf
.gnu_longname
!= NULL
)
102 free(t
->th_buf
.gnu_longname
);
103 if (t
->th_buf
.gnu_longlink
!= NULL
)
104 free(t
->th_buf
.gnu_longlink
);
105 memset(&(t
->th_buf
), 0, sizeof(struct tar_header
));
107 i
= th_read_internal(t
);
110 else if (i
!= T_BLOCKSIZE
)
117 /* check for GNU long link extention */
118 if (TH_ISLONGLINK(t
))
121 j
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0);
123 printf(" th_read(): GNU long linkname detected "
124 "(%ld bytes, %d blocks)\n", sz
, j
);
126 t
->th_buf
.gnu_longlink
= (char *)malloc(j
* T_BLOCKSIZE
);
127 if (t
->th_buf
.gnu_longlink
== NULL
)
130 for (ptr
= t
->th_buf
.gnu_longlink
; j
> 0;
131 j
--, ptr
+= T_BLOCKSIZE
)
134 printf(" th_read(): reading long linkname "
135 "(%d blocks left, ptr == %ld)\n", j
, ptr
);
137 i
= tar_block_read(t
, ptr
);
138 if (i
!= T_BLOCKSIZE
)
145 printf(" th_read(): read block == \"%s\"\n", ptr
);
149 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
150 t
->th_buf
.gnu_longlink
);
153 i
= th_read_internal(t
);
154 if (i
!= T_BLOCKSIZE
)
162 /* check for GNU long name extention */
163 if (TH_ISLONGNAME(t
))
166 j
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0);
168 printf(" th_read(): GNU long filename detected "
169 "(%ld bytes, %d blocks)\n", sz
, j
);
171 t
->th_buf
.gnu_longname
= (char *)malloc(j
* T_BLOCKSIZE
);
172 if (t
->th_buf
.gnu_longname
== NULL
)
175 for (ptr
= t
->th_buf
.gnu_longname
; j
> 0;
176 j
--, ptr
+= T_BLOCKSIZE
)
179 printf(" th_read(): reading long filename "
180 "(%d blocks left, ptr == %ld)\n", j
, ptr
);
182 i
= tar_block_read(t
, ptr
);
183 if (i
!= T_BLOCKSIZE
)
190 printf(" th_read(): read block == \"%s\"\n", ptr
);
194 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
195 t
->th_buf
.gnu_longname
);
198 i
= th_read_internal(t
);
199 if (i
!= T_BLOCKSIZE
)
209 ** work-around for old archive files with broken typeflag fields
210 ** NOTE: I fixed this in the TH_IS*() macros instead
214 ** (directories are signified with a trailing '/')
216 if (t
->th_buf
.typeflag
== AREGTYPE
217 && t
->th_buf
.name
[strlen(t
->th_buf
.name
) - 1] == '/')
218 t
->th_buf
.typeflag
= DIRTYPE
;
221 ** fallback to using mode bits
223 if (t
->th_buf
.typeflag
== AREGTYPE
)
225 mode
= (mode_t
)oct_to_int(t
->th_buf
.mode
);
228 t
->th_buf
.typeflag
= REGTYPE
;
229 else if (S_ISDIR(mode
))
230 t
->th_buf
.typeflag
= DIRTYPE
;
231 else if (S_ISFIFO(mode
))
232 t
->th_buf
.typeflag
= FIFOTYPE
;
233 else if (S_ISCHR(mode
))
234 t
->th_buf
.typeflag
= CHRTYPE
;
235 else if (S_ISBLK(mode
))
236 t
->th_buf
.typeflag
= BLKTYPE
;
237 else if (S_ISLNK(mode
))
238 t
->th_buf
.typeflag
= SYMTYPE
;
246 /* write a header block */
254 char buf
[T_BLOCKSIZE
];
257 printf("==> th_write(TAR=\"%s\")\n", t
->pathname
);
261 if ((t
->options
& TAR_GNU
) && t
->th_buf
.gnu_longlink
!= NULL
)
264 printf("th_write(): using gnu_longlink (\"%s\")\n",
265 t
->th_buf
.gnu_longlink
);
267 /* save old size and type */
268 type2
= t
->th_buf
.typeflag
;
269 sz2
= th_get_size(t
);
271 /* write out initial header block with fake size and type */
272 t
->th_buf
.typeflag
= GNU_LONGLINK_TYPE
;
273 sz
= strlen(t
->th_buf
.gnu_longlink
);
276 i
= tar_block_write(t
, &(t
->th_buf
));
277 if (i
!= T_BLOCKSIZE
)
284 /* write out extra blocks containing long name */
285 for (j
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0),
286 ptr
= t
->th_buf
.gnu_longlink
; j
> 1;
287 j
--, ptr
+= T_BLOCKSIZE
)
289 i
= tar_block_write(t
, ptr
);
290 if (i
!= T_BLOCKSIZE
)
297 memset(buf
, 0, T_BLOCKSIZE
);
298 strncpy(buf
, ptr
, T_BLOCKSIZE
);
299 i
= tar_block_write(t
, &buf
);
300 if (i
!= T_BLOCKSIZE
)
307 /* reset type and size to original values */
308 t
->th_buf
.typeflag
= type2
;
312 if ((t
->options
& TAR_GNU
) && t
->th_buf
.gnu_longname
!= NULL
)
315 printf("th_write(): using gnu_longname (\"%s\")\n",
316 t
->th_buf
.gnu_longname
);
318 /* save old size and type */
319 type2
= t
->th_buf
.typeflag
;
320 sz2
= th_get_size(t
);
322 /* write out initial header block with fake size and type */
323 t
->th_buf
.typeflag
= GNU_LONGNAME_TYPE
;
324 sz
= strlen(t
->th_buf
.gnu_longname
);
327 i
= tar_block_write(t
, &(t
->th_buf
));
328 if (i
!= T_BLOCKSIZE
)
335 /* write out extra blocks containing long name */
336 for (j
= (sz
/ T_BLOCKSIZE
) + (sz
% T_BLOCKSIZE
? 1 : 0),
337 ptr
= t
->th_buf
.gnu_longname
; j
> 1;
338 j
--, ptr
+= T_BLOCKSIZE
)
340 i
= tar_block_write(t
, ptr
);
341 if (i
!= T_BLOCKSIZE
)
348 memset(buf
, 0, T_BLOCKSIZE
);
349 strncpy(buf
, ptr
, T_BLOCKSIZE
);
350 i
= tar_block_write(t
, &buf
);
351 if (i
!= T_BLOCKSIZE
)
358 /* reset type and size to original values */
359 t
->th_buf
.typeflag
= type2
;
366 /* print tar header */
370 i
= tar_block_write(t
, &(t
->th_buf
));
371 if (i
!= T_BLOCKSIZE
)
379 puts("th_write(): returning 0");