aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules4
m---------lib/microtar0
-rw-r--r--lib/microtar/LICENSE21
-rw-r--r--lib/microtar/README.md100
-rw-r--r--lib/microtar/src/microtar.c434
-rw-r--r--lib/microtar/src/microtar.h99
-rw-r--r--src/lpm.c150
-rw-r--r--src/lpm.lua2
8 files changed, 794 insertions, 16 deletions
diff --git a/.gitmodules b/.gitmodules
index c171b3a..b83fa2d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -15,10 +15,6 @@
path = lib/libzip
url = https://github.com/nih-at/libzip.git
shallow = true
-[submodule "lib/microtar"]
- path = lib/microtar
- url = https://github.com/rxi/microtar.git
- shallow = true
[submodule "lib/mbedtls"]
path = lib/mbedtls
url = https://github.com/Mbed-TLS/mbedtls.git
diff --git a/lib/microtar b/lib/microtar
deleted file mode 160000
-Subproject 27076e1b9290e9c7842bb7890a54fcf172406c8
diff --git a/lib/microtar/LICENSE b/lib/microtar/LICENSE
new file mode 100644
index 0000000..3502bc5
--- /dev/null
+++ b/lib/microtar/LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2017 rxi
+Copyright (c) 2024 Gaspartcho
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/lib/microtar/README.md b/lib/microtar/README.md
new file mode 100644
index 0000000..78d2f05
--- /dev/null
+++ b/lib/microtar/README.md
@@ -0,0 +1,100 @@
+# microtar (a fork)
+A lightweight tar library written in ANSI C
+Initially forked from https://github.com/rxi/microtar
+
+
+## Basic Usage
+The library consists of `microtar.c` and `microtar.h`. These two files can be
+dropped into an existing project and compiled along with it.
+
+
+#### Reading
+```c
+mtar_t tar;
+mtar_header_t h;
+char *p;
+
+/* Open archive for reading */
+mtar_open(&tar, "test.tar", "r");
+
+/* Print all file names and sizes */
+while ( (mtar_read_header(&tar, &h)) != MTAR_ENULLRECORD ) {
+ printf("%s (%d bytes)\n", h.name, h.size);
+ mtar_next(&tar);
+}
+
+/* Load and print contents of file "test.txt" */
+mtar_find(&tar, "test.txt", &h);
+p = calloc(1, h.size + 1);
+mtar_read_data(&tar, p, h.size);
+printf("%s", p);
+free(p);
+
+/* Close archive */
+mtar_close(&tar);
+```
+
+#### Writing
+```c
+mtar_t tar;
+const char *str1 = "Hello world";
+const char *str2 = "Goodbye world";
+
+/* Open archive for writing */
+mtar_open(&tar, "test.tar", "w");
+
+/* Write strings to files `test1.txt` and `test2.txt` */
+mtar_write_file_header(&tar, "test1.txt", strlen(str1));
+mtar_write_data(&tar, str1, strlen(str1));
+mtar_write_file_header(&tar, "test2.txt", strlen(str2));
+mtar_write_data(&tar, str2, strlen(str2));
+
+/* Finalize -- this needs to be the last thing done before closing */
+mtar_finalize(&tar);
+
+/* Close archive */
+mtar_close(&tar);
+```
+
+
+## Error handling
+All functions which return an `int` will return `MTAR_ESUCCESS` if the operation
+is successful. If an error occurs an error value less-than-zero will be
+returned; this value can be passed to the function `mtar_strerror()` to get its
+corresponding error string.
+
+
+## Wrapping a stream
+If you want to read or write from something other than a file, the `mtar_t`
+struct can be manually initialized with your own callback functions and a
+`stream` pointer.
+
+All callback functions are passed a pointer to the `mtar_t` struct as their
+first argument. They should return `MTAR_ESUCCESS` if the operation succeeds
+without an error, or an integer below zero if an error occurs.
+
+After the `stream` field has been set, all required callbacks have been set and
+all unused fields have been zeroset the `mtar_t` struct can be safely used with
+the microtar functions. `mtar_open` *should not* be called if the `mtar_t`
+struct was initialized manually.
+
+#### Reading
+The following callbacks should be set for reading an archive from a stream:
+
+Name | Arguments | Description
+--------|------------------------------------------|---------------------------
+`read` | `mtar_t *tar, void *data, unsigned size` | Read data from the stream
+`seek` | `mtar_t *tar, unsigned pos` | Set the position indicator
+`close` | `mtar_t *tar` | Close the stream
+
+#### Writing
+The following callbacks should be set for writing an archive to a stream:
+
+Name | Arguments | Description
+--------|------------------------------------------------|---------------------
+`write` | `mtar_t *tar, const void *data, unsigned size` | Write data to the stream
+
+
+## License
+This library is free software; you can redistribute it and/or modify it under
+the terms of the MIT license. See [LICENSE](LICENSE) for details.
diff --git a/lib/microtar/src/microtar.c b/lib/microtar/src/microtar.c
new file mode 100644
index 0000000..1cd9920
--- /dev/null
+++ b/lib/microtar/src/microtar.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2017 rxi
+ * Copyright (c) 2024 Gaspartcho
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "microtar.h"
+
+typedef struct {
+ // Original tar header fields
+ char file_path[100];
+ char file_mode[8];
+ char owner_user_id[8];
+ char owner_group_id[8];
+ char file_size[12];
+ char file_mtime[12];
+ char header_checksum[8];
+ char file_type;
+ char link_path[100];
+
+ // New UStar fields
+ char magic_bytes[6];
+ char version[2];
+ char owner_user_name[32];
+ char owner_group_name[32];
+ char device_major_number[8];
+ char device_minor_number[8];
+ char prefix[155];
+
+ char padding[12];
+} mtar_raw_header_t;
+
+
+static unsigned round_up(unsigned n, unsigned incr) {
+ return n + (incr - n % incr) % incr;
+}
+
+
+static unsigned checksum(const mtar_raw_header_t* rh) {
+ unsigned i;
+ unsigned char *p = (unsigned char*) rh;
+ unsigned res = 256;
+ for (i = 0; i < offsetof(mtar_raw_header_t, header_checksum); i++) {
+ res += p[i];
+ }
+ for (i = offsetof(mtar_raw_header_t, file_type); i < sizeof(*rh); i++) {
+ res += p[i];
+ }
+ return res;
+}
+
+
+static int tread(mtar_t *tar, void *data, unsigned size) {
+ int err = tar->read(tar, data, size);
+ tar->pos += size;
+ return err;
+}
+
+
+static int twrite(mtar_t *tar, const void *data, unsigned size) {
+ int err = tar->write(tar, data, size);
+ tar->pos += size;
+ return err;
+}
+
+
+static int write_null_bytes(mtar_t *tar, int n) {
+ int i, err;
+ char nul = '\0';
+ for (i = 0; i < n; i++) {
+ err = twrite(tar, &nul, 1);
+ if (err) {
+ return err;
+ }
+ }
+ return MTAR_ESUCCESS;
+}
+
+static int read_filename(char *dest, const char *name, const char *prefix) {
+ // If there's no prefix, use name directly
+ if (prefix[0] == '\0') {
+ strcpy(dest, name);
+ dest[100] = '\0';
+ return MTAR_ESUCCESS;
+ }
+
+ // If there is a prefix, the path is: <prefix> '/' <path>
+ strcpy(dest, prefix);
+ strcat(dest, "/");
+ strcat(dest, name);
+ dest[256] = '\0';
+
+ return MTAR_ESUCCESS;
+}
+
+
+static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
+ unsigned chksum1, chksum2;
+
+ /* If the checksum starts with a null byte we assume the record is NULL */
+ if (*rh->header_checksum == '\0') {
+ return MTAR_ENULLRECORD;
+ }
+
+ /* Build and compare checksum */
+ chksum1 = checksum(rh);
+ sscanf(rh->header_checksum, "%o", &chksum2);
+ if (chksum1 != chksum2) {
+ return MTAR_EBADCHKSUM;
+ }
+
+ /* Load raw header into header */
+ sscanf(rh->file_mode, "%o", &h->mode);
+ sscanf(rh->owner_user_id, "%o", &h->owner);
+ sscanf(rh->file_size, "%o", &h->size);
+ sscanf(rh->file_mtime, "%o", &h->mtime);
+ h->type = rh->file_type;
+ read_filename(h->name, rh->file_path, rh->prefix);
+ read_filename(h->linkname, rh->link_path, rh->prefix);
+
+ return MTAR_ESUCCESS;
+}
+
+
+static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
+ unsigned chksum;
+
+ /* Load header into raw header */
+ memset(rh, 0, sizeof(*rh));
+ sprintf(rh->file_mode , "%o", h->mode);
+ sprintf(rh->owner_user_id, "%o", h->owner);
+ sprintf(rh->file_size, "%o", h->size);
+ sprintf(rh->file_mtime, "%o", h->mtime);
+ rh->file_type = h->type ? h->type : MTAR_TREG;
+ strcpy(rh->file_path, h->name);
+ strcpy(rh->link_path, h->linkname);
+
+
+ /* Calculate and write checksum */
+ chksum = checksum(rh);
+ sprintf(rh->header_checksum, "%06o", chksum);
+ rh->header_checksum[7] = ' ';
+
+ return MTAR_ESUCCESS;
+}
+
+
+const char* mtar_strerror(int err) {
+ switch (err) {
+ case MTAR_ESUCCESS : return "success";
+ case MTAR_EFAILURE : return "failure";
+ case MTAR_EOPENFAIL : return "could not open";
+ case MTAR_EREADFAIL : return "could not read";
+ case MTAR_EWRITEFAIL : return "could not write";
+ case MTAR_ESEEKFAIL : return "could not seek";
+ case MTAR_EBADCHKSUM : return "bad checksum";
+ case MTAR_ENULLRECORD : return "null record";
+ case MTAR_ENOTFOUND : return "file not found";
+ }
+ return "unknown error";
+}
+
+
+static int file_write(mtar_t *tar, const void *data, unsigned size) {
+ unsigned res = fwrite(data, 1, size, tar->stream);
+ return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL;
+}
+
+static int file_read(mtar_t *tar, void *data, unsigned size) {
+ unsigned res = fread(data, 1, size, tar->stream);
+ return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
+}
+
+static int file_seek(mtar_t *tar, unsigned offset) {
+ int res = fseek(tar->stream, offset, SEEK_SET);
+ return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
+}
+
+static int file_close(mtar_t *tar) {
+ fclose(tar->stream);
+ return MTAR_ESUCCESS;
+}
+
+
+int mtar_open(mtar_t *tar, const char *filename, const char *mode) {
+ int err;
+ mtar_header_t h;
+
+ /* Init tar struct and functions */
+ memset(tar, 0, sizeof(*tar));
+ tar->write = file_write;
+ tar->read = file_read;
+ tar->seek = file_seek;
+ tar->close = file_close;
+
+ /* Assure mode is always binary */
+ if ( strchr(mode, 'r') ) mode = "rb";
+ if ( strchr(mode, 'w') ) mode = "wb";
+ if ( strchr(mode, 'a') ) mode = "ab";
+ /* Open file */
+ tar->stream = fopen(filename, mode);
+ if (!tar->stream) {
+ return MTAR_EOPENFAIL;
+ }
+ /* Read first header to check it is valid if mode is `r` */
+ if (*mode == 'r') {
+ err = mtar_read_header(tar, &h);
+ if (err != MTAR_ESUCCESS) {
+ mtar_close(tar);
+ return err;
+ }
+ }
+
+ /* Return ok */
+ return MTAR_ESUCCESS;
+}
+
+
+int mtar_close(mtar_t *tar) {
+ return tar->close(tar);
+}
+
+
+int mtar_seek(mtar_t *tar, unsigned pos) {
+ int err = tar->seek(tar, pos);
+ tar->pos = pos;
+ return err;
+}
+
+
+int mtar_rewind(mtar_t *tar) {
+ tar->remaining_data = 0;
+ tar->last_header = 0;
+ return mtar_seek(tar, 0);
+}
+
+
+int mtar_next(mtar_t *tar) {
+ int err, n;
+ mtar_header_t h;
+ /* Load header */
+ err = mtar_read_header(tar, &h);
+ if (err) {
+ return err;
+ }
+ /* Seek to next record */
+ n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
+ return mtar_seek(tar, tar->pos + n);
+}
+
+
+int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) {
+ int err;
+ mtar_header_t header;
+ /* Start at beginning */
+ err = mtar_rewind(tar);
+ if (err) {
+ return err;
+ }
+ /* Iterate all files until we hit an error or find the file */
+ while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) {
+ if ( !strcmp(header.name, name) ) {
+ if (h) {
+ *h = header;
+ }
+ return MTAR_ESUCCESS;
+ }
+ mtar_next(tar);
+ }
+ /* Return error */
+ if (err == MTAR_ENULLRECORD) {
+ err = MTAR_ENOTFOUND;
+ }
+ return err;
+}
+
+
+int mtar_read_header(mtar_t *tar, mtar_header_t *h) {
+ int err;
+ mtar_raw_header_t rh;
+ /* Save header position */
+ tar->last_header = tar->pos;
+ /* Read raw header */
+ err = tread(tar, &rh, sizeof(rh));
+ if (err) {
+ return err;
+ }
+ /* Seek back to start of header */
+ err = mtar_seek(tar, tar->last_header);
+ if (err) {
+ return err;
+ }
+ /* Load raw header into header struct and return */
+ return raw_to_header(h, &rh);
+}
+
+
+int mtar_update_header(mtar_header_t *h, mtar_header_t *oh) {
+ if (oh->mode) h->mode = oh->mode;
+ if (oh->owner) h->owner = oh->owner;
+ if (oh->size) h->size = oh->size;
+ if (oh->mtime) h->mtime = oh->mtime;
+ if (oh->type) h->type = oh->type;
+
+ if (oh->name[0] != '\0') strcpy(h->name, oh->name);
+ if (oh->linkname[0] != '\0') strcpy(h->linkname, oh->linkname);
+
+ return MTAR_ESUCCESS;
+}
+
+
+int mtar_clear_header(mtar_header_t *h){
+ h->mode = 0;
+ h->owner = 0;
+ h->size = 0;
+ h->mtime = 0;
+ h->type = 0;
+ bzero(h->name, strlen(h->name));
+ bzero(h->linkname, strlen(h->linkname));
+
+ return MTAR_ESUCCESS;
+}
+
+
+int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
+ int err;
+ /* If we have no remaining data then this is the first read, we get the size,
+ * set the remaining data and seek to the beginning of the data */
+ if (tar->remaining_data == 0) {
+ mtar_header_t h;
+ /* Read header */
+ err = mtar_read_header(tar, &h);
+ if (err) {
+ return err;
+ }
+ /* Seek past header and init remaining data */
+ err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
+ if (err) {
+ return err;
+ }
+ tar->remaining_data = h.size;
+ }
+ /* Read data */
+ err = tread(tar, ptr, size);
+ if (err) {
+ return err;
+ }
+ tar->remaining_data -= size;
+ /* If there is no remaining data we've finished reading and seek back to the
+ * header */
+ if (tar->remaining_data == 0) {
+ return mtar_seek(tar, tar->last_header);
+ }
+ return MTAR_ESUCCESS;
+}
+
+
+int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
+ mtar_raw_header_t rh;
+ /* Build raw header and write */
+ header_to_raw(&rh, h);
+ tar->remaining_data = h->size;
+ return twrite(tar, &rh, sizeof(rh));
+}
+
+
+int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) {
+ mtar_header_t h;
+ /* Build header */
+ memset(&h, 0, sizeof(h));
+ strcpy(h.name, name);
+ h.size = size;
+ h.type = MTAR_TREG;
+ h.mode = 0664;
+ /* Write header */
+ return mtar_write_header(tar, &h);
+}
+
+
+int mtar_write_dir_header(mtar_t *tar, const char *name) {
+ mtar_header_t h;
+ /* Build header */
+ memset(&h, 0, sizeof(h));
+ strcpy(h.name, name);
+ h.type = MTAR_TDIR;
+ h.mode = 0775;
+ /* Write header */
+ return mtar_write_header(tar, &h);
+}
+
+
+int mtar_write_data(mtar_t *tar, const void *data, unsigned size) {
+ int err;
+ /* Write data */
+ err = twrite(tar, data, size);
+ if (err) {
+ return err;
+ }
+ tar->remaining_data -= size;
+ /* Write padding if we've written all the data for this file */
+ if (tar->remaining_data == 0) {
+ return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos);
+ }
+ return MTAR_ESUCCESS;
+}
+
+
+int mtar_finalize(mtar_t *tar) {
+ /* Write two NULL records */
+ return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2);
+}
+
diff --git a/lib/microtar/src/microtar.h b/lib/microtar/src/microtar.h
new file mode 100644
index 0000000..1b3c09d
--- /dev/null
+++ b/lib/microtar/src/microtar.h
@@ -0,0 +1,99 @@
+
+/**
+ * Copyright (c) 2017 rxi
+ * Copyright (c) 2024 Gaspartcho
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the MIT license. See `microtar.c` for details.
+ */
+
+#ifndef MICROTAR_H
+#define MICROTAR_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define MTAR_VERSION "0.1.0"
+
+enum {
+ MTAR_ESUCCESS = 0,
+ MTAR_EFAILURE = -1,
+ MTAR_EOPENFAIL = -2,
+ MTAR_EREADFAIL = -3,
+ MTAR_EWRITEFAIL = -4,
+ MTAR_ESEEKFAIL = -5,
+ MTAR_EBADCHKSUM = -6,
+ MTAR_ENULLRECORD = -7,
+ MTAR_ENOTFOUND = -8
+};
+
+enum {
+ MTAR_TREG = '0',
+ MTAR_TLNK = '1',
+ MTAR_TSYM = '2',
+ MTAR_TCHR = '3',
+ MTAR_TBLK = '4',
+ MTAR_TDIR = '5',
+ MTAR_TFIFO = '6',
+ MTAR_TEHR = 'x', // PAX file format
+ MTAR_TEHRA = 'g', // PAX file format
+ MTAR_TGFP = 'K', // GNU file format
+ MTAR_TGLP = 'L' // GNU file format
+};
+
+typedef struct {
+ unsigned mode;
+ unsigned owner;
+ unsigned size;
+ unsigned mtime;
+ unsigned type;
+ char name[4096];
+ char linkname[4096];
+} mtar_header_t;
+
+
+typedef struct mtar_t mtar_t;
+
+struct mtar_t {
+ int (*read)(mtar_t *tar, void *data, unsigned size);
+ int (*write)(mtar_t *tar, const void *data, unsigned size);
+ int (*seek)(mtar_t *tar, unsigned pos);
+ int (*close)(mtar_t *tar);
+ void *stream;
+ unsigned pos;
+ unsigned remaining_data;
+ unsigned last_header;
+};
+
+
+const char* mtar_strerror(int err);
+
+int mtar_open(mtar_t *tar, const char *filename, const char *mode);
+int mtar_close(mtar_t *tar);
+
+int mtar_seek(mtar_t *tar, unsigned pos);
+int mtar_rewind(mtar_t *tar);
+int mtar_next(mtar_t *tar);
+int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
+int mtar_read_header(mtar_t *tar, mtar_header_t *h);
+int mtar_update_header(mtar_header_t *h, mtar_header_t *oh);
+int mtar_clear_header(mtar_header_t *h);
+int mtar_read_data(mtar_t *tar, void *ptr, unsigned size);
+
+int mtar_write_header(mtar_t *tar, const mtar_header_t *h);
+int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size);
+int mtar_write_dir_header(mtar_t *tar, const char *name);
+int mtar_write_data(mtar_t *tar, const void *data, unsigned size);
+int mtar_finalize(mtar_t *tar);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/lpm.c b/src/lpm.c
index cecd061..11084ed 100644
--- a/src/lpm.c
+++ b/src/lpm.c
@@ -668,6 +668,7 @@ static int lpm_extract(lua_State* L) {
if (strstr(src, ".zip")) {
int zip_error_code;
zip_t* archive = zip_open(src, ZIP_RDONLY, &zip_error_code);
+
if (!archive) {
zip_error_t zip_error;
zip_error_init_with_code(&zip_error, zip_error_code);
@@ -675,22 +676,27 @@ static int lpm_extract(lua_State* L) {
zip_error_fini(&zip_error);
return lua_error(L);
}
+
zip_int64_t entries = zip_get_num_entries(archive, 0);
for (zip_int64_t i = 0; i < entries; ++i) {
zip_file_t* zip_file = zip_fopen_index(archive, i, 0);
const char* zip_name = zip_get_name(archive, i, ZIP_FL_ENC_GUESS);
+
if (!zip_file) {
lua_pushfstring(L, "can't read zip archive file %s: %s", zip_name, zip_strerror(archive));
zip_close(archive);
return lua_error(L);
}
+
char target[MAX_PATH];
int target_length = snprintf(target, sizeof(target), "%s/%s", dst, zip_name);
+
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 = lua_fopen(L, target, "wb");
if (!file) {
@@ -702,6 +708,7 @@ static int lpm_extract(lua_State* L) {
mode_t m = S_IRUSR | S_IRGRP | S_IROTH;
zip_uint8_t os;
zip_uint32_t attr;
+
zip_file_get_external_attributes(archive, i, 0, &os, &attr);
if (os == ZIP_OPSYS_DOS) {
if (0 == (attr & FA_RDONLY))
@@ -711,52 +718,73 @@ static int lpm_extract(lua_State* L) {
} else {
m = (attr >> 16);
}
+
if (chmod(target, m)) {
zip_fclose(zip_file);
zip_close(archive);
return luaL_error(L, "can't chmod file %s: %s", target, strerror(errno));
}
+
while (1) {
char buffer[8192];
zip_int64_t length = zip_fread(zip_file, buffer, sizeof(buffer));
+
if (length == -1) {
lua_pushfstring(L, "can't read zip archive file %s: %s", zip_name, zip_file_strerror(zip_file));
zip_fclose(zip_file);
zip_close(archive);
return lua_error(L);
}
+
if (length == 0) break;
fwrite(buffer, sizeof(char), length, file);
}
+
fclose(file);
}
zip_fclose(zip_file);
}
zip_close(archive);
- } else {
+ }
+
+ else {
char actual_src[PATH_MAX];
- if (strstr(src, ".gz")) {
+
+ 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"))
- strcpy(actual_src, dst);
- else
+ 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");
+
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));
if (length == 0)
break;
fwrite(buffer, sizeof(char), length, file);
}
+
char error[128];
error[0] = 0;
if (!gzeof(gzfile)) {
@@ -764,57 +792,157 @@ static int lpm_extract(lua_State* L) {
strncpy(error, gzerror(gzfile, &error_number), sizeof(error));
error[sizeof(error)-1] = 0;
}
+
fclose(file);
gzclose(gzfile);
+
if (error[0])
return luaL_error(L, "can't unzip gzip archive %s: %s", src, error);
- } else {
+
+ } else
strcpy(actual_src, src);
- }
- if (strstr(src, ".tar")) {
- mtar_t tar = {0};
+
+ 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;*/
+
+ mtar_t tar = {0};
int err;
if ((err = mtar_open(&tar, actual_src, "r")))
return luaL_error(L, "can't open tar archive %s: %s", src, mtar_strerror(err));
+
mtar_header_t h;
+ mtar_header_t before_h;
+ mtar_header_t allways_h;
+ int has_ext_before = 0;
+ int has_ext_allways = 0;
+
while ((mtar_read_header(&tar, &h)) != MTAR_ENULLRECORD ) {
if (h.type == MTAR_TREG) {
+
+ if (has_ext_before) {
+ mtar_update_header(&h, &before_h);
+ has_ext_before = 0;
+ mtar_clear_header(&before_h);
+ }
+ if (has_ext_allways)
+ mtar_update_header(&h, &allways_h);
+
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));
}
+
if (chmod(target, h.mode))
return luaL_error(L, "can't extract tar archive file %s, can't chmod 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);
}
+
+ else if (h.type == MTAR_TEHR || h.type == MTAR_TEHRA) {
+ mtar_header_t *h_to_change;
+ if (h.type == MTAR_TEHR)
+ h_to_change = &before_h;
+ else
+ h_to_change = &allways_h;
+
+ char buffer[4096] = {0};
+ char current_read[8192] = {0}; // If a line is more than 8192 char long, will not work!
+ char last_read[4096] = {0};
+ int remaining = h.size;
+
+ has_ext_before = 1;
+
+ while (remaining > 0) {
+ int read_size = remaining < sizeof(buffer) ? remaining : sizeof(buffer);
+ remaining -= read_size;
+
+ if (mtar_read_data(&tar, buffer, read_size) != MTAR_ESUCCESS) {
+ mtar_close(&tar);
+ return luaL_error(L, "Error while reading extended: %s", strerror(errno));
+ }
+
+ strcpy(current_read, last_read);
+ current_read[strlen(last_read)] = '\0';
+ strcat(current_read, buffer);
+ current_read[strlen(last_read) + read_size] = '\0';
+
+ char *n_line_ptr = NULL;
+ char **l_line_ptr = NULL;
+ char *line = strtok_r(current_read, "\n", &n_line_ptr);
+
+ while (line != NULL) {
+ char *in_line_ptr = NULL;
+ strtok_r(line, " ", &in_line_ptr);
+ char *header_key = strtok_r(NULL, "=", &in_line_ptr);
+ char *header_val = strtok_r(NULL, "=", &in_line_ptr);
+
+ if (!strcmp(header_key, "path")) strcpy(h_to_change->name, header_val);
+ if (!strcmp(header_key, "linkpath")) strcpy(h_to_change->linkname, header_val);
+ // possibility to add more later
+
+ l_line_ptr = &n_line_ptr;
+ line = strtok_r(NULL, "\n", &n_line_ptr);
+ }
+
+ if (current_read[strlen(last_read) + read_size - 1] != '\n')
+ strcpy(last_read, strtok_r(current_read, "\n", l_line_ptr));
+ else
+ bzero(last_read, strlen(last_read));
+ }
+ }
+
+ else if (h.type == MTAR_TGFP) {
+ has_ext_before = 1;
+ int read_size = before_h.size < sizeof(before_h.name) ? before_h.size : sizeof(before_h.name);
+
+ if (mtar_read_data(&tar, before_h.name, read_size) != MTAR_ESUCCESS) {
+ mtar_close(&tar);
+ return luaL_error(L, "Error while reading GNU extended: %s", strerror(errno));
+ }
+ }
+
+ else if (h.type == MTAR_TGLP) {
+ has_ext_before = 1;
+ int read_size = before_h.size < sizeof(before_h.linkname) ? before_h.size : sizeof(before_h.linkname);
+
+ if (mtar_read_data(&tar, before_h.linkname, read_size) != MTAR_ESUCCESS) {
+ mtar_close(&tar);
+ return luaL_error(L, "Error while reading GNU extended: %s", strerror(errno));
+ }
+ }
+
mtar_next(&tar);
}
mtar_close(&tar);
- if (strstr(src, ".gz"))
+ if (strstr(src, ".gz") || strstr(src, ".tgz"))
unlink(actual_src);
}
}
diff --git a/src/lpm.lua b/src/lpm.lua
index 7beb181..3f2a6ab 100644
--- a/src/lpm.lua
+++ b/src/lpm.lua
@@ -873,7 +873,7 @@ function Addon:install(bottle, installing)
else
common.get(file.url, temporary_path, file.checksum, write_progress_bar)
local basename = common.basename(target_path)
- local is_archive = basename:find("%.zip$") or basename:find("%.tar%.gz$")
+ local is_archive = basename:find("%.zip$") or basename:find("%.tar%.gz$") or basename:find("%.tgz$")
local target = temporary_path
if is_archive or basename:find("%.gz$") then
log_action("Extracting file " .. basename .. " in " .. install_path)