void filein(register Archive_t* ap, register File_t* f) { register off_t c; register int n; register char* s; int dfd; int wfd; long checksum; Filter_t* fp; Proc_t* pp; Tv_t t1; Tv_t t2; struct stat st; if (f->skip) goto skip; else if (state.list) { if (fp = filter(ap, f)) { for (n = 0; s = fp->argv[n]; n++) { while (*s) if (*s++ == '%' && *s == '(') break; if (*s) { s = fp->argv[n]; listprintf(state.tmp.str, ap, f, s); if (!(fp->argv[n] = sfstruse(state.tmp.str))) nospace(); break; } } pp = procopen(*fp->argv, fp->argv, NiL, NiL, PROC_WRITE); if (s) fp->argv[n] = s; if (!pp) { error(2, "%s: %s: cannot execute filter %s", ap->name, f->path, *fp->argv); goto skip; } if (!ap->format->getdata || !(*ap->format->getdata)(&state, ap, f, pp->wfd)) { checksum = 0; for (c = f->st->st_size; c > 0; c -= n) { n = (c > state.buffersize) ? state.buffersize : c; if (!(s = bget(ap, n, NiL))) { error(ERROR_SYSTEM|2, "%s: read error", f->name); break; } if (write(pp->wfd, s, n) != n) { error(ERROR_SYSTEM|2, "%s: write error", f->name); break; } if (ap->format->checksum) checksum = (*ap->format->checksum)(&state, ap, f, s, n, checksum); } } if (ap->format->checksum && checksum != f->checksum) error(1, "%s: %s checksum error (0x%08x != 0x%08x)", f->name, ap->format->name, checksum, f->checksum); /* * explicitly ignore exit status */ procclose(pp); return; } listentry(f); goto skip; } else switch (f->delta.op) { case DELTA_create: if (f->delta.base) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); if (ap->delta->format->flags & PSEUDO) goto regular; if ((wfd = openout(ap, f)) < 0) goto skip; else paxdelta(NiL, ap, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, f->st->st_size, 0); break; case DELTA_update: if (!f->delta.base || (unsigned long)f->delta.base->mtime.tv_sec >= (unsigned long)f->st->st_mtime) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); c = f->st->st_size; if ((wfd = openout(ap, f)) < 0) goto skip; if (state.ordered) { if (!f->delta.base->uncompressed) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0)) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); } else if (!f->delta.base->uncompressed) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); else if (!paxdelta(NiL, ap, f, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0)) paxdelta(NiL, ap, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, f->delta.base->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT, wfd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap, c, 0); break; case DELTA_verify: if (!f->delta.base || f->delta.base->mtime.tv_sec != f->st->st_mtime) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); if ((*state.statf)(f->name, &st)) error(2, "%s: not copied from base archive", f->name); else if (st.st_size != f->delta.base->size || state.modtime && tvcmp(tvmtime(&t1, &st), tvmtime(&t2, f->st))) error(1, "%s: changed from base archive", f->name); break; case DELTA_delete: if (!f->delta.base) error(3, "%s: base archive mismatch [%s#%d]", f->name, __FILE__, __LINE__); /*FALLTHROUGH*/ default: regular: wfd = openout(ap, f); if (wfd >= 0) { holeinit(wfd); if (!ap->format->getdata || !(*ap->format->getdata)(&state, ap, f, wfd)) { checksum = 0; for (c = f->st->st_size; c > 0; c -= n) { n = (c > state.buffersize) ? state.buffersize : c; if (!(s = bget(ap, n, NiL))) { error(ERROR_SYSTEM|2, "%s: read error", f->name); break; } if (holewrite(wfd, s, n) != n) { error(ERROR_SYSTEM|2, "%s: write error", f->name); break; } if (ap->format->checksum) checksum = (*ap->format->checksum)(&state, ap, f, s, n, checksum); } } holedone(wfd); closeout(ap, f, wfd); setfile(ap, f); if (ap->format->checksum && checksum != f->checksum) error(1, "%s: %s checksum error (0x%08x != 0x%08x)", f->name, ap->format->name, checksum, f->checksum); } else if (ap->format->getdata) (*ap->format->getdata)(&state, ap, f, wfd); else { if (wfd < -1) listentry(f); goto skip; } break; } listentry(f); return; skip: fileskip(ap, f); }
int copyinout(Ftw_t* ftw) { register File_t* f = &state.out->file; register char* s; register off_t c; register ssize_t n; register int rfd; register int wfd; if (getfile(state.out, f, ftw) && selectfile(state.out, f)) { s = f->name; f->name = stash(&state.out->path.copy, NiL, state.pwdlen + f->namesize); strcpy(stpcpy(f->name, state.pwd), s + (*s == '/')); if ((wfd = openout(state.out, f)) >= 0) { if ((rfd = openin(state.out, f)) >= 0) { #if defined(SEEK_DATA) && defined(SEEK_HOLE) off_t data; off_t hole; int more; data = 0; more = 1; while (more) { if ((hole = lseek(rfd, data, SEEK_HOLE)) < data) { hole = lseek(rfd, 0, SEEK_END); more = 0; } while ((c = hole - data) > 0) { if (c > state.buffersize) c = state.buffersize; if (lseek(rfd, data, SEEK_SET) != data || (n = read(rfd, state.tmp.buffer, (size_t)c)) <= 0) { error(ERROR_SYSTEM|2, "%s: read error", f->name); more = 0; break; } if (lseek(wfd, data, SEEK_SET) != data || write(wfd, state.tmp.buffer, n) != n) { error(ERROR_SYSTEM|2, "%s: write error", f->name); more = 0; break; } state.out->io->count += n; data += n; } if (!more) break; if ((data = lseek(rfd, hole, SEEK_DATA)) < hole) { if ((data = lseek(rfd, -1, SEEK_END)) < 0 || (data + 1) > hole && (lseek(wfd, data, SEEK_SET) != data || write(wfd, "", 1) != 1)) error(ERROR_SYSTEM|2, "%s: write error", f->name); state.out->io->count += 1; break; } } #else holeinit(wfd); for (c = f->st->st_size; c > 0; c -= n) { if ((n = read(rfd, state.tmp.buffer, (size_t)((c > state.buffersize) ? state.buffersize : c))) <= 0) { error(ERROR_SYSTEM|2, "%s: read error", f->name); break; } if (holewrite(wfd, state.tmp.buffer, n) != n) { error(ERROR_SYSTEM|2, "%s: write error", f->name); break; } state.out->io->count += n; } holedone(wfd); #endif closeout(state.out, f, wfd); closein(state.out, f, rfd); setfile(state.out, f); listentry(f); } else closeout(state.out, f, wfd); } else if (wfd != -1) listentry(f); } return 0; }
static int paxdata(Pax_t* pax, Paxarchive_t* ap, Paxfile_t* f, int fd, void* b, off_t n) { return holewrite(fd, b, n) == n ? 0 : -1; }