/* pow! - the pow!erful package manager Copyright (C) 2026 forever2k38 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "pow_lua.h" #include "config.h" #include "log.h" #include "archive.h" #include "stdio.h" #include "archive_entry.h" #include "lauxlib.h" #include "stdlib.h" #include "unistd.h" #include "string.h" #include "sys/sendfile.h" int pow_lua_extract(lua_State *L) { int r; ssize_t size; struct archive *a; struct archive_entry *entry; if (!lua_isstring(L, 1)) { lua_pushnil(L); lua_pushstring(L, "arg 1 must be string (src)"); return 2; } if (!lua_isstring(L, 2)) { lua_pushnil(L); lua_pushstring(L, "arg 2 must be string (dest)"); return 2; } const char *filename = lua_tostring(L, 1); const char *dest = lua_tostring(L, 2); a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); if ((r = archive_read_open_filename(a, filename, 10240))) { return 0; } for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) pow_log_info("warn while unpacking: %s", archive_error_string(a)); if (r < ARCHIVE_WARN) { pow_log_error("error while unpacking: %s", archive_error_string(a)); lua_pop(L, 1); char *error_msg = malloc(256); lua_pushnil(L); if (!error_msg) { lua_pushstring(L, "error while unpacking and failed to malloc to push " "real error message"); pow_log_error("error while unpacking and failed to push real error message"); return 2; } snprintf(error_msg, 256, "error while unpacking: %s", archive_error_string(a)); lua_pushstring(L, error_msg); free(error_msg); return 2; } const char *cur = archive_entry_pathname(entry); if (cur) { size_t need = strlen(dest) + strlen(cur) + 2; char *full = malloc(need); if (!full) { lua_pushnil(L); lua_pushstring(L, "failed to malloc entry path\n"); archive_read_close(a); archive_read_free(a); return 2; } snprintf(full, need, "%s/%s", dest, cur); archive_entry_set_pathname(entry, full); free(full); } r = archive_read_extract(a, entry, 0); if (r < ARCHIVE_WARN) { lua_pushnil(L); lua_pushfstring( L, "failed to extract '%s': %s", archive_entry_pathname(entry), archive_error_string(a) ? archive_error_string(a) : "unknown"); archive_read_close(a); archive_read_free(a); return 2; } } archive_read_close(a); archive_read_free(a); lua_pushboolean(L, 1); return 1; } int pow_lua_install(lua_State *L) { if (!lua_isstring(L, 1)) { lua_pushnil(L); lua_pushstring(L, "arg 1 must be string (src)"); return 2; } if (!lua_isstring(L, 2)) { lua_pushnil(L); lua_pushstring(L, "arg 2 must be string (dest)"); return 2; } char *src = strdup(lua_tostring(L, 1)); if (!src) { pow_log_error("failed to strdup source string"); return 2; } char *dest = strdup(lua_tostring(L, 2)); if (!dest) { free(src); pow_log_error("failed to strdup dest string"); return 2; } pow_log_info("installing: %s to %s", src, dest); FILE *src_stream = fopen(src, "r"); if (!src_stream) { free(src); free(dest); pow_log_error("failed to open source file %s while installing", src); return 2; } FILE *dest_stream = fopen(dest, "w"); if (!dest_stream) { free(src); free(dest); fclose(src_stream); pow_log_error("failed to open destination file %s for writing while installing", dest); return 2; } int src_fd = fileno(src_stream); int dest_fd = fileno(dest_stream); struct stat src_stat = {0}; int result = fstat(src_fd, &src_stat); off_t copied = 0; while (result == 0 && copied < src_stat.st_size) { ssize_t written = sendfile(dest_fd, src_fd, &copied, SIZE_MAX); copied += written; if (written == -1) { result = -1; } } if (fchmod(dest_fd, src_stat.st_mode) == -1) { pow_log_error("failed to set permission bits, expect breakage!"); } return 1; } luaL_Reg libpow[] = {{"extract", pow_lua_extract}, {"install", pow_lua_install}, {NULL, NULL}}; int pow_lua_load(lua_State *L, pow_config *cfg) { luaL_newlib(L, libpow); lua_createtable(L, 0, 1); lua_pushstring(L, cfg->makeopts); lua_setfield(L, -2, "makeopts"); lua_setfield(L, -2, "config"); lua_setglobal(L, "pow"); return 0; }