diff options
Diffstat (limited to 'src/package.c')
-rw-r--r-- | src/package.c | 434 |
1 files changed, 301 insertions, 133 deletions
diff --git a/src/package.c b/src/package.c index 2c396be..9eb3aad 100644 --- a/src/package.c +++ b/src/package.c @@ -28,8 +28,11 @@ #include <assert.h> #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include "package.h" +#include "util.h" +#include "syrep.h" struct package_item; @@ -43,30 +46,44 @@ struct package_item { struct package { char *base; int count; + int read_fd, write_fd; + int x_endianess; + int compressed; struct package_item *items; struct package_item *last; }; -static int copy(FILE *f, FILE *t, uint32_t len) { - static char buf[2048*4]; + +static ssize_t package_read(struct package *p, void *d, size_t l) { + if (!p->compressed) + return loop_read(p->read_fd, d, l); + + assert(0); - while (len > 0) { - uint32_t n; - - if (feof(f)) - return -1; + return -1; +} - n = len > sizeof(buf) ? sizeof(buf) : len; - - if (fread(buf, n, 1, f) != 1) - return -1; - - if (fwrite(buf, n, 1, t) != 1) - return -1; - len -= n; - } +static ssize_t package_write(struct package *p, void *d, size_t l) { + if (!args.compress_flag) + return loop_write(p->write_fd, d, l); + assert(0); + + return -1; +} + +static int copy_deflate(struct package *p, int sfd, size_t l) { + + assert(0); + + return 0; +} + +static int copy_inflate(struct package *p, int dfd, size_t l) { + + assert(0); + return 0; } @@ -118,9 +135,153 @@ fail: return NULL; } +static void append_item(struct package *p, struct package_item *i) { + assert(p && i && !!p->last == !!p->items); + + i->next = NULL; + + if (p->last) { + p->last->next = i; + p->last = i; + } else + p->items = p->last = i; +} + +#define X(i) (((i)<<24)|(((i)<<8)&0x0F00)|(((i)>>8)&0x00F0)|((i)>>24)) + +static int read_item(struct package *p) { + char name[PACKAGE_ITEMNAMELEN+1]; + char path[PATH_MAX] = ""; + uint32_t size; + ssize_t r; + int fd = -1; + struct package_item *i; + + if (p->read_fd < 0) + return 0; + + if ((r = package_read(p, name, PACKAGE_ITEMNAMELEN)) != PACKAGE_ITEMNAMELEN) { + if (r == 0) { + close(p->read_fd); + p->read_fd = -1; + return 0; + } else if (r > 0) + fprintf(stderr, "Short read\n"); + else + fprintf(stderr, "read(): %s\n", strerror(errno)); + + goto fail; + } + + if ((r = package_read(p, &size, 4) != 4)) { + if (r >= 0) + fprintf(stderr, "Short read\n"); + else + fprintf(stderr, "read(): %s\n", strerror(errno)); + + goto fail; + } + + if (p->x_endianess) + size = X(size); + + snprintf(path, sizeof(path), "%s/%i", p->base, p->count++); + + if ((fd = open(path, O_RDWR|O_CREAT|O_EXCL, 0666)) < 0) { /* RDWR for mmap compatibility */ + fprintf(stderr, "open(\"%s\"): %s\n", path, strerror(errno)); + goto fail; + } + + if (!p->compressed) { + if (copy_fd(p->read_fd, fd, size) < 0) + goto fail; + } else { + if (copy_fd_inflate(p->read_fd, fd, size) < 0) + goto fail; + } + + if (!(i = item_new(name, path, 1))) + goto fail; + + append_item(p, i); + + close(fd); + + return 1; + +fail: + + if (fd >= 0) + close(fd); + + if (path[0]) + unlink(path); + + return -1; +} + + +static int write_item(struct package *p, struct package_item *i) { + char name[PACKAGE_ITEMNAMELEN+1]; + ssize_t r; + int fd = -1; + uint32_t size; + + if ((fd = open(i->path, O_RDONLY)) < 0) { + if (errno == ENOENT) + return 0; + + fprintf(stderr, "open(\"%s\"): %s\n", i->path, strerror(errno)); + goto fail; + } + + if ((size = filesize(fd)) < 0) + return -1; + + memset(name, 0, sizeof(name)); + strncpy(name, i->name, PACKAGE_ITEMNAMELEN); + + if ((r = package_write(p, name, PACKAGE_ITEMNAMELEN) != PACKAGE_ITEMNAMELEN)) { + if (r >= 0) + fprintf(stderr, "Short write\n"); + else + fprintf(stderr, "write(): %s\n", strerror(errno)); + + goto fail; + } + + if ((r = package_write(p, &size, 4) != 4)) { + if (r >= 0) + fprintf(stderr, "Short write\n"); + else + fprintf(stderr, "write(): %s\n", strerror(errno)); + + goto fail; + } + + if (size) { + if (!args.compress_flag) { + if (copy_fd(fd, p->write_fd, size) < 0) + goto fail; + } else { + if (copy_fd_deflate(fd, p->write_fd, size) < 0) + goto fail; + } + } + + close(fd); + return 0; + +fail: + + if (fd > 0) + close(fd); + + return -1; +} + struct package* package_open(const char *fn, int force) { struct package *p; - FILE *f = NULL; char path[PATH_MAX]; if (!(p = malloc(sizeof(struct package)))) { @@ -129,6 +290,7 @@ struct package* package_open(const char *fn, int force) { } memset(p, 0, sizeof(struct package)); + p->read_fd = p->write_fd = -1; tmp(path, sizeof(path)); if (!mkdtemp(path)) { @@ -142,71 +304,46 @@ struct package* package_open(const char *fn, int force) { } if (fn) { - if (!(f = fopen(fn, "r"))) { + if ((p->read_fd = open(fn, O_RDONLY)) < 0) { + if (errno != ENOENT || !force) { fprintf(stderr, "Failed to open <%s>: %s\n", fn, strerror(errno)); goto finish; } - } - - if (f) { - - for (;;) { - uint32_t len; - char name[PACKAGE_ITEM_NAME_LEN+1]; - FILE *d = NULL; - struct package_item *pi; - - if (!fread(name, sizeof(name)-1, 1, f)) - break; - - name[sizeof(name)-1] = 0; - - if (fread(&len, sizeof(len), 1, f) != 1) { - fprintf(stderr, "Short read while reading length: %s\n", strerror(errno)); - goto finish; - } - - snprintf(path, sizeof(path), "%s/%i", p->base, p->count++); - if (!(d = fopen(path, "w+"))) { - fprintf(stderr, "Failed to open target file: %s\n", strerror(errno)); - goto finish; - } - if (copy(f, d, len) < 0) { - fprintf(stderr, "Copy failed: %s\n", strerror(errno)); - fclose(d); - unlink(path); - goto finish; - } + } else if (p->read_fd >= 0) { + uint32_t id; + ssize_t r; - fclose(d); - if (!(pi = item_new(name, path, 1))) { - unlink(path); - fprintf(stderr, "Failed to allocate memory.\n"); - goto finish; - } - - assert(!!p->last == !!p->items); - - if (p->last) { - p->last->next = pi; - p->last = pi; - } else - p->items = p->last = pi; - } + if ((r = loop_read(p->read_fd, &id, 4)) != 4) { + if (r < 0) + fprintf(stderr, "read(): %s\n", strerror(errno)); + else + fprintf(stderr, "Short read\n"); + goto finish; + } - fclose(f); + if (id == PACKAGE_FILEID) + p->x_endianess = 0; + else if (id == X(PACKAGE_FILEID)) + p->x_endianess = 1; + else if (id == PACKAGE_FILEIDCOMPRESSED) + p->x_endianess = !(p->compressed = 1); + else if (id == X(PACKAGE_FILEIDCOMPRESSED)) + p->x_endianess = p->compressed = 1; + else { + fprintf(stderr, "%s is not a syrep snapshot or patch\n", fn); + goto finish; + } } + } return p; finish: - if (f) - fclose(f); if (p) package_remove(p); @@ -214,69 +351,68 @@ finish: return NULL; } +static int load_complete(struct package *p) { + int r; + + assert(p); + + if (p->read_fd < 0) + return 0; + + while ((r = read_item(p)) > 0); + + return r; +} + int package_save(struct package *p, const char *fn) { - FILE *f, *s = NULL; - int r = 0; + int r = -1; struct package_item *i; + uint32_t id; + ssize_t n; - assert(p); + assert(p && p->write_fd < 0); - if (!fn) - f = stdout; - else if (!(f = fopen(fn, "w+"))) - return -1; + if (load_complete(p) < 0) + goto finish; - for (i = p->items; i; i = i->next) { - char name[PACKAGE_ITEM_NAME_LEN+1]; - uint32_t len; - struct stat st; + if (!fn) + p->write_fd = STDOUT_FILENO; + else if ((p->write_fd = open(fn, O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) { /* RDWR for mmap compatibility */ + fprintf(stderr, "open(\"%s\") XX: %s\n", fn, strerror(errno)); + goto finish; + } - if (!i->name || !i->path) - continue; + id = p->compressed ? PACKAGE_FILEIDCOMPRESSED : PACKAGE_FILEID; - if (!(s = fopen(i->path, "r"))) - continue; + if ((n = loop_write(p->write_fd, &id, 4) != 4)) { + if (n < 0) + fprintf(stderr, "write(): %s\n", strerror(errno)); + else + fprintf(stderr, "Short write\n"); - //fprintf(stderr, "Saving %s (%s)...\n", i->name, i->path); - - memset(name, 0, sizeof(name)); - strncpy(name, i->name, sizeof(name)-1); - - if (fwrite(name, sizeof(name)-1, 1, f) != 1) { - r = 1; - break; - } - - if (fstat(fileno(s), &st) < 0) { - fprintf(stderr, "Could not get file size: %s\n", strerror(errno)); - r = 1; - break; - } - - len = st.st_size; - - if (fwrite(&len, sizeof(len), 1, f) != 1) { - r = 1; - break; - } + goto finish; + } - if (copy(s, f, len) < 0) { - fprintf(stderr, "Could not copy file to package: %s\n", strerror(errno)); - r = 1; - break; - } + + for (i = p->items; i; i = i->next) { - fclose(s); - s = NULL; + if (!i->name || !i->path) + continue; + + if (write_item(p, i) < 0) + goto finish; } + + r = 0; - if (s) - fclose(s); +finish: + + if (fn && p->write_fd >= 0) + close(p->write_fd); - if (fn) - fclose(f); + p->write_fd = -1; - if (r != 0) + if (r < 0 && fn) unlink(fn); return r; @@ -288,9 +424,23 @@ const char *package_get_item(struct package* p, const char *name, int c) { assert(p && name); for (i = p->items; i; i = i->next) - if (strncmp(name, i->name, PACKAGE_ITEM_NAME_LEN) == 0) + if (!strncmp(name, i->name, PACKAGE_ITEMNAMELEN)) return i->path; + for (;;) { + int r; + + if ((r = read_item(p)) < 0) + return NULL; + + if (r == 0) + break; + + assert(p->last); + if (!strncmp(name, p->last->name, PACKAGE_ITEMNAMELEN)) + return p->last->path; + } + if (!c) return NULL; @@ -301,13 +451,7 @@ const char *package_get_item(struct package* p, const char *name, int c) { return NULL; } - assert(!!p->last == !!p->items); - - if (p->last) { - p->last->next = i; - p->last = i; - } else - p->items = p->last = i; + append_item(p, i); return i->path; } @@ -317,17 +461,12 @@ int package_add_file(struct package *p, const char *name, const char *fn) { if (!(i = item_new(name, fn, 0))) return -1; - - if (p->last) { - p->last->next = i; - p->last = i; - } else - p->items = p->last = i; + + append_item(p, i); return 0; } - void package_remove(struct package *p) { struct package_item *i, *n; assert(p); @@ -353,17 +492,46 @@ void package_remove(struct package *p) { free(p->base); } + + if (p->read_fd >= 0) + close(p->read_fd); + + if (p->write_fd >= 0) + close(p->write_fd); + free(p); } int package_foreach(struct package *p, int (*cb) (struct package *p, const char *name, const char *path, void *u), void *u) { struct package_item *i; + char rname[PACKAGE_ITEMNAMELEN+1]; assert(p); - for (i = p->items; i; i = i->next) - if (cb(p, i->name, i->path, u) < 0) + for (i = p->items; i; i = i->next) { + memset(rname, 0, sizeof(rname)); + strncpy(rname, i->name, PACKAGE_ITEMNAMELEN); + if (cb(p, rname, i->path, u) < 0) return -1; + } + + for (;;) { + int r; + + if ((r = read_item(p)) < 0) + return -1; + + if (r == 0) + break; + assert(p->last); + + memset(rname, 0, sizeof(rname)); + strncpy(rname, p->last->name, PACKAGE_ITEMNAMELEN); + + if (cb(p, rname, p->last->path, u) < 0) + return -1; + } + return 0; } |