lib/tar.c

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

Generated on Fri Aug 31 10:38:33 2007 for rpm by  doxygen 1.5.1