rpm 5.3.12
rpmio/ar.c
Go to the documentation of this file.
00001 
00006 #undef  JBJ_WRITEPAD
00007 
00008 #include "system.h"
00009 
00010 #include <rpmio_internal.h>     /* XXX fdGetCpioPos writing AR_MAGIC */
00011 
00012 #include <rpmmacro.h>
00013 #include <ugid.h>
00014 #include <ar.h>
00015 #define _IOSM_INTERNAL
00016 #include <iosm.h>
00017 
00018 #include "debug.h"
00019 
00020 /*@access IOSM_t @*/
00021 
00022 /*@unchecked@*/
00023 int _ar_debug = 0;
00024 
00033 static int strntoul(const char *str, /*@null@*/ /*@out@*/char **endptr,
00034                 int base, size_t num)
00035         /*@modifies *endptr @*/
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 
00055 /* Translate archive read/write ssize_t return for iosmStage(). */
00056 #define _IOSMRC(_rc)    \
00057         if ((_rc) <= 0) return ((_rc) ? (int) -rc : IOSMERR_HDR_TRAILER)
00058 
00059 static ssize_t arRead(void * _iosm, void * buf, size_t count)
00060         /*@globals fileSystem @*/
00061         /*@modifies _iosm, *buf, fileSystem @*/
00062 {
00063     IOSM_t iosm = _iosm;
00064     char * t = buf;
00065     size_t nb = 0;
00066     size_t rc;
00067 
00068 if (_ar_debug)
00069 fprintf(stderr, "\t  arRead(%p, %p[%u])\n", iosm, buf, (unsigned)count);
00070 
00071     while (count > 0) {
00072 
00073         /* Read next ar block. */
00074         iosm->wrlen = count;
00075         rc = _iosmNext(iosm, IOSM_DREAD);
00076         if (!rc && iosm->rdnb != iosm->wrlen) {
00077             if (iosm->rdnb == 0) return -IOSMERR_HDR_TRAILER;   /* EOF */
00078             rc = IOSMERR_READ_FAILED;
00079         }
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 
00092 int arHeaderRead(void * _iosm, struct stat * st)
00093         /*@modifies _iosm, *st @*/
00094 {
00095     IOSM_t iosm = _iosm;
00096     arHeader hdr = (arHeader) iosm->wrbuf;
00097     ssize_t rc = 0;
00098 
00099 if (_ar_debug)
00100 fprintf(stderr, "    arHeaderRead(%p, %p)\n", iosm, st);
00101 
00102     /* XXX Read AR_MAGIC to beginning of ar(1) archive. */
00103     if (fdGetCpioPos(iosm->cfd) == 0) {
00104         rc = arRead(iosm, iosm->wrbuf, sizeof(AR_MAGIC)-1);
00105         _IOSMRC(rc);
00106 
00107         /* Verify archive magic. */
00108         if (strncmp(iosm->wrbuf, AR_MAGIC, sizeof(AR_MAGIC)-1))
00109             return IOSMERR_BAD_MAGIC;
00110     }
00111 
00112 top:
00113     /* Make sure block aligned. */
00114     rc = _iosmNext(iosm, IOSM_POS);
00115     if (rc) return (int) rc;
00116 
00117     rc = arRead(iosm, hdr, sizeof(*hdr));
00118     _IOSMRC(rc);
00119 if (_ar_debug)
00120 fprintf(stderr, "==> %p[%u] \"%.*s\"\n", hdr, (unsigned)rc, (int)sizeof(*hdr)-2, (char *)hdr);
00121 
00122     /* Verify header marker. */
00123     if (strncmp(hdr->marker, AR_MARKER, sizeof(AR_MARKER)-1))
00124         return IOSMERR_BAD_MAGIC;
00125 
00126     st->st_size = strntoul(hdr->filesize, NULL, 10, sizeof(hdr->filesize));
00127 
00128     /* Special ar(1) archive members. */
00129     if (hdr->name[0] == '/') {
00130         /* GNU: on "//":        Read long member name string table. */
00131         if (hdr->name[1] == '/' && hdr->name[2] == ' ') {
00132             char * t;
00133             size_t i;
00134 
00135             rc = arRead(iosm, iosm->wrbuf, st->st_size);
00136             _IOSMRC(rc);
00137 
00138             iosm->wrbuf[rc] = '\0';
00139             iosm->lmtab = t = xstrdup(iosm->wrbuf);
00140             iosm->lmtablen = rc;
00141             iosm->lmtaboff = 0;
00142 
00143             for (i = 1; i < iosm->lmtablen; i++) {
00144                 t++;
00145                 if (t[0] != '\n') continue;
00146                 t[0] = '\0';
00147                 /* GNU: trailing '/' to permit file names with trailing ' '. */
00148                 if (t[-1] == '/') t[-1] = '\0';
00149             }
00150             goto top;
00151         }
00152         /* GNU: on "/": Skip symbol table. */
00153         if (hdr->name[1] == ' ') {
00154             rc = arRead(iosm, iosm->wrbuf, st->st_size);
00155             _IOSMRC(rc);
00156             goto top;
00157         }
00158         /* GNU: on "/123": Read "123" offset to substitute long member name. */
00159         if (xisdigit((int)hdr->name[1])) {
00160             char * te = NULL;
00161             int i = strntoul(&hdr->name[1], &te, 10, sizeof(hdr->name)-2);
00162             if (*te == ' ' && iosm->lmtab != NULL && i < (int)iosm->lmtablen)
00163                 iosm->path = xstrdup(iosm->lmtab + i);
00164         }
00165     } else
00166     if (hdr->name[0] != ' ') {  /* Short member name. */
00167         size_t nb = sizeof(hdr->name);
00168         char t[sizeof(hdr->name)+1];
00169         memcpy(t, hdr->name, nb);
00170         t[nb] = '\0';
00171         while (nb > 0 && t[nb-1] == ' ')
00172             t[--nb] = '\0';
00173         /* GNU: trailing '/' to permit file names with trailing ' '. */
00174         if (nb > 0 && t[nb - 1] == '/')
00175             t[--nb] = '\0';
00176         iosm->path = xstrdup(t);
00177     }
00178 
00179     st->st_mtime = strntoul(hdr->mtime, NULL, 10, sizeof(hdr->mtime));
00180     st->st_ctime = st->st_atime = st->st_mtime;
00181 
00182     st->st_uid = strntoul(hdr->uid, NULL, 10, sizeof(hdr->uid));
00183     st->st_gid = strntoul(hdr->gid, NULL, 10, sizeof(hdr->gid));
00184 
00185     st->st_mode = strntoul(hdr->mode, NULL, 8, sizeof(hdr->mode));
00186 
00187     st->st_nlink = 1;
00188     rc = 0;
00189 
00190 if (_ar_debug)
00191 fprintf(stderr, "\t     %06o%3d (%4d,%4d)%12lu %s\n",
00192                 (unsigned)st->st_mode, (int)st->st_nlink,
00193                 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
00194                 (iosm->path ? iosm->path : ""));
00195 
00196     return (int) rc;
00197 }
00198 
00199 static ssize_t arWrite(void * _iosm, const void *buf, size_t count)
00200         /*@globals fileSystem @*/
00201         /*@modifies _iosm, fileSystem @*/
00202 {
00203     IOSM_t iosm = _iosm;
00204     const char * s = buf;
00205     size_t nb = 0;
00206     size_t rc;
00207 
00208 if (_ar_debug)
00209 fprintf(stderr, "\tarWrite(%p, %p[%u])\n", iosm, buf, (unsigned)count);
00210 
00211     while (count > 0) {
00212 
00213         /* XXX DWRITE uses rdnb for I/O length. */
00214         iosm->rdnb = count;
00215         if (s != iosm->rdbuf)
00216             memmove(iosm->rdbuf, s + nb, iosm->rdnb);
00217 
00218         rc = _iosmNext(iosm, IOSM_DWRITE);
00219         if (!rc && iosm->rdnb != iosm->wrnb)
00220                 rc = IOSMERR_WRITE_FAILED;
00221         if (rc) return -rc;
00222 
00223         nb += iosm->rdnb;
00224         count -= iosm->rdnb;
00225     }
00226 
00227 #if defined(JBJ_WRITEPAD)
00228     /* Pad to next block boundary. */
00229     if ((rc = _iosmNext(iosm, IOSM_PAD)) != 0) return -rc;
00230 #endif
00231 
00232     return nb;
00233 }
00234 
00235 int arHeaderWrite(void * _iosm, struct stat * st)
00236 {
00237     IOSM_t iosm = _iosm;
00238     arHeader hdr = (arHeader) iosm->rdbuf;
00239     const char * path = (iosm && iosm->path ? iosm->path : "");
00240     size_t nb;
00241     ssize_t rc = 0;
00242 
00243 if (_ar_debug)
00244 fprintf(stderr, "    arHeaderWrite(%p, %p)\n", iosm, st);
00245 
00246     /* At beginning of ar(1) archive, write magic and long member table. */
00247     if (fdGetCpioPos(iosm->cfd) == 0) {
00248         /* Write ar(1) magic. */
00249         rc = arWrite(iosm, AR_MAGIC, sizeof(AR_MAGIC)-1);
00250         _IOSMRC(rc);
00251         /* GNU: on "//":        Write long member name string table. */
00252         if (iosm->lmtab != NULL) {
00253             memset(hdr, (int) ' ', sizeof(*hdr));
00254             hdr->name[0] = '/';
00255             hdr->name[1] = '/';
00256             sprintf(hdr->filesize, "%-10d", (unsigned) (iosm->lmtablen & 037777777777));
00257             strncpy(hdr->marker, AR_MARKER, sizeof(AR_MARKER)-1);
00258 
00259             rc = arWrite(iosm, hdr, sizeof(*hdr));
00260             _IOSMRC(rc);
00261             rc = arWrite(iosm, iosm->lmtab, iosm->lmtablen);
00262             _IOSMRC(rc);
00263 #if !defined(JBJ_WRITEPAD)
00264             rc = _iosmNext(iosm, IOSM_PAD);
00265             if (rc) return (int)rc;
00266 #endif
00267         }
00268     }
00269 
00270     memset(hdr, (int)' ', sizeof(*hdr));
00271 
00272     nb = strlen(path);
00273     if (nb >= sizeof(hdr->name)) {
00274         const char * t;
00275         const char * te;
00276 assert(iosm->lmtab != NULL);
00277         t = iosm->lmtab + iosm->lmtaboff;
00278         te = strchr(t, '\n');
00279         /* GNU: on "/123": Write "/123" offset for long member name. */
00280         nb = snprintf(hdr->name, sizeof(hdr->name)-1, "/%u", (unsigned)iosm->lmtaboff);
00281         hdr->name[nb] = ' ';
00282         if (te != NULL)
00283             iosm->lmtaboff += (te - t) + 1;
00284     } else {
00285         strncpy(hdr->name, path, nb);
00286         hdr->name[nb] = '/';
00287     }
00288 
00289     sprintf(hdr->mtime, "%-12u", (unsigned) (st->st_mtime & 037777777777));
00290     sprintf(hdr->uid, "%-6u", (unsigned int)(st->st_uid & 07777777));
00291     sprintf(hdr->gid, "%-6u", (unsigned int)(st->st_gid & 07777777));
00292 
00293     sprintf(hdr->mode, "%-8o", (unsigned int)(st->st_mode & 07777777));
00294     sprintf(hdr->filesize, "%-10u", (unsigned) (st->st_size & 037777777777));
00295 
00296     strncpy(hdr->marker, AR_MARKER, sizeof(AR_MARKER)-1);
00297 
00298 rc = (int) sizeof(*hdr);
00299 if (_ar_debug)
00300 fprintf(stderr, "==> %p[%u] \"%.*s\"\n", hdr, (unsigned)rc, (int)sizeof(*hdr), (char *)hdr);
00301 
00302     rc = arWrite(iosm, hdr, sizeof(*hdr));
00303     _IOSMRC(rc);
00304     rc = 0;
00305 
00306     return (int) rc;
00307 }
00308 
00309 int arTrailerWrite(void * _iosm)
00310 {
00311     IOSM_t iosm = _iosm;
00312     size_t rc = 0;
00313 
00314 if (_ar_debug)
00315 fprintf(stderr, "    arTrailerWrite(%p)\n", iosm);
00316 
00317 #if defined(JBJ_WRITEPAD)
00318     rc = arWrite(iosm, NULL, 0);        /* XXX _iosmNext(iosm, IOSM_PAD) */
00319     _IOSMRC(rc);
00320 #else
00321     rc = _iosmNext(iosm, IOSM_PAD);     /* XXX likely unnecessary. */
00322 #endif
00323 
00324     return (int) rc;
00325 }