#include <config.h>
#include <compat.h>
+#include <assert.h>
#include <errno.h>
+#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <dpkg/fdio.h>
+#define MAXSHADOW 16
+static struct shadow {
+ int fd, shadow;
+ dev_t dev; ino_t ino;
+} shadowtab[MAXSHADOW];
+static size_t nshadow;
+
+static struct shadow *find_shadow(int fd)
+{
+ size_t i, j;
+ int rc;
+ struct stat st;
+
+ rc = fstat(fd, &st); assert(!rc);
+
+ for (i = j = 0; i < nshadow; i++) {
+ if (shadowtab[i].fd == fd) {
+ if (st.st_dev != shadowtab[i].dev || st.st_ino != shadowtab[i].ino)
+ { close(shadowtab[i].shadow); continue; }
+ return (&shadowtab[i]);
+ }
+ if (i != j) shadowtab[j] = shadowtab[i];
+ j++;
+ }
+ nshadow = j;
+ return (0);
+}
+
+int shadowed_fd_p(int fd) { return (!!find_shadow(fd)); }
+
+static void write_to_shadow(int fd, const void *p, size_t sz)
+{
+ const struct shadow *shadow = find_shadow(fd);
+ ssize_t n;
+
+ if (shadow) { n = write(shadow->shadow, p, sz); assert((size_t)n == sz); }
+}
+
+void save_copy(const char *path, const char *label, const char *ext)
+{
+ char buf[256];
+ int err = errno;
+ int i = 0;
+
+ for (;;) {
+ sprintf(buf, "/tmp/mdw/%s#%d.%s", label, i, ext);
+ if (!link(path, buf)) break;
+ assert(errno == EEXIST);
+ i++;
+ }
+ fprintf(stderr, ";; save `%s' as `%s'\n", path, buf);
+ errno = err;
+}
+
+void save_shadow(const char *label, const char *ext)
+{
+ char buf[256];
+
+ sprintf(buf, "/tmp/mdw/t.shadow-%s", label);
+ save_copy(buf, label, ext);
+}
+
+void open_shadow(int fd, const char *label)
+{
+ struct shadow *shadow;
+ struct stat st;
+ int rc;
+ char buf[256];
+
+ assert(!find_shadow(fd));
+ assert(nshadow < MAXSHADOW); shadow = &shadowtab[nshadow++];
+ sprintf(buf, "/tmp/mdw/t.shadow-%s", label);
+ unlink(buf);
+ shadow->fd = fd;
+ shadow->shadow = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+ assert(shadow->shadow >= 0);
+ rc = fstat(fd, &st); assert(!rc);
+ shadow->dev = st.st_dev;
+ shadow->ino = st.st_ino;
+}
+
+void close_shadow(int fd)
+{
+ int rc;
+ struct shadow *shadow;
+
+ shadow = find_shadow(fd); if (!shadow) return;
+ rc = close(shadow->shadow); assert(!rc);
+ assert(nshadow); nshadow--;
+ if (shadow != &shadowtab[nshadow]) *shadow = shadowtab[nshadow];
+}
+
ssize_t
fd_read(int fd, void *buf, size_t len)
{
}
if (n == 0)
break;
+write_to_shadow(fd, ptr + total, n);
total += n;
len -= n;
}
if (n == 0)
break;
+write_to_shadow(fd, buf, n);
total += n;
len -= n;
#include <sys/stat.h>
+#include <assert.h>
#include <errno.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
static int
tar_header_decode(struct tar_header *h, struct tar_entry *d)
{
- long checksum;
+ long checksum, calc_checksum;
errno = 0;
+if (errno) fprintf(stderr, ";; checkpoint #0: %s\n", strerror(errno));
if (memcmp(h->magic, TAR_MAGIC_GNU, 6) == 0)
d->format = TAR_FORMAT_GNU;
d->format = TAR_FORMAT_USTAR;
else
d->format = TAR_FORMAT_OLD;
+//if (errno) fprintf(stderr, ";; checkpoint #1: %s\n", strerror(errno));
d->type = (enum tar_filetype)h->linkflag;
if (d->type == TAR_FILETYPE_FILE0)
d->type = TAR_FILETYPE_FILE;
+if (errno) fprintf(stderr, ";; checkpoint #2: %s\n", strerror(errno));
/* Concatenate prefix and name to support ustar style long names. */
- if (d->format == TAR_FORMAT_USTAR && h->prefix[0] != '\0')
+ if (d->format == TAR_FORMAT_USTAR && h->prefix[0] != '\0') {
d->name = tar_header_get_prefix_name(h);
- else
+if (errno) fprintf(stderr, ";; checkpoint #3a: %s\n", strerror(errno));
+ } else {
d->name = m_strndup(h->name, sizeof(h->name));
+if (errno) fprintf(stderr, ";; checkpoint #3b: %s\n", strerror(errno));
+ }
d->linkname = m_strndup(h->linkname, sizeof(h->linkname));
d->stat.mode = tar_header_get_unix_mode(h);
/* Even though off_t is signed, we use an unsigned parser here because
* negative offsets are not allowed. */
d->size = TAR_ATOUL(h->size, off_t);
d->mtime = TAR_ATOSL(h->mtime, time_t);
+if (errno) fprintf(stderr, ";; checkpoint #4: %s\n", strerror(errno));
if (d->type == TAR_FILETYPE_CHARDEV || d->type == TAR_FILETYPE_BLOCKDEV)
d->dev = makedev(TAR_ATOUL(h->devmajor, dev_t),
TAR_ATOUL(h->devminor, dev_t));
else
d->dev = makedev(0, 0);
+//if (errno) fprintf(stderr, ";; checkpoint #5: %s\n", strerror(errno));
if (*h->user)
d->stat.uname = m_strndup(h->user, sizeof(h->user));
else
d->stat.uname = NULL;
d->stat.uid = TAR_ATOUL(h->uid, uid_t);
+//if (errno) fprintf(stderr, ";; checkpoint #6: %s\n", strerror(errno));
if (*h->group)
d->stat.gname = m_strndup(h->group, sizeof(h->group));
else
d->stat.gname = NULL;
d->stat.gid = TAR_ATOUL(h->gid, gid_t);
+//if (errno) fprintf(stderr, ";; checkpoint #7: %s\n", strerror(errno));
checksum = tar_atol8(h->checksum, sizeof(h->checksum));
+//if (errno) fprintf(stderr, ";; checkpoint #8: %s\n", strerror(errno));
/* Check for parse errors. */
- if (errno)
- return 0;
- return tar_header_checksum(h) == checksum;
+ if (errno) {
+fprintf(stderr, ";; header parse failed: %s\n", strerror(errno));
+ goto bad;
+ }
+ calc_checksum = tar_header_checksum(h);
+if (checksum != calc_checksum) {
+ fprintf(stderr, ";; header checksum %ld /= %ld\n", checksum, calc_checksum);
+ goto bad;
+}
+ return 1;
+
+
+bad: {
+ if (h->name[0]) {
+ int fd;
+ ssize_t n;
+ fd = open("/tmp/mdw/badhdr", O_CREAT | O_TRUNC | O_WRONLY, 0666); assert(fd >= 0);
+ n = write(fd, h, 512); assert(n == 512);
+ close(fd);
+ }
+ return (0);
+}
}
/**
while ((status = ops->read(ctx, buffer, TARBLKSZ)) == TARBLKSZ) {
int name_len;
+//fprintf(stderr, ";; ops->read -> %d\n", status);
if (!tar_header_decode((struct tar_header *)buffer, &h)) {
if (h.name[0] == '\0') {
/* End of tape. */
status = 0;
+fprintf(stderr, ";; End of tape.\n");
} else {
/* Indicates broken tarfile:
* “Header checksum error”. */
errno = 0;
status = -1;
+fprintf(stderr, ";; `Header checksum error'.\n");
}
tar_entry_destroy(&h);
break;
/* Indicates broken tarfile: “Bad header data”. */
errno = 0;
status = -1;
+fprintf(stderr, ";; `Bad header data'.\n");
tar_entry_destroy(&h);
break;
}
/* Compatibility with pre-ANSI ustar. */
if (h.name[name_len - 1] != '/') {
status = ops->extract_file(ctx, &h);
+if (status) fprintf(stderr, ";; extract_file(%s) failed: %s\n", h.name, strerror(errno));
break;
}
/* Else, fall through. */
h.name[name_len - 1] = '\0';
}
status = ops->mkdir(ctx, &h);
+if (status) fprintf(stderr, ";; mkdir(%s) failed: %s\n", h.name, strerror(errno));
break;
case TAR_FILETYPE_HARDLINK:
status = ops->link(ctx, &h);
+if (status) fprintf(stderr, ";; link(%s) failed: %s\n", h.name, strerror(errno));
break;
case TAR_FILETYPE_SYMLINK:
symlink_node = m_malloc(sizeof(*symlink_node));
case TAR_FILETYPE_BLOCKDEV:
case TAR_FILETYPE_FIFO:
status = ops->mknod(ctx, &h);
+if (status) fprintf(stderr, ";; mknod(%s) failed: %s\n", h.name, strerror(errno));
break;
case TAR_FILETYPE_GNU_LONGLINK:
status = tar_gnu_long(ctx, ops, &h, &next_long_link);
+if (status) fprintf(stderr, ";; long-link(%s) failed: %s\n", h.name, strerror(errno));
break;
case TAR_FILETYPE_GNU_LONGNAME:
status = tar_gnu_long(ctx, ops, &h, &next_long_name);
+if (status) fprintf(stderr, ";; long-name(%s) failed: %s\n", h.name, strerror(errno));
break;
default:
/* Indicates broken tarfile: “Bad header field”. */
errno = 0;
status = -1;
+fprintf(stderr, ";; `Bad header field'.\n");
}
tar_entry_destroy(&h);
- if (status != 0)
+ if (status != 0) {
/* Pass on status from coroutine. */
+fprintf(stderr, ";; bailing due to error\n");
break;
+ }
}
while (symlink_head) {
symlink_node = symlink_head->next;
- if (status == 0)
+ if (status == 0) {
status = ops->symlink(ctx, &symlink_head->h);
+if (status) fprintf(stderr, ";; symlink(%s) failed: %s\n", symlink_head->h.name, strerror(errno));
+ }
tar_entry_destroy(&symlink_head->h);
free(symlink_head);
symlink_head = symlink_node;
if (status > 0) {
/* Indicates broken tarfile: “Read partial header record”. */
errno = 0;
+fprintf(stderr, ";; `Read partial header record'.\n");
return -1;
} else {
/* Return whatever I/O function returned. */