libtar-1.2.11 tarball sources, taken from Debian's orig tar
[libtar.git] / lib / block.c
blob2917dc67f3c346d0339561b1e1e744ba6e508a48
1 /*
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
13 #include <internal.h>
15 #include <errno.h>
17 #ifdef STDC_HEADERS
18 # include <string.h>
19 # include <stdlib.h>
20 #endif
23 #define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
26 /* read a header block */
27 int
28 th_read_internal(TAR *t)
30 int i;
31 int num_zero_blocks = 0;
33 #ifdef DEBUG
34 printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname);
35 #endif
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')
42 num_zero_blocks++;
43 if (!BIT_ISSET(t->options, TAR_IGNORE_EOT)
44 && num_zero_blocks >= 2)
45 return 0; /* EOF */
46 else
47 continue;
50 /* verify magic and version */
51 if (BIT_ISSET(t->options, TAR_CHECK_MAGIC)
52 && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0)
54 #ifdef DEBUG
55 puts("!!! unknown magic value in tar header");
56 #endif
57 return -2;
60 if (BIT_ISSET(t->options, TAR_CHECK_VERSION)
61 && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0)
63 #ifdef DEBUG
64 puts("!!! unknown version value in tar header");
65 #endif
66 return -2;
69 /* check chksum */
70 if (!BIT_ISSET(t->options, TAR_IGNORE_CRC)
71 && !th_crc_ok(t))
73 #ifdef DEBUG
74 puts("!!! tar header checksum error");
75 #endif
76 return -2;
79 break;
82 #ifdef DEBUG
83 printf("<== th_read_internal(): returning %d\n", i);
84 #endif
85 return i;
89 /* wrapper function for th_read_internal() to handle GNU extensions */
90 int
91 th_read(TAR *t)
93 int i, j;
94 size_t sz;
95 char *ptr;
97 #ifdef DEBUG
98 printf("==> th_read(t=0x%lx)\n", t);
99 #endif
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);
108 if (i == 0)
109 return 1;
110 else if (i != T_BLOCKSIZE)
112 if (i != -1)
113 errno = EINVAL;
114 return -1;
117 /* check for GNU long link extention */
118 if (TH_ISLONGLINK(t))
120 sz = th_get_size(t);
121 j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
122 #ifdef DEBUG
123 printf(" th_read(): GNU long linkname detected "
124 "(%ld bytes, %d blocks)\n", sz, j);
125 #endif
126 t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE);
127 if (t->th_buf.gnu_longlink == NULL)
128 return -1;
130 for (ptr = t->th_buf.gnu_longlink; j > 0;
131 j--, ptr += T_BLOCKSIZE)
133 #ifdef DEBUG
134 printf(" th_read(): reading long linkname "
135 "(%d blocks left, ptr == %ld)\n", j, ptr);
136 #endif
137 i = tar_block_read(t, ptr);
138 if (i != T_BLOCKSIZE)
140 if (i != -1)
141 errno = EINVAL;
142 return -1;
144 #ifdef DEBUG
145 printf(" th_read(): read block == \"%s\"\n", ptr);
146 #endif
148 #ifdef DEBUG
149 printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n",
150 t->th_buf.gnu_longlink);
151 #endif
153 i = th_read_internal(t);
154 if (i != T_BLOCKSIZE)
156 if (i != -1)
157 errno = EINVAL;
158 return -1;
162 /* check for GNU long name extention */
163 if (TH_ISLONGNAME(t))
165 sz = th_get_size(t);
166 j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0);
167 #ifdef DEBUG
168 printf(" th_read(): GNU long filename detected "
169 "(%ld bytes, %d blocks)\n", sz, j);
170 #endif
171 t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE);
172 if (t->th_buf.gnu_longname == NULL)
173 return -1;
175 for (ptr = t->th_buf.gnu_longname; j > 0;
176 j--, ptr += T_BLOCKSIZE)
178 #ifdef DEBUG
179 printf(" th_read(): reading long filename "
180 "(%d blocks left, ptr == %ld)\n", j, ptr);
181 #endif
182 i = tar_block_read(t, ptr);
183 if (i != T_BLOCKSIZE)
185 if (i != -1)
186 errno = EINVAL;
187 return -1;
189 #ifdef DEBUG
190 printf(" th_read(): read block == \"%s\"\n", ptr);
191 #endif
193 #ifdef DEBUG
194 printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n",
195 t->th_buf.gnu_longname);
196 #endif
198 i = th_read_internal(t);
199 if (i != T_BLOCKSIZE)
201 if (i != -1)
202 errno = EINVAL;
203 return -1;
207 #if 0
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);
227 if (S_ISREG(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;
240 #endif
242 return 0;
246 /* write a header block */
248 th_write(TAR *t)
250 int i, j;
251 char type2;
252 size_t sz, sz2;
253 char *ptr;
254 char buf[T_BLOCKSIZE];
256 #ifdef DEBUG
257 printf("==> th_write(TAR=\"%s\")\n", t->pathname);
258 th_print(t);
259 #endif
261 if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL)
263 #ifdef DEBUG
264 printf("th_write(): using gnu_longlink (\"%s\")\n",
265 t->th_buf.gnu_longlink);
266 #endif
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);
274 th_set_size(t, sz);
275 th_finish(t);
276 i = tar_block_write(t, &(t->th_buf));
277 if (i != T_BLOCKSIZE)
279 if (i != -1)
280 errno = EINVAL;
281 return -1;
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)
292 if (i != -1)
293 errno = EINVAL;
294 return -1;
297 memset(buf, 0, T_BLOCKSIZE);
298 strncpy(buf, ptr, T_BLOCKSIZE);
299 i = tar_block_write(t, &buf);
300 if (i != T_BLOCKSIZE)
302 if (i != -1)
303 errno = EINVAL;
304 return -1;
307 /* reset type and size to original values */
308 t->th_buf.typeflag = type2;
309 th_set_size(t, sz2);
312 if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL)
314 #ifdef DEBUG
315 printf("th_write(): using gnu_longname (\"%s\")\n",
316 t->th_buf.gnu_longname);
317 #endif
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);
325 th_set_size(t, sz);
326 th_finish(t);
327 i = tar_block_write(t, &(t->th_buf));
328 if (i != T_BLOCKSIZE)
330 if (i != -1)
331 errno = EINVAL;
332 return -1;
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)
343 if (i != -1)
344 errno = EINVAL;
345 return -1;
348 memset(buf, 0, T_BLOCKSIZE);
349 strncpy(buf, ptr, T_BLOCKSIZE);
350 i = tar_block_write(t, &buf);
351 if (i != T_BLOCKSIZE)
353 if (i != -1)
354 errno = EINVAL;
355 return -1;
358 /* reset type and size to original values */
359 t->th_buf.typeflag = type2;
360 th_set_size(t, sz2);
363 th_finish(t);
365 #ifdef DEBUG
366 /* print tar header */
367 th_print(t);
368 #endif
370 i = tar_block_write(t, &(t->th_buf));
371 if (i != T_BLOCKSIZE)
373 if (i != -1)
374 errno = EINVAL;
375 return -1;
378 #ifdef DEBUG
379 puts("th_write(): returning 0");
380 #endif
381 return 0;