rpm  4.5
tar.c
Go to the documentation of this file.
1 
6 #include "system.h"
7 
8 #include <rpmio_internal.h>
9 #include <rpmlib.h>
10 
11 #include "tar.h"
12 #include "fsm.h"
13 #include "ugid.h"
14 
15 #include "rpmerr.h"
16 #include "debug.h"
17 
18 /*@access FSM_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, /*@out@*/char **endptr, int base, int num)
35  /*@modifies *endptr @*/
36  /*@requires maxSet(endptr) >= 0 @*/
37 {
38  char * buf, * end;
39  unsigned long ret;
40 
41  buf = alloca(num + 1);
42  strncpy(buf, str, num);
43  buf[num] = '\0';
44 
45  ret = strtoul(buf, &end, base);
46 /*@-boundsread@*/ /* LCL: strtoul annotations */
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 /*@=boundsread@*/
54 
55  return ret;
56 }
57 
65 static int tarHeaderReadName(FSM_t fsm, int len, /*@out@*/ const char ** fnp)
66  /*@globals h_errno, fileSystem, internalState @*/
67  /*@modifies fsm, *fnp, fileSystem, internalState @*/
68 {
69  char * t;
70  int nb;
71  int rc = 0;
72 
73  *fnp = t = xmalloc(len + 1);
74  while (len > 0) {
75  /* Read next tar block. */
76  fsm->wrlen = TAR_BLOCK_SIZE;
77  rc = fsmNext(fsm, FSM_DREAD);
78  if (!rc && fsm->rdnb != fsm->wrlen)
80  if (rc) break;
81 
82  /* Append to name. */
83  nb = (len > fsm->rdnb ? fsm->rdnb : len);
84  memcpy(t, fsm->wrbuf, nb);
85  t += nb;
86  len -= nb;
87  }
88  *t = '\0';
89 
90  if (rc)
91  *fnp = _free(*fnp);
92  return rc;
93 }
94 
95 int tarHeaderRead(FSM_t fsm, struct stat * st)
96  /*@modifies fsm, *st @*/
97 {
98  tarHeader hdr = (tarHeader) fsm->wrbuf;
99  char * t;
100  int nb;
101  int major, minor;
102  int rc = 0;
103  int zblk = 0;
104 
105 if (_tar_debug)
106 fprintf(stderr, " %s(%p, %p)\n", __FUNCTION__, fsm, st);
107 
108 top:
109  do {
110  /* Read next tar block. */
111  fsm->wrlen = TAR_BLOCK_SIZE;
112  rc = fsmNext(fsm, FSM_DREAD);
113  if (!rc && fsm->rdnb != fsm->wrlen)
114  rc = CPIOERR_READ_FAILED;
115  if (rc) return rc;
116 
117  /* Look for end-of-archive, i.e. 2 (or more) zero blocks. */
118  if (hdr->name[0] == '\0' && hdr->checksum[0] == '\0') {
119  if (++zblk == 2)
120  return CPIOERR_HDR_TRAILER;
121  }
122  } while (zblk > 0);
123 
124  /* Verify header checksum. */
125  { const unsigned char * hp = (const unsigned char *) hdr;
126  char checksum[8];
127  char hdrchecksum[8];
128  long sum = 0;
129  int i;
130 
131  memcpy(hdrchecksum, hdr->checksum, sizeof(hdrchecksum));
132  memset(hdr->checksum, ' ', sizeof(hdr->checksum));
133 
134  for (i = 0; i < TAR_BLOCK_SIZE; i++)
135  sum += *hp++;
136 
137 #if 0
138  for (i = 0; i < sizeof(hdr->checksum) - 1; i++)
139  sum += (' ' - hdr->checksum[i]);
140 fprintf(stderr, "\tsum %ld\n", sum);
141  if (sum != 0)
142  return CPIOERR_BAD_HEADER;
143 #else
144  memset(checksum, ' ', sizeof(checksum));
145  sprintf(checksum, "%06o", (unsigned) (sum & 07777777));
146 if (_tar_debug)
147 fprintf(stderr, "\tmemcmp(\"%s\", \"%s\", %u)\n", hdrchecksum, checksum, (unsigned)sizeof(hdrchecksum));
148  if (memcmp(hdrchecksum, checksum, sizeof(hdrchecksum)))
149  if (!nochksum)
150  return CPIOERR_BAD_HEADER;
151 #endif
152 
153  }
154 
155  /* Verify header magic. */
156  if (strncmp(hdr->magic, TAR_MAGIC, sizeof(TAR_MAGIC)-1))
157  return CPIOERR_BAD_MAGIC;
158 
159  st->st_size = strntoul(hdr->filesize, NULL, 8, sizeof(hdr->filesize));
160 
161  st->st_nlink = 1;
162  st->st_mode = strntoul(hdr->mode, NULL, 8, sizeof(hdr->mode));
163  st->st_mode &= ~S_IFMT;
164  switch (hdr->typeflag) {
165  case 'x': /* Extended header referring to next file in archive. */
166  case 'g': /* Global extended header. */
167  default:
168  break;
169  case '7': /* reserved (contiguous files?) */
170  case '\0': /* (ancient) regular file */
171  case '0': /* regular file */
172  st->st_mode |= S_IFREG;
173  break;
174  case '1': /* hard link */
175  st->st_mode |= S_IFREG;
176 #ifdef DYING
177  st->st_nlink++;
178 #endif
179  break;
180  case '2': /* symbolic link */
181  st->st_mode |= S_IFLNK;
182  break;
183  case '3': /* character special */
184  st->st_mode |= S_IFCHR;
185  break;
186  case '4': /* block special */
187  st->st_mode |= S_IFBLK;
188  break;
189  case '5': /* directory */
190  st->st_mode |= S_IFDIR;
191  st->st_nlink++;
192  break;
193  case '6': /* FIFO special */
194  st->st_mode |= S_IFIFO;
195  break;
196 #ifdef REFERENCE
197  case 'A': /* Solaris ACL */
198  case 'E': /* Solaris XATTR */
199  case 'I': /* Inode only, as in 'star' */
200  case 'X': /* POSIX 1003.1-2001 eXtended (VU version) */
201  case 'D': /* GNU dumpdir (with -G, --incremental) */
202  case 'M': /* GNU multivol (with -M, --multi-volume) */
203  case 'N': /* GNU names */
204  case 'S': /* GNU sparse (with -S, --sparse) */
205  case 'V': /* GNU tape/volume header (with -Vlll, --label=lll) */
206 #endif
207  case 'K': /* GNU long (>100 chars) link name */
208  rc = tarHeaderReadName(fsm, st->st_size, &fsm->lpath);
209  if (rc) return rc;
210  goto top;
211  /*@notreached@*/ break;
212  case 'L': /* GNU long (>100 chars) file name */
213  rc = tarHeaderReadName(fsm, st->st_size, &fsm->path);
214  if (rc) return rc;
215  goto top;
216  /*@notreached@*/ break;
217  }
218 
219  st->st_uid = strntoul(hdr->uid, NULL, 8, sizeof(hdr->uid));
220  st->st_gid = strntoul(hdr->gid, NULL, 8, sizeof(hdr->gid));
221  st->st_mtime = strntoul(hdr->mtime, NULL, 8, sizeof(hdr->mtime));
222  st->st_ctime = st->st_atime = st->st_mtime; /* XXX compat? */
223 
224  major = strntoul(hdr->devMajor, NULL, 8, sizeof(hdr->devMajor));
225  minor = strntoul(hdr->devMinor, NULL, 8, sizeof(hdr->devMinor));
226  /*@-shiftimplementation@*/
227  st->st_dev = makedev(major, minor);
228  /*@=shiftimplementation@*/
229  st->st_rdev = st->st_dev; /* XXX compat? */
230 
231  /* char prefix[155]; */
232  /* char padding[12]; */
233 
234  /* Read short file name. */
235  if (fsm->path == NULL && hdr->name[0] != '\0') {
236  nb = strlen(hdr->name);
237  t = xmalloc(nb + 1);
238 /*@-boundswrite@*/
239  memcpy(t, hdr->name, nb);
240  t[nb] = '\0';
241 /*@=boundswrite@*/
242  fsm->path = t;
243  }
244 
245  /* Read short link name. */
246  if (fsm->lpath == NULL && hdr->linkname[0] != '\0') {
247  nb = strlen(hdr->linkname);
248  t = xmalloc(nb + 1);
249 /*@-boundswrite@*/
250  memcpy(t, hdr->linkname, nb);
251  t[nb] = '\0';
252 /*@=boundswrite@*/
253  fsm->lpath = t;
254  }
255 
256 if (_tar_debug)
257 fprintf(stderr, "\t %06o%3d (%4d,%4d)%10d %s\n\t-> %s\n",
258  (unsigned)st->st_mode, (int)st->st_nlink,
259  (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
260  (fsm->path ? fsm->path : ""), (fsm->lpath ? fsm->lpath : ""));
261 
262  return rc;
263 }
264 
271 static int tarHeaderWriteName(FSM_t fsm, const char * path)
272  /*@globals h_errno, fileSystem, internalState @*/
273  /*@modifies fsm, fileSystem, internalState @*/
274 {
275  const char * s = path;
276  int nb = strlen(s);
277  int rc = 0;
278 
279 if (_tar_debug)
280 fprintf(stderr, "\t%s(%p, %s) nb %d\n", __FUNCTION__, fsm, path, nb);
281 
282  while (nb > 0) {
283  memset(fsm->rdbuf, 0, TAR_BLOCK_SIZE);
284 
285  /* XXX DWRITE uses rdnb for I/O length. */
286  fsm->rdnb = (nb < TAR_BLOCK_SIZE) ? nb : TAR_BLOCK_SIZE;
287  memmove(fsm->rdbuf, s, fsm->rdnb);
288  rc = fsmNext(fsm, FSM_DWRITE);
289  if (!rc && fsm->rdnb != fsm->wrnb)
291 
292  if (rc) break;
293  s += fsm->rdnb;
294  nb -= fsm->rdnb;
295  }
296 
297  if (!rc)
298  rc = fsmNext(fsm, FSM_PAD);
299 
300  return rc;
301 }
302 
310 static int tarHeaderWriteBlock(FSM_t fsm, struct stat * st, tarHeader hdr)
311  /*@globals h_errno, fileSystem, internalState @*/
312  /*@modifies fsm, hdr, fileSystem, internalState @*/
313 {
314  int rc;
315 
316 if (_tar_debug)
317 fprintf(stderr, "\t%s(%p, %p) type %c\n", __FUNCTION__, fsm, hdr, hdr->typeflag);
318 if (_tar_debug)
319 fprintf(stderr, "\t %06o%3d (%4d,%4d)%10d %s\n",
320  (unsigned)st->st_mode, (int)st->st_nlink,
321  (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
322  (fsm->path ? fsm->path : ""));
323 
324 
325  (void) stpcpy( stpcpy(hdr->magic, TAR_MAGIC), TAR_VERSION);
326 
327  /* Calculate header checksum. */
328  { const unsigned char * hp = (const unsigned char *) hdr;
329  long sum = 0;
330  int i;
331 
332  memset(hdr->checksum, ' ', sizeof(hdr->checksum));
333  for (i = 0; i < TAR_BLOCK_SIZE; i++)
334  sum += *hp++;
335  sprintf(hdr->checksum, "%06o", (unsigned)(sum & 07777777));
336 if (_tar_debug)
337 fprintf(stderr, "\thdrchksum \"%s\"\n", hdr->checksum);
338  }
339 
340  /* XXX DWRITE uses rdnb for I/O length. */
341  fsm->rdnb = TAR_BLOCK_SIZE;
342  rc = fsmNext(fsm, FSM_DWRITE);
343  if (!rc && fsm->rdnb != fsm->wrnb)
345 
346  return rc;
347 }
348 
349 int tarHeaderWrite(FSM_t fsm, struct stat * st)
350 {
351 /*@observer@*/
352  static const char * llname = "././@LongLink";
353  tarHeader hdr = (tarHeader) fsm->rdbuf;
354  char * t;
355  dev_t dev;
356  int rc = 0;
357  int len;
358 
359 if (_tar_debug)
360 fprintf(stderr, " %s(%p, %p)\n", __FUNCTION__, fsm, st);
361 
362  len = strlen(fsm->path);
363  if (len > sizeof(hdr->name)) {
364  memset(hdr, 0, sizeof(*hdr));
365  strcpy(hdr->name, llname);
366  sprintf(hdr->mode, "%07o", 0);
367  sprintf(hdr->uid, "%07o", 0);
368  sprintf(hdr->gid, "%07o", 0);
369  sprintf(hdr->filesize, "%011o", (unsigned) (len & 037777777777));
370  sprintf(hdr->mtime, "%011o", 0);
371  hdr->typeflag = 'L';
372  strncpy(hdr->uname, "root", sizeof(hdr->uname));
373  strncpy(hdr->gname, "root", sizeof(hdr->gname));
374  rc = tarHeaderWriteBlock(fsm, st, hdr);
375  if (rc) return rc;
376  rc = tarHeaderWriteName(fsm, fsm->path);
377  if (rc) return rc;
378  }
379 
380  if (fsm->lpath && fsm->lpath[0] != '0') {
381  len = strlen(fsm->lpath);
382  if (len > sizeof(hdr->name)) {
383  memset(hdr, 0, sizeof(*hdr));
384  strcpy(hdr->linkname, llname);
385  sprintf(hdr->mode, "%07o", 0);
386  sprintf(hdr->uid, "%07o", 0);
387  sprintf(hdr->gid, "%07o", 0);
388  sprintf(hdr->filesize, "%011o", (unsigned) (len & 037777777777));
389  sprintf(hdr->mtime, "%011o", 0);
390  hdr->typeflag = 'K';
391  strncpy(hdr->uname, "root", sizeof(hdr->uname));
392  strncpy(hdr->gname, "root", sizeof(hdr->gname));
393  rc = tarHeaderWriteBlock(fsm, st, hdr);
394  if (rc) return rc;
395  rc = tarHeaderWriteName(fsm, fsm->lpath);
396  if (rc) return rc;
397  }
398  }
399 
400  memset(hdr, 0, sizeof(*hdr));
401 
402  strncpy(hdr->name, fsm->path, sizeof(hdr->name));
403 
404  if (fsm->lpath && fsm->lpath[0] != '0')
405  strncpy(hdr->linkname, fsm->lpath, sizeof(hdr->linkname));
406 
407  sprintf(hdr->mode, "%07o", (st->st_mode & 00007777));
408  sprintf(hdr->uid, "%07o", (st->st_uid & 07777777));
409  sprintf(hdr->gid, "%07o", (st->st_gid & 07777777));
410 
411  sprintf(hdr->filesize, "%011o", (unsigned) (st->st_size & 037777777777));
412  sprintf(hdr->mtime, "%011o", (unsigned) (st->st_mtime & 037777777777));
413 
414  hdr->typeflag = '0'; /* XXX wrong! */
415  if (S_ISLNK(st->st_mode))
416  hdr->typeflag = '2';
417  else if (S_ISCHR(st->st_mode))
418  hdr->typeflag = '3';
419  else if (S_ISBLK(st->st_mode))
420  hdr->typeflag = '4';
421  else if (S_ISDIR(st->st_mode))
422  hdr->typeflag = '5';
423  else if (S_ISFIFO(st->st_mode))
424  hdr->typeflag = '6';
425 #ifdef WHAT2DO
426  else if (S_ISSOCK(st->st_mode))
427  hdr->typeflag = '?';
428 #endif
429  else if (S_ISREG(st->st_mode))
430  hdr->typeflag = (fsm->lpath != NULL ? '1' : '0');
431 
432  /* XXX FIXME: map uname/gname from uid/gid. */
433  t = uidToUname(st->st_uid);
434  if (t == NULL) t = "root";
435  strncpy(hdr->uname, t, sizeof(hdr->uname));
436  t = gidToGname(st->st_gid);
437  if (t == NULL) t = "root";
438  strncpy(hdr->gname, t, sizeof(hdr->gname));
439 
440  /* XXX W2DO? st_dev or st_rdev? */
441  dev = major((unsigned)st->st_dev);
442  sprintf(hdr->devMajor, "%07o", (unsigned) (dev & 07777777));
443  dev = minor((unsigned)st->st_dev);
444  sprintf(hdr->devMinor, "%07o", (unsigned) (dev & 07777777));
445 
446  rc = tarHeaderWriteBlock(fsm, st, hdr);
447 
448  /* XXX Padding is unnecessary but shouldn't hurt. */
449  if (!rc)
450  rc = fsmNext(fsm, FSM_PAD);
451 
452  return rc;
453 }
454 
456 {
457  int rc = 0;
458 
459 if (_tar_debug)
460 fprintf(stderr, " %s(%p)\n", __FUNCTION__, fsm);
461 
462  /* Pad up to 20 blocks (10Kb) of zeroes. */
463  fsm->blksize *= 20;
464  if (!rc)
465  rc = fsmNext(fsm, FSM_PAD);
466  fsm->blksize /= 20;
467 
468  return rc;
469 }