00001
00006 #include "system.h"
00007
00008 #include <rpmio.h>
00009 #include <rpmlib.h>
00010
00011 #include "tar.h"
00012 #include "fsm.h"
00013 #include "ugid.h"
00014
00015 #include "debug.h"
00016
00017
00018
00019
00020 int _tar_debug = 0;
00021
00022
00023 static int nochksum = 0;
00024
00033 static int strntoul(const char *str, char **endptr, int base, int num)
00034
00035
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);
00048 else
00049 *endptr = ((char *)str) + strlen(buf);
00050 }
00051
00052 return ret;
00053 }
00054
00062 static int tarHeaderReadName(FSM_t fsm, int len, const char ** fnp)
00063
00064
00065 {
00066 char * t;
00067 int nb;
00068 int rc = 0;
00069
00070 *fnp = t = xmalloc(len + 1);
00071 while (len > 0) {
00072
00073 fsm->wrlen = TAR_BLOCK_SIZE;
00074 rc = fsmNext(fsm, FSM_DREAD);
00075 if (!rc && fsm->rdnb != fsm->wrlen)
00076 rc = CPIOERR_READ_FAILED;
00077 if (rc) break;
00078
00079
00080 nb = (len > fsm->rdnb ? fsm->rdnb : len);
00081 memcpy(t, fsm->wrbuf, nb);
00082 t += nb;
00083 len -= nb;
00084 }
00085 *t = '\0';
00086
00087 if (rc)
00088 *fnp = _free(*fnp);
00089 return rc;
00090 }
00091
00092 int tarHeaderRead(FSM_t fsm, struct stat * st)
00093
00094 {
00095 tarHeader hdr = (tarHeader) fsm->wrbuf;
00096 char * t;
00097 int nb;
00098 int major, minor;
00099 int rc = 0;
00100 int zblk = 0;
00101
00102 if (_tar_debug)
00103 fprintf(stderr, " tarHeaderRead(%p, %p)\n", fsm, st);
00104
00105 top:
00106 do {
00107
00108 fsm->wrlen = TAR_BLOCK_SIZE;
00109 rc = fsmNext(fsm, FSM_DREAD);
00110 if (!rc && fsm->rdnb != fsm->wrlen)
00111 rc = CPIOERR_READ_FAILED;
00112 if (rc) return rc;
00113
00114
00115 if (hdr->name[0] == '\0' && hdr->checksum[0] == '\0') {
00116 if (++zblk == 2)
00117 return CPIOERR_HDR_TRAILER;
00118 }
00119 } while (zblk > 0);
00120
00121
00122 { const unsigned char * hp = (const unsigned char *) hdr;
00123 char checksum[8];
00124 char hdrchecksum[8];
00125 long sum = 0;
00126 int i;
00127
00128 memcpy(hdrchecksum, hdr->checksum, sizeof(hdrchecksum));
00129 memset(hdr->checksum, ' ', sizeof(hdr->checksum));
00130
00131 for (i = 0; i < TAR_BLOCK_SIZE; i++)
00132 sum += *hp++;
00133
00134 #if 0
00135 for (i = 0; i < sizeof(hdr->checksum) - 1; i++)
00136 sum += (' ' - hdr->checksum[i]);
00137 fprintf(stderr, "\tsum %ld\n", sum);
00138 if (sum != 0)
00139 return CPIOERR_BAD_HEADER;
00140 #else
00141 memset(checksum, ' ', sizeof(checksum));
00142 sprintf(checksum, "%06o", (unsigned) (sum & 07777777));
00143 if (_tar_debug)
00144 fprintf(stderr, "\tmemcmp(\"%s\", \"%s\", %u)\n", hdrchecksum, checksum, (unsigned)sizeof(hdrchecksum));
00145 if (memcmp(hdrchecksum, checksum, sizeof(hdrchecksum)))
00146 if (!nochksum)
00147 return CPIOERR_BAD_HEADER;
00148 #endif
00149
00150 }
00151
00152
00153 if (strncmp(hdr->magic, TAR_MAGIC, sizeof(TAR_MAGIC)-1))
00154 return CPIOERR_BAD_MAGIC;
00155
00156 st->st_size = strntoul(hdr->filesize, NULL, 8, sizeof(hdr->filesize));
00157
00158 st->st_nlink = 1;
00159 st->st_mode = strntoul(hdr->mode, NULL, 8, sizeof(hdr->mode));
00160 st->st_mode &= ~S_IFMT;
00161 switch (hdr->typeflag) {
00162 case 'x':
00163 case 'g':
00164 default:
00165 break;
00166 case '7':
00167 case '\0':
00168 case '0':
00169 st->st_mode |= S_IFREG;
00170 break;
00171 case '1':
00172 st->st_mode |= S_IFREG;
00173 #ifdef DYING
00174 st->st_nlink++;
00175 #endif
00176 break;
00177 case '2':
00178 st->st_mode |= S_IFLNK;
00179 break;
00180 case '3':
00181 st->st_mode |= S_IFCHR;
00182 break;
00183 case '4':
00184 st->st_mode |= S_IFBLK;
00185 break;
00186 case '5':
00187 st->st_mode |= S_IFDIR;
00188 st->st_nlink++;
00189 break;
00190 case '6':
00191 st->st_mode |= S_IFIFO;
00192 break;
00193 #ifdef REFERENCE
00194 case 'A':
00195 case 'E':
00196 case 'I':
00197 case 'X':
00198 case 'D':
00199 case 'M':
00200 case 'N':
00201 case 'S':
00202 case 'V':
00203 #endif
00204 case 'K':
00205 rc = tarHeaderReadName(fsm, st->st_size, &fsm->lpath);
00206 if (rc) return rc;
00207 goto top;
00208 break;
00209 case 'L':
00210 rc = tarHeaderReadName(fsm, st->st_size, &fsm->path);
00211 if (rc) return rc;
00212 goto top;
00213 break;
00214 }
00215
00216 st->st_uid = strntoul(hdr->uid, NULL, 8, sizeof(hdr->uid));
00217 st->st_gid = strntoul(hdr->gid, NULL, 8, sizeof(hdr->gid));
00218 st->st_mtime = strntoul(hdr->mtime, NULL, 8, sizeof(hdr->mtime));
00219 st->st_ctime = st->st_atime = st->st_mtime;
00220
00221 major = strntoul(hdr->devMajor, NULL, 8, sizeof(hdr->devMajor));
00222 minor = strntoul(hdr->devMinor, NULL, 8, sizeof(hdr->devMinor));
00223
00224 st->st_dev = Makedev(major, minor);
00225
00226 st->st_rdev = st->st_dev;
00227
00228
00229
00230
00231
00232 if (fsm->path == NULL && hdr->name[0] != '\0') {
00233 nb = strlen(hdr->name);
00234 t = xmalloc(nb + 1);
00235 memcpy(t, hdr->name, nb);
00236 t[nb] = '\0';
00237 fsm->path = t;
00238 }
00239
00240
00241 if (fsm->lpath == NULL && hdr->linkname[0] != '\0') {
00242 nb = strlen(hdr->linkname);
00243 t = xmalloc(nb + 1);
00244 memcpy(t, hdr->linkname, nb);
00245 t[nb] = '\0';
00246 fsm->lpath = t;
00247 }
00248
00249 if (_tar_debug)
00250 fprintf(stderr, "\t %06o%3d (%4d,%4d)%10d %s\n\t-> %s\n",
00251 (unsigned)st->st_mode, (int)st->st_nlink,
00252 (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
00253 (fsm->path ? fsm->path : ""), (fsm->lpath ? fsm->lpath : ""));
00254
00255 return rc;
00256 }
00257
00264 static int tarHeaderWriteName(FSM_t fsm, const char * path)
00265
00266
00267 {
00268 const char * s = path;
00269 int nb = strlen(s);
00270 int rc = 0;
00271
00272 if (_tar_debug)
00273 fprintf(stderr, "\ttarHeaderWriteName(%p, %s) nb %d\n", fsm, path, nb);
00274
00275 while (nb > 0) {
00276 memset(fsm->rdbuf, 0, TAR_BLOCK_SIZE);
00277
00278
00279 fsm->rdnb = (nb < TAR_BLOCK_SIZE) ? nb : TAR_BLOCK_SIZE;
00280 memmove(fsm->rdbuf, s, fsm->rdnb);
00281 rc = fsmNext(fsm, FSM_DWRITE);
00282 if (!rc && fsm->rdnb != fsm->wrnb)
00283 rc = CPIOERR_WRITE_FAILED;
00284
00285 if (rc) break;
00286 s += fsm->rdnb;
00287 nb -= fsm->rdnb;
00288 }
00289
00290 if (!rc)
00291 rc = fsmNext(fsm, FSM_PAD);
00292
00293 return rc;
00294 }
00295
00303 static int tarHeaderWriteBlock(FSM_t fsm, struct stat * st, tarHeader hdr)
00304
00305
00306 {
00307 int rc;
00308
00309 if (_tar_debug)
00310 fprintf(stderr, "\ttarHeaderWriteBlock(%p, %p) type %c\n", fsm, hdr, hdr->typeflag);
00311 if (_tar_debug)
00312 fprintf(stderr, "\t %06o%3d (%4d,%4d)%10d %s\n",
00313 (unsigned)st->st_mode, (int)st->st_nlink,
00314 (int)st->st_uid, (int)st->st_gid, (int)st->st_size,
00315 (fsm->path ? fsm->path : ""));
00316
00317
00318 (void) stpcpy( stpcpy(hdr->magic, TAR_MAGIC), TAR_VERSION);
00319
00320
00321 { const unsigned char * hp = (const unsigned char *) hdr;
00322 long sum = 0;
00323 int i;
00324
00325 memset(hdr->checksum, ' ', sizeof(hdr->checksum));
00326 for (i = 0; i < TAR_BLOCK_SIZE; i++)
00327 sum += *hp++;
00328 sprintf(hdr->checksum, "%06o", (unsigned)(sum & 07777777));
00329 if (_tar_debug)
00330 fprintf(stderr, "\thdrchksum \"%s\"\n", hdr->checksum);
00331 }
00332
00333
00334 fsm->rdnb = TAR_BLOCK_SIZE;
00335 rc = fsmNext(fsm, FSM_DWRITE);
00336 if (!rc && fsm->rdnb != fsm->wrnb)
00337 rc = CPIOERR_WRITE_FAILED;
00338
00339 return rc;
00340 }
00341
00342 int tarHeaderWrite(FSM_t fsm, struct stat * st)
00343 {
00344
00345 static const char * llname = "././@LongLink";
00346 tarHeader hdr = (tarHeader) fsm->rdbuf;
00347 char * t;
00348 dev_t dev;
00349 int rc = 0;
00350 int len;
00351
00352 if (_tar_debug)
00353 fprintf(stderr, " tarHeaderWrite(%p, %p)\n", fsm, st);
00354
00355 len = strlen(fsm->path);
00356 if (len > sizeof(hdr->name)) {
00357 memset(hdr, 0, sizeof(*hdr));
00358 strcpy(hdr->name, llname);
00359 sprintf(hdr->mode, "%07o", 0);
00360 sprintf(hdr->uid, "%07o", 0);
00361 sprintf(hdr->gid, "%07o", 0);
00362 sprintf(hdr->filesize, "%011o", (unsigned) (len & 037777777777));
00363 sprintf(hdr->mtime, "%011o", 0);
00364 hdr->typeflag = 'L';
00365 strncpy(hdr->uname, "root", sizeof(hdr->uname));
00366 strncpy(hdr->gname, "root", sizeof(hdr->gname));
00367 rc = tarHeaderWriteBlock(fsm, st, hdr);
00368 if (rc) return rc;
00369 rc = tarHeaderWriteName(fsm, fsm->path);
00370 if (rc) return rc;
00371 }
00372
00373 if (fsm->lpath && fsm->lpath[0] != '0') {
00374 len = strlen(fsm->lpath);
00375 if (len > sizeof(hdr->name)) {
00376 memset(hdr, 0, sizeof(*hdr));
00377 strcpy(hdr->linkname, llname);
00378 sprintf(hdr->mode, "%07o", 0);
00379 sprintf(hdr->uid, "%07o", 0);
00380 sprintf(hdr->gid, "%07o", 0);
00381 sprintf(hdr->filesize, "%011o", (unsigned) (len & 037777777777));
00382 sprintf(hdr->mtime, "%011o", 0);
00383 hdr->typeflag = 'K';
00384 strncpy(hdr->uname, "root", sizeof(hdr->uname));
00385 strncpy(hdr->gname, "root", sizeof(hdr->gname));
00386 rc = tarHeaderWriteBlock(fsm, st, hdr);
00387 if (rc) return rc;
00388 rc = tarHeaderWriteName(fsm, fsm->lpath);
00389 if (rc) return rc;
00390 }
00391 }
00392
00393 memset(hdr, 0, sizeof(*hdr));
00394
00395 strncpy(hdr->name, fsm->path, sizeof(hdr->name));
00396
00397 if (fsm->lpath && fsm->lpath[0] != '0')
00398 strncpy(hdr->linkname, fsm->lpath, sizeof(hdr->linkname));
00399
00400 sprintf(hdr->mode, "%07o", (unsigned int)(st->st_mode & 00007777));
00401 sprintf(hdr->uid, "%07o", (unsigned int)(st->st_uid & 07777777));
00402 sprintf(hdr->gid, "%07o", (unsigned int)(st->st_gid & 07777777));
00403
00404 sprintf(hdr->filesize, "%011o", (unsigned) (st->st_size & 037777777777));
00405 sprintf(hdr->mtime, "%011o", (unsigned) (st->st_mtime & 037777777777));
00406
00407 hdr->typeflag = '0';
00408 if (S_ISLNK(st->st_mode))
00409 hdr->typeflag = '2';
00410 else if (S_ISCHR(st->st_mode))
00411 hdr->typeflag = '3';
00412 else if (S_ISBLK(st->st_mode))
00413 hdr->typeflag = '4';
00414 else if (S_ISDIR(st->st_mode))
00415 hdr->typeflag = '5';
00416 else if (S_ISFIFO(st->st_mode))
00417 hdr->typeflag = '6';
00418 #ifdef WHAT2DO
00419 else if (S_ISSOCK(st->st_mode))
00420 hdr->typeflag = '?';
00421 #endif
00422 else if (S_ISREG(st->st_mode))
00423 hdr->typeflag = (fsm->lpath != NULL ? '1' : '0');
00424
00425
00426 t = uidToUname(st->st_uid);
00427 if (t == NULL) t = "root";
00428 strncpy(hdr->uname, t, sizeof(hdr->uname));
00429 t = gidToGname(st->st_gid);
00430 if (t == NULL) t = "root";
00431 strncpy(hdr->gname, t, sizeof(hdr->gname));
00432
00433
00434 dev = major((unsigned)st->st_dev);
00435 sprintf(hdr->devMajor, "%07o", (unsigned) (dev & 07777777));
00436 dev = minor((unsigned)st->st_dev);
00437 sprintf(hdr->devMinor, "%07o", (unsigned) (dev & 07777777));
00438
00439 rc = tarHeaderWriteBlock(fsm, st, hdr);
00440
00441
00442 if (!rc)
00443 rc = fsmNext(fsm, FSM_PAD);
00444
00445 return rc;
00446 }
00447
00448 int tarTrailerWrite(FSM_t fsm)
00449 {
00450 int rc = 0;
00451
00452 if (_tar_debug)
00453 fprintf(stderr, " tarTrailerWrite(%p)\n", fsm);
00454
00455
00456 fsm->blksize *= 20;
00457 if (!rc)
00458 rc = fsmNext(fsm, FSM_PAD);
00459 fsm->blksize /= 20;
00460
00461 return rc;
00462 }