rpm  5.2.1
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 }