-- 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 }