rpm 5.3.12
rpmio/cpio.c
Go to the documentation of this file.
00001 
00005 #undef  JBJ_WRITEPAD
00006 
00007 #include "system.h"
00008 
00009 #include <rpmio.h>
00010 #include <ugid.h>
00011 #include <cpio.h>
00012 #define _IOSM_INTERNAL
00013 #include <iosm.h>
00014 
00015 #include "debug.h"
00016 
00017 /*@access IOSM_t @*/
00018 
00019 /*@unchecked@*/
00020 int _cpio_debug = 0;
00021 
00030 static int strntoul(const char *str, /*@null@*/ /*@out@*/char **endptr,
00031                 int base, size_t num)
00032         /*@modifies *endptr @*/
00033         /*@requires maxSet(endptr) >= 0 @*/
00034 {
00035     char * buf, * end;
00036     unsigned long ret;
00037 
00038     buf = alloca(num + 1);
00039     strncpy(buf, str, num);
00040     buf[num] = '\0';
00041 
00042     ret = strtoul(buf, &end, base);
00043     if (endptr != NULL) {
00044         if (*end != '\0')
00045             *endptr = ((char *)str) + (end - buf);      /* XXX discards const */
00046         else
00047             *endptr = ((char *)str) + strlen(buf);
00048     }
00049 
00050     return ret;
00051 }
00052 
00053 /* Translate archive read/write ssize_t return for iosmStage(). */
00054 #define _IOSMRC(_rc)    \
00055         if ((_rc) <= 0) return ((_rc) ? (int) -rc : IOSMERR_HDR_TRAILER)
00056 
00057 static ssize_t cpioRead(void * _iosm, void * buf, size_t count)
00058         /*@globals fileSystem @*/
00059         /*@modifies _iosm, *buf, fileSystem @*/
00060 {
00061     IOSM_t iosm = _iosm;
00062     char * t = buf;
00063     size_t nb = 0;
00064     size_t rc;
00065 
00066 if (_cpio_debug)
00067 fprintf(stderr, "          cpioRead(%p, %p[%u])\n", iosm, buf, (unsigned)count);
00068 
00069     while (count > 0) {
00070 
00071         /* Read next cpio block. */
00072         iosm->wrlen = count;
00073         rc = _iosmNext(iosm, IOSM_DREAD);
00074         if (!rc && iosm->rdnb != iosm->wrlen)
00075             rc = IOSMERR_READ_FAILED;
00076         if (rc) return -rc;
00077 
00078         /* Append to buffer. */
00079         rc = (count > iosm->rdnb ? iosm->rdnb : count);
00080         if (buf != iosm->wrbuf)
00081              memcpy(t + nb, iosm->wrbuf, rc);
00082         nb += rc;
00083         count -= rc;
00084     }
00085     return nb;
00086 }
00087 
00088 #define GET_NUM_FIELD(phys, log) \
00089         log = strntoul(phys, &end, 16, sizeof(phys)); \
00090         if ( (end - phys) != sizeof(phys) ) return IOSMERR_BAD_HEADER;
00091 #define SET_NUM_FIELD(phys, val, space) \
00092         sprintf(space, "%8.8lx", (unsigned long) (val)); \
00093         memcpy(phys, space, 8)
00094 
00095 int cpioHeaderRead(void * _iosm, struct stat * st)
00096 {
00097     IOSM_t iosm = _iosm;
00098     cpioHeader hdr = (cpioHeader) iosm->wrbuf;
00099     size_t nb;
00100     char * end;
00101     int major, minor;
00102     ssize_t rc = 0;
00103 
00104 if (_cpio_debug)
00105 fprintf(stderr, "    cpioHeaderRead(%p, %p)\n", iosm, st);
00106 
00107     /* Read next header. */
00108     rc = cpioRead(iosm, hdr, PHYS_HDR_SIZE);
00109     _IOSMRC(rc);
00110 
00111     /* Verify header magic. */
00112     if (strncmp(CPIO_CRC_MAGIC, hdr->magic, sizeof(CPIO_CRC_MAGIC)-1) &&
00113         strncmp(CPIO_NEWC_MAGIC, hdr->magic, sizeof(CPIO_NEWC_MAGIC)-1))
00114         return IOSMERR_BAD_MAGIC;
00115 
00116     /* Convert header to stat(2). */
00117     GET_NUM_FIELD(hdr->inode, st->st_ino);
00118     GET_NUM_FIELD(hdr->mode, st->st_mode);
00119     GET_NUM_FIELD(hdr->uid, st->st_uid);
00120     GET_NUM_FIELD(hdr->gid, st->st_gid);
00121     GET_NUM_FIELD(hdr->nlink, st->st_nlink);
00122     GET_NUM_FIELD(hdr->mtime, st->st_mtime);
00123     GET_NUM_FIELD(hdr->filesize, st->st_size);
00124 
00125     GET_NUM_FIELD(hdr->devMajor, major);
00126     GET_NUM_FIELD(hdr->devMinor, minor);
00127     /*@-shiftimplementation@*/
00128     st->st_dev = Makedev(major, minor);
00129     /*@=shiftimplementation@*/
00130 
00131     GET_NUM_FIELD(hdr->rdevMajor, major);
00132     GET_NUM_FIELD(hdr->rdevMinor, minor);
00133     /*@-shiftimplementation@*/
00134     st->st_rdev = Makedev(major, minor);
00135     /*@=shiftimplementation@*/
00136 
00137     GET_NUM_FIELD(hdr->namesize, nb);
00138     if (nb >= iosm->wrsize)
00139         return IOSMERR_BAD_HEADER;
00140 
00141     /* Read file name. */
00142     {   char * t = xmalloc(nb + 1);
00143         rc = cpioRead(iosm, t, nb);
00144         if (rc < 0) {
00145             t = _free(t);
00146             iosm->path = NULL;
00147         } else {
00148             _IOSMRC(rc);
00149             t[nb] = '\0';
00150             iosm->path = t;
00151         }
00152     }
00153 
00154     /* Read link name. */
00155     if (S_ISLNK(st->st_mode)) {
00156         char * t;
00157 
00158         /* Make sure block aligned. */
00159         rc = _iosmNext(iosm, IOSM_POS);
00160         if (rc) return (int) -rc;
00161 
00162         nb = (size_t) st->st_size;
00163         t = xmalloc(nb + 1);
00164         rc = cpioRead(iosm, t, nb);
00165         if (rc < 0) {
00166             t = _free(t);
00167             iosm->lpath = NULL;
00168         } else {
00169             _IOSMRC(rc);
00170             t[nb] = '\0';
00171             iosm->lpath = t;
00172         }
00173     }
00174 
00175     rc = 0;
00176 
00177 /*@-usereleased@*/
00178 if (_cpio_debug)
00179 fprintf(stderr, "\t     %06o%3d (%4d,%4d)%12lu %s\n\t-> %s\n",
00180                 (unsigned)st->st_mode, (int)st->st_nlink,
00181                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
00182                 (iosm->path ? iosm->path : ""), (iosm->lpath ? iosm->lpath : ""));
00183 /*@=usereleased@*/
00184 
00185     return (int) rc;
00186 }
00187 
00188 static ssize_t cpioWrite(void * _iosm, const void *buf, size_t count)
00189         /*@globals fileSystem @*/
00190         /*@modifies _iosm, fileSystem @*/
00191 {
00192     IOSM_t iosm = _iosm;
00193     const char * s = buf;
00194     size_t nb = 0;
00195     size_t rc;
00196 
00197 if (_cpio_debug)
00198 fprintf(stderr, "\t  cpioWrite(%p, %p[%u])\n", iosm, buf, (unsigned)count);
00199 
00200     while (count > 0) {
00201 
00202         /* XXX DWRITE uses rdnb for I/O length. */
00203         iosm->rdnb = count;
00204         if (s != iosm->rdbuf)
00205             memmove(iosm->rdbuf, s + nb, iosm->rdnb);
00206 
00207         rc = _iosmNext(iosm, IOSM_DWRITE);
00208         if (!rc && iosm->rdnb != iosm->wrnb)
00209                 rc = IOSMERR_WRITE_FAILED;
00210         if (rc) return -rc;
00211 
00212         nb += iosm->rdnb;
00213         count -= iosm->rdnb;
00214     }
00215 
00216 #if defined(JBJ_WRITEPAD)
00217     /* Pad to next block boundary. */
00218     if ((rc = _iosmNext(iosm, IOSM_PAD)) != 0) return -rc;
00219 #endif
00220 
00221     return nb;
00222 }
00223 
00224 int cpioHeaderWrite(void * _iosm, struct stat * st)
00225 {
00226     IOSM_t iosm = _iosm;
00227     cpioHeader hdr = (cpioHeader) iosm->rdbuf;
00228     const char * path = (iosm && iosm->path ? iosm->path : "");
00229     const char * lpath = (iosm && iosm->lpath ? iosm->lpath : "");
00230     char field[64];
00231     size_t nb;
00232     dev_t dev;
00233     ssize_t rc = 0;
00234 
00235 if (_cpio_debug)
00236 fprintf(stderr, "    cpioHeaderWrite(%p, %p)\n", iosm, st);
00237 
00238     memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
00239     SET_NUM_FIELD(hdr->inode, st->st_ino, field);
00240     SET_NUM_FIELD(hdr->mode, st->st_mode, field);
00241     SET_NUM_FIELD(hdr->uid, st->st_uid, field);
00242     SET_NUM_FIELD(hdr->gid, st->st_gid, field);
00243     SET_NUM_FIELD(hdr->nlink, st->st_nlink, field);
00244     SET_NUM_FIELD(hdr->mtime, st->st_mtime, field);
00245     SET_NUM_FIELD(hdr->filesize, st->st_size, field);
00246 
00247     dev = major((unsigned)st->st_dev); SET_NUM_FIELD(hdr->devMajor, dev, field);
00248     dev = minor((unsigned)st->st_dev); SET_NUM_FIELD(hdr->devMinor, dev, field);
00249     dev = major((unsigned)st->st_rdev); SET_NUM_FIELD(hdr->rdevMajor, dev, field);
00250     dev = minor((unsigned)st->st_rdev); SET_NUM_FIELD(hdr->rdevMinor, dev, field);
00251 
00252     nb = strlen(path) + 1; SET_NUM_FIELD(hdr->namesize, nb, field);
00253     memcpy(hdr->checksum, "00000000", 8);
00254 
00255     /* XXX Coalesce hdr+name into single I/O. */
00256     memcpy(iosm->rdbuf + PHYS_HDR_SIZE, path, nb);
00257     nb += PHYS_HDR_SIZE;
00258     rc = cpioWrite(iosm, hdr, nb);
00259     _IOSMRC(rc);
00260 
00261     if (S_ISLNK(st->st_mode)) {
00262 #if !defined(JBJ_WRITEPAD)
00263         rc = _iosmNext(iosm, IOSM_PAD);
00264         if (rc) return (int) rc;
00265 #endif
00266 
00267         nb = strlen(lpath);
00268         rc = cpioWrite(iosm, lpath, nb);
00269         _IOSMRC(rc);
00270     }
00271 
00272 #if !defined(JBJ_WRITEPAD)
00273     rc = _iosmNext(iosm, IOSM_PAD);
00274 #endif
00275 
00276     return (int) rc;
00277 }
00278 
00279 int cpioTrailerWrite(void * _iosm)
00280 {
00281     IOSM_t iosm = _iosm;
00282     cpioHeader hdr = (cpioHeader) iosm->rdbuf;
00283     size_t nb;
00284     ssize_t rc = 0;
00285 
00286 if (_cpio_debug)
00287 fprintf(stderr, "   cpioTrailerWrite(%p)\n", iosm);
00288 
00289     memset(hdr, (int)'0', PHYS_HDR_SIZE);
00290     memcpy(hdr->magic, CPIO_NEWC_MAGIC, sizeof(hdr->magic));
00291     memcpy(hdr->nlink, "00000001", 8);
00292     memcpy(hdr->namesize, "0000000b", 8);
00293 
00294     nb = sizeof(CPIO_TRAILER);
00295     /* XXX Coalesce hdr+trailer into single I/O. */
00296     memcpy(iosm->rdbuf + PHYS_HDR_SIZE, CPIO_TRAILER, nb);
00297     nb += PHYS_HDR_SIZE;
00298 
00299     rc = cpioWrite(iosm, hdr, nb);
00300     _IOSMRC(rc);
00301 
00302     /*
00303      * GNU cpio pads to 512 bytes here, but we don't. This may matter for
00304      * tape device(s) and/or concatenated cpio archives. <shrug>
00305      */
00306 #if !defined(JBJ_WRITEPAD)
00307     rc = _iosmNext(iosm, IOSM_PAD);
00308 #endif
00309     rc = 0;
00310 
00311     return (int) rc;
00312 }
00313