delta.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1987-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Bell Laboratories
*
* pax delta archive support
*/
#include "pax.h"
#include <update.h>
/*
*/
static void
{
register char* s;
register char* e;
register int n;
char c;
return;
n = 0;
{
if (c == '\t' || c == '\n')
{
if (n)
{
*s = 0;
switch (n)
{
case DELTA_checksum:
break;
case DELTA_index:
break;
case DELTA_trailer:
{
}
break;
/*
* ignore unknown ops for future
*/
}
n = 0;
}
if (c == '\n')
break;
}
else if (!n) n = c;
else if (s < e) *s++ = c;
}
}
/*
* get supplemental delta header info
*/
void
{
register char* s;
int n;
unsigned long sum;
char c;
{
if (ap->delta && ap->delta->format && (ap->delta->format->variant == DELTA_94 || ap->delta->format->variant == DELTA_IGNORE && state.delta2delta))
{
{
else
{
getdeltaops(ap, f);
{
n = 12;
{
{
unsigned char* u = (unsigned char*)s;
int i;
i = *u++;
u += (i >> 3) & 07;
f->uncompressed = 0;
i &= 07;
while (i-- > 0)
}
{
}
}
}
}
}
}
}
}
/*
* get supplemental delta trailer info
*/
void
{
long n;
unsigned long x;
{
{
getdeltaops(ap, f);
}
{
}
else
{
error(2, "%s: %s: corrupt archive: checksum mismatch -- expected %08lx, got %08lx", ap->name, f->name, f->delta.checksum & 0xffffffff, x & 0xffffffff);
}
{
if (n > 0)
else
error(2, "%s: %s: corrupt archive: delta index out of sync by %d file%s", ap->name, f->name, -n, -n == 1 ? "" : "s");
}
}
}
/*
* initialize delta header output info
*/
void
{
register char* s;
register int n;
{
{
{
case DELTA_create:
s = "create";
break;
case DELTA_delete:
s = "delete";
break;
case DELTA_pass:
s = "pass";
break;
case DELTA_update:
s = "update";
break;
case DELTA_verify:
s = "verify";
break;
}
putkey(ap, ap->tmp.extended, &options[OPT_delta_checksum], NiL, f->delta.base->info->checksum & 0xffffffff);
}
else
{
n = sfsprintf(s, sizeof(ap->delta->hdrbuf), "%c%c%d\t%c%d\n", f->delta.op, DELTA_index, ap->delta->index, DELTA_trailer, DELTA_TRAILER);
n += DELTA_TRAILER;
}
}
}
/*
* output supplementary delta header info
*/
void
{
int n;
{
n += DELTA_TRAILER;
}
}
/*
* output supplementary delta trailer info
*/
void
{
register char* s;
register int n;
{
{
if (n != DELTA_TRAILER)
}
}
}
/*
* initialize delta tables
*/
void
{
nospace();
if (!ap->delta->tab && !(ap->delta->tab = hashalloc(NiL, HASH_set, HASH_ALLOCATE, HASH_name, "delta", 0)))
nospace();
}
/*
* get delta base archive info
*/
void
{
return;
{
}
else
{
{
if (!getprologue(bp))
}
else
{
}
}
{
}
}
/*
* verify untouched base files
*/
void
{
register int wfd;
register Member_t* d;
register off_t c;
register off_t n;
if (!state.delta.update && !state.list && ap->delta && ap->delta->base != ap && (pos = hashscan(ap->delta->tab, 0)))
{
{
{
if (!d->uncompressed)
{
{
if ((n = state.ordered ? bread(ap, state.tmp.buffer, n, n, 1) : read(ap->delta->base->io->fd, state.tmp.buffer, n)) <= 0)
{
break;
}
{
break;
}
}
}
else if (state.ordered) paxdelta(NiL, ap, d->info, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ap->delta->base, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT|DELTA_LIST, wfd, 0);
else paxdelta(NiL, ap, d->info, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ap->delta->base->io->fd, d->offset, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_OUTPUT|DELTA_COUNT|DELTA_LIST, wfd, 0);
}
}
}
}
/*
* output prefix dirs to the archive first
*/
static void
{
register char* s;
register Member_t* m;
d->mark = 1;
{
*s = 0;
{
nospace();
m->mark = 1;
}
else if (!m->mark)
*s = '/';
}
}
/*
* delta file if necessary and copy out
*/
void
{
register Member_t* d;
int dfd;
int skip;
if (d = op->delta && op->delta->tab && f->name ? (Member_t*)hashget(op->delta->tab, f->name) : (Member_t*)0)
d->mark = 1;
{
if (f->type == X_IFREG && f->linktype == NOLINK && (!d || f->st->st_mtime != d->mtime.tv_sec || (f->st->st_mode & X_IPERM) != (d->mode & X_IPERM)))
{
if (f->ordered)
{
f->ordered = 0;
return;
}
if (d)
{
message((-2, "delta: delta: file=%s offset=%ld size=%ld expand=%d", f->name, d->offset, d->size, d->uncompressed));
{
if (!d->uncompressed)
paxdelta(ip, op, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, op->delta->base, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
else if (!paxdelta(ip, op, d->info, DELTA_DEL|DELTA_BIO|DELTA_SIZE, op->delta->base, d->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, d->uncompressed, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
}
else if (!d->uncompressed)
paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, op->delta->base->io->fd, d->offset, d->size, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
else if (!paxdelta(ip, op, d->info, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, op->delta->base->io->fd, d->offset, d->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &dfd, 0))
paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_SIZE|DELTA_FREE, dfd, d->uncompressed, DELTA_TAR|DELTA_FD|DELTA_SIZE|DELTA_FREE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
}
else
{
paxdelta(ip, op, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
}
skip = 0;
}
else
{
if (skip)
{
skip = 0;
}
}
}
{
register char* s;
{
*s = 0;
*s = '/';
}
}
else if (f->fd >= 0)
else if (skip)
}
/*
* copy file from input to output archive
*/
static void
{
{
{
if (state.ordered) paxdelta(ip, NiL, f->delta.base->info, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
else paxdelta(ip, NiL, f->delta.base->info, DELTA_DEL|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ip->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
}
{
f->fd = -1;
f->ordered = 1;
}
}
}
/*
* copy the delta base archive delete entries
*/
void
{
register File_t* f;
register Member_t* d;
{
{
{
{
{
}
else
{
}
puttrailer(ap, f);
}
}
}
}
}
/*
* update file deltas from archive and output to archive
*/
void
{
register File_t* f;
register off_t c;
register ssize_t n;
Member_t* d;
Member_t* h;
char* p;
state.delta2delta = 0;
putprologue(op, 0);
while (getprologue(ip))
{
{
f->fd = -1;
if (f->ro)
else if (state.delta2delta)
{
else
}
{
case DELTA_create:
{
goto pass;
}
{
paxdelta(ip, op, f, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, 0);
{
paxdelta(ip, op, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
}
}
break;
case DELTA_pass:
{
{
paxdelta(ip, op, f, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
}
{
int wfd;
static char* tmp;
if (!tmp)
{
break;
}
{
{
break;
}
{
break;
}
}
p = f->path;
f->path = p;
}
}
break;
case DELTA_delete:
break;
case DELTA_update:
{
if (state.ordered) paxdelta(ip, op, f, DELTA_SRC|DELTA_BIO|DELTA_SIZE, ip->delta->base, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, 0);
else paxdelta(ip, op, f, DELTA_SRC|DELTA_FD|DELTA_OFFSET|DELTA_SIZE, ip->delta->base->io->fd, f->delta.base->offset, f->delta.base->size, DELTA_TAR|DELTA_TEMP|DELTA_OUTPUT, &f->fd, DELTA_DEL|DELTA_BIO|DELTA_SIZE, ip, f->st->st_size, 0);
{
paxdelta(ip, op, f, DELTA_TAR|DELTA_FD|DELTA_FREE|DELTA_SIZE, f->fd, f->st->st_size, DELTA_DEL|DELTA_TEMP|DELTA_OUTPUT, &f->fd, 0);
}
}
break;
case DELTA_verify:
pass:
{
}
break;
default:
break;
}
gettrailer(ip, f);
}
if (!getepilogue(ip))
break;
}
{
/*
* copy the non-empty untouched base hard links first
*/
{
{
if (!d->mark && d->info->linktype != HARDLINK && d->info->st->st_size > 0 && selectfile(op, d->info))
{
d->mark = 1;
}
}
}
/*
* copy the remaining untouched base files and deletes
*/
{
{
{
d->mark = 1;
{
{
d = h;
}
}
}
}
}
}
}
/*
* set delta info from pseudo file
*/
void
{
char* t;
int type;
dp = 0;
if (*++s == INFO_SEP)
{
*t++ = 0;
if (*s)
{
if (isdigit(*s))
s = sfprints("delta%s", s);
}
/*
* [<INFO_SEP>[<OP>]<VAL>]* may appear here
*/
while ((s = t) && *s != INFO_SEP)
{
*t++ = 0;
switch (*s++)
{
case INFO_ORDERED:
break;
}
}
}
if (!dp)
ap->checkdelta = 0;
}
/*
* check for delta pseudo file
*/
int
{
register char* s;
register char* t;
unsigned long checksum;
if (!f || !f->st->st_size && !f->st->st_dev && !f->st->st_ino && !(f->st->st_mode & (X_IRWXU|X_IRWXG|X_IRWXO)) && strmatch(f->name, INFO_MATCH))
{
if (ap->checkdelta)
{
ap->checkdelta = 0;
if (f)
{
s = f->name;
if (streq(s, "DELTA!!!"))
else if (*s++ == INFO_SEP)
{
else
{
*t = 0;
return 0;
}
}
}
{
}
{
{
message((-5, "checkdelta: %s size=%I*d:%I*d checksum=%08x:%08x", ap->delta->format->name, sizeof(size), size, sizeof(bp->size), bp->size, checksum, bp->checksum));
{
{
error(3, "%s: %s: base archive size mismatch -- expected %I*u, got %I*u", ap->name, bp->name, sizeof(size), size, sizeof(bp->size), bp->size);
}
error(1, "%s: %s: base archive checksum mismatch -- expected %08lx, got %08lx", ap->name, bp->name, checksum & 0xffffffff, bp->checksum & 0xffffffff);
}
}
{
}
return 1;
}
if (f)
}
else if (f && *f->name == INFO_SEP && strneq(f->name + 1, ID, IDLEN) && *(f->name + IDLEN + 1) == INFO_SEP)
{
getdeltaheader(ap, f);
return 1;
}
}
return 0;
}
#include <vdelta.h>
typedef struct
{
int* pfd;
int fd;
int op;
} Vdio_t;
#define Vdoff_t long
/*
* delta discipline read
*/
static int
{
message((-6, "delread: op=%o buf=%p n=%d off=%I*d nxt=%I*d", dp->op, buf, n, sizeof(off), off, sizeof(dp->offset), dp->offset));
{
{
}
else
{
{
return -1;
}
}
}
if (n <= 0)
{
message((-8, "delread: fd=%d n=%d siz=%I*d off=%I*d: seek error", dp->fd, n, sizeof(dp->vd.size), dp->vd.size, sizeof(dp->offset), dp->offset));
return 0;
}
if (n > 0)
return n;
}
/*
* delta discipline write
*/
static int
{
ssize_t k;
{
return n;
}
{
{
return n;
}
return -1;
}
}
/*
*/
int
{
ssize_t n;
int bufferclash = 0;
int hole = 0;
#if DEBUG
#endif
#if 0
#else
{
}
{
}
#endif
#if DEBUG
#endif
while (op)
{
#if DEBUG
#endif
{
{
}
{
op |= DELTA_BUFFER;
bufferclash = 1;
}
#if DEBUG
#endif
}
else if (op & DELTA_TEMP)
{
op &= ~DELTA_FREE;
#if DEBUG
#endif
}
else if (op & DELTA_BUFFER)
{
#if DEBUG
#endif
}
if (op & DELTA_OFFSET)
{
#if DEBUG
#endif
}
if (op & DELTA_SIZE)
{
#if DEBUG
#endif
}
if ((op & (DELTA_BIO|DELTA_OUTPUT)) == DELTA_BIO && dp->vd.size > 0 && dp->vd.size <= state.buffersize && (dp->vd.data = bget(dp->bp, dp->vd.size, NiL)))
{
op |= DELTA_BUFFER;
#if DEBUG
#endif
}
{
if (op & DELTA_OUTPUT)
{
{
hole = 1;
op |= DELTA_HOLE;
}
}
if ((op & (DELTA_FD|DELTA_TEMP)) == DELTA_FD && dp->base && lseek(dp->fd, dp->base, SEEK_SET) != dp->base)
#if DEBUG
#endif
}
if (op & DELTA_OUTPUT)
{
#if DEBUG
#endif
}
#if DEBUG
#endif
#if DEBUG
#endif
}
if (!gen)
#if 0
#endif
{
if (!(state.test & 0000020) && fp->variant != DELTA_88 && (state.buffer[bufferclash ? (state.delta.bufferindex = !state.delta.bufferindex) : state.delta.bufferindex].base || (state.buffer[state.delta.bufferindex].base = newof(0, char, state.delta.buffersize, 0)) || (state.delta.buffersize >>= 1) && (state.buffer[state.delta.bufferindex].base = newof(0, char, state.delta.buffersize, 0))))
{
}
}
{
case DELTA_88:
case DELTA_PATCH:
/*
* force the new interface into the old
* not the most efficient way but at least
* the rest of the code is clean
*/
{
static char* tmp;
{
{
{
}
{
case DELTA_BIO:
nospace();
if (bread(data[op].bp, data[op].vd.data, data[op].vd.size, data[op].vd.size, 1) != data[op].vd.size)
break;
case DELTA_FD:
nospace();
break;
}
}
{
case DELTA_88:
n = delta(data[DELTA_SRC].vd.data, data[DELTA_SRC].vd.size, data[DELTA_TAR].vd.data, data[DELTA_TAR].vd.size, data[DELTA_DEL].fd) ? -1L : lseek(data[DELTA_DEL].fd, (off_t)0, SEEK_END);
break;
case DELTA_PATCH:
error(1, "AHA %s %s/%s SRC=%d:%p TAR=%d:%p DEL=%d:%p", fp->name, ap->name, f->path, data[DELTA_SRC].vd.size, data[DELTA_SRC].vd.data, data[DELTA_TAR].vd.size, data[DELTA_TAR].vd.data, data[DELTA_DEL].vd.size, data[DELTA_DEL].vd.data);
n = 0;
break;
}
}
else
{
{
{
}
{
case DELTA_BIO:
nospace();
if (bread(data[op].bp, data[op].vd.data, data[op].vd.size, data[op].vd.size, 1) != data[op].vd.size)
/*FALLTHROUGH*/
case DELTA_BUFFER:
{
}
break;
}
}
{
case DELTA_88:
n = update(data[DELTA_SRC].fd, data[DELTA_SRC].base, data[DELTA_DEL].fd, data[DELTA_TAR].fd) ? -1L : lseek(data[DELTA_TAR].fd, (off_t)0, SEEK_END);
break;
case DELTA_PATCH:
break;
}
}
}
break;
default:
n = 0;
{
if (n == 15)
}
else
n = vdupdate((Vddisc_t*)&data[DELTA_SRC], (Vddisc_t*)&data[DELTA_TAR], (Vddisc_t*)&data[DELTA_DEL]);
break;
}
#if DEBUG
if (mp)
{
message((-5, "%s %s: %s:%s return=%ld", gen == &data[DELTA_DEL] ? "delta" : "update", fp->name, f->name, sfstruse(mp), n));
sfstrclose(mp);
}
#endif
if (n < 0)
{
return -1;
}
{
{
case DELTA_BUFFER|DELTA_FREE:
break;
case DELTA_FD|DELTA_FREE:
else
break;
}
{
}
listentry(f);
}
{
{
}
else
{
}
}
return 0;
}