rpm 5.3.12
|
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 const char * path = (iosm && iosm->path ? iosm->path : ""); 00355 ssize_t rc; 00356 00357 if (_tar_debug) 00358 fprintf(stderr, "\ttarHeaderWriteBlock(%p, %p) type %c\n", iosm, hdr, hdr->typeflag); 00359 if (_tar_debug) 00360 fprintf(stderr, "\t %06o%3d (%4d,%4d)%12lu %s\n", 00361 (unsigned)st->st_mode, (int)st->st_nlink, 00362 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size, 00363 path); 00364 00365 00366 (void) stpcpy( stpcpy(hdr->magic, TAR_MAGIC), TAR_VERSION); 00367 00368 /* Calculate header checksum. */ 00369 { const unsigned char * hp = (const unsigned char *) hdr; 00370 long sum = 0; 00371 int i; 00372 00373 memset(hdr->checksum, (int)' ', sizeof(hdr->checksum)); 00374 for (i = 0; i < TAR_BLOCK_SIZE; i++) 00375 sum += (long) *hp++; 00376 sprintf(hdr->checksum, "%06o", (unsigned)(sum & 07777777)); 00377 if (_tar_debug) 00378 fprintf(stderr, "\thdrchksum \"%s\"\n", hdr->checksum); 00379 } 00380 00381 rc = tarWrite(_iosm, hdr, TAR_BLOCK_SIZE); 00382 00383 return rc; 00384 } 00385 00386 int tarHeaderWrite(void * _iosm, struct stat * st) 00387 { 00388 IOSM_t iosm = _iosm; 00389 /*@observer@*/ 00390 static const char * llname = "././@LongLink"; 00391 tarHeader hdr = (tarHeader) iosm->rdbuf; 00392 const char * path = (iosm && iosm->path ? iosm->path : ""); 00393 const char * lpath = (iosm && iosm->lpath ? iosm->lpath : ""); 00394 char * t; 00395 dev_t dev; 00396 size_t nb; 00397 ssize_t rc = 0; 00398 00399 if (_tar_debug) 00400 fprintf(stderr, " tarHeaderWrite(%p, %p)\n", iosm, st); 00401 00402 nb = strlen(path); 00403 if (nb > sizeof(hdr->name)) { 00404 memset(hdr, 0, sizeof(*hdr)); 00405 strcpy(hdr->name, llname); 00406 sprintf(hdr->mode, "%07o", 0); 00407 sprintf(hdr->uid, "%07o", 0); 00408 sprintf(hdr->gid, "%07o", 0); 00409 sprintf(hdr->filesize, "%011o", (unsigned) (nb & 037777777777)); 00410 sprintf(hdr->mtime, "%011o", 0); 00411 hdr->typeflag = 'L'; 00412 strncpy(hdr->uname, "root", sizeof(hdr->uname)); 00413 strncpy(hdr->gname, "root", sizeof(hdr->gname)); 00414 rc = tarHeaderWriteBlock(iosm, st, hdr); 00415 _IOSMRC(rc); 00416 rc = tarHeaderWriteName(iosm, path); 00417 _IOSMRC(rc); 00418 } 00419 00420 if (lpath && lpath[0] != '0') { 00421 nb = strlen(lpath); 00422 if (nb > sizeof(hdr->name)) { 00423 memset(hdr, 0, sizeof(*hdr)); 00424 strcpy(hdr->linkname, llname); 00425 sprintf(hdr->mode, "%07o", 0); 00426 sprintf(hdr->uid, "%07o", 0); 00427 sprintf(hdr->gid, "%07o", 0); 00428 sprintf(hdr->filesize, "%011o", (unsigned) (nb & 037777777777)); 00429 sprintf(hdr->mtime, "%011o", 0); 00430 hdr->typeflag = 'K'; 00431 strncpy(hdr->uname, "root", sizeof(hdr->uname)); 00432 strncpy(hdr->gname, "root", sizeof(hdr->gname)); 00433 rc = tarHeaderWriteBlock(iosm, st, hdr); 00434 _IOSMRC(rc); 00435 rc = tarHeaderWriteName(iosm, path); 00436 _IOSMRC(rc); 00437 } 00438 } 00439 00440 memset(hdr, 0, sizeof(*hdr)); 00441 00442 strncpy(hdr->name, path, sizeof(hdr->name)); 00443 00444 if (lpath && lpath[0] != '\0') 00445 strncpy(hdr->linkname, lpath, sizeof(hdr->linkname)); 00446 00447 sprintf(hdr->mode, "%07o", (unsigned int)(st->st_mode & 00007777)); 00448 sprintf(hdr->uid, "%07o", (unsigned int)(st->st_uid & 07777777)); 00449 sprintf(hdr->gid, "%07o", (unsigned int)(st->st_gid & 07777777)); 00450 00451 sprintf(hdr->filesize, "%011o", (unsigned) (st->st_size & 037777777777)); 00452 sprintf(hdr->mtime, "%011o", (unsigned) (st->st_mtime & 037777777777)); 00453 00454 hdr->typeflag = '0'; /* XXX wrong! */ 00455 if (S_ISLNK(st->st_mode)) 00456 hdr->typeflag = '2'; 00457 else if (S_ISCHR(st->st_mode)) 00458 hdr->typeflag = '3'; 00459 else if (S_ISBLK(st->st_mode)) 00460 hdr->typeflag = '4'; 00461 else if (S_ISDIR(st->st_mode)) 00462 hdr->typeflag = '5'; 00463 else if (S_ISFIFO(st->st_mode)) 00464 hdr->typeflag = '6'; 00465 #ifdef WHAT2DO 00466 else if (S_ISSOCK(st->st_mode)) 00467 hdr->typeflag = '?'; 00468 #endif 00469 else if (S_ISREG(st->st_mode)) 00470 hdr->typeflag = (lpath && lpath[0] != '\0' ? '1' : '0'); 00471 00472 /* XXX FIXME: map uname/gname from uid/gid. */ 00473 t = uidToUname(st->st_uid); 00474 if (t == NULL) t = "root"; 00475 strncpy(hdr->uname, t, sizeof(hdr->uname)); 00476 t = gidToGname(st->st_gid); 00477 if (t == NULL) t = "root"; 00478 strncpy(hdr->gname, t, sizeof(hdr->gname)); 00479 00480 /* XXX W2DO? st_dev or st_rdev? */ 00481 dev = major((unsigned)st->st_dev); 00482 sprintf(hdr->devMajor, "%07o", (unsigned) (dev & 07777777)); 00483 dev = minor((unsigned)st->st_dev); 00484 sprintf(hdr->devMinor, "%07o", (unsigned) (dev & 07777777)); 00485 00486 rc = tarHeaderWriteBlock(iosm, st, hdr); 00487 _IOSMRC(rc); 00488 rc = 0; 00489 00490 #if !defined(JBJ_WRITEPAD) 00491 /* XXX Padding is unnecessary but shouldn't hurt. */ 00492 rc = _iosmNext(iosm, IOSM_PAD); 00493 #endif 00494 00495 return (int) rc; 00496 } 00497 00498 int tarTrailerWrite(void * _iosm) 00499 { 00500 IOSM_t iosm = _iosm; 00501 ssize_t rc = 0; 00502 00503 if (_tar_debug) 00504 fprintf(stderr, " tarTrailerWrite(%p)\n", iosm); 00505 00506 /* Pad up to 20 blocks (10Kb) of zeroes. */ 00507 iosm->blksize *= 20; 00508 #if defined(JBJ_WRITEPAD) 00509 rc = tarWrite(iosm, NULL, 0); /* XXX _iosmNext(iosm, IOSM_PAD) */ 00510 #else 00511 rc = _iosmNext(iosm, IOSM_PAD); 00512 #endif 00513 iosm->blksize /= 20; 00514 #if defined(JBJ_WRITEPAD) 00515 _IOSMRC(rc); 00516 #endif 00517 00518 return (int) -rc; 00519 }