OC-KittenOS/repository/libs/metamachine-vfs.lua

162 lines
3.8 KiB
Lua
Raw Normal View History

-- This is released into the public domain.
-- No warranty is provided, implied or otherwise.
-- metamachine-vgpu.lua : Virtual GPU library
-- Authors: 20kdc
return function (icecap, address, path, ro)
if path ~= "/" then
icecap.makeDirectory(path:sub(1, #path - 1))
end
local function resolvePath(p, post)
local pth = {}
local issue = false
string.gsub(p, "[^\\/]+", function (str)
if str == ".." then
if not pth[1] then
issue = true
else
table.remove(pth, #pth)
end
elseif str ~= "." then
table.insert(pth, str)
end
end)
if issue then
return
end
local str = path
if post then
str = str:sub(1, #str - 1)
end
for k, v in ipairs(pth) do
if k > 1 or post then
str = str .. "/"
end
str = str .. v
end
return str
end
local function wrapThing(fn, post, roStop)
-- If we're adding a "/", we get rid of the original "/".
--
local pofx = ""
if post then
pofx = "/"
end
return function (p)
if ro and roStop then
return false, "read-only filesystem"
end
p = resolvePath(p, post)
if p then
local nt = {pcall(fn, p .. pofx)}
if nt[1] then
return table.unpack(nt, 2)
end
end
return nil, "no such file or directory"
end
end
local function wrapStat(s)
return wrapThing(function (px)
local stat = icecap.stat(px)
if stat then
return stat[s]
end
end, false, false)
end
local handles = {}
local lHandle = 0
local modeMapping = {
r = false,
rb = false,
w = true,
wb = true,
a = "append",
ab = "append"
}
return {
type = "filesystem",
getLabel = function ()
return "VFS"
end,
setLabel = function (label)
end,
isReadOnly = function ()
return ro or icecap.isReadOnly()
end,
spaceUsed = function ()
return icecap.spaceUsed()
end,
spaceTotal = function ()
return icecap.spaceTotal()
end,
list = wrapThing(icecap.list, true, false),
exists = wrapThing(function (px)
if icecap.stat(px) then
return true
end
return false
end, false, false),
isDirectory = wrapStat(1),
size = wrapStat(2),
lastModified = wrapStat(3),
makeDirectory = wrapThing(icecap.makeDirectory, false, true),
rename = function (a, b)
if ro then return false, "read-only filesystem" end
a = resolvePath(a)
b = resolvePath(b)
if not (a and b) then
return nil, a
end
return icecap.rename(a, b)
end,
remove = wrapThing(icecap.remove, false, true),
--
open = function (p, mode)
checkArg(1, p, "string")
p = resolvePath(p)
if not p then return nil, "failed to open" end
if rawequal(mode, nil) then mode = "r" end
if modeMapping[mode] == nil then
error("unsupported mode " .. tostring(mode))
end
mode = modeMapping[mode]
if (mode ~= false) and ro then return nil, "read-only filesystem" end
lHandle = lHandle + 1
handles[lHandle] = icecap.open(p, mode)
if not handles[lHandle] then
return nil, "failed to open"
end
return lHandle
end,
read = function (fh, len)
checkArg(1, fh, "number")
checkArg(2, len, "number")
if not handles[fh] then return nil, "bad file descriptor" end
if not handles[fh].read then return nil, "bad file descriptor" end
return handles[fh].read(len)
end,
write = function (fh, data)
checkArg(1, fh, "number")
if not handles[fh] then return nil, "bad file descriptor" end
if not handles[fh].write then return nil, "bad file descriptor" end
return handles[fh].write(data)
end,
seek = function (fh, whence, point)
checkArg(1, fh, "number")
if not handles[fh] then return nil, "bad file descriptor" end
if not handles[fh].seek then return nil, "bad file descriptor" end
return handles[fh].seek(whence, point)
end,
close = function (fh)
checkArg(1, fh, "number")
if not handles[fh] then return nil, "bad file descriptor" end
handles[fh].close()
handles[fh] = nil
return true
end,
}
end