OC-PsychOS/modules/lib/fs.lua

282 lines
5.8 KiB
Lua

do
_G.fs = {}
local dfsattr = {read = "*", write = "*"}
local fsattr = {}
local fT,hT = {},{["_c"]=0}
local function parseacl(acl)
acl = acl or ""
local tacl = {}
if acl == "*" then
setmetatable(tacl,{__index = function() return true end})
else
for n in acl:gmatch("[^,]+") do
tacl[n] = true
log(n)
end
end
return tacl
end
local function canread(fn)
fn = fs.canonical(fn)
if os.getuid() == "nobody" then return false end
if os.getuid() ~= "superuser" and fsattr[fn] then
if not parseacl(fsattr[fn].read or "")[os.getuid()] then return false end
end
return true
end
local function canwrite(fn)
fn = fs.canonical(fn)
if os.getuid() == "nobody" then return false end
if os.getuid() ~= "superuser" and fsattr[fn] then
if not parseacl(fsattr[fn].write)[os.getuid()] then return false end
end
return true
end
fs.parseacl = parseacl
fs.canread = canread
fs.canwrite = canwrite
local function getattr(fn,k)
fn = fs.canonical(fn)
if not canread(fn) then return false end
if fsattr[fn] then
return fsattr[fn][k]
else
return dfsattr[k]
end
end
local function setattr(fn,k,v)
fn = fs.canonical(fn)
if not canwrite(fn) then return false end
if k:find("\t") or v:find("\t") then return false end
log(parseacl(getattr(fn,"write"))[os.getuid()])
if not fsattr[fn] then
fsattr[fn] = {}
setmetatable(fsattr[fn],{__index=dfsattr})
end
fsattr[fn][k] = tostring(v)
end
function fs.mount(mp,pr)
fT[mp] = pr
end
function fs.simplify(p)
local pt,npt,rp = {},{},""
for P in p:gmatch("[^/]+") do
pt[#pt+1] = P
end
for k,v in pairs(pt) do
if v == ".." then
npt[#npt] = nil
elseif v ~= "." then
npt[#npt+1] = v
end
end
for k,v in pairs(npt) do
rp=rp.."/"..v
end
if p:sub(1,1) ~= "/" then rp = rp:sub(2) end
return rp
end
function fs.resolve(p)
if p:sub(1,1) ~= "/" then -- absolute/relative path
p=(os.getenv("PWD") or "").."/"..p
end
p=fs.simplify(p)
local pt,spt = {},""
for P in p:gmatch("[^/]+") do
pt[#pt+1] = P
end
for i = 2, #pt do
spt=spt.."/"..pt[i]
end
return pt, pt[1], spt
end
function fs.canonical(p)
local _,d,rp = fs.resolve(p)
return fs.simplify("/"..d.."/"..rp)
end
function fs.exec(fc,m,...)
return fT[fc][m](...)
end
function fs.open(p,m)
if m:sub(1,1) == "r" then
if not canread(p) then return false end
elseif m:sub(1,1) == "w" or m:sub(1,1) == "a" then
if not canwrite(p) then return false end
end
local _,d,p = fs.resolve(p)
local d = fT[d]
if d then
local f,C=d.open(p,m),hT._c
if f then
hT._c = C + 1
hT[C] = {d,f}
return C
end
return false
end
end
function fs.close(h)
if hT[h] then
hT[h][1].close(hT[h][2])
end
return false
end
function fs.read(h,n)
if hT[h] then
return hT[h][1].read(hT[h][2],n)
end
return false
end
function fs.readall(f)
local s=""
while true do
c=fs.read(f,2048)
if not c then break end
s=s..c
end
return s
end
function fs.write(h,d)
if hT[h] then
return hT[h][1].write(hT[h][2],d)
end
return false
end
function fs.list(s)
if not canread(s) then return false end
s=s or ""
local _,d,p = fs.resolve(s)
if not d then
local kt = {}
for k,v in pairs(fT) do
kt[#kt+1] = k
end
return kt
end
return fT[d].list(p or "/")
end
function fs.mkdir(s)
local _,d,p = fs.resolve(s)
return fT[d].makeDirectory(p or "/")
end
function fs.rm(s)
if not canwrite(s) then return false end
local _,d,p = fs.resolve(s)
return fT[d].remove(p)
end
function fs.exists(s)
local _,d,p = fs.resolve(s)
if d then
return fT[d].exists(p)
end
end
function fs.isdir(s)
local _,d,p = fs.resolve(s)
return fT[d].isDirectory(p)
end
local function flushattr()
local f = fs.open("/boot/sys/fsattr.dat","wb")
if f then
for k,v in pairs(fsattr) do
fs.write(f,k.."\t")
for l,m in pairs(v) do
fs.write(f,"\t"..l.."="..m)
end
fs.write(f,"\n")
end
fs.close(f)
return true
end
return false
end
local function readattr()
local f=fs.open("/boot/sys/fsattr.dat","rb")
if not f then return false end
local C=fs.readall(f)
fs.close(f)
for line in C:gmatch("[^\n]+") do
local ifn = true
local fn = ""
for kv in line:gmatch("[^\t]+") do
if ifn then
fn = kv
ifn = false
else
local k,v = kv:match("(.+)%=(.+)")
setattr(fn,k,v)
end
end
end
end
spawn("read fs attributes",readattr)
function fs.getattr(fn,k)
if fs.exists(fn) then
return getattr(fn,k)
end
return false
end
function fs.setattr(fn,k,v)
if fs.exists(fn) then
local res={setattr(fn,k,v)}
flushattr()
return table.unpack(res)
end
return false
end
end
function fs.cd(p)
if p:sub(1,1) ~= "/" then
p=(os.getenv("PWD") or "").."/"..p
end
p=fs.simplify(p)
if fs.exists(p) and fs.isdir(p) then
os.setenv("PWD",p)
else
error("non-existent/not a dir")
end
end
function fs.cp(s,d)
if not fs.canread(s) then return false end
if not fs.canwrite(d) then return false end
local df = fs.open(d,"wb")
local sf = fs.open(s,"rb")
if df and sf then
local c = ""
while true do
c=fs.read(sf,2048)
if not c then break end
fs.write(df,c)
end
fs.close(df)
fs.close(sf)
return true
end
return false
end
function fs.mv(s,d)
fs.cp(s,d)
fs.rm(s)
end
function loadfile(fn)
local f=io.open(fn,"rb")
if not f then return false, "cannot read file" end
local S=f:read("*a")
f:close()
return load(S,"=("..fn..")","bt",os.genenv())
end
function run(fn,...)
local lf = loadfile(fn)
if not lf then return false, "cannot load file" end
local r = {pcall(lf,...)}
if r[1] == true then
table.remove(r,1)
end
print(table.unpack(r))
end
function srun(fn,...)
local lf = loadfile(fn)
if not lf then return false, "cannot load file" end
spawn(fn,log(pcall(lf,...)))
end
os.execute = run