rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

tar.c
Go to the documentation of this file.
1
6 #undef JBJ_WRITEPAD
7
8 #include "system.h"
9
10 #include <rpmio.h>
11 #include <ugid.h>
12 #include <tar.h>
13 #define _IOSM_INTERNAL
14 #include <iosm.h>
15
16 #include "debug.h"
17
18 /*@access IOSM_t @*/
19
20 /*@unchecked@*/
21 int _tar_debug = 0;
22
23 /*@unchecked@*/
24 static int nochksum = 0;
25
34 static int strntoul(const char *str, /*@null@*/ /*@out@*/char **endptr,
35 int base, size_t num)
36 /*@modifies *endptr @*/
37 /*@requires maxSet(endptr) >= 0 @*/
38 {
39 char * buf, * end;
40 unsigned long ret;
41
42 buf = alloca(num + 1);
43 strncpy(buf, str, num);
44 buf[num] = '\0';
45
46 ret = strtoul(buf, &end, base);
47 if (endptr != NULL) {
48 if (*end != '\0')
49 *endptr = ((char *)str) + (end - buf); /* XXX discards const */
50 else
51 *endptr = ((char *)str) + strlen(buf);
52 }
53
54 return ret;
55 }
56
57 /* Translate archive read/write ssize_t return for iosmStage(). */
58 #define _IOSMRC(_rc) \
59 if ((_rc) <= 0) return ((_rc) ? (int) -rc : IOSMERR_HDR_TRAILER)
60
61 static ssize_t tarRead(void * _iosm, void * buf, size_t count)
62 /*@globals fileSystem @*/
63 /*@modifies _iosm, *buf, fileSystem @*/
64 {
65 IOSM_t iosm = _iosm;
66 char * t = buf;
67 size_t nb = 0;
68
69 if (_tar_debug)
70 fprintf(stderr, "\ttarRead(%p, %p[%u])\n", iosm, buf, (unsigned)count);
71
72 while (count > 0) {
73 size_t rc;
74
75 /* Read next tar block. */
76 iosm->wrlen = count;
77 rc = _iosmNext(iosm, IOSM_DREAD);
78 if (!rc && iosm->rdnb != iosm->wrlen)
79 rc = IOSMERR_READ_FAILED;
80 if (rc) return -rc;
81
82 /* Append to buffer. */
83 rc = (count > iosm->rdnb ? iosm->rdnb : count);
84 if (buf != iosm->wrbuf)
85 memcpy(t + nb, iosm->wrbuf, rc);
86 nb += rc;
87 count -= rc;
88 }
89 return nb;
90 }
91
99 static ssize_t tarHeaderReadName(void * _iosm, size_t len,
100 /*@out@*/ const char ** fnp)
101 /*@globals fileSystem, internalState @*/
102 /*@modifies _iosm, *fnp, fileSystem, internalState @*/
103 {
104 IOSM_t iosm = _iosm;
105 size_t nb = len + 1;
106 char * t = xmalloc(nb);
107 ssize_t rc = tarRead(iosm, t, nb);
108
109 if (rc > 0) /* success */
110 t[rc] = '\0';
111 else /* failure or EOF */
112 t = _free(t);
113 if (fnp != NULL)
114 *fnp = t;
115
116 if (_tar_debug)
117 fprintf(stderr, "\ttarHeaderReadName(%p, %u, %p) rc 0x%x\n", _iosm, (unsigned)len, fnp, (unsigned)rc);
118
119 return rc;
120 }
121
122 int tarHeaderRead(void * _iosm, struct stat * st)
123 /*@modifies _iosm, *st @*/
124 {
125 IOSM_t iosm = _iosm;
126 tarHeader hdr = (tarHeader) iosm->wrbuf;
127 char * t;
128 size_t nb;
129 int major, minor;
130 ssize_t rc = 0;
131 int zblk = 0;
132
133 if (_tar_debug)
134 fprintf(stderr, " tarHeaderRead(%p, %p)\n", iosm, st);
135
136 top:
137 do {
138 /* Read next header. */
139 rc = tarRead(_iosm, hdr, TAR_BLOCK_SIZE);
140 _IOSMRC(rc);
141
142 /* Look for end-of-archive, i.e. 2 (or more) zero blocks. */
143 if (hdr->name[0] == '\0' && hdr->checksum[0] == '\0') {
144 if (++zblk == 2)
145 return IOSMERR_HDR_TRAILER;
146 }
147 } while (zblk > 0);
148
149 /* Verify header checksum. */
150 { const unsigned char * hp = (const unsigned char *) hdr;
151 char checksum[8];
152 char hdrchecksum[8];
153 long sum = 0;
154 int i;
155
156 memcpy(hdrchecksum, hdr->checksum, sizeof(hdrchecksum));
157 memset(hdr->checksum, (int)' ', sizeof(hdr->checksum));
158
159 for (i = 0; i < TAR_BLOCK_SIZE; i++)
160 sum += (long)*hp++;
161
162 memset(checksum, (int)' ', sizeof(checksum));
163 sprintf(checksum, "%06o", (unsigned) (sum & 07777777));
164 if (_tar_debug)
165 fprintf(stderr, "\tmemcmp(\"%s\", \"%s\", %u)\n", hdrchecksum, checksum, (unsigned)sizeof(hdrchecksum));
166 if (memcmp(hdrchecksum, checksum, sizeof(hdrchecksum)))
167 if (!nochksum)
168 return IOSMERR_BAD_HEADER;
169
170 }
171
172 /* Verify header magic. */
173 if (strncmp(hdr->magic, TAR_MAGIC, sizeof(TAR_MAGIC)-1))
174 return IOSMERR_BAD_MAGIC;
175
176 /* Convert header to stat(2). */
177 st->st_size = strntoul(hdr->filesize, NULL, 8, sizeof(hdr->filesize));
178
179 st->st_nlink = 1;
180 st->st_mode = strntoul(hdr->mode, NULL, 8, sizeof(hdr->mode));
181 st->st_mode &= ~S_IFMT;
182 switch (hdr->typeflag) {
183 case 'x': /* Extended header referring to next file in archive. */
184 case 'g': /* Global extended header. */
185 default:
186 break;
187 case '7': /* reserved (contiguous files?) */
188 case '\0': /* (ancient) regular file */
189 case '0': /* regular file */
190 st->st_mode |= S_IFREG;
191 break;
192 case '1': /* hard link */
193 st->st_mode |= S_IFREG;
194 #ifdef DYING
195 st->st_nlink++;
196 #endif
197 break;
198 case '2': /* symbolic link */
199 st->st_mode |= S_IFLNK;
200 break;
201 case '3': /* character special */
202 st->st_mode |= S_IFCHR;
203 break;
204 case '4': /* block special */
205 st->st_mode |= S_IFBLK;
206 break;
207 case '5': /* directory */
208 st->st_mode |= S_IFDIR;
209 st->st_nlink++;
210 break;
211 case '6': /* FIFO special */
212 st->st_mode |= S_IFIFO;
213 break;
214 #ifdef REFERENCE
215 case 'A': /* Solaris ACL */
216 case 'E': /* Solaris XATTR */
217 case 'I': /* Inode only, as in 'star' */
218 case 'X': /* POSIX 1003.1-2001 eXtended (VU version) */
219 case 'D': /* GNU dumpdir (with -G, --incremental) */
220 case 'M': /* GNU multivol (with -M, --multi-volume) */
221 case 'N': /* GNU names */
222 case 'S': /* GNU sparse (with -S, --sparse) */
223 case 'V': /* GNU tape/volume header (with -Vlll, --label=lll) */
224 #endif
225 case 'K': /* GNU long (>100 chars) link name */
226 rc = tarHeaderReadName(iosm, st->st_size, &iosm->lpath);
227 _IOSMRC(rc);
228 goto top;
229 /*@notreached@*/ break;
230 case 'L': /* GNU long (>100 chars) file name */
231 rc = tarHeaderReadName(iosm, st->st_size, &iosm->path);
232 _IOSMRC(rc);
233 goto top;
234 /*@notreached@*/ break;
235 }
236
237 st->st_uid = strntoul(hdr->uid, NULL, 8, sizeof(hdr->uid));
238 st->st_gid = strntoul(hdr->gid, NULL, 8, sizeof(hdr->gid));
239 st->st_mtime = strntoul(hdr->mtime, NULL, 8, sizeof(hdr->mtime));
240 st->st_ctime = st->st_atime = st->st_mtime; /* XXX compat? */
241
242 major = strntoul(hdr->devMajor, NULL, 8, sizeof(hdr->devMajor));
243 minor = strntoul(hdr->devMinor, NULL, 8, sizeof(hdr->devMinor));
244 /*@-shiftimplementation@*/
245 st->st_dev = Makedev(major, minor);
246 /*@=shiftimplementation@*/
247 st->st_rdev = st->st_dev; /* XXX compat? */
248
249 /* char prefix[155]; */
250 /* char padding[12]; */
251
252 /* Read short file name. */
253 if (iosm->path == NULL && hdr->name[0] != '\0') {
254 nb = strlen(hdr->name);
255 t = xmalloc(nb + 1);
256 memcpy(t, hdr->name, nb);
257 t[nb] = '\0';
258 iosm->path = t;
259 }
260
261 /* Read short link name. */
262 if (iosm->lpath == NULL && hdr->linkname[0] != '\0') {
263 nb = strlen(hdr->linkname);
264 t = xmalloc(nb + 1);
265 memcpy(t, hdr->linkname, nb);
266 t[nb] = '\0';
267 iosm->lpath = t;
268 }
269
270 rc = 0;
271
272 if (_tar_debug)
273 fprintf(stderr, "\t %06o%3d (%4d,%4d)%12lu %s\n\t-> %s\n",
274 (unsigned)st->st_mode, (int)st->st_nlink,
275 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
276 (iosm->path ? iosm->path : ""), (iosm->lpath ? iosm->lpath : ""));
277
278 return (int) rc;
279 }
280
281 static ssize_t tarWrite(void * _iosm, const void *buf, size_t count)
282 /*@globals fileSystem @*/
283 /*@modifies _iosm, fileSystem @*/
284 {
285 IOSM_t iosm = _iosm;
286 const char * s = buf;
287 size_t nb = 0;
288 size_t rc;
289
290 if (_tar_debug)
291 fprintf(stderr, "\t tarWrite(%p, %p[%u])\n", iosm, buf, (unsigned)count);
292
293 while (count > 0) {
294
295 /* XXX DWRITE uses rdnb for I/O length. */
296 iosm->rdnb = count;
297 if (s != iosm->rdbuf)
298 memmove(iosm->rdbuf, s + nb, iosm->rdnb);
299
300 rc = _iosmNext(iosm, IOSM_DWRITE);
301 if (!rc && iosm->rdnb != iosm->wrnb)
302 rc = IOSMERR_WRITE_FAILED;
303 if (rc) return -rc;
304
305 nb += iosm->rdnb;
306 count -= iosm->rdnb;
307 }
308
309 #if defined(JBJ_WRITEPAD)
310 /* Pad to next block boundary. */
311 if ((rc = _iosmNext(iosm, IOSM_PAD)) != 0) return rc;
312 #endif
313
314 return nb;
315 }
316
323 static ssize_t tarHeaderWriteName(void * _iosm, const char * path)
324 /*@globals fileSystem, internalState @*/
325 /*@modifies _iosm, fileSystem, internalState @*/
326 {
327 ssize_t rc = tarWrite(_iosm, path, strlen(path));
328
329 #if !defined(JBJ_WRITEPAD)
330 if (rc >= 0) {
331 rc = _iosmNext(_iosm, IOSM_PAD);
332 if (rc) rc = -rc;
333 }
334 #endif
335
336 if (_tar_debug)
337 fprintf(stderr, "\ttarHeaderWriteName(%p, %s) rc 0x%x\n", _iosm, path, (unsigned)rc);
338
339 return rc;
340 }
341
349 static ssize_t tarHeaderWriteBlock(void * _iosm, struct stat * st, tarHeader hdr)
350 /*@globals fileSystem, internalState @*/
351 /*@modifies _iosm, hdr, fileSystem, internalState @*/
352 {
353 IOSM_t iosm = _iosm;
354 ssize_t rc;
355
356 if (_tar_debug)
357 fprintf(stderr, "\ttarHeaderWriteBlock(%p, %p) type %c\n", iosm, hdr, hdr->typeflag);
358 if (_tar_debug)
359 fprintf(stderr, "\t %06o%3d (%4d,%4d)%12lu %s\n",
360 (unsigned)st->st_mode, (int)st->st_nlink,
361 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
362 (iosm->path ? iosm->path : ""));
363
364
365 (void) stpcpy( stpcpy(hdr->magic, TAR_MAGIC), TAR_VERSION);
366
367 /* Calculate header checksum. */
368 { const unsigned char * hp = (const unsigned char *) hdr;
369 long sum = 0;
370 int i;
371
372 memset(hdr->checksum, (int)' ', sizeof(hdr->checksum));
373 for (i = 0; i < TAR_BLOCK_SIZE; i++)
374 sum += (long) *hp++;
375 sprintf(hdr->checksum, "%06o", (unsigned)(sum & 07777777));
376 if (_tar_debug)
377 fprintf(stderr, "\thdrchksum \"%s\"\n", hdr->checksum);
378 }
379
380 rc = tarWrite(_iosm, hdr, TAR_BLOCK_SIZE);
381
382 return rc;
383 }
384
385 int tarHeaderWrite(void * _iosm, struct stat * st)
386 {
387 IOSM_t iosm = _iosm;
388 /*@observer@*/
389 static const char * llname = "././@LongLink";
390 tarHeader hdr = (tarHeader) iosm->rdbuf;
391 char * t;
392 dev_t dev;
393 size_t nb;
394 ssize_t rc = 0;
395
396 if (_tar_debug)
397 fprintf(stderr, " tarHeaderWrite(%p, %p)\n", iosm, st);
398
399 nb = strlen(iosm->path);
400 if (nb > sizeof(hdr->name)) {
401 memset(hdr, 0, sizeof(*hdr));
402 strcpy(hdr->name, llname);
403 sprintf(hdr->mode, "%07o", 0);
404 sprintf(hdr->uid, "%07o", 0);
405 sprintf(hdr->gid, "%07o", 0);
406 sprintf(hdr->filesize, "%011o", (unsigned) (nb & 037777777777));
407 sprintf(hdr->mtime, "%011o", 0);
408 hdr->typeflag = 'L';
409 strncpy(hdr->uname, "root", sizeof(hdr->uname));
410 strncpy(hdr->gname, "root", sizeof(hdr->gname));
411 rc = tarHeaderWriteBlock(iosm, st, hdr);
412 _IOSMRC(rc);
413 rc = tarHeaderWriteName(iosm, iosm->path);
414 _IOSMRC(rc);
415 }
416
417 if (iosm->lpath && iosm->lpath[0] != '0') {
418 nb = strlen(iosm->lpath);
419 if (nb > sizeof(hdr->name)) {
420 memset(hdr, 0, sizeof(*hdr));
421 strcpy(hdr->linkname, llname);
422 sprintf(hdr->mode, "%07o", 0);
423 sprintf(hdr->uid, "%07o", 0);
424 sprintf(hdr->gid, "%07o", 0);
425 sprintf(hdr->filesize, "%011o", (unsigned) (nb & 037777777777));
426 sprintf(hdr->mtime, "%011o", 0);
427 hdr->typeflag = 'K';
428 strncpy(hdr->uname, "root", sizeof(hdr->uname));
429 strncpy(hdr->gname, "root", sizeof(hdr->gname));
430 rc = tarHeaderWriteBlock(iosm, st, hdr);
431 _IOSMRC(rc);
432 rc = tarHeaderWriteName(iosm, iosm->lpath);
433 _IOSMRC(rc);
434 }
435 }
436
437 memset(hdr, 0, sizeof(*hdr));
438
439 strncpy(hdr->name, iosm->path, sizeof(hdr->name));
440
441 if (iosm->lpath && iosm->lpath[0] != '0')
442 strncpy(hdr->linkname, iosm->lpath, sizeof(hdr->linkname));
443
444 sprintf(hdr->mode, "%07o", (unsigned int)(st->st_mode & 00007777));
445 sprintf(hdr->uid, "%07o", (unsigned int)(st->st_uid & 07777777));
446 sprintf(hdr->gid, "%07o", (unsigned int)(st->st_gid & 07777777));
447
448 sprintf(hdr->filesize, "%011o", (unsigned) (st->st_size & 037777777777));
449 sprintf(hdr->mtime, "%011o", (unsigned) (st->st_mtime & 037777777777));
450
451 hdr->typeflag = '0'; /* XXX wrong! */
452 if (S_ISLNK(st->st_mode))
453 hdr->typeflag = '2';
454 else if (S_ISCHR(st->st_mode))
455 hdr->typeflag = '3';
456 else if (S_ISBLK(st->st_mode))
457 hdr->typeflag = '4';
458 else if (S_ISDIR(st->st_mode))
459 hdr->typeflag = '5';
460 else if (S_ISFIFO(st->st_mode))
461 hdr->typeflag = '6';
462 #ifdef WHAT2DO
463 else if (S_ISSOCK(st->st_mode))
464 hdr->typeflag = '?';
465 #endif
466 else if (S_ISREG(st->st_mode))
467 hdr->typeflag = (iosm->lpath != NULL ? '1' : '0');
468
469 /* XXX FIXME: map uname/gname from uid/gid. */
470 t = uidToUname(st->st_uid);
471 if (t == NULL) t = "root";
472 strncpy(hdr->uname, t, sizeof(hdr->uname));
473 t = gidToGname(st->st_gid);
474 if (t == NULL) t = "root";
475 strncpy(hdr->gname, t, sizeof(hdr->gname));
476
477 /* XXX W2DO? st_dev or st_rdev? */
478 dev = major((unsigned)st->st_dev);
479 sprintf(hdr->devMajor, "%07o", (unsigned) (dev & 07777777));
480 dev = minor((unsigned)st->st_dev);
481 sprintf(hdr->devMinor, "%07o", (unsigned) (dev & 07777777));
482
483 rc = tarHeaderWriteBlock(iosm, st, hdr);
484 _IOSMRC(rc);
485 rc = 0;
486
487 #if !defined(JBJ_WRITEPAD)
488 /* XXX Padding is unnecessary but shouldn't hurt. */
489 rc = _iosmNext(iosm, IOSM_PAD);
490 #endif
491
492 return (int) rc;
493 }
494
495 int tarTrailerWrite(void * _iosm)
496 {
497 IOSM_t iosm = _iosm;
498 ssize_t rc = 0;
499
500 if (_tar_debug)
501 fprintf(stderr, " tarTrailerWrite(%p)\n", iosm);
502
503 /* Pad up to 20 blocks (10Kb) of zeroes. */
504 iosm->blksize *= 20;
505 #if defined(JBJ_WRITEPAD)
506 rc = tarWrite(iosm, NULL, 0); /* XXX _iosmNext(iosm, IOSM_PAD) */
507 #else
508 rc = _iosmNext(iosm, IOSM_PAD);
509 #endif
510 iosm->blksize /= 20;
511 #if defined(JBJ_WRITEPAD)
512 _IOSMRC(rc);
513 #endif
514
515 return (int) -rc;
516 }