aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rwxr-xr-xbuild.sh6
m---------lib/xz0
-rw-r--r--src/lpm.c126
4 files changed, 94 insertions, 41 deletions
diff --git a/.gitmodules b/.gitmodules
index b83fa2d..7ebbbb6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -20,3 +20,6 @@
url = https://github.com/Mbed-TLS/mbedtls.git
tag = mbedtls-2.28.3
shallow = true
+[submodule "lib/xz"]
+ path = lib/xz
+ url = https://github.com/tukaani-project/xz.git
diff --git a/build.sh b/build.sh
index f5c13d4..f1d3c04 100755
--- a/build.sh
+++ b/build.sh
@@ -23,6 +23,10 @@ if [[ "$@" != *"-lz"* ]]; then
[[ ! -e "lib/zlib/build" ]] && { cd lib/zlib && mkdir build && cd build && $CC $COMPILE_FLAGS -O3 -D_LARGEFILE64_SOURCE -I.. ../*.c -c && $AR rc libz.a *.o && cp libz.a ../../prefix/lib && cp ../*.h ../../prefix/include && cd ../../../ || exit -1; }
LINK_FLAGS="$LINK_FLAGS -lz"
fi
+if [[ "$@" != *"-llzma"* ]]; then
+ [ ! -e "lib/xz/build" ] && { cd lib/xz && mkdir build && cd build && CFLAGS="$COMPILE_FLAGS -Wno-incompatible-pointer-types" cmake .. -G "Unix Makefiles" $CMAKE_DEFAULT_FLAGS&& $MAKE -j $JOBS && $MAKE install && cd ../../../ || exit -1; }
+ LINK_FLAGS="$LINK_FLAGS -llzma"
+fi
if [[ "$@" != *"-lmbedtls"* && "$@" != *"-lmbedcrypto"* && "$@" != *"-lmbedx509"* ]]; then
[ ! -e "lib/mbedtls/build" ] && { cd lib/mbedtls && mkdir build && cd build && CFLAGS="$COMPILE_FLAGS $CFLAGS_MBEDTLS -DMBEDTLS_MD4_C=1 -DMBEDTLS_DEBUG_C -w" cmake .. $CMAKE_DEFAULT_FLAGS -G "Unix Makefiles" -DENABLE_TESTING=OFF -DENABLE_PROGRAMS=OFF $SSL_CONFIGURE && CFLAGS="$COMPILE_FLAGS $CFLAGS_MBEDTLS -DMBEDTLS_MD4_C=1 -w" $MAKE -j $JOBS && $MAKE install && cd ../../../ || exit -1; }
LINK_FLAGS="$LINK_FLAGS -lmbedtls -lmbedx509 -lmbedcrypto"
@@ -32,7 +36,7 @@ if [[ "$@" != *"-lgit2"* ]]; then
LINK_FLAGS="-lgit2 $LINK_FLAGS"
fi
if [[ "$@" != *"-lzip"* ]]; then
- [ ! -e "lib/libzip/build" ] && { cd lib/libzip && mkdir build && cd build && CFLAGS="$COMPILE_FLAGS -Wno-incompatible-pointer-types" cmake .. -G "Unix Makefiles" $CMAKE_DEFAULT_FLAGS -DBUILD_TOOLS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_DOC=OFF -DENABLE_COMMONCRYPTO=OFF -DENABLE_GNUTLS=OFF -DENABLE_OPENSSL=OFF -DENABLE_BZIP2=OFF -DENABLE_LZMA=OFF -DENABLE_ZSTD=OFF && $MAKE -j $JOBS && $MAKE install && cd ../../../ || exit -1; }
+ [ ! -e "lib/libzip/build" ] && { cd lib/libzip && mkdir build && cd build && CFLAGS="$COMPILE_FLAGS -Wno-incompatible-pointer-types" cmake .. -G "Unix Makefiles" $CMAKE_DEFAULT_FLAGS -DBUILD_TOOLS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_DOC=OFF -DENABLE_COMMONCRYPTO=OFF -DENABLE_GNUTLS=OFF -DENABLE_OPENSSL=OFF -DENABLE_BZIP2=OFF -DENABLE_LZMA=ON -DENABLE_ZSTD=OFF && $MAKE -j $JOBS && $MAKE install && cd ../../../ || exit -1; }
LINK_FLAGS="$LINK_FLAGS -lzip"
fi
[[ "$@" != *"-lmicrotar"* ]] && COMPILE_FLAGS="$COMPILE_FLAGS -Ilib/microtar/src" && SRCS="$SRCS lib/microtar/src/microtar.c"
diff --git a/lib/xz b/lib/xz
new file mode 160000
+Subproject dbca3d078ec581600600abebbb18769d3d71391
diff --git a/src/lpm.c b/src/lpm.c
index ba509cd..bb40a39 100644
--- a/src/lpm.c
+++ b/src/lpm.c
@@ -31,6 +31,7 @@
#include <sys/stat.h>
#include <sys/file.h>
#include <git2.h>
+#include <lzma.h>
#include <mbedtls/sha256.h>
#include <mbedtls/x509.h>
#include <mbedtls/entropy.h>
@@ -873,10 +874,33 @@ static int mkdirp(lua_State* L, char* path, int len) {
#define FA_RDONLY 0x01 // FILE_ATTRIBUTE_READONLY
#define FA_DIREC 0x10 // FILE_ATTRIBUTE_DIRECTORY
+// Strips .tar.gz to .tar, .tgz to .tar, .txz to .tar, .tar.xz to .tar.
+// Assumes sizeof(dst) >= sizeof(src)
+static const char* strip_to_tar(char* dst, const char* src) {
+ int len = strlen(src);
+ if (strstr(src, ".tar") && (strstr(src, ".gz") || strstr(src, ".xz"))) {
+ strncpy(dst, src, imin(len - 3, PATH_MAX));
+ len -= 3;
+ } else if (strstr(src, ".tgz") || strstr(src, ".txz")) {
+ strncpy(dst, src, imin(len - 3, PATH_MAX));
+ strcat(dst, "tar");
+ } else
+ strcpy(dst, src);
+ dst[len] = 0;
+ return dst;
+}
+
static int lpm_extract(lua_State* L) {
const char* src = luaL_checkstring(L, 1);
const char* dst = luaL_checkstring(L, 2);
+ if (strlen(src) > PATH_MAX)
+ return luaL_error(L, "source path too large");
+
+ char error[128] = {0};
+ uint8_t inbuf[4096];
+ uint8_t outbuf[4096];
+
if (strstr(src, ".zip")) {
int zip_error_code;
zip_t* archive = zip_open(src, ZIP_RDONLY, &zip_error_code);
@@ -962,62 +986,84 @@ static int lpm_extract(lua_State* L) {
if (strstr(src, ".gz") || strstr(src, ".tgz")) {
gzFile gzfile = gzopen(src, "rb");
-
if (!gzfile)
return luaL_error(L, "can't open tar.gz archive %s: %s", src, strerror(errno));
-
- char buffer[8192];
- int len = strlen(src) - 3;
-
- if (strstr(src, ".tar"))
- strncpy(actual_src, src, len < PATH_MAX ? len : PATH_MAX);
- else if (strstr(src, ".tgz")) {
- strncpy(actual_src, src, len < PATH_MAX ? len : PATH_MAX);
- strcat(actual_src, "tar");
- len = strlen(src);
- }
- else
- strcpy(actual_src, dst);
-
- actual_src[len] = 0;
- FILE* file = lua_fopen(L, actual_src, "wb");
-
+ FILE* file = lua_fopen(L, strip_to_tar(actual_src, src), "wb");
if (!file) {
gzclose(gzfile);
return luaL_error(L, "can't open %s for writing: %s", actual_src, strerror(errno));
}
-
while (1) {
- int length = gzread(gzfile, buffer, sizeof(buffer));
+ int length = gzread(gzfile, inbuf, sizeof(inbuf));
if (length == 0)
break;
- fwrite(buffer, sizeof(char), length, file);
+ fwrite(inbuf, sizeof(char), length, file);
}
-
- char error[128];
- error[0] = 0;
- if (!gzeof(gzfile)) {
- int error_number;
- strncpy(error, gzerror(gzfile, &error_number), sizeof(error));
- error[sizeof(error)-1] = 0;
- }
-
+ char error[128] = {0};
+ int error_code = 0;
+ if (!gzeof(gzfile))
+ strncpy(error, gzerror(gzfile, &error_code), sizeof(error) - 1);
+
fclose(file);
gzclose(gzfile);
-
- if (error[0])
+
+ if (error_code)
return luaL_error(L, "can't unzip gzip archive %s: %s", src, error);
+ } else if (strstr(src, ".xz") || strstr(src, ".txz")) {
+ lzma_stream strm = LZMA_STREAM_INIT;
+ lzma_ret ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED);
+ if (ret != LZMA_OK)
+ return luaL_error(L, "can't unzip xz archive %s: %s", src, error);
+ lzma_action action = LZMA_RUN;
+
+ FILE* input = lua_fopen(L, src, "rb");
+ if (!input)
+ return luaL_error(L, "can't open %s for reading: %s", src, strerror(errno));
+ FILE* output = lua_fopen(L, strip_to_tar(actual_src, src), "wb");
+ if (!output) {
+ fclose(input);
+ return luaL_error(L, "can't open %s for writing: %s", actual_src, strerror(errno));
+ }
- } else
+ strm.next_in = inbuf;
+ strm.avail_in = 0;
+ strm.next_out = outbuf;
+ strm.avail_out = sizeof(outbuf);
+
+ while (ret != LZMA_STREAM_END) {
+ if (strm.avail_in == 0 && !feof(input)) {
+ strm.next_in = inbuf;
+ if ((strm.avail_in = fread(inbuf, 1, sizeof(inbuf), input)) < 0) {
+ lua_pushfstring(L, "can't read and unzip xz archive: %s: %s\n", src, strerror(errno));
+ break;
+ }
+ if (feof(input))
+ action = LZMA_FINISH;
+ }
+ ret = lzma_code(&strm, action);
+ if (strm.avail_out == 0 || ret == LZMA_STREAM_END) {
+ size_t write_size = sizeof(outbuf) - strm.avail_out;
+ if (fwrite(outbuf, 1, write_size, output) != write_size) {
+ lua_pushfstring(L, "can't write unzip xz archive: %s: %s\n", src, strerror(errno));
+ break;
+ }
+ strm.avail_out = sizeof(outbuf);
+ strm.next_out = outbuf;
+ }
+ if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
+ lua_pushfstring(L, "can't unzip xz archive %s, error: %d\n", src, ret);
+ break;
+ }
+ }
+ fclose(input);
+ fclose(output);
+ if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+ lua_error(L);
+ } else
strcpy(actual_src, src);
if (strstr(src, ".tar") || strstr(src, ".tgz")) {
- /* It's incredibly slow to do it this way, probably because of all the seeking.
- For now, just gunzip the whole file at once, and then untar it.
- tar.read = gzip_read;
- tar.seek = gzip_seek;
- tar.close = gzip_close;*/
-
+ // It's incredily slow to seek/read directly from a gzfile; so just unzip to an intermediate file first.
mtar_t tar = {0};
int err;
if ((err = mtar_open(&tar, actual_src, "r")))
@@ -1162,7 +1208,7 @@ static int lpm_extract(lua_State* L) {
}
}
mtar_close(&tar);
- if (strstr(src, ".gz") || strstr(src, ".tgz"))
+ if (strcmp(actual_src, src) != 0)
unlink(actual_src);
}
}