105 lines
3.1 KiB
Lua
105 lines
3.1 KiB
Lua
|
-- mkdir only
|
||
|
-- A portable filesystem API using LuaJIT's FFI
|
||
|
-- Retrieved 2024-07-13 from https://gist.githubusercontent.com/Techcable/503f35ceea9554fb81cf3a5c1aa550da/raw/33a29f59207335b743824fbb657e4721a12ce280/fs.lua
|
||
|
local ffi = require("ffi")
|
||
|
local table = require("table")
|
||
|
require("string")
|
||
|
-- Cache needed functions and locals
|
||
|
local C, errno, string = ffi.C, ffi.errno, ffi.string
|
||
|
local concat, insert = table.concat, table.insert
|
||
|
|
||
|
-- "Standard" C99 functions
|
||
|
ffi.cdef[[
|
||
|
char *strerror(int errnum);
|
||
|
]]
|
||
|
|
||
|
local exists, mkdir, PATH_SEPARATOR
|
||
|
if ffi.os == "Windows" then
|
||
|
ffi.cdef[[
|
||
|
bool CreateDirectoryA(const char *path, void *lpSecurityAttributes);
|
||
|
int _access(const char *path, int mode);
|
||
|
]]
|
||
|
function exists(path)
|
||
|
assert(type(path) == "string", "path isn't a string")
|
||
|
local result = C._access(path, 0) -- Check existence
|
||
|
return result == 0
|
||
|
end
|
||
|
|
||
|
function mkdir(path, _)
|
||
|
assert(type(path) == "string", "path isn't a string")
|
||
|
if not C.CreateDirectoryA(path, nil) then
|
||
|
local message = string(C.strerror(errno()))
|
||
|
error("Unable to create directory " .. path .. ": " .. message)
|
||
|
end
|
||
|
end
|
||
|
PATH_SEPARATOR = "\\"
|
||
|
elseif ffi.os == "Linux" or ffi.os == "OSX" then
|
||
|
ffi.cdef[[
|
||
|
int mkdir(const char *path, int mode);
|
||
|
int access(const char *path, int amode);
|
||
|
]]
|
||
|
function exists(path)
|
||
|
assert(type(path) == "string", "path isn't a string")
|
||
|
local result = C.access(path, 0) -- Check existence
|
||
|
return result == 0
|
||
|
end
|
||
|
function mkdir(path, mode)
|
||
|
assert(type(path) == "string", "path isn't a string")
|
||
|
local mode = tonumber(mode or "755", 8)
|
||
|
if C.mkdir(path, mode) ~= 0 then
|
||
|
local message = string(C.strerror(errno()))
|
||
|
error("Unable to create directory " .. path .. ": " .. message)
|
||
|
end
|
||
|
end
|
||
|
PATH_SEPARATOR = "/"
|
||
|
else
|
||
|
error("Unsupported operating system: " .. ffi.os)
|
||
|
end
|
||
|
|
||
|
local function join(...)
|
||
|
local parts = {}
|
||
|
for i = 1, select("#", ...) do
|
||
|
local part = select(i, ...)
|
||
|
insert(parts, part)
|
||
|
end
|
||
|
return concat(parts, PATH_SEPARATOR)
|
||
|
end
|
||
|
|
||
|
local function splitPath(path)
|
||
|
assert(type(path) == "string", "path isn't a string!")
|
||
|
local parts = {}
|
||
|
local lastIndex = 0
|
||
|
for i = 1, path:len() do
|
||
|
if path:sub(i, i) == PATH_SEPARATOR then
|
||
|
insert(parts, path:sub(lastIndex, i - 1))
|
||
|
lastIndex = i + 1
|
||
|
end
|
||
|
end
|
||
|
insert(parts, path:sub(lastIndex))
|
||
|
return parts
|
||
|
end
|
||
|
|
||
|
local function mkdirs(path)
|
||
|
local parts = splitPath(path)
|
||
|
local currentPath = parts[1]
|
||
|
for i=2, #parts do
|
||
|
if not exists(currentPath) then
|
||
|
mkdir(currentPath)
|
||
|
end
|
||
|
-- Note: This isn't suboptimal, since we really do need the intermediate results
|
||
|
currentPath = currentPath .. PATH_SEPARATOR .. parts[i]
|
||
|
end
|
||
|
if not exists(path) then
|
||
|
mkdir(path)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return {
|
||
|
exists = exists,
|
||
|
join = join,
|
||
|
mkdir = mkdir,
|
||
|
mkdirs = mkdirs,
|
||
|
splitPath = splitPath,
|
||
|
PATH_SEPERATOR = PATH_SEPARATOR
|
||
|
}
|