aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lpm.c99
1 files changed, 60 insertions, 39 deletions
diff --git a/src/lpm.c b/src/lpm.c
index b17e2ae..5c0f232 100644
--- a/src/lpm.c
+++ b/src/lpm.c
@@ -35,7 +35,7 @@
#include <mbedtls/net.h>
#include <zlib.h>
-#include <libtar.h>
+#include <microtar.h>
#include <zip.h>
static char hex_digits[] = "0123456789abcdef";
@@ -438,27 +438,21 @@ static int lpm_certs(lua_State* L) {
}
-// We can have one because we're single-threaded, and extracting is an atomic operation.
-static gzFile gzf;
-static int gzopen_frontend(char *pathname, int oflags, int mode) {
- int fd = open(pathname, oflags, mode);
- if (fd == -1)
- return -1;
- if (!(gzf = gzdopen(fd, "rb"))) {
- errno = ENOMEM;
- gzf = NULL;
- return -1;
- }
- return fd;
+static int mkdirp(char* path, int len) {
+ for (int i = 0; i < len; ++i) {
+ if (path[i] == '/') {
+ path[i] = 0;
+ if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) && errno != EEXIST)
+ return -1;
+ path[i] = '/';
+ }
+ }
+ return 0;
}
-static int gzread_frontend(int fd, void* buf, size_t len) { return gzread(gzf, buf, len); }
-static int gzwrite_frontend(int fd, void* buf, size_t len) { return gzwrite(gzf, buf, len); }
-static int gzclose_frontend(int fd) { gzclose(gzf); }
-tartype_t gztype = {
- (openfunc_t) gzopen_frontend, (closefunc_t) gzclose_frontend,
- (readfunc_t) gzread_frontend, (writefunc_t) gzwrite_frontend
-};
+static int gzip_read(mtar_t* tar, void* data, unsigned int size) { return gzread(tar->stream, data, size) >= 0 ? MTAR_ESUCCESS : -1; }
+static int gzip_seek(mtar_t* tar, unsigned int pos) { return gzseek(tar->stream, pos, SEEK_SET) >= 0 ? MTAR_ESUCCESS : -1; }
+static int gzip_close(mtar_t* tar) { return gzclose(tar->stream) == Z_OK ? MTAR_ESUCCESS : -1; }
static int lpm_extract(lua_State* L) {
const char* src = luaL_checkstring(L, 1);
@@ -485,16 +479,10 @@ static int lpm_extract(lua_State* L) {
}
char target[MAX_PATH];
int target_length = snprintf(target, sizeof(target), "%s/%s", dst, zip_name);
- for (int i = 0; i < target_length; ++i) {
- if (target[i] == '/') {
- target[i] = 0;
- if (mkdir(target, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) && errno != EEXIST) {
- zip_fclose(zip_file);
- zip_close(archive);
- return luaL_error(L, "can't extract zip archive file %s, can't create directory %s: %s", src, target, strerror(errno));
- }
- target[i] = '/';
- }
+ if (!mkdirp(target, target_length)) {
+ zip_fclose(zip_file);
+ zip_close(archive);
+ return luaL_error(L, "can't extract zip archive file %s, can't create directory %s: %s", src, target, strerror(errno));
}
if (target[target_length-1] != '/') {
FILE* file = fopen(target, "wb");
@@ -521,15 +509,48 @@ static int lpm_extract(lua_State* L) {
}
zip_close(archive);
} else if (strstr(src, ".tar")) {
- TAR* archive;
- if (tar_open(&archive, src, strstr(src, ".gz") ? &gztype : NULL, O_RDONLY, 0, TAR_GNU))
- return luaL_error(L, "can't open tar archive %s: %s", src, strerror(errno));
- if (tar_extract_all(archive, (char*)dst)) {
- tar_close(archive);
- return luaL_error(L, "can't extract tar archive %s to %s: %s", src, dst, strerror(errno));
- }
- if (tar_close(archive))
- return luaL_error(L, "can't close tar archive %s: %s", src, strerror(errno));
+ mtar_t tar = {0};
+ int err;
+ if (strstr(src, ".gz")) {
+ tar.stream = gzopen(src, "rb");
+ if (!tar.stream)
+ return luaL_error(L, "can't open tar.gz archive %s: %s", src, strerror(errno));
+ tar.read = gzip_read;
+ tar.seek = gzip_seek;
+ tar.close = gzip_close;
+ } else if ((err = mtar_open(&tar, src, "r")))
+ return luaL_error(L, "can't open tar archive %s: %s", src, mtar_strerror(err));
+ mtar_header_t h;
+ while ((mtar_read_header(&tar, &h)) != MTAR_ENULLRECORD ) {
+ if (h.type == MTAR_TREG) {
+ char target[MAX_PATH];
+ int target_length = snprintf(target, sizeof(target), "%s/%s", dst, h.name);
+ if (mkdirp(target, target_length)) {
+ mtar_close(&tar);
+ return luaL_error(L, "can't extract tar archive file %s, can't create directory %s: %s", src, target, strerror(errno));
+ }
+ char buffer[8192];
+ FILE* file = fopen(target, "wb");
+ if (!file) {
+ mtar_close(&tar);
+ return luaL_error(L, "can't extract tar archive file %s, can't create file %s: %s", src, target, strerror(errno));
+ }
+ int remaining = h.size;
+ while (remaining > 0) {
+ int read_size = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
+ if (mtar_read_data(&tar, buffer, read_size) != MTAR_ESUCCESS) {
+ fclose(file);
+ mtar_close(&tar);
+ return luaL_error(L, "can't write file %s: %s", target, strerror(errno));
+ }
+ fwrite(buffer, sizeof(char), read_size, file);
+ remaining -= read_size;
+ }
+ fclose(file);
+ }
+ mtar_next(&tar);
+ }
+ mtar_close(&tar);
} else
return luaL_error(L, "unrecognized archive format %s", src);
return 0;