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
00019
00020
00021 int _tar_debug = 0;
00022
00023
00024 static int nochksum = 0;
00025
00034 static int strntoul(const char *str, char **endptr, int base, int num)
00035
00036
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
00047 if (endptr != NULL) {
00048 if (*end != '\0')
00049 *endptr = ((char *)str) + (end - buf);
00050 else
00051 *endptr = ((char *)str) + strlen(buf);
00052 }
00053
00054
00055 return ret;
00056 }
00057
00065 static int tarHeaderReadName(FSM_t fsm, int len, const char ** fnp)
00066
00067
00068 {
00069 char * t;
00070 int nb;
00071 int rc = 0;
00072
00073 *fnp = t = xmalloc(len + 1);
00074 while (len > 0) {
00075
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
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
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
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
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
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
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':
00166 case 'g':
00167 default:
00168 break;
00169 case '7':
00170 case '\0':
00171 case '0':
00172 st->st_mode |= S_IFREG;
00173 break;
00174 case '1':
00175 st->st_mode |= S_IFREG;
00176 #ifdef DYING
00177 st->st_nlink++;
00178 #endif
00179 break;
00180 case '2':
00181 st->st_mode |= S_IFLNK;
00182 break;
00183 case '3':
00184 st->st_mode |= S_IFCHR;
00185 break;
00186 case '4':
00187 st->st_mode |= S_IFBLK;
00188 break;
00189 case '5':
00190 st->st_mode |= S_IFDIR;
00191 st->st_nlink++;
00192 break;
00193 case '6':
00194 st->st_mode |= S_IFIFO;
00195 break;
00196 #ifdef REFERENCE
00197 case 'A':
00198 case 'E':
00199 case 'I':
00200 case 'X':
00201 case 'D':
00202 case 'M':
00203 case 'N':
00204 case 'S':
00205 case 'V':
00206 #endif
00207 case 'K':
00208 rc = tarHeaderReadName(fsm, st->st_size, &fsm->lpath);
00209 if (rc) return rc;
00210 goto top;
00211 break;
00212 case 'L':
00213 rc = tarHeaderReadName(fsm, st->st_size, &fsm->path);
00214 if (rc) return rc;
00215 goto top;
00216 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;
00223
00224 major = strntoul(hdr->devMajor, NULL, 8, sizeof(hdr->devMajor));
00225 minor = strntoul(hdr->devMinor, NULL, 8, sizeof(hdr->devMinor));
00226
00227 st->st_dev = makedev(major, minor);
00228
00229 st->st_rdev = st->st_dev;
00230
00231
00232
00233
00234
00235 if (fsm->path == NULL && hdr->name[0] != '\0') {
00236 nb = strlen(hdr->name);
00237 t = xmalloc(nb + 1);
00238
00239 memcpy(t, hdr->name, nb);
00240 t[nb] = '\0';
00241
00242 fsm->path = t;
00243 }
00244
00245
00246 if (fsm->lpath == NULL && hdr->linkname[0] != '\0') {
00247 nb = strlen(hdr->linkname);
00248 t = xmalloc(nb + 1);
00249
00250 memcpy(t, hdr->linkname, nb);
00251 t[nb] = '\0';
00252
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
00273
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
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
00312
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
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
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
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';
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
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
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
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
00463 fsm->blksize *= 20;
00464 if (!rc)
00465 rc = fsmNext(fsm, FSM_PAD);
00466 fsm->blksize /= 20;
00467
00468 return rc;
00469 }