forked from Hyperion/HyperionOS
179 lines
5.8 KiB
Plaintext
179 lines
5.8 KiB
Plaintext
local args = {...}
|
|
local kernel = args[1]
|
|
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
|
local disk = {}
|
|
disk.address = address
|
|
local isRO = readOnly or false
|
|
|
|
local backend = {
|
|
["/"] = { __dir = true }
|
|
}
|
|
|
|
-----------------------------------------------------------------
|
|
-- Helpers
|
|
-----------------------------------------------------------------
|
|
|
|
local function norm(path)
|
|
if not path or path == "" then return "/" end
|
|
if path:sub(1,1) ~= "/" then path = "/" .. path end
|
|
path = path:gsub("/+", "/")
|
|
return path
|
|
end
|
|
|
|
local function split(path)
|
|
local parts = {}
|
|
for p in path:gmatch("[^/]+") do table.insert(parts, p) end
|
|
return parts
|
|
end
|
|
|
|
local function getNode(path)
|
|
path = norm(path)
|
|
if path == "/" then return backend["/"] end
|
|
local node = backend["/"]
|
|
for _, part in ipairs(split(path)) do
|
|
node = node[part]
|
|
if not node then return nil end
|
|
end
|
|
return node
|
|
end
|
|
|
|
local function getParent(path)
|
|
local parts = split(norm(path))
|
|
local name = table.remove(parts)
|
|
local parentPath = "/" .. table.concat(parts, "/")
|
|
return getNode(parentPath), name
|
|
end
|
|
|
|
local function ensureWrite()
|
|
if isRO then return false, "read-only" end
|
|
return true
|
|
end
|
|
|
|
-----------------------------------------------------------------
|
|
-- File IO (supports string or file-object with read/write funcs)
|
|
-----------------------------------------------------------------
|
|
|
|
local function fileRead(node, ...)
|
|
if type(node) == "string" then
|
|
return node
|
|
elseif type(node) == "table" and node.__file and node.read then
|
|
return node.read(...)
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function fileWrite(parent, name, text, ...)
|
|
local node = parent[name]
|
|
if type(node) == "string" then
|
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
parent[name] = text
|
|
return true
|
|
elseif type(node) == "table" and node.__file and node.write then
|
|
return node.write(text, ...)
|
|
end
|
|
parent[name] = text
|
|
return true
|
|
end
|
|
|
|
local function fileAppend(parent, name, text, ...)
|
|
local node = parent[name]
|
|
if type(node) == "string" then
|
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
parent[name] = node .. text
|
|
return true
|
|
elseif type(node) == "table" and node.__file and node.write then
|
|
return node.write((node.read() or "") .. text, ...)
|
|
end
|
|
parent[name] = text
|
|
return true
|
|
end
|
|
|
|
-----------------------------------------------------------------
|
|
-- API
|
|
-----------------------------------------------------------------
|
|
|
|
function disk:isReadOnly() return isRO end
|
|
function disk:spaceUsed() return 0 end
|
|
function disk:spaceTotal() return 0 end
|
|
|
|
function disk:readAllText(path, ...)
|
|
local node = getNode(path)
|
|
if not node then return nil, "file not found" end
|
|
return fileRead(node, ...)
|
|
end
|
|
|
|
function disk:writeAllText(path, text, ...)
|
|
local parent, name = getParent(path)
|
|
if not parent or not parent.__dir then return false, "invalid directory" end
|
|
return fileWrite(parent, name, tostring(text), ...)
|
|
end
|
|
|
|
function disk:appendAllText(path, text, ...)
|
|
local parent, name = getParent(path)
|
|
if not parent or not parent.__dir then return false, "invalid directory" end
|
|
return fileAppend(parent, name, tostring(text), ...)
|
|
end
|
|
|
|
function disk:list(path)
|
|
local node = getNode(path)
|
|
if not node or not node.__dir then return nil, "not a directory" end
|
|
local out = {}
|
|
for k, _ in pairs(node) do if k ~= "__dir" then table.insert(out, k) end end
|
|
return out
|
|
end
|
|
|
|
function disk:fileExists(path)
|
|
local node = getNode(path)
|
|
return type(node) == "string" or (type(node) == "table" and node.__file)
|
|
end
|
|
|
|
function disk:directoryExists(path)
|
|
local node = getNode(path)
|
|
return node and type(node) == "table" and node.__dir or false
|
|
end
|
|
|
|
function disk:makeDirectory(path)
|
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
local parent, name = getParent(path)
|
|
if not parent or not parent.__dir then return false, "invalid parent directory" end
|
|
parent[name] = { __dir = true }
|
|
return true
|
|
end
|
|
|
|
function disk:remove(path)
|
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
local parent, name = getParent(path)
|
|
if not parent or not parent[name] then return false, "not found" end
|
|
parent[name] = nil
|
|
return true
|
|
end
|
|
|
|
function disk:setLabel(new)
|
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
label = tostring(new)
|
|
end
|
|
|
|
function disk:getLabel()
|
|
return label
|
|
end
|
|
|
|
function disk:size(path, ...)
|
|
local node = getNode(path)
|
|
if type(node) == "string" then return #node end
|
|
if type(node) == "table" and node.__file and node.read then
|
|
local v = node.read(...)
|
|
return v and #v or 0
|
|
end
|
|
return 0
|
|
end
|
|
|
|
-----------------------------------------------------------------
|
|
-- Auto-register with kernel and return backend
|
|
-----------------------------------------------------------------
|
|
if autoRegister then
|
|
kernel.fs.virtDisk(disk)
|
|
end
|
|
|
|
return backend, disk
|
|
end |