diff options
Diffstat (limited to 'src/version.c')
| -rw-r--r-- | src/version.c | 148 |
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; +} |
