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

# lib/tar.c

Go to the documentation of this file.

    00001
    00006 #include "system.h"
    00007
    00008 #include <rpmio.h>
    00009 #include <rpmlib.h>
    00010
    00011 #include "tar.h"
    00012 #include "fsm.h"
    00013 #include "ugid.h"
    00014
    00015 #include "debug.h"
    00016
    00017 /*@access FSM_t @*/
    00018
    00019 /*@unchecked@*/
    00020 int _tar_debug = 0;
    00021
    00022 /*@unchecked@*/
    00023 static int nochksum = 0;
    00024
    00033 static int strntoul(const char *str, /*@out@*/char **endptr, int base, int num)
    00034         /*@modifies *endptr @*/
    00035         /*@requires maxSet(endptr) >= 0 @*/
    00036 {
    00037     char * buf, * end;
    00038     unsigned long ret;
    00039
    00040     buf = alloca(num + 1);
    00041     strncpy(buf, str, num);
    00042     buf[num] = '\0';
    00043
    00044     ret = strtoul(buf, &end, base);
    00045     if (endptr != NULL) {
    00046         if (*end != '\0')
    00047             *endptr = ((char *)str) + (end - buf);      /* XXX discards const */
    00048         else
    00049             *endptr = ((char *)str) + strlen(buf);
    00050     }
    00051
    00052     return ret;
    00053 }
    00054
    00062 static int tarHeaderReadName(FSM_t fsm, int len, /*@out@*/ const char ** fnp)
    00063         /*@globals h_errno, fileSystem, internalState @*/
    00064         /*@modifies fsm, *fnp, fileSystem, internalState @*/
    00065 {
    00066     char * t;
    00067     int nb;
    00068     int rc = 0;
    00069
    00070     *fnp = t = xmalloc(len + 1);
    00071     while (len > 0) {
    00072         /* Read next tar block. */
    00073         fsm->wrlen = TAR_BLOCK_SIZE;
    00074         rc = fsmNext(fsm, FSM_DREAD);
    00075         if (!rc && fsm->rdnb != fsm->wrlen)
    00076                 rc = CPIOERR_READ_FAILED;
    00077         if (rc) break;
    00078
    00079         /* Append to name. */
    00080         nb = (len > fsm->rdnb ? fsm->rdnb : len);
    00081         memcpy(t, fsm->wrbuf, nb);
    00082         t += nb;
    00083         len -= nb;
    00084     }
    00085     *t = '\0';
    00086
    00087     if (rc)
    00088         *fnp = _free(*fnp);
    00089     return rc;
    00090 }
    00091
    00092 int tarHeaderRead(FSM_t fsm, struct stat * st)
    00093         /*@modifies fsm, *st @*/
    00094 {
    00095     tarHeader hdr = (tarHeader) fsm->wrbuf;
    00096     char * t;
    00097     int nb;
    00098     int major, minor;
    00099     int rc = 0;
    00100     int zblk = 0;
    00101
    00102 if (_tar_debug)
    00103 fprintf(stderr, "    tarHeaderRead(%p, %p)\n", fsm, st);
    00104
    00105 top:
    00106     do {
    00107         /* Read next tar block. */
    00108         fsm->wrlen = TAR_BLOCK_SIZE;
    00109         rc = fsmNext(fsm, FSM_DREAD);
    00110         if (!rc && fsm->rdnb != fsm->wrlen)
    00111             rc = CPIOERR_READ_FAILED;
    00112         if (rc) return rc;
    00113
    00114         /* Look for end-of-archive, i.e. 2 (or more) zero blocks. */
    00115         if (hdr->name[0] == '\0' && hdr->checksum[0] == '\0') {
    00116             if (++zblk == 2)
    00117                 return CPIOERR_HDR_TRAILER;
    00118         }
    00119     } while (zblk > 0);
    00120
    00121     /* Verify header checksum. */
    00122     {   const unsigned char * hp = (const unsigned char *) hdr;
    00123         char checksum[8];
    00124         char hdrchecksum[8];
    00125         long sum = 0;
    00126         int i;
    00127
    00128         memcpy(hdrchecksum, hdr->checksum, sizeof(hdrchecksum));
    00129         memset(hdr->checksum, ' ', sizeof(hdr->checksum));
    00130
    00131         for (i = 0; i < TAR_BLOCK_SIZE; i++)
    00132             sum += *hp++;
    00133
    00134 #if 0
    00135         for (i = 0; i < sizeof(hdr->checksum) - 1; i++)
    00136             sum += (' ' - hdr->checksum[i]);
    00137 fprintf(stderr, "\tsum %ld\n", sum);
    00138         if (sum != 0)
    00139             return CPIOERR_BAD_HEADER;
    00140 #else
    00141         memset(checksum, ' ', sizeof(checksum));
    00142         sprintf(checksum, "%06o", (unsigned) (sum & 07777777));
    00143 if (_tar_debug)
    00144 fprintf(stderr, "\tmemcmp(\"%s\", \"%s\", %u)\n", hdrchecksum, checksum, (unsigned)sizeof(hdrchecksum));
    00145         if (memcmp(hdrchecksum, checksum, sizeof(hdrchecksum)))
    00146             if (!nochksum)
    00147                 return CPIOERR_BAD_HEADER;
    00148 #endif
    00149
    00150     }
    00151
    00152     /* Verify header magic. */
    00153     if (strncmp(hdr->magic, TAR_MAGIC, sizeof(TAR_MAGIC)-1))
    00154         return CPIOERR_BAD_MAGIC;
    00155
    00156     st->st_size = strntoul(hdr->filesize, NULL, 8, sizeof(hdr->filesize));
    00157
    00158     st->st_nlink = 1;
    00159     st->st_mode = strntoul(hdr->mode, NULL, 8, sizeof(hdr->mode));
    00160     st->st_mode &= ~S_IFMT;
    00161     switch (hdr->typeflag) {
    00162     case 'x':           /* Extended header referring to next file in archive. */
    00163     case 'g':           /* Global extended header. */
    00164     default:
    00165         break;
    00166     case '7':           /* reserved (contiguous files?) */
    00167     case '\0':          /* (ancient) regular file */
    00168     case '0':           /* regular file */
    00169         st->st_mode |= S_IFREG;
    00170         break;
    00171     case '1':           /* hard link */
    00172         st->st_mode |= S_IFREG;
    00173 #ifdef DYING
    00174         st->st_nlink++;
    00175 #endif
    00176         break;
    00177     case '2':           /* symbolic link */
    00178         st->st_mode |= S_IFLNK;
    00179         break;
    00180     case '3':           /* character special */
    00181         st->st_mode |= S_IFCHR;
    00182         break;
    00183     case '4':           /* block special */
    00184         st->st_mode |= S_IFBLK;
    00185         break;
    00186     case '5':           /* directory */
    00187         st->st_mode |= S_IFDIR;
    00188         st->st_nlink++;
    00189         break;
    00190     case '6':           /* FIFO special */
    00191         st->st_mode |= S_IFIFO;
    00192         break;
    00193 #ifdef  REFERENCE
    00194     case 'A':           /* Solaris ACL */
    00195     case 'E':           /* Solaris XATTR */
    00196     case 'I':           /* Inode only, as in 'star' */
    00197     case 'X':           /* POSIX 1003.1-2001 eXtended (VU version) */
    00198     case 'D':           /* GNU dumpdir (with -G, --incremental) */
    00199     case 'M':           /* GNU multivol (with -M, --multi-volume) */
    00200     case 'N':           /* GNU names */
    00201     case 'S':           /* GNU sparse  (with -S, --sparse) */
    00202     case 'V':           /* GNU tape/volume header (with -Vlll, --label=lll) */
    00203 #endif
    00204     case 'K':           /* GNU long (>100 chars) link name */
    00205         rc = tarHeaderReadName(fsm, st->st_size, &fsm->lpath);
    00206         if (rc) return rc;
    00207         goto top;
    00208         /*@notreached@*/ break;
    00209     case 'L':           /* GNU long (>100 chars) file name */
    00210         rc = tarHeaderReadName(fsm, st->st_size, &fsm->path);
    00211         if (rc) return rc;
    00212         goto top;
    00213         /*@notreached@*/ break;
    00214     }
    00215
    00216     st->st_uid = strntoul(hdr->uid, NULL, 8, sizeof(hdr->uid));
    00217     st->st_gid = strntoul(hdr->gid, NULL, 8, sizeof(hdr->gid));
    00218     st->st_mtime = strntoul(hdr->mtime, NULL, 8, sizeof(hdr->mtime));
    00219     st->st_ctime = st->st_atime = st->st_mtime;         /* XXX compat? */
    00220
    00221     major = strntoul(hdr->devMajor, NULL, 8, sizeof(hdr->devMajor));
    00222     minor = strntoul(hdr->devMinor, NULL, 8, sizeof(hdr->devMinor));
    00223     /*@-shiftimplementation@*/
    00224     st->st_dev = Makedev(major, minor);
    00225     /*@=shiftimplementation@*/
    00226     st->st_rdev = st->st_dev;           /* XXX compat? */
    00227
    00228     /* char prefix[155]; */
    00229     /* char padding[12]; */
    00230
    00231     /* Read short file name. */
    00232     if (fsm->path == NULL && hdr->name[0] != '\0') {
    00233         nb = strlen(hdr->name);
    00234         t = xmalloc(nb + 1);
    00235         memcpy(t, hdr->name, nb);
    00236         t[nb] = '\0';
    00237         fsm->path = t;
    00238     }
    00239
    00240     /* Read short link name. */
    00241     if (fsm->lpath == NULL && hdr->linkname[0] != '\0') {
    00242         nb = strlen(hdr->linkname);
    00243         t = xmalloc(nb + 1);
    00244         memcpy(t, hdr->linkname, nb);
    00245         t[nb] = '\0';
    00246         fsm->lpath = t;
    00247     }
    00248
    00249 if (_tar_debug)
    00250 fprintf(stderr, "\t     %06o%3d (%4d,%4d)%10d %s\n\t-> %s\n",
    00251                 (unsigned)st->st_mode, (int)st->st_nlink,
    00252                 (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
    00253                 (fsm->path ? fsm->path : ""), (fsm->lpath ? fsm->lpath : ""));
    00254
    00255     return rc;
    00256 }
    00257
    00264 static int tarHeaderWriteName(FSM_t fsm, const char * path)
    00265         /*@globals h_errno, fileSystem, internalState @*/
    00266         /*@modifies fsm, fileSystem, internalState @*/
    00267 {
    00268     const char * s = path;
    00269     int nb = strlen(s);
    00270     int rc = 0;
    00271
    00272 if (_tar_debug)
    00273 fprintf(stderr, "\ttarHeaderWriteName(%p, %s) nb %d\n", fsm, path, nb);
    00274
    00275     while (nb > 0) {
    00276         memset(fsm->rdbuf, 0, TAR_BLOCK_SIZE);
    00277
    00278         /* XXX DWRITE uses rdnb for I/O length. */
    00279         fsm->rdnb = (nb < TAR_BLOCK_SIZE) ? nb : TAR_BLOCK_SIZE;
    00280         memmove(fsm->rdbuf, s, fsm->rdnb);
    00281         rc = fsmNext(fsm, FSM_DWRITE);
    00282         if (!rc && fsm->rdnb != fsm->wrnb)
    00283                 rc = CPIOERR_WRITE_FAILED;
    00284
    00285         if (rc) break;
    00286         s += fsm->rdnb;
    00287         nb -= fsm->rdnb;
    00288     }
    00289
    00290     if (!rc)
    00291         rc = fsmNext(fsm, FSM_PAD);
    00292
    00293     return rc;
    00294 }
    00295
    00303 static int tarHeaderWriteBlock(FSM_t fsm, struct stat * st, tarHeader hdr)
    00304         /*@globals h_errno, fileSystem, internalState @*/
    00305         /*@modifies fsm, hdr, fileSystem, internalState @*/
    00306 {
    00307     int rc;
    00308
    00309 if (_tar_debug)
    00310 fprintf(stderr, "\ttarHeaderWriteBlock(%p, %p) type %c\n", fsm, hdr, hdr->typeflag);
    00311 if (_tar_debug)
    00312 fprintf(stderr, "\t     %06o%3d (%4d,%4d)%10d %s\n",
    00313                 (unsigned)st->st_mode, (int)st->st_nlink,
    00314                 (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
    00315                 (fsm->path ? fsm->path : ""));
    00316
    00317
    00318     (void) stpcpy( stpcpy(hdr->magic, TAR_MAGIC), TAR_VERSION);
    00319
    00320     /* Calculate header checksum. */
    00321     {   const unsigned char * hp = (const unsigned char *) hdr;
    00322         long sum = 0;
    00323         int i;
    00324
    00325         memset(hdr->checksum, ' ', sizeof(hdr->checksum));
    00326         for (i = 0; i < TAR_BLOCK_SIZE; i++)
    00327             sum += *hp++;
    00328         sprintf(hdr->checksum, "%06o", (unsigned)(sum & 07777777));
    00329 if (_tar_debug)
    00330 fprintf(stderr, "\thdrchksum \"%s\"\n", hdr->checksum);
    00331     }
    00332
    00333     /* XXX DWRITE uses rdnb for I/O length. */
    00334     fsm->rdnb = TAR_BLOCK_SIZE;
    00335     rc = fsmNext(fsm, FSM_DWRITE);
    00336     if (!rc && fsm->rdnb != fsm->wrnb)
    00337         rc = CPIOERR_WRITE_FAILED;
    00338
    00339     return rc;
    00340 }
    00341
    00342 int tarHeaderWrite(FSM_t fsm, struct stat * st)
    00343 {
    00344 /*@observer@*/
    00345     static const char * llname = "././@LongLink";
    00346     tarHeader hdr = (tarHeader) fsm->rdbuf;
    00347     char * t;
    00348     dev_t dev;
    00349     int rc = 0;
    00350     int len;
    00351
    00352 if (_tar_debug)
    00353 fprintf(stderr, "    tarHeaderWrite(%p, %p)\n", fsm, st);
    00354
    00355     len = strlen(fsm->path);
    00356     if (len > sizeof(hdr->name)) {
    00357         memset(hdr, 0, sizeof(*hdr));
    00358         strcpy(hdr->name, llname);
    00359         sprintf(hdr->mode, "%07o", 0);
    00360         sprintf(hdr->uid, "%07o", 0);
    00361         sprintf(hdr->gid, "%07o", 0);
    00362         sprintf(hdr->filesize, "%011o", (unsigned) (len & 037777777777));
    00363         sprintf(hdr->mtime, "%011o", 0);
    00364         hdr->typeflag = 'L';
    00365         strncpy(hdr->uname, "root", sizeof(hdr->uname));
    00366         strncpy(hdr->gname, "root", sizeof(hdr->gname));
    00367         rc = tarHeaderWriteBlock(fsm, st, hdr);
    00368         if (rc) return rc;
    00369         rc = tarHeaderWriteName(fsm, fsm->path);
    00370         if (rc) return rc;
    00371     }
    00372
    00373     if (fsm->lpath && fsm->lpath[0] != '0') {
    00374         len = strlen(fsm->lpath);
    00375         if (len > sizeof(hdr->name)) {
    00376             memset(hdr, 0, sizeof(*hdr));
    00377             strcpy(hdr->linkname, llname);
    00378         sprintf(hdr->mode, "%07o", 0);
    00379         sprintf(hdr->uid, "%07o", 0);
    00380         sprintf(hdr->gid, "%07o", 0);
    00381             sprintf(hdr->filesize, "%011o", (unsigned) (len & 037777777777));
    00382         sprintf(hdr->mtime, "%011o", 0);
    00383             hdr->typeflag = 'K';
    00384         strncpy(hdr->uname, "root", sizeof(hdr->uname));
    00385         strncpy(hdr->gname, "root", sizeof(hdr->gname));
    00386             rc = tarHeaderWriteBlock(fsm, st, hdr);
    00387             if (rc) return rc;
    00388             rc = tarHeaderWriteName(fsm, fsm->lpath);
    00389             if (rc) return rc;
    00390         }
    00391     }
    00392
    00393     memset(hdr, 0, sizeof(*hdr));
    00394
    00395     strncpy(hdr->name, fsm->path, sizeof(hdr->name));
    00396
    00397     if (fsm->lpath && fsm->lpath[0] != '0')
    00398         strncpy(hdr->linkname, fsm->lpath, sizeof(hdr->linkname));
    00399
    00400     sprintf(hdr->mode, "%07o", (unsigned int)(st->st_mode & 00007777));
    00401     sprintf(hdr->uid, "%07o", (unsigned int)(st->st_uid & 07777777));
    00402     sprintf(hdr->gid, "%07o", (unsigned int)(st->st_gid & 07777777));
    00403
    00404     sprintf(hdr->filesize, "%011o", (unsigned) (st->st_size & 037777777777));
    00405     sprintf(hdr->mtime, "%011o", (unsigned) (st->st_mtime & 037777777777));
    00406
    00407     hdr->typeflag = '0';        /* XXX wrong! */
    00408     if (S_ISLNK(st->st_mode))
    00409         hdr->typeflag = '2';
    00410     else if (S_ISCHR(st->st_mode))
    00411         hdr->typeflag = '3';
    00412     else if (S_ISBLK(st->st_mode))
    00413         hdr->typeflag = '4';
    00414     else if (S_ISDIR(st->st_mode))
    00415         hdr->typeflag = '5';
    00416     else if (S_ISFIFO(st->st_mode))
    00417         hdr->typeflag = '6';
    00418 #ifdef WHAT2DO
    00419     else if (S_ISSOCK(st->st_mode))
    00420         hdr->typeflag = '?';
    00421 #endif
    00422     else if (S_ISREG(st->st_mode))
    00423         hdr->typeflag = (fsm->lpath != NULL ? '1' : '0');
    00424
    00425     /* XXX FIXME: map uname/gname from uid/gid. */
    00426     t = uidToUname(st->st_uid);
    00427     if (t == NULL) t = "root";
    00428     strncpy(hdr->uname, t, sizeof(hdr->uname));
    00429     t = gidToGname(st->st_gid);
    00430     if (t == NULL) t = "root";
    00431     strncpy(hdr->gname, t, sizeof(hdr->gname));
    00432
    00433     /* XXX W2DO? st_dev or st_rdev? */
    00434     dev = major((unsigned)st->st_dev);
    00435     sprintf(hdr->devMajor, "%07o", (unsigned) (dev & 07777777));
    00436     dev = minor((unsigned)st->st_dev);
    00437     sprintf(hdr->devMinor, "%07o", (unsigned) (dev & 07777777));
    00438
    00439     rc = tarHeaderWriteBlock(fsm, st, hdr);
    00440
    00441     /* XXX Padding is unnecessary but shouldn't hurt. */
    00442     if (!rc)
    00443         rc = fsmNext(fsm, FSM_PAD);
    00444
    00445     return rc;
    00446 }
    00447
    00448 int tarTrailerWrite(FSM_t fsm)
    00449 {
    00450     int rc = 0;
    00451
    00452 if (_tar_debug)
    00453 fprintf(stderr, "    tarTrailerWrite(%p)\n", fsm);
    00454
    00455     /* Pad up to 20 blocks (10Kb) of zeroes. */
    00456     fsm->blksize *= 20;
    00457     if (!rc)
    00458         rc = fsmNext(fsm, FSM_PAD);
    00459     fsm->blksize /= 20;
    00460
    00461     return rc;
    00462 }