rpm 5.2.1

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

- File List
- Globals

rpmio/tar.c
Go to the documentation of this file.

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