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
00019
00020
00021 int _tar_debug = 0;
00022
00023
00024 static int nochksum = 0;
00025
00034 static int strntoul(const char *str, char **endptr,
00035 int base, size_t num)
00036
00037
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);
00050 else
00051 *endptr = ((char *)str) + strlen(buf);
00052 }
00053
00054 return ret;
00055 }
00056
00057
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
00063
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
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
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 const char ** fnp)
00101
00102
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)
00110 t[rc] = '\0';
00111 else
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
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
00139 rc = tarRead(_iosm, hdr, TAR_BLOCK_SIZE);
00140 _IOSMRC(rc);
00141
00142
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
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
00173 if (strncmp(hdr->magic, TAR_MAGIC, sizeof(TAR_MAGIC)-1))
00174 return IOSMERR_BAD_MAGIC;
00175
00176
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':
00184 case 'g':
00185 default:
00186 break;
00187 case '7':
00188 case '\0':
00189 case '0':
00190 st->st_mode |= S_IFREG;
00191 break;
00192 case '1':
00193 st->st_mode |= S_IFREG;
00194 #ifdef DYING
00195 st->st_nlink++;
00196 #endif
00197 break;
00198 case '2':
00199 st->st_mode |= S_IFLNK;
00200 break;
00201 case '3':
00202 st->st_mode |= S_IFCHR;
00203 break;
00204 case '4':
00205 st->st_mode |= S_IFBLK;
00206 break;
00207 case '5':
00208 st->st_mode |= S_IFDIR;
00209 st->st_nlink++;
00210 break;
00211 case '6':
00212 st->st_mode |= S_IFIFO;
00213 break;
00214 #ifdef REFERENCE
00215 case 'A':
00216 case 'E':
00217 case 'I':
00218 case 'X':
00219 case 'D':
00220 case 'M':
00221 case 'N':
00222 case 'S':
00223 case 'V':
00224 #endif
00225 case 'K':
00226 rc = tarHeaderReadName(iosm, st->st_size, &iosm->lpath);
00227 _IOSMRC(rc);
00228 goto top;
00229 break;
00230 case 'L':
00231 rc = tarHeaderReadName(iosm, st->st_size, &iosm->path);
00232 _IOSMRC(rc);
00233 goto top;
00234 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;
00241
00242 major = strntoul(hdr->devMajor, NULL, 8, sizeof(hdr->devMajor));
00243 minor = strntoul(hdr->devMinor, NULL, 8, sizeof(hdr->devMinor));
00244
00245 st->st_dev = Makedev(major, minor);
00246
00247 st->st_rdev = st->st_dev;
00248
00249
00250
00251
00252
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
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
00283
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
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
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
00325
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
00351
00352 {
00353 IOSM_t iosm = _iosm;
00354 ssize_t rc;
00355
00356 if (_tar_debug)
00357 fprintf(stderr, "\ttarHeaderWriteBlock(%p, %p) type %c\n", iosm, hdr, hdr->typeflag);
00358 if (_tar_debug)
00359 fprintf(stderr, "\t %06o%3d (%4d,%4d)%12lu %s\n",
00360 (unsigned)st->st_mode, (int)st->st_nlink,
00361 (int)st->st_uid, (int)st->st_gid, (unsigned long)st->st_size,
00362 (iosm->path ? iosm->path : ""));
00363
00364
00365 (void) stpcpy( stpcpy(hdr->magic, TAR_MAGIC), TAR_VERSION);
00366
00367
00368 { const unsigned char * hp = (const unsigned char *) hdr;
00369 long sum = 0;
00370 int i;
00371
00372 memset(hdr->checksum, (int)' ', sizeof(hdr->checksum));
00373 for (i = 0; i < TAR_BLOCK_SIZE; i++)
00374 sum += (long) *hp++;
00375 sprintf(hdr->checksum, "%06o", (unsigned)(sum & 07777777));
00376 if (_tar_debug)
00377 fprintf(stderr, "\thdrchksum \"%s\"\n", hdr->checksum);
00378 }
00379
00380 rc = tarWrite(_iosm, hdr, TAR_BLOCK_SIZE);
00381
00382 return rc;
00383 }
00384
00385 int tarHeaderWrite(void * _iosm, struct stat * st)
00386 {
00387 IOSM_t iosm = _iosm;
00388
00389 static const char * llname = "././@LongLink";
00390 tarHeader hdr = (tarHeader) iosm->rdbuf;
00391 char * t;
00392 dev_t dev;
00393 size_t nb;
00394 ssize_t rc = 0;
00395
00396 if (_tar_debug)
00397 fprintf(stderr, " tarHeaderWrite(%p, %p)\n", iosm, st);
00398
00399 nb = strlen(iosm->path);
00400 if (nb > sizeof(hdr->name)) {
00401 memset(hdr, 0, sizeof(*hdr));
00402 strcpy(hdr->name, llname);
00403 sprintf(hdr->mode, "%07o", 0);
00404 sprintf(hdr->uid, "%07o", 0);
00405 sprintf(hdr->gid, "%07o", 0);
00406 sprintf(hdr->filesize, "%011o", (unsigned) (nb & 037777777777));
00407 sprintf(hdr->mtime, "%011o", 0);
00408 hdr->typeflag = 'L';
00409 strncpy(hdr->uname, "root", sizeof(hdr->uname));
00410 strncpy(hdr->gname, "root", sizeof(hdr->gname));
00411 rc = tarHeaderWriteBlock(iosm, st, hdr);
00412 _IOSMRC(rc);
00413 rc = tarHeaderWriteName(iosm, iosm->path);
00414 _IOSMRC(rc);
00415 }
00416
00417 if (iosm->lpath && iosm->lpath[0] != '0') {
00418 nb = strlen(iosm->lpath);
00419 if (nb > sizeof(hdr->name)) {
00420 memset(hdr, 0, sizeof(*hdr));
00421 strcpy(hdr->linkname, llname);
00422 sprintf(hdr->mode, "%07o", 0);
00423 sprintf(hdr->uid, "%07o", 0);
00424 sprintf(hdr->gid, "%07o", 0);
00425 sprintf(hdr->filesize, "%011o", (unsigned) (nb & 037777777777));
00426 sprintf(hdr->mtime, "%011o", 0);
00427 hdr->typeflag = 'K';
00428 strncpy(hdr->uname, "root", sizeof(hdr->uname));
00429 strncpy(hdr->gname, "root", sizeof(hdr->gname));
00430 rc = tarHeaderWriteBlock(iosm, st, hdr);
00431 _IOSMRC(rc);
00432 rc = tarHeaderWriteName(iosm, iosm->lpath);
00433 _IOSMRC(rc);
00434 }
00435 }
00436
00437 memset(hdr, 0, sizeof(*hdr));
00438
00439 strncpy(hdr->name, iosm->path, sizeof(hdr->name));
00440
00441 if (iosm->lpath && iosm->lpath[0] != '0')
00442 strncpy(hdr->linkname, iosm->lpath, sizeof(hdr->linkname));
00443
00444 sprintf(hdr->mode, "%07o", (unsigned int)(st->st_mode & 00007777));
00445 sprintf(hdr->uid, "%07o", (unsigned int)(st->st_uid & 07777777));
00446 sprintf(hdr->gid, "%07o", (unsigned int)(st->st_gid & 07777777));
00447
00448 sprintf(hdr->filesize, "%011o", (unsigned) (st->st_size & 037777777777));
00449 sprintf(hdr->mtime, "%011o", (unsigned) (st->st_mtime & 037777777777));
00450
00451 hdr->typeflag = '0';
00452 if (S_ISLNK(st->st_mode))
00453 hdr->typeflag = '2';
00454 else if (S_ISCHR(st->st_mode))
00455 hdr->typeflag = '3';
00456 else if (S_ISBLK(st->st_mode))
00457 hdr->typeflag = '4';
00458 else if (S_ISDIR(st->st_mode))
00459 hdr->typeflag = '5';
00460 else if (S_ISFIFO(st->st_mode))
00461 hdr->typeflag = '6';
00462 #ifdef WHAT2DO
00463 else if (S_ISSOCK(st->st_mode))
00464 hdr->typeflag = '?';
00465 #endif
00466 else if (S_ISREG(st->st_mode))
00467 hdr->typeflag = (iosm->lpath != NULL ? '1' : '0');
00468
00469
00470 t = uidToUname(st->st_uid);
00471 if (t == NULL) t = "root";
00472 strncpy(hdr->uname, t, sizeof(hdr->uname));
00473 t = gidToGname(st->st_gid);
00474 if (t == NULL) t = "root";
00475 strncpy(hdr->gname, t, sizeof(hdr->gname));
00476
00477
00478 dev = major((unsigned)st->st_dev);
00479 sprintf(hdr->devMajor, "%07o", (unsigned) (dev & 07777777));
00480 dev = minor((unsigned)st->st_dev);
00481 sprintf(hdr->devMinor, "%07o", (unsigned) (dev & 07777777));
00482
00483 rc = tarHeaderWriteBlock(iosm, st, hdr);
00484 _IOSMRC(rc);
00485 rc = 0;
00486
00487 #if !defined(JBJ_WRITEPAD)
00488
00489 rc = _iosmNext(iosm, IOSM_PAD);
00490 #endif
00491
00492 return (int) rc;
00493 }
00494
00495 int tarTrailerWrite(void * _iosm)
00496 {
00497 IOSM_t iosm = _iosm;
00498 ssize_t rc = 0;
00499
00500 if (_tar_debug)
00501 fprintf(stderr, " tarTrailerWrite(%p)\n", iosm);
00502
00503
00504 iosm->blksize *= 20;
00505 #if defined(JBJ_WRITEPAD)
00506 rc = tarWrite(iosm, NULL, 0);
00507 #else
00508 rc = _iosmNext(iosm, IOSM_PAD);
00509 #endif
00510 iosm->blksize /= 20;
00511 #if defined(JBJ_WRITEPAD)
00512 _IOSMRC(rc);
00513 #endif
00514
00515 return (int) -rc;
00516 }