// pw.fs: read-only access to the pack's files. The host confines every path to the pack root // and enforces every limit (SPEC.md section 7.5). #include "bindings.hpp" #include "host.hpp" #include "lua.h" #include "lualib.h" #include #include namespace packluau::bindings { namespace { /// 16 MiB by default; never more than 1 GiB in one read. constexpr std::uint64_t default_limit = 16ULL << 20U; constexpr std::uint64_t maximum_limit = 1ULL << 30U; int read(lua_State *state) { const std::string_view path = check_string(state, 1); const std::uint64_t limit = limit_option(state, 2, default_limit, maximum_limit); RunContext &run = context(state, Capability::read_fs); pl_str bytes{}; check(state, run, run.host->fs_read(run.host->ctx, str(path), limit, &bytes), "pw.fs.read"); const std::string_view text = view(bytes); push_text(state, text); return 1; } int list(lua_State *state) { const std::string_view directory = check_string(state, 1); RunContext &run = context(state, Capability::read_fs); pl_str_list entries{}; check(state, run, run.host->fs_list(run.host->ctx, str(directory), &entries), "pw.fs.list"); push_list(state, entries); return 1; } pl_file_kind kind_of(lua_State *state) { const std::string_view path = check_string(state, 1); RunContext &run = context(state, Capability::read_fs); pl_file_kind kind = PL_FILE_NONE; check(state, run, run.host->fs_stat(run.host->ctx, str(path), &kind), "pw.fs"); return kind; } int exists(lua_State *state) { lua_pushboolean(state, kind_of(state) != PL_FILE_NONE ? 1 : 0); return 1; } int is_directory(lua_State *state) { lua_pushboolean(state, kind_of(state) == PL_FILE_DIRECTORY ? 1 : 0); return 1; } int is_symlink(lua_State *state) { lua_pushboolean(state, kind_of(state) == PL_FILE_SYMLINK ? 1 : 0); return 1; } int sha512(lua_State *state) { const std::string_view path = check_string(state, 1); RunContext &run = context(state, Capability::read_fs); pl_str hex{}; check(state, run, run.host->fs_sha512(run.host->ctx, str(path), &hex), "pw.fs.sha512"); const std::string_view text = view(hex); push_text(state, text); return 1; } } // namespace void install_fs(lua_State *state) { lua_createtable(state, 0, 6); lua_pushcfunction(state, &read, "pw.fs.read"); lua_setfield(state, -2, "read"); lua_pushcfunction(state, &list, "pw.fs.list"); lua_setfield(state, -2, "list"); lua_pushcfunction(state, &exists, "pw.fs.exists"); lua_setfield(state, -2, "exists"); lua_pushcfunction(state, &is_directory, "pw.fs.is_directory"); lua_setfield(state, -2, "is_directory"); lua_pushcfunction(state, &is_symlink, "pw.fs.is_symlink"); lua_setfield(state, -2, "is_symlink"); lua_pushcfunction(state, &sha512, "pw.fs.sha512"); lua_setfield(state, -2, "sha512"); seal(state); } } // namespace packluau::bindings