aboutsummaryrefslogtreecommitdiffstats
path: root/src/version.c
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2024-01-05 04:53:20 -0600
committerLibravatar bigfoot547 <[email protected]>2024-01-05 04:53:20 -0600
commit11672146b9bf67cae05e8e3207c9bd1e47d52220 (patch)
tree4d72fd88efbabeeb37509cdc99c5404528183ca1 /src/version.c
parentdownloads assets correctly (diff)
extracts natives
Diffstat (limited to 'src/version.c')
-rw-r--r--src/version.c148
1 files changed, 141 insertions, 7 deletions
diff --git a/src/version.c b/src/version.c
index 3568cf2..af7b56e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include <unistd.h>
#include <pcre2.h>
+#include <zip.h>
const char *const l2_version__messages[] = {
"Success",
@@ -27,6 +28,7 @@ const char *const l2_version__messages[] = {
"Error downloading version",
"Version not found",
"Max recursion depth exceeded",
+ "JAR format error",
NULL
};
@@ -971,13 +973,7 @@ unsigned l2_version__gen_one_library(json_t *lib, l2_subst_t *subst, struct l2_v
goto cleanup;
}
- if (classifier) {
- retlib->extract.extracttype = EXTRACT_OLD;
- } else if (has_class) {
- retlib->extract.extracttype = EXTRACT_NEW;
- } else {
- retlib->extract.extracttype = EXTRACT_NONE;
- }
+ retlib->extract.extract = !!json_is_object(json_object_get(lib, "natives"));
/* first, find the URL of the library */
json_t *jurl = json_object_get(lib, "url");
@@ -1367,3 +1363,141 @@ unsigned l2_version_download_jar(json_t *version, const char *specifier, char **
*path = pathstr;
return VERSION_SUCCESS;
}
+
+unsigned l2_version__extract_one_file(zip_t *archive, const char *dbg_libname, char **exclude, const char *template, zip_int64_t idx)
+{
+#define EXTRACT_READBUF_SIZE (4096)
+ unsigned res = VERSION_SUCCESS;
+ char *fname;
+ size_t sz;
+
+ FILE *ofile = NULL;
+ zip_file_t *file = NULL;
+ unsigned char buf[EXTRACT_READBUF_SIZE];
+
+ const char *entname = zip_get_name(archive, idx, ZIP_FL_ENC_GUESS);
+ if (!entname) {
+ CMD_WARN("Failed to get entry name in library %s: %s", dbg_libname, zip_strerror(archive));
+ res = VERSION_EZIP;
+ goto cleanup;
+ }
+
+ if (exclude) {
+ for (char **cur = exclude; *cur; ++cur) {
+ if (l2_launcher_strpre(*cur, entname)) {
+ res = VERSION_SUCCESS;
+ goto cleanup;
+ }
+ }
+ }
+
+ file = zip_fopen_index(archive, idx, 0);
+ if (!file) {
+ CMD_WARN("Failed to open entry in library %s: %s", dbg_libname, zip_strerror(archive));
+ res = VERSION_EZIP;
+ goto cleanup;
+ }
+
+ L2_ASPRINTF(fname, sz, "%s/%s", template, entname);
+ if (l2_launcher_mkdir_parents_ex(fname, 1) < 0) { /* TODO: maybe don't repeatedly check if /tmp exists lol */
+ CMD_WARN("Failed to extract entry %s from library %s: error making directory", entname, dbg_libname);
+ res = VERSION_ERRNO;
+ goto cleanup;
+ }
+
+ ofile = fopen(fname, "wb");
+ if (!ofile) {
+ CMD_WARN("Failed to open %s to extract %s from library %s: %s", fname, entname, dbg_libname, strerror(errno));
+ res = VERSION_ERRNO;
+ goto cleanup;
+ }
+
+ zip_int64_t nread;
+ while ((nread = zip_fread(file, buf, EXTRACT_READBUF_SIZE)) > 0) {
+ if (fwrite(buf, 1, nread, ofile) < (size_t)nread) {
+ CMD_WARN("Partial write while extracting %s from library %s", entname, dbg_libname);
+ res = VERSION_ERRNO;
+ goto cleanup;
+ }
+ }
+
+ CMD_DEBUG("Extracted %s for library %s", entname, dbg_libname);
+ res = VERSION_SUCCESS;
+
+cleanup:
+ if (file) zip_fclose(file);
+ if (ofile) fclose(ofile);
+ return res;
+
+#undef EXTRACT_READBUF_SIZE
+}
+
+unsigned l2_version__extract_lib_natives(struct l2_version_library *lib, const char *template)
+{
+ int err = 0;
+ unsigned res = VERSION_SUCCESS;
+ zip_t *archive = zip_open(lib->fullpath, ZIP_RDONLY, &err);
+
+ if (!archive) {
+ zip_error_t ze;
+ zip_error_init_with_code(&ze, err);
+ CMD_WARN("Failed to open library jar %s: %s", lib->artifactpath, zip_error_strerror(&ze));
+ zip_error_fini(&ze);
+ return VERSION_EZIP;
+ }
+
+ zip_int64_t nentry = zip_get_num_entries(archive, 0);
+ for (zip_int64_t idx = 0; idx < nentry; ++idx) {
+ if ((res = l2_version__extract_one_file(archive, lib->artifactpath, lib->extract.exclude, template, idx)) != VERSION_SUCCESS) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (archive) {
+ zip_discard(archive);
+ }
+
+ return res;
+}
+
+unsigned l2_version_extract_natives(struct l2_version_library *libs, char **out_nativesdir)
+{
+ char template[] = "/tmp/l2su-natives-XXXXXX"; /* TODO: make portable */
+ char *nativesdir;
+
+ for (struct l2_version_library *cur = libs; cur; cur = cur->next) {
+ if (cur->extract.extract) goto found;
+ }
+
+ CMD_INFO0("Not extracting natives, there are no libraries that require it.");
+ return 0;
+
+found:
+
+ if (!mkdtemp(template)) {
+ CMD_WARN("Failed to create directory for extracted natives: %s", strerror(errno));
+ return VERSION_ERRNO;
+ }
+
+ nativesdir = strdup(template);
+ if (!nativesdir) {
+ return VERSION_EALLOC;
+ }
+
+ unsigned res;
+ for (struct l2_version_library *cur = libs; cur; cur = cur->next) {
+ if (!cur->extract.extract) continue;
+ if ((res = l2_version__extract_lib_natives(cur, template)) != VERSION_SUCCESS) {
+ goto cleanup;
+ }
+ }
+
+ res = VERSION_SUCCESS;
+ *out_nativesdir = nativesdir;
+ nativesdir = NULL;
+
+cleanup:
+ free(nativesdir);
+ return res;
+}