aboutsummaryrefslogtreecommitdiff
path: root/lpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'lpm.c')
-rw-r--r--lpm.c575
1 files changed, 0 insertions, 575 deletions
diff --git a/lpm.c b/lpm.c
deleted file mode 100644
index c8584a5..0000000
--- a/lpm.c
+++ /dev/null
@@ -1,575 +0,0 @@
-#include <git2.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <lua.h>
-#include <lauxlib.h>
-#include <ctype.h>
-#include <lualib.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <archive.h>
-#include <archive_entry.h>
-
-#include <sys/stat.h>
-#include <git2.h>
-#include <openssl/evp.h>
-#include <curl/curl.h>
-
-#ifdef _WIN32
- #include <direct.h>
- #include <winsock2.h>
- #include <windows.h>
- #include <fileapi.h>
-#else
- #define MAX_PATH PATH_MAX
-#endif
-
-static char hex_digits[] = "0123456789abcdef";
-static int lpm_hash(lua_State* L) {
- size_t len;
- const char* data = luaL_checklstring(L, 1, &len);
- const char* type = luaL_optstring(L, 2, "string");
- unsigned char buffer[EVP_MAX_MD_SIZE];
- EVP_MD_CTX* c = EVP_MD_CTX_new();
- EVP_MD_CTX_init(c);
- EVP_DigestInit_ex(c, EVP_sha256(), NULL);
- if (strcmp(type, "file") == 0) {
- FILE* file = fopen(data, "rb");
- if (!file) {
- EVP_DigestFinal(c, buffer, NULL);
- return luaL_error(L, "can't open %s", data);
- }
- while (1) {
- unsigned char chunk[4096];
- size_t bytes = fread(chunk, 1, sizeof(chunk), file);
- EVP_DigestUpdate(c, chunk, bytes);
- if (bytes < 4096)
- break;
- }
- fclose(file);
- } else {
- EVP_DigestUpdate(c, data, len);
- }
- int digest_length;
- EVP_DigestFinal(c, buffer, &digest_length);
- EVP_MD_CTX_free(c);
- char hex_buffer[EVP_MAX_MD_SIZE * 2];
- for (size_t i = 0; i < digest_length; ++i) {
- hex_buffer[i*2+0] = hex_digits[buffer[i] >> 4];
- hex_buffer[i*2+1] = hex_digits[buffer[i] & 0xF];
- }
- lua_pushlstring(L, hex_buffer, digest_length * 2);
- hex_buffer[digest_length*2]=0;
- return 1;
-}
-
-int lpm_symlink(lua_State* L) {
- #ifndef _WIN32
- if (symlink(luaL_checkstring(L, 1), luaL_checkstring(L, 2)))
- return luaL_error(L, "can't create symlink %s: %s", luaL_checkstring(L, 2), strerror(errno));
- return 0;
- #else
- return luaL_error(L, "can't create symbolic link %s: your operating system sucks", luaL_checkstring(L, 2));
- #endif
-}
-
-int lpm_chmod(lua_State* L) {
- if (chmod(luaL_checkstring(L, 1), luaL_checkinteger(L, 2)))
- return luaL_error(L, "can't chmod %s: %s", luaL_checkstring(L, 1), strerror(errno));
- return 0;
-}
-
-/** BEGIN STOLEN LITE CODE **/
-#if _WIN32
-static LPWSTR utfconv_utf8towc(const char *str) {
- LPWSTR output;
- int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
- if (len == 0)
- return NULL;
- output = (LPWSTR) malloc(sizeof(WCHAR) * len);
- if (output == NULL)
- return NULL;
- len = MultiByteToWideChar(CP_UTF8, 0, str, -1, output, len);
- if (len == 0) {
- free(output);
- return NULL;
- }
- return output;
-}
-
-static char *utfconv_wctoutf8(LPCWSTR str) {
- char *output;
- int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
- if (len == 0)
- return NULL;
- output = (char *) malloc(sizeof(char) * len);
- if (output == NULL)
- return NULL;
- len = WideCharToMultiByte(CP_UTF8, 0, str, -1, output, len, NULL, NULL);
- if (len == 0) {
- free(output);
- return NULL;
- }
- return output;
-}
-#endif
-
-static int lpm_ls(lua_State *L) {
- const char *path = luaL_checkstring(L, 1);
-
-#ifdef _WIN32
- lua_settop(L, 1);
- lua_pushstring(L, path[0] == 0 || strchr("\\/", path[strlen(path) - 1]) != NULL ? "*" : "/*");
- lua_concat(L, 2);
- path = lua_tostring(L, -1);
-
- LPWSTR wpath = utfconv_utf8towc(path);
- if (wpath == NULL)
- return luaL_error(L, "can't ls %s: invalid utf8 character conversion", path);
-
- WIN32_FIND_DATAW fd;
- HANDLE find_handle = FindFirstFileExW(wpath, FindExInfoBasic, &fd, FindExSearchNameMatch, NULL, 0);
- free(wpath);
- if (find_handle == INVALID_HANDLE_VALUE)
- return luaL_error(L, "can't ls %s: %d", path, GetLastError());
- char mbpath[MAX_PATH * 4]; // utf-8 spans 4 bytes at most
- int len, i = 1;
- lua_newtable(L);
-
- do
- {
- if (wcscmp(fd.cFileName, L".") == 0) { continue; }
- if (wcscmp(fd.cFileName, L"..") == 0) { continue; }
-
- len = WideCharToMultiByte(CP_UTF8, 0, fd.cFileName, -1, mbpath, MAX_PATH * 4, NULL, NULL);
- if (len == 0) { break; }
- lua_pushlstring(L, mbpath, len - 1); // len includes \0
- lua_rawseti(L, -2, i++);
- } while (FindNextFileW(find_handle, &fd));
-
- int err = GetLastError();
- FindClose(find_handle);
- if (err != ERROR_NO_MORE_FILES)
- return luaL_error(L, "can't ls %s: %d", path, GetLastError());
- return 1;
-#else
- DIR *dir = opendir(path);
- if (!dir)
- return luaL_error(L, "can't ls %s: %d", path, strerror(errno));
- lua_newtable(L);
- int i = 1;
- struct dirent *entry;
- while ( (entry = readdir(dir)) ) {
- if (strcmp(entry->d_name, "." ) == 0) { continue; }
- if (strcmp(entry->d_name, "..") == 0) { continue; }
- lua_pushstring(L, entry->d_name);
- lua_rawseti(L, -2, i);
- i++;
- }
- closedir(dir);
- return 1;
-#endif
-}
-
-static int lpm_rmdir(lua_State *L) {
- const char *path = luaL_checkstring(L, 1);
-#ifdef _WIN32
- LPWSTR wpath = utfconv_utf8towc(path);
- int deleted = RemoveDirectoryW(wpath);
- free(wpath);
- if (!deleted)
- return luaL_error(L, "can't rmdir %s: %d", path, GetLastError());
-#else
- if (remove(path))
- return luaL_error(L, "can't rmdir %s: %s", path, strerror(errno));
-#endif
- return 0;
-}
-
-static int lpm_mkdir(lua_State *L) {
- const char *path = luaL_checkstring(L, 1);
-#ifdef _WIN32
- LPWSTR wpath = utfconv_utf8towc(path);
- if (wpath == NULL)
- return luaL_error(L, "can't mkdir %s: invalid utf8 character conversion", path);
- int err = _wmkdir(wpath);
- free(wpath);
-#else
- int err = mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
-#endif
- if (err < 0)
- return luaL_error(L, "can't mkdir %s: %s", path, strerror(errno));
- return 0;
-}
-
-static int lpm_stat(lua_State *L) {
- const char *path = luaL_checkstring(L, 1);
- lua_newtable(L);
-#ifdef _WIN32
- #define realpath(x, y) _wfullpath(y, x, MAX_PATH)
- struct _stat s;
- LPWSTR wpath = utfconv_utf8towc(path);
- if (wpath == NULL)
- return luaL_error(L, "can't stat %s: invalid utf8 character conversion", path);
- int err = _wstat(wpath, &s);
- LPWSTR wfullpath = realpath(wpath, NULL);
- free(wpath);
- if (!wfullpath) return 0;
- char *abs_path = utfconv_wctoutf8(wfullpath);
- free(wfullpath);
-#else
- struct stat s;
- int err = lstat(path, &s);
- char *abs_path = realpath(path, NULL);
-#endif
- if (err || !abs_path) {
- lua_pushnil(L);
- lua_pushstring(L, strerror(errno));
- return 2;
- }
- lua_pushstring(L, abs_path); lua_setfield(L, -2, "abs_path");
- lua_pushvalue(L, 1); lua_setfield(L, -2, "path");
-
-#if __linux__
- if (S_ISLNK(s.st_mode)) {
- char buffer[PATH_MAX];
- ssize_t len = readlink(path, buffer, sizeof(buffer));
- if (len < 0)
- return 0;
- lua_pushlstring(L, buffer, len);
- } else
- lua_pushnil(L);
- lua_setfield(L, -2, "symlink");
- if (S_ISLNK(s.st_mode))
- err = stat(path, &s);
- if (err)
- return 1;
-#endif
- lua_pushinteger(L, s.st_mtime); lua_setfield(L, -2, "modified");
- lua_pushinteger(L, s.st_size); lua_setfield(L, -2, "size");
- if (S_ISREG(s.st_mode)) {
- lua_pushstring(L, "file");
- } else if (S_ISDIR(s.st_mode)) {
- lua_pushstring(L, "dir");
- } else {
- lua_pushnil(L);
- }
- lua_setfield(L, -2, "type");
- return 1;
-}
-/** END STOLEN LITE CODE **/
-
-static const char* git_error_last_string() {
- const git_error* last_error = git_error_last();
- return last_error->message;
-}
-
-static int git_get_id(git_oid* commit_id, git_repository* repository, const char* name) {
- int length = strlen(name);
- int is_hex = length == 40;
- for (int i = 0; is_hex && i < length; ++i)
- is_hex = isxdigit(name[i]);
- if (!is_hex)
- return git_reference_name_to_id(commit_id, repository, name);
- return git_oid_fromstr(commit_id, name);
-}
-
-static git_repository* luaL_checkgitrepo(lua_State* L, int index) {
- const char* path = luaL_checkstring(L, index);
- git_repository* repository;
- if (git_repository_open(&repository, path))
- return (void*)(long long)luaL_error(L, "git open error: %s", git_error_last_string());
- return repository;
-}
-
-
-static git_commit* git_retrieve_commit(git_repository* repository, const char* commit_name) {
- git_oid commit_id;
- git_commit* commit;
- if (git_get_id(&commit_id, repository, commit_name) || git_commit_lookup(&commit, repository, &commit_id))
- return NULL;
- return commit;
-}
-
-
-static int lpm_reset(lua_State* L) {
- git_repository* repository = luaL_checkgitrepo(L, 1);
- const char* commit_name = luaL_checkstring(L, 2);
- const char* type = luaL_checkstring(L, 3);
- git_commit* commit = git_retrieve_commit(repository, commit_name);
- if (!commit) {
- git_repository_free(repository);
- return luaL_error(L, "git retrieve commit error: %s", git_error_last_string());
- }
- git_reset_t reset_type = GIT_RESET_SOFT;
- if (strcmp(type, "mixed") == 0)
- reset_type = GIT_RESET_MIXED;
- else if (strcmp(type, "hard") == 0)
- reset_type = GIT_RESET_HARD;
- int result = git_reset(repository, (git_object*)commit, reset_type, NULL);
- git_commit_free(commit);
- git_repository_free(repository);
- if (result)
- return luaL_error(L, "git reset error: %s", git_error_last_string());
- return 0;
-}
-
-
-static int lpm_init(lua_State* L) {
- const char* path = luaL_checkstring(L, 1);
- const char* url = luaL_checkstring(L, 2);
- git_repository* repository;
- if (git_repository_init(&repository, path, 0) != 0)
- return luaL_error(L, "git init error: %s", git_error_last_string());
- git_remote* remote;
- if (git_remote_create(&remote, repository, "origin", url)) {
- git_repository_free(repository);
- return luaL_error(L, "git remote add error: %s", git_error_last_string());
- }
- git_remote_free(remote);
- git_repository_free(repository);
- return 0;
-}
-
-
-static int lpm_fetch(lua_State* L) {
- git_repository* repository = luaL_checkgitrepo(L, 1);
- git_remote* remote;
- if (git_remote_lookup(&remote, repository, "origin")) {
- git_repository_free(repository);
- return luaL_error(L, "git remote fetch error: %s", git_error_last_string());
- }
- git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
- if (git_remote_fetch(remote, NULL, &fetch_opts, NULL)) {
- git_remote_free(remote);
- git_repository_free(repository);
- return luaL_error(L, "git remote fetch error: %s", git_error_last_string());
- }
- git_remote_free(remote);
- git_repository_free(repository);
- return 0;
-}
-
-
-static CURL *curl;
-static int lpm_certs(lua_State* L) {
- const char* type = luaL_checkstring(L, 1);
- const char* path = luaL_checkstring(L, 2);
- if (strcmp(type, "dir") == 0) {
- git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, path);
- curl_easy_setopt(curl, CURLOPT_CAINFO, path);
- } else {
- git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, path, NULL);
- curl_easy_setopt(curl, CURLOPT_CAPATH, path);
- }
- return 0;
-}
-
-static int lpm_extract(lua_State* L) {
- const char* src = luaL_checkstring(L, 1);
- const char* dst = luaL_optstring(L, 2, ".");
-
- char error_buffer[1024] = {0};
- struct archive_entry *entry;
- const void *buff;
- int flags = 0;
- int r;
- size_t size;
-#if ARCHIVE_VERSION_NUMBER >= 3000000
- int64_t offset;
-#else
- off_t offset;
-#endif
- struct archive *ar = archive_read_new();
- struct archive *aw = archive_write_disk_new();
- archive_write_disk_set_options(aw, flags);
- archive_read_support_format_tar(ar);
- archive_read_support_format_zip(ar);
- archive_read_support_filter_gzip(ar);
- if ((r = archive_read_open_filename(ar, src, 10240))) {
- snprintf(error_buffer, sizeof(error_buffer), "error extracting archive %s: %s", src, archive_error_string(ar));
- goto cleanup;
- }
- for (;;) {
- int r = archive_read_next_header(ar, &entry);
- if (r == ARCHIVE_EOF)
- break;
- if (r != ARCHIVE_OK) {
- snprintf(error_buffer, sizeof(error_buffer), "error extracting archive %s: %s", src, archive_error_string(ar));
- goto cleanup;
- }
- char path[MAX_PATH];
- strcpy(path, dst); strcat(path, "/");
- strncat(path, archive_entry_pathname(entry), sizeof(path) - 3); path[MAX_PATH-1] = 0;
- archive_entry_set_pathname(entry, path);
- if (archive_write_header(aw, entry) != ARCHIVE_OK) {
- snprintf(error_buffer, sizeof(error_buffer), "error extracting archive %s: %s", src, archive_error_string(aw));
- goto cleanup;
- }
- for (;;) {
- int r = archive_read_data_block(ar, &buff, &size, &offset);
- if (r == ARCHIVE_EOF)
- break;
- if (r != ARCHIVE_OK) {
- snprintf(error_buffer, sizeof(error_buffer), "error extracting archive %s: %s", src, archive_error_string(ar));
- goto cleanup;
- }
- if (archive_write_data_block(aw, buff, size, offset) != ARCHIVE_OK) {
- snprintf(error_buffer, sizeof(error_buffer), "error extracting archive %s: %s", src, archive_error_string(aw));
- goto cleanup;
- }
- }
- if (archive_write_finish_entry(aw) != ARCHIVE_OK) {
- snprintf(error_buffer, sizeof(error_buffer), "error extracting archive %s: %s", src, archive_error_string(aw));
- goto cleanup;
- }
- }
- cleanup:
- archive_read_close(ar);
- archive_read_free(ar);
- archive_write_close(aw);
- archive_write_free(aw);
- if (error_buffer[0])
- return luaL_error(L, "error extracting archive %s: %s", src, archive_error_string(ar));
- return 0;
-}
-
-static size_t lpm_curl_write_callback(char *ptr, size_t size, size_t nmemb, void *BL) {
- luaL_Buffer* B = BL;
- luaL_addlstring(B, ptr, size*nmemb);
- return size*nmemb;
-}
-
-static int lpm_get(lua_State* L) {
- long response_code;
- const char* url = luaL_checkstring(L, 1);
- const char* path = luaL_optstring(L, 2, NULL);
- // curl_easy_reset(curl);
- curl_easy_setopt(curl, CURLOPT_URL, url);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
- #ifdef _WIN32
- curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
- #endif
- if (path) {
- FILE* file = fopen(path, "wb");
- if (!file)
- return luaL_error(L, "error opening file %s: %s", path, strerror(errno));
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
- CURLcode res = curl_easy_perform(curl);
- if (res != CURLE_OK) {
- fclose(file);
- return luaL_error(L, "curl error accessing %s: %s", url, curl_easy_strerror(res));
- }
- fclose(file);
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
- if (response_code != 200)
- return luaL_error(L, "curl error accessing %s, non-200 response code: %d", url, response_code);
- lua_pushnil(L);
- lua_newtable(L);
- return 2;
- } else {
- luaL_Buffer B;
- luaL_buffinit(L, &B);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, lpm_curl_write_callback);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, &B);
- CURLcode res = curl_easy_perform(curl);
- if (res != CURLE_OK)
- return luaL_error(L, "curl error accessing %s: %s", url, curl_easy_strerror(res));
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
- if (response_code != 200)
- return luaL_error(L, "curl error accessing %s, non-200 response code: %d", url, response_code);
- luaL_pushresult(&B);
- lua_newtable(L);
- }
- return 2;
-}
-
-
-static const luaL_Reg system_lib[] = {
- { "ls", lpm_ls }, // Returns an array of files.
- { "stat", lpm_stat }, // Returns info about a single file.
- { "mkdir", lpm_mkdir }, // Makes a directory.
- { "rmdir", lpm_rmdir }, // Removes a directory.
- { "hash", lpm_hash }, // Returns a hex sha256 hash.
- { "symlink", lpm_symlink }, // Creates a symlink.
- { "chmod", lpm_chmod }, // Chmod's a file.
- { "init", lpm_init }, // Initializes a git repository with the specified remote.
- { "fetch", lpm_fetch }, // Updates a git repository with the specified remote.
- { "reset", lpm_reset }, // Updates a git repository to the specified commit/hash/branch.
- { "get", lpm_get }, // HTTP(s) GET request.
- { "extract", lpm_extract }, // Extracts .tar.gz, and .zip files.
- { "certs", lpm_certs }, // Sets the SSL certificate chain folder/file.
- { NULL, NULL }
-};
-
-
-#ifndef LPM_VERSION
- #define LPM_VERSION "unknown"
-#endif
-
-
-#ifndef LITE_ARCH_TUPLE
- #if __x86_64__ || _WIN64 || __MINGW64__
- #define ARCH_PROCESSOR "x86_64"
- #else
- #define ARCH_PROCESSOR "x86"
- #endif
- #if _WIN32
- #define ARCH_PLATFORM "windows"
- #elif __linux__
- #define ARCH_PLATFORM "linux"
- #elif __APPLE__
- #define ARCH_PLATFORM "darwin"
- #else
- #error "Please define -DLITE_ARCH_TUPLE."
- #endif
- #define LITE_ARCH_TUPLE ARCH_PROCESSOR "-" ARCH_PLATFORM
-#endif
-
-
-extern const char lpm_lua[];
-extern unsigned int lpm_lua_len;
-int main(int argc, char* argv[]) {
- curl = curl_easy_init();
- if (!curl)
- return -1;
- git_libgit2_init();
- lua_State* L = luaL_newstate();
- luaL_openlibs(L);
- luaL_newlib(L, system_lib);
- lua_setglobal(L, "system");
- lua_newtable(L);
- for (int i = 0; i < argc; ++i) {
- lua_pushstring(L, argv[i]);
- lua_rawseti(L, -2, i+1);
- }
- lua_setglobal(L, "ARGV");
- lua_pushliteral(L, LPM_VERSION);
- lua_setglobal(L, "VERSION");
- #if _WIN32
- lua_pushliteral(L, "windows");
- lua_pushliteral(L, "\\");
- #else
- lua_pushliteral(L, "posix");
- lua_pushliteral(L, "/");
- #endif
- lua_setglobal(L, "PATHSEP");
- lua_setglobal(L, "PLATFORM");
- lua_pushliteral(L, LITE_ARCH_TUPLE);
- lua_setglobal(L, "ARCH");
- #if LPM_LIVE
- if (luaL_loadfile(L, "lpm.lua") || lua_pcall(L, 0, 1, 0)) {
- #else
- if (luaL_loadbuffer(L, lpm_lua, lpm_lua_len, "lpm.lua") || lua_pcall(L, 0, 1, 0)) {
- #endif
- fprintf(stderr, "internal error when starting the application: %s\n", lua_tostring(L, -1));
- return -1;
- }
- int status = lua_tointeger(L, -1);
- lua_close(L);
- git_libgit2_shutdown();
- curl_easy_cleanup(curl);
- return status;
-}