201 lines
6.5 KiB
C++
201 lines
6.5 KiB
C++
// @lua-module fs FsLib
|
|
// @lua-const MAX_READ_BYTES integer 65536 Largest portable whole-file or line
|
|
// read.
|
|
|
|
#include "../helpers.h"
|
|
|
|
namespace esp32lua {
|
|
namespace bindings {
|
|
namespace {
|
|
|
|
constexpr int32_t MAX_READ_BYTES = 65536;
|
|
|
|
int32_t checkReadLimit(lua_State* state, int index) {
|
|
const int32_t maxBytes = checkInt(state, index);
|
|
luaL_argcheck(state, maxBytes >= 0 && maxBytes <= MAX_READ_BYTES, index,
|
|
"exceeds fs.MAX_READ_BYTES");
|
|
return maxBytes;
|
|
}
|
|
|
|
int exists(lua_State* state) {
|
|
const std::string path = checkString(state, 1);
|
|
lua_pushboolean(state, Runtime::from(state)->fs().exists(path));
|
|
return 1;
|
|
}
|
|
|
|
int fileSize(lua_State* state) {
|
|
const std::string path = checkString(state, 1);
|
|
int32_t size = 0;
|
|
const Status status = Runtime::from(state)->fs().fileSize(path, size);
|
|
if (!status.ok)
|
|
return pushError(state, status.error);
|
|
lua_pushinteger(state, size);
|
|
return 1;
|
|
}
|
|
|
|
int list(lua_State* state, bool directories) {
|
|
const std::string path = checkString(state, 1);
|
|
std::vector<std::string> names;
|
|
const FsProvider& fs = Runtime::from(state)->fs();
|
|
const Status status =
|
|
directories ? fs.listDirs(path, names) : fs.listFiles(path, names);
|
|
if (!status.ok)
|
|
return pushError(state, status.error);
|
|
pushStrings(state, names);
|
|
return 1;
|
|
}
|
|
|
|
int listDirs(lua_State* state) { return list(state, true); }
|
|
int listFiles(lua_State* state) { return list(state, false); }
|
|
|
|
int mkdir(lua_State* state) {
|
|
const std::string path = checkString(state, 1);
|
|
return pushStatus(state, Runtime::from(state)->fs().mkdir(path));
|
|
}
|
|
|
|
int readFile(lua_State* state) {
|
|
const int32_t maxBytes = checkReadLimit(state, 2);
|
|
const std::string path = checkString(state, 1);
|
|
std::string content;
|
|
const Status status =
|
|
Runtime::from(state)->fs().readFile(path, maxBytes, content);
|
|
if (!status.ok)
|
|
return pushError(state, status.error);
|
|
pushString(state, content);
|
|
return 1;
|
|
}
|
|
|
|
int readLineAt(lua_State* state) {
|
|
const int32_t offset = checkInt(state, 2);
|
|
const int32_t maxBytes = checkReadLimit(state, 3);
|
|
luaL_argcheck(state, offset >= 0, 2, "must not be negative");
|
|
const std::string path = checkString(state, 1);
|
|
|
|
bool found = false;
|
|
int32_t nextOffset = 0;
|
|
std::string line;
|
|
const Status status = Runtime::from(state)->fs().readLineAt(
|
|
path, offset, maxBytes, found, line, nextOffset);
|
|
if (!status.ok) {
|
|
lua_pushnil(state);
|
|
lua_pushnil(state);
|
|
pushString(state, status.error);
|
|
return 3;
|
|
}
|
|
if (!found) {
|
|
lua_pushnil(state);
|
|
return 1;
|
|
}
|
|
pushString(state, line);
|
|
lua_pushinteger(state, nextOffset);
|
|
return 2;
|
|
}
|
|
|
|
int remove(lua_State* state) {
|
|
const std::string path = checkString(state, 1);
|
|
return pushStatus(state, Runtime::from(state)->fs().remove(path));
|
|
}
|
|
|
|
int removeTree(lua_State* state) {
|
|
const std::string path = checkString(state, 1);
|
|
return pushStatus(state, Runtime::from(state)->fs().removeTree(path));
|
|
}
|
|
|
|
int rename(lua_State* state) {
|
|
const std::string source = checkString(state, 1);
|
|
const std::string destination = checkString(state, 2);
|
|
return pushStatus(state,
|
|
Runtime::from(state)->fs().rename(source, destination));
|
|
}
|
|
|
|
int writeFile(lua_State* state) {
|
|
const std::string path = checkString(state, 1);
|
|
const std::string content = checkString(state, 2);
|
|
return pushStatus(state, Runtime::from(state)->fs().writeFile(path, content));
|
|
}
|
|
|
|
const luaL_Reg FUNCTIONS[] = {
|
|
// --- Whether a path exists.
|
|
// @param path string Absolute SD-card path; traversal components are
|
|
// rejected.
|
|
// @return boolean
|
|
{"exists", exists},
|
|
// --- Returns the size of a file in bytes.
|
|
// @param path string Absolute SD-card path.
|
|
// @return integer|nil size
|
|
// @return string|nil error Present when the path is missing or not a file.
|
|
{"fileSize", fileSize},
|
|
// --- Lists the directories in a directory.
|
|
// @param path string Absolute directory path.
|
|
// @return string[]|nil names Sorted names, excluding hidden entries.
|
|
// @return string|nil error
|
|
{"listDirs", listDirs},
|
|
// --- Lists the files in a directory.
|
|
// @param path string Absolute directory path.
|
|
// @return string[]|nil names Sorted names, excluding hidden entries.
|
|
// @return string|nil error
|
|
{"listFiles", listFiles},
|
|
// --- Creates a directory.
|
|
// @param path string Absolute directory path.
|
|
// @return true|nil ok
|
|
// @return string|nil error
|
|
{"mkdir", mkdir},
|
|
// --- Reads a whole file.
|
|
// @param path string Absolute file path.
|
|
// @param maxBytes integer Maximum bytes to allocate, up to
|
|
// fs.MAX_READ_BYTES; oversized files fail rather than truncate.
|
|
// @return string|nil content
|
|
// @return string|nil error
|
|
{"readFile", readFile},
|
|
// --- Reads one line starting at a byte offset.
|
|
// @param path string Absolute file path.
|
|
// @param offset integer Zero-based byte offset; a mid-line offset advances
|
|
// to the next line.
|
|
// @param maxBytes integer Maximum line bytes to allocate, up to
|
|
// fs.MAX_READ_BYTES.
|
|
// @return string|nil line Nil at end of file or on failure.
|
|
// @return integer|nil nextOffset Byte offset of the following line.
|
|
// @return string|nil error Present when the file cannot be read or the line
|
|
// exceeds maxBytes.
|
|
{"readLineAt", readLineAt},
|
|
// --- Removes a file.
|
|
// @param path string Absolute file path. Firmware-protected roots cannot be
|
|
// removed.
|
|
// @return true|nil ok
|
|
// @return string|nil error
|
|
{"remove", remove},
|
|
// --- Removes a directory and everything below it.
|
|
// @param path string Absolute directory path. Firmware-protected roots
|
|
// cannot be removed.
|
|
// @return true|nil ok
|
|
// @return string|nil error
|
|
{"removeTree", removeTree},
|
|
// --- Renames a file or directory.
|
|
// @param source string Absolute source path.
|
|
// @param destination string Absolute destination path, which must not
|
|
// exist.
|
|
// @return true|nil ok
|
|
// @return string|nil error
|
|
{"rename", rename},
|
|
// --- Atomically replaces the destination or leaves its previous contents
|
|
// intact.
|
|
// @param path string Absolute file path.
|
|
// @param content string
|
|
// @return true|nil ok
|
|
// @return string|nil error
|
|
{"writeFile", writeFile},
|
|
{nullptr, nullptr},
|
|
};
|
|
|
|
} // namespace
|
|
|
|
void registerFs(lua_State* state) {
|
|
luaL_newlib(state, FUNCTIONS);
|
|
lua_pushinteger(state, MAX_READ_BYTES);
|
|
lua_setfield(state, -2, "MAX_READ_BYTES");
|
|
lua_setglobal(state, "fs");
|
|
}
|
|
|
|
} // namespace bindings
|
|
} // namespace esp32lua
|