patriik/

janky fs proxy thing

5 KiB 5 3 months ago 3 months ago
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)