slimpack/src/entry/fs.c
2025-03-16 01:50:21 +02:00

126 lines
2.5 KiB
C

#define _GNU_SOURCE
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <err.h>
#include "lib.h"
static const char *fs_check_path(lua_State *ctx, int i, size_t *psize) {
size_t n;
const char *path = luaL_checklstring(ctx, 1, &n);
size_t real_len = strlen(path);
if (n != real_len) {
luaL_error(ctx, "path may not contain \\0");
return NULL;
}
if (psize) *psize = n;
return path;
}
static int lib_fs_mkdir(lua_State *ctx) {
size_t path_size;
const char *ro_path = fs_check_path(ctx, 1, &path_size);
bool recursive = lua_toboolean(ctx, 2);
if (recursive) {
char path[path_size + 1];
memcpy(path, ro_path, path_size + 1);
for (size_t i = 0; i <= path_size ; i++) {
if (path[i] == '/' || path[i] == '\0') {
path[i] = '\0';
if (mkdir(path, 0755) < 0 && errno != EEXIST) {
lua_pushnil(ctx);
lua_pushfstring(ctx, "can't make directory: %s", strerror(errno));
return 12;
}
if (i < path_size) path[i] = '/';
}
}
}
else {
if (mkdir(ro_path, 0755) < 0) {
lua_pushnil(ctx);
lua_pushfstring(ctx, "can't make directory: %s", strerror(errno));
return 12;
}
}
lua_pushboolean(ctx, true);
return 1;
}
static int lib_fs_symlink(lua_State *ctx) {
const char *src = fs_check_path(ctx, 1, NULL);
const char *dst = fs_check_path(ctx, 2, NULL);
if (symlink(src, dst) < 0) {
lua_pushnil(ctx);
lua_pushfstring(ctx, "failed to chmod: %s", strerror(errno));
return 2;
}
lua_pushboolean(ctx, true);
return 1;
}
static int lib_fs_chmod(lua_State *ctx) {
const char *path = fs_check_path(ctx, 1, NULL);
int mode;
if (lua_isinteger(ctx, 2)) {
mode = lua_tointeger(ctx, 2);
mode = mode & 0xFFF;
}
else {
const char *strmode = luaL_checkstring(ctx, 2);
mode = 0;
for (size_t i = 0; strmode[i]; i++) {
char c = strmode[i];
if (c >= '0' && c <= '7') {
mode <<= 3;
mode |= c - '0';
}
else {
return luaL_error(ctx, "invalid mode '%s' - must be an octal integer", strmode);
}
}
}
if (chmod(path, mode) < 0) {
lua_pushnil(ctx);
lua_pushfstring(ctx, "failed to chmod: %s", strerror(errno));
return 2;
}
lua_pushboolean(ctx, true);
return 1;
}
int fs_open_lib(lua_State *ctx) {
luaL_newlib(ctx, ((luaL_Reg[]) {
{ "mkdir", lib_fs_mkdir },
{ "chmod", lib_fs_chmod },
{ "symlink", lib_fs_symlink },
{ NULL, NULL },
}));
return 1;
}