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