print("Proxying fs")
sleep(0.5)
local function shallowCopy(t)
local res = {}
for k,v in pairs(t) do
res[k] = v
end
return res
end
-- capture originals immediately, before anything else touches fs
local realfs = shallowCopy(fs)
local newRoot = "/disk"
local shellPath = "/rom/programs/shell.lua"
-- no mounts in mounts please!
-- also please top level only
local mounts = {
{ prefix = "rom", realPath = "rom" },
}
realfs.makeDir(newRoot)
local function dofileWithEnv(path, env)
local h = assert(realfs.open(path, "r"))
local d = h.readAll()
h.close()
local fn = assert(load(d, nil, nil, env))
fn()
end
local function split(inputstr, sep)
sep = sep or "%s"
local t = {}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
local function safeCanonicalize(path)
-- use realfs so this never accidentally calls the proxy
local t = split(realfs.combine(path), "/")
local res = {}
for i,v in ipairs(t) do
if v ~= ".." then
table.insert(res, v)
end
end
return table.concat(res, "/")
end
local function findMount(path)
local pathSplit = split(safeCanonicalize(path), "/")
local firstSegment = pathSplit[1]
for _,v in ipairs(mounts) do
if v.prefix == firstSegment then
-- copy so we don't mutate pathSplit
local pathInMount = {}
for i = 2, #pathSplit do
pathInMount[#pathInMount + 1] = pathSplit[i]
end
return v, table.concat(pathInMount, "/")
end
end
end
local function proxyPath(path, rootPath)
local m, pathInMount = findMount(path)
if m then
return realfs.combine(m.realPath, pathInMount)
else
return realfs.combine(rootPath, safeCanonicalize(path))
end
end
-- only works with path as first arg
local function autoProxy(func, rootPath, checkFunc)
return function(...)
local args = {...}
if checkFunc then checkFunc(safeCanonicalize(args[1])) end
args[1] = proxyPath(args[1], rootPath)
return func(table.unpack(args))
end
end
local function autoProxy2Paths(func, rootPath, checkFunc)
return function(...)
local args = {...}
if checkFunc then checkFunc(safeCanonicalize(args[1]), safeCanonicalize(args[2])) end
args[1] = proxyPath(args[1], rootPath)
args[2] = proxyPath(args[2], rootPath)
return func(table.unpack(args))
end
end
-- this isnt all 100% accurate, but it shooould only be in error handling
local fakefs
fakefs = {
complete = autoProxy(realfs.complete, newRoot),
find = autoProxy(realfs.find, newRoot),
isDriveRoot = function(path)
return realfs.combine(path) == ""
end,
list = function(path)
local proxied = proxyPath(path, newRoot)
local results = realfs.list(proxied)
-- if listing the fake root, also inject mount prefixes
if safeCanonicalize(path) == "" then
for _, m in ipairs(mounts) do
-- only add if not already present
local found = false
for _, name in ipairs(results) do
if name == m.prefix then found = true; break end
end
if not found then
table.insert(results, m.prefix)
end
end
end
return results
end,
combine = realfs.combine,
getName = autoProxy(realfs.getName, newRoot),
getDir = realfs.getDir,
getSize = autoProxy(realfs.getSize, newRoot),
exists = autoProxy(realfs.exists, newRoot),
isDir = autoProxy(realfs.isDir, newRoot),
isReadOnly = autoProxy(realfs.isReadOnly, newRoot),
makeDir = autoProxy(realfs.makeDir, newRoot),
move = autoProxy2Paths(realfs.move, newRoot, function(path1, path2)
if path1 == "" or path2 == "" then
error("cannot move from or to /")
end
end),
copy = autoProxy2Paths(realfs.copy, newRoot, function(path1, path2)
if path1 == "" or path2 == "" then
error("cannot copy from or to /")
end
end),
delete = autoProxy(realfs.delete, newRoot, function(path)
if path == "" then
error("cannot delete /")
end
end),
open = autoProxy(realfs.open, newRoot),
getDrive = autoProxy(realfs.getDrive, newRoot),
getFreeSpace = autoProxy(realfs.getFreeSpace, newRoot),
getCapacity = autoProxy(realfs.getCapacity, newRoot),
attributes = autoProxy(realfs.attributes, newRoot)
}
-- overwrite fs with our proxied versions
for k, v in pairs(fakefs) do
_G.fs[k] = v
end
_G.shell = nil
term.clear()
os.run({}, shellPath)
-- this isnt sandboxing, so we dont really need to deepcopy the env
--local env = shallowCopy(_G)
--env.fs = fakefs
--_G.ffs = fakefs
--dofileWithEnv(shellPath, env)