BananaOS/test/lib/filesystem.lua
2025-02-21 00:33:21 -05:00

175 lines
4.9 KiB
Lua

local debug = ...
local filesystem = {}
local component = require("component")
local computer = require("computer")
local mounts = {}
--false if file, true if dir
local function isFileOrDir(path)
return (string.sub(path, -1) == "/")
end
local function removeFilename(path) -- this sucks
local t = {}
local s = ""
for i in string.gmatch(path, "[^/]+") do
table.insert(t,i)
end
table.remove(t,#t)
if #t == 0 then
return "/"
end
for i=1,#t do
s = s .. t[i] .. "/"
end
if s:sub(1,1) ~= "/" then
s = "/" .. s
end
return s
end
local function log(msg,d)
if d then
if debug then
Journal.write(msg)
end
elseif not d then
Journal.write(msg)
end
end
-- Mount/node handling
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.findNode(path,skipFileDirCheck)
--go through mounts
-- abc - / 1st iteration, does match
-- def - /mnt 2nd iteration, matches better
if not skipFileDirCheck then
if not isFileOrDir(path) then
path = removeFilename(path)
end
end
local candidate = nil
local lastNum = 0
for i=1, #mounts do
local s,e = string.find(path,mounts[i].path)
log(string.format(" [FILESYSTEM.findNode] s:%s e:%s path:%s candidate:%s lastNum:%s - tagainst %s, is id %s",s,e,path,candidate,lastNum,mounts[i].path,mounts[i].disk.address or "n/a"), true)
if e == nil then
e = 0
end
if e > lastNum and s == 1 then
candidate = mounts[i]
lastNum = e
end
end
if lastNum == 0 then
log(" [FILESYSTEM.findNode] failed", true)
return false, "did not find any matching"
else
log(" [FILESYSTEM.findNode] candidate has addr "..candidate.disk.address, true)
return candidate, nil, lastNum
end
end
function filesystem.mount(disk, path)
log(string.format(" [FILESYSTEM] mounting %sas %s", AlignString(disk,7),path),false)
-- check if disk exists
if component.get(disk, "filesystem") then
table.insert(mounts, {
["disk"]=component.proxy(disk),
["path"]=path
})
return mounts[#mounts]
else
log(string.format(" [FILESYSTEM] drive does not exist", false))
return nil, "no filesystem at address"
end
end
-- File operations
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.open(path, mode)
local mount,reason,lastNum = filesystem.findNode(path)
assert(mount,reason)
local id = mount.disk.open(path:sub(lastNum),mode)
assert(id, string.format("id is '%s', not a handle, when opening '%s' (actually '%s') as '%s'",id,path,path:sub(lastNum),mode))
return {["id"]=id,["disk"]=mount}
end
function filesystem.write(handle, data)
handle.disk.disk.write(handle.id,data)
end
function filesystem.read(handle,count)
if count == nil then
count = math.maxinteger or math.huge
end
local buffer = ""
repeat
local data = handle.disk.disk.read(handle.id, count)
buffer = buffer .. (data or "")
until not data
return buffer
end
function filesystem.close(handle)
return handle.disk.disk.close(handle.id)
end
-- Directory operations
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.makeDirectory(path)
local addr,reason,lastNum = filesystem.findNode(path,true)
assert(addr, reason)
return addr.disk.makeDirectory(path:sub(lastNum))
end
-- Misc
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
function filesystem.exists(path)
local addr,reason,lastNum = filesystem.findNode(path)
assert(addr, reason)
if addr.disk.isDirectory(path:sub(lastNum)) or
addr.disk.exists(path:sub(lastNum)) then
return true
end
return false
end
function filesystem.loadfile(path, workspace)
local handle = filesystem.open(path, "r")
local data = filesystem.read(handle)
filesystem.close(handle)
if workspace == nil then
return load(data, "=" .. path, "bt", _G)
else
return load(data, "=" .. path, "bt", workspace)
end
end
function filesystem.getlisting(path) -- handle.disk.files[path]
local mount,reason,lastNum = filesystem.findNode(path)
assert(mount, reason)
return mount.disk.list(path:sub(lastNum))
end
return filesystem