Files
Halyde/halyde/lib/filesystem.lua
2026-04-30 15:09:56 +00:00

1 line
8.0 KiB
Lua

local a=...local b,c;if a then unicode=a("/halyde/lib/unicode.lua")(a)b=a("/halyde/lib/component.lua")(a)c=_G.computer elseif import then unicode=import("unicode")b=import("component")c=import("computer")end;local a={}function a.canonical(a)checkArg(1,a,"string")local b={}if a:sub(1,1)~="/"then a="/"..a end;a=a:gsub("/+","/")for a in a:gmatch("[^/]+")do if a==".."and b[1]then table.remove(b,#b)elseif a~="."then table.insert(b,a)end end;return"/"..table.concat(b,"/")end;function a.concat(...)local a={...}for a,b in ipairs(a)do checkArg(a,b,"string")end;local b=a[1]:match("(.+)/?$")for c=2,#a do b=b.."/"..a[c]:match("^/?(.+)/?$")end;return b end;function a.absolutePath(d)checkArg(1,d,"string")d=a.canonical(d)local a=nil;if d:find("^/tmp")then a=c.tmpAddress()d=d:sub(5)elseif d:find("^/mnt/...")then a=b.get(d:sub(6,8))if not a then a=c.getBootAddress()else d=d:sub(9)end else a=c.getBootAddress()end;if not a then return nil,"no such component"end;return a,d end;function a.exists(d)checkArg(1,d,"string")local a,d=a.absolutePath(d)if not a then return false end;if d:find("^/special/drive/...")then return not not(c.getBootAddress()and b.get(d:sub(16,18)))end;if d:find("^/special/eeprom/")then return table.find({"init.lua","data.bin","label.txt"},d:sub(17))end;return b.invoke(a,"exists",d)end;local function d(a,b)b=b or 1;if b==1 then local a=a:read(1)if a==nil then return nil end;return string.byte(a)end;local b,c={string.byte(a:read(b),1,b)},0;if a.littleEndian then for a=#b,1,-1 do c=(c<<8)&4294967295|b[a]end else for a=1,#b do c=(c<<8)&4294967295|b[a]end end;return c end;local function e(a)return unicode.readChar(function()return a:readBytes(1)end)end;local function f(a)return function()local b=d(a,1)if b==nil then a:close()end;return b end end;local function g(a)return unicode.iterate(f(a))end;function a.makeReadStream(a)local b={}local c=1;function b.read(b,b)checkArg(2,b,"number")local d=string.len(a)+1;local e=nil;if c<d then if b==math.huge then e=string.sub(a,math.min(c,d))else e=string.sub(a,math.min(c,d),math.min(c+b-1,d))end end;c=c+b;if e==""then return nil end;return e end;b.readBytes=d;b.readUnicodeChar=e;b.iterateBytes=f;b.iterateUnicodeChars=g;function b.write()return nil end;function b.close()a=nil end;return b end;function a.open(h,i,j)checkArg(1,h,"string")checkArg(2,i,"string","nil")checkArg(3,j,"boolean","nil")if not i then i="r"end;if j==nil then j=true end;if not(i=="r"or i=="w"or i=="rb"or i=="wb"or i=="a"or i=="ab")then return nil,"invalid handle type"end;if h:find("^/special")and not a.exists(h)then return nil,"/special does not allow creating files"end;local h,k=a.absolutePath(h)local l=h==c.getBootAddress()and k:find("^/special/drive")local m,n,o,p;if l then m=b.proxy(b.get(k:sub(16,18)))n=m.getSectorSize()o=math.ceil(m.getCapacity()/n)elseif not(h==c.getBootAddress()and k:find("^/special/"))then local a={b.invoke(h,"open",k,i)}p=a[1]if not p then return table.unpack(a)end;a=nil end;local q={}q.handle=p;q.address=h;local r=nil;local s=1;if j and i:sub(1,1)=="r"then r=""repeat tmpdata=b.invoke(h,"read",p,math.huge or math.maxinteger)r=r..(tmpdata or"")until not tmpdata;b.invoke(h,"close",p)end;function q.read(a,c)checkArg(2,c,"number")if l then local a=((s-1)//n)+1;if a>o then return nil end;local a=m.readSector(a)local a=a:sub(((s-1)%n)+1,((s+math.min(c,n)-2)%n)+1)s=s+#a;if a==""then return nil end;return a else if j then local a=string.len(r)+1;local b=nil;if s<a then if c==math.huge then b=string.sub(r,math.min(s,a))else b=string.sub(r,math.min(s,a),math.min(s+c-1,a))end end;s=s+c;if b==""then return nil end;return b else return b.invoke(a.address,"read",a.handle,c)end end end;q.readBytes=d;q.readUnicodeChar=e;q.iterateBytes=f;q.iterateUnicodeChars=g;function q.write(a,c)checkArg(2,c,"string")if l then local a=((s-1)//n)+1;if a>o then return nil,"not enough space"end;local b=((s-1)%n)+1;local d=m.readSector(a)m.writeSector(a,d:sub(1,b-1)..c:sub(1,n-b+1))for d=2,(#c+b)//n do if a+d-1>o then return nil,"not enough space"end;m.writeSector(a+d-1,c:sub(b+n*(d-1),b+n*d-1))end;s=s+#c;return true else return b.invoke(a.address,"write",a.handle,c)end end;function q.close(a)if j then r=nil else return b.invoke(a.address,"close",a.handle)end end;if h==c.getBootAddress()then local c;pcall(function()c=b.eeprom end)if c then local b,d;if k=="/special/eeprom/init.lua"then b,d="get","set"elseif k=="/special/eeprom/data.bin"then b,d="getData","setData"elseif k=="/special/eeprom/label.txt"then b,d="getLabel","setLabel"end;if i:sub(1,1)=="r"and b then local a=a.makeReadStream(c[b]()or"")q.read=a.read;q.close=a.close elseif i:sub(1,1)=="w"and d then local a=""function q.write(b,b)checkArg(2,b,"string")a=a..b end;function q.close(b)return c[d](a)end end end end;return q end;function a.list(d)checkArg(1,d,"string")d=a.canonical(d)if d=="/mnt"then local a={}local c=c.tmpAddress()for b,d in b.list("filesystem")do if b~=c then table.insert(a,b:sub(1,3).."/")end end;return a elseif d=="/special/drive"then local a={}local c=c.tmpAddress()for b,d in b.list("drive")do if b~=c and d=="drive"then table.insert(a,b:sub(1,3))end end;return a elseif d=="/special/eeprom"then return{"init.lua","data.bin","label.txt"}else local a,c=a.absolutePath(d)if not a then return false end;return b.invoke(a,"list",c)end end;function a.size(d)checkArg(1,d,"string")local a,d=a.absolutePath(d)if not a then return false end;if a==c.getBootAddress()then if d:find("^/special/drive")then local a=b.get(d:sub(16,18))if not a then return false end;return b.invoke(a,"getCapacity")elseif d:find("^/special/eeprom")then local a;pcall(function()a=b.eeprom end)if a then local b;if d=="/special/eeprom/init.lua"then b="get"elseif d=="/special/eeprom/data.bin"then b="getData"elseif d=="/special/eeprom/label.txt"then b="getLabel"end;return#(a[b]())end end end;return b.invoke(a,"size",d)end;local function d(a,c)local d=b.invoke(a,"list",c)local e={}local f=true;while f do f=false;for g=1,#d do if b.invoke(a,"isDirectory",c.."/"..d[g])then f=true;local f=d[g]if f:sub(-1)=="/"then f=f:sub(1,-2)end;table.insert(e,f)table.remove(d,g)local a=b.invoke(a,"list",c.."/"..f)for b=1,#a do table.insert(d,f.."/"..a[b])end end end end;return d,e end;local function e(a,b)if not(a and b)then return end;local c=math.floor(c.freeMemory()*0.8)local d;while true do d=a:read(c)if not d then break end;local a,b=b:write(d)if a~=true then break end end;a:close()b:close()end;local function c(a,c,f,g)if c:sub(-1)=="/"then c=c:sub(1,-2)end;if g:sub(-1)=="/"then g=g:sub(1,-2)end;b.invoke(f,"makeDirectory",g)local d,h=d(a,c)for a=1,#h do b.invoke(f,"makeDirectory",g.."/"..h[a])end;for h=1,#d do local c,d=c.."/"..d[h],g.."/"..d[h]local c=b.invoke(a,"open",c,"r")local c=b.invoke(f,"open",d,"w")e({["read"]=function(...)return b.invoke(a,"read",handle,...)end,["close"]=function(...)return b.invoke(a,"close",handle,...)end},{["write"]=function(...)return b.invoke(a,"write",handle,...)end,["close"]=function(...)return b.invoke(a,"close",handle,...)end})end end;function a.isDirectory(c)checkArg(1,c,"string")local a,c=a.absolutePath(c)if not a then return false end;return b.invoke(a,"isDirectory",c)end;function a.rename(d,e)checkArg(1,d,"string")checkArg(2,e,"string")local f,g=a.absolutePath(d)local h,i=a.absolutePath(e)if not f or not h then return false end;if f==h then return b.invoke(f,"rename",g,i)elseif a.isDirectory(d)then c(f,g,h,i)a.remove(d)else local b,c,f=a.open(d),"",nil;repeat f=b:read(math.huge or math.maxinteger)c=c..(f or"")until not f;f=b:close()local b=a.open(e)b:write(c)b:close()a.remove(d)end end;function a.copy(b,d)checkArg(1,b,"string")checkArg(2,d,"string")local f,g=a.absolutePath(b)local h,i=a.absolutePath(d)if not f or not h then return false end;if a.isDirectory(b)then c(f,g,h,i)else e(a.open(b,"r"),a.open(d,"w"))end end;function a.remove(c)checkArg(1,c,"string")local a,c=a.absolutePath(c)if not a then return false end;if c:find("^/special")then return false end;if c:find("^/tmp")then return false end;if c:find("^/mnt")then return false end;return b.invoke(a,"remove",c)end;function a.makeDirectory(c)checkArg(1,c,"string")local a,c=a.absolutePath(c)if not a then return false end;return b.invoke(a,"makeDirectory",c)end;return(a)