• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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 }

Generated on Mon Nov 29 2010 05:18:45 for rpm by  doxygen 1.7.2