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

166 lines
4.4 KiB
Lua

-- Copyright (C) 2018-2021 by KittenOS NEO contributors
--
-- Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
-- THIS SOFTWARE.
-- 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