summaryrefslogtreecommitdiffstats
path: root/src/package.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/package.c')
-rw-r--r--src/package.c434
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;
}