Files
HyperionOS/prod/Hyperion-kernel/lib/modules/hyperion/13_loopdev.kmod

2 lines
9.3 KiB
Plaintext

local a=...local b=nil;local function c()if b==nil then local d,e=pcall(require,"store.deflate")b=d and e or false end;return b or nil end;local function f(g)g=math.floor(g)%4294967296;return string.char(g%256,math.floor(g/256)%256,math.floor(g/65536)%256,math.floor(g/16777216)%256)end;local function h(i,j)local k,l,m,n=i:byte(j,j+3)return(k or 0)+(l or 0)*256+(m or 0)*65536+(n or 0)*16777216 end;local o="BHFS"local p="\001"local q=1;local r="\001"local s="\002"local t="\003"local u="\255"local v={}do local k="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"for j=1,#k do v[k:sub(j,j)]=j-1 end end;local function w(i)i=i:gsub("[^A-Za-z0-9+/=]","")local x,j={},1;while j<=#i do local y=v[i:sub(j,j)]or 0;local z=v[i:sub(j+1,j+1)]or 0;local A=v[i:sub(j+2,j+2)]or 0;local B=v[i:sub(j+3,j+3)]or 0;local g=y*262144+z*4096+A*64+B;x[#x+1]=string.char(math.floor(g/65536)%256)if i:sub(j+2,j+2)~="="then x[#x+1]=string.char(math.floor(g/256)%256)end;if i:sub(j+3,j+3)~="="then x[#x+1]=string.char(g%256)end;j=j+4 end;return table.concat(x)end;local C={}local D=0;local function E(F,G)local H={address=F,isvirt=false}H.isReadOnly=function()return false end;H.spaceUsed=function()return 0 end;H.spaceTotal=function()return 0 end;H.setLabel=function()end;H.getLabel=function()return F end;local function I()local J,K="/","$"for L,M in pairs(a.vfs.mounts)do if G==M or M=="/"and G:sub(1,1)=="/"or G:sub(1,#M+1)==M.."/"then if#M>#J then J=M;K=L end end end;return a.vfs.disks[K],G:sub(#J+1)end;local function N(O)local P,Q=I()local l=(Q==""or Q=="/")and""or Q:gsub("^/+","")local R=O:gsub("^/+","")local m=(l==""and"/"..R or"/"..l.."/"..R):gsub("//+","/")local S=m:sub(2)if S==""then S="/"end;return P,S end;function H:open(O,T)local U,S=N(O)return U:open(S,T)end;function H:type(O)local U,S=N(O)return U:type(S)end;function H:list(O)local U,S=N(O)return U:list(S)end;function H:fileExists(O)local U,S=N(O)return U:fileExists(S)end;function H:attributes(O)local U,S=N(O)return U:attributes(S)end;function H:makeDirectory(O)local U,S=N(O)return U:makeDirectory(S)end;function H:remove(O)local U,S=N(O)return U:remove(S)end;return H end;local function V(F,W)local X={kind="dir",children={}}local function Y(O,Z)local _={}for R in O:gmatch("[^/]+")do _[#_+1]=R end;local a0=X;for j=1,#_ do local a1=_[j]if not a0.children then if not Z then return nil end;a0.children={}end;if not a0.children[a1]then if not Z then return nil end;a0.children[a1]={kind="dir",children={}}end;a0=a0.children[a1]end;return a0 end;local function a2(O)local a3=O:match("^(.*)/[^/]+$")or""if a3~=""then local g=Y(a3,true)if not g.children then g.children={}end end end;if W:sub(1,4)==o then local a4=9;while a4<=#W do local a5=W:sub(a4,a4)a4=a4+1;if a5==u then break end;local a6=h(W,a4)a4=a4+4;local a7=h(W,a4)a4=a4+4;local a8=h(W,a4)a4=a4+4;local O=W:sub(a4,a4+a6-1)a4=a4+a6;local a9=W:sub(a4,a4+a8-1)a4=a4+a8;local aa=a9;if a8<a7 then local ab=c()if ab then aa=ab.decompress(a9)or a9 end end;if a5==s then if O~=""and O~="/"then a2(O)local g=Y(O,true)g.kind="dir"g.children=g.children or{}end elseif a5==r then a2(O)local g=Y(O,true)g.kind="file"g.data=aa;g.size=#aa;g.children=nil elseif a5==t then a2(O)local g=Y(O,true)g.kind="link"g.target=aa;g.children=nil end end else for ac in(W.."\n"):gmatch("([^\n]*)\n")do if ac=="END"then break elseif ac:sub(1,4)=="DIR "then local R=ac:sub(5):match("^%s*(.-)%s*$")if R and R~=""and R~="/"then a2(R)local g=Y(R,true)g.kind="dir"g.children=g.children or{}end elseif ac:sub(1,5)=="FILE "then local R,ad,ae=ac:sub(6):match("^(%S+)%s+(%d+)%s*(.-)%s*$")if R then a2(R)local aa=(tonumber(ad)or 0)>0 and w(ae)or""local g=Y(R,true)g.kind="file"g.data=aa;g.size=#aa;g.children=nil end elseif ac:sub(1,5)=="LINK "then local R,af=ac:sub(6):match("^(%S+)%s+(.+)$")if R then a2(R)local g=Y(R,true)g.kind="link"g.target=af;g.children=nil end end end end;local H={address=F,isvirt=false}H.isReadOnly=function()return false end;H.spaceTotal=function()return 1024*1024*64 end;H.spaceUsed=function()local ag=0;local function ah(g)if g.kind=="file"then ag=ag+(g.size or 0)elseif g.kind=="dir"then for ai,m in pairs(g.children or{})do ah(m)end end end;ah(X)return ag end;H.setLabel=function()end;H.getLabel=function()return F end;local function aj(O)return O:gsub("^/+",""):gsub("/+$","")end;function H:type(O)local R=aj(O)if R==""then return"directory"end;local g=Y(R)if not g then return nil end;if g.kind=="dir"then return"directory"end;return"file"end;function H:fileExists(O)local R=aj(O)if R==""then return true end;return Y(R)~=nil end;function H:list(O)local R=aj(O)local a0=R==""and X or Y(R)if not a0 or a0.kind~="dir"then return{}end;local ak={}for a1 in pairs(a0.children or{})do ak[#ak+1]=a1 end;return ak end;function H:attributes(O)local R=aj(O)local a0=R==""and X or Y(R)if not a0 then return nil end;return{size=a0.kind=="file"and(a0.size or 0)or 0,isDir=a0.kind=="dir",isReadOnly=false,created=0,modified=0}end;function H:open(O,T)local R=aj(O)local a0=Y(R)if T=="r"then if not a0 or a0.kind~="file"then error("ENOENT: "..O)end;local aa,a4=a0.data or"",1;return{read=function(g)if a4>#aa then return nil end;local al=aa:sub(a4,a4+(g or 1)-1)a4=a4+#al;return al end,readAll=function()local am=aa:sub(a4)a4=#aa+1;return am end,readLine=function()if a4>#aa then return nil end;local an=aa:find("\n",a4,true)local ac;if an then ac=aa:sub(a4,an-1)a4=an+1 else ac=aa:sub(a4)a4=#aa+1 end;return ac end,seek=function(ah,ao)ao=ao or 0;if ah=="set"then a4=ao+1 elseif ah=="cur"then a4=a4+ao elseif ah=="end"then a4=#aa+1+ao end;return a4-1 end,close=function()end}elseif T=="w"or T=="a"then local ap=T=="a"and a0 and a0.kind=="file"and{a0.data or""}or{}local aq=false;local function ar()if aq then return end;aq=true;local aa=table.concat(ap)if not a0 then a2(R)a0=Y(R,true)end;a0.kind="file"a0.data=aa;a0.size=#aa;a0.children=nil end;return{write=function(i)ap[#ap+1]=tostring(i)end,writeLine=function(i)ap[#ap+1]=tostring(i).."\n"end,flush=function()end,close=ar}else error("EINVAL: unknown mode: "..tostring(T))end end;function H:makeDirectory(O)local R=aj(O)if R==""then return end;a2(R)local g=Y(R,true)g.kind="dir"g.children=g.children or{}g.data=nil;g.size=nil end;function H:remove(O)local R=aj(O)if R==""then error("EBUSY: cannot remove root")end;local a3=R:match("^(.*)/[^/]+$")or""local a1=R:match("([^/]+)$")local as=a3==""and X or Y(a3)if as and as.children then as.children[a1]=nil end end;H._root=X;return H end;local function at(au)local ab=c()local av=ab~=nil;local aw=av and q or 0;local _={o,p,string.char(aw),"\0\0"}au=au:gsub("/$","")local ax=64;local function ay(az)local aA=a.vfs.type(az)if aA=="directory"then if az~=au then local aB=az:sub(#au+1)_[#_+1]=s;_[#_+1]=f(#aB)_[#_+1]=f(0)_[#_+1]=f(0)_[#_+1]=aB end;local d,aC=pcall(a.vfs.listdir,az)if d and aC then table.sort(aC)for ai,a1 in ipairs(aC)do ay(az:gsub("/$","").."/"..a1)end end elseif aA=="file"then local aB=az:sub(#au+1)local d,aD=pcall(a.vfs.open,az,"r")if d then local aE=""local aF,aG=pcall(a.vfs.read,aD,1024*1024)if aF then aE=aG or""end;pcall(a.vfs.close,aD)local aH=aE;if av and#aE>=ax then local aI=ab.compress(aE)if aI and#aI<#aE then aH=aI end end;_[#_+1]=r;_[#_+1]=f(#aB)_[#_+1]=f(#aE)_[#_+1]=f(#aH)_[#_+1]=aB;_[#_+1]=aH end end end;ay(au)_[#_+1]=u;return table.concat(_)end;a.syscalls["losetup"]=function(aJ,aK)if not aJ then error("EINVAL")end;local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;aJ=aJ:gsub("/$","")local F="loop"..tostring(D)D=D+1;local aA=a.vfs.type(aJ)local H,T;if not aK and aA=="directory"then H=E(F,aJ)T="bind"elseif aA=="file"or aK then if aA~="file"then error("ENOENT: not a file: "..aJ)end;local aN;local d,aD=pcall(a.vfs.open,aJ,"rb")if d then local aF,aa=pcall(a.vfs.read,aD,1024*1024*16)pcall(a.vfs.close,aD)if aF and aa then aN=aa end end;if not aN then local aF,aO=pcall(a.vfs.open,aJ,"r")if not aF then error("EIO: cannot open image: "..aJ)end;local aP,aa=pcall(a.vfs.read,aO,1024*1024*16)pcall(a.vfs.close,aO)if not aP or not aa then error("EIO: cannot read image: "..aJ)end;aN=aa end;H=V(F,aN)T="image"else error("EINVAL: path must be a directory or .hfs image file")end;a.vfs.disks[F]=H;C[F]={path=aJ,disk=H,mode=T}a.log("losetup: attached "..F.." ("..T..") -> "..aJ,"INFO")return F end;a.syscalls["lodetach"]=function(F)local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;if not C[F]then error("ENXIO")end;for K in pairs(a.vfs.mounts)do if K==F then error("EBUSY: loop device is still mounted")end end;a.vfs.disks[F]=nil;C[F]=nil;a.log("lodetach: detached "..F,"INFO")end;a.syscalls["lolist"]=function()local aQ={}for F,aR in pairs(C)do aQ[F]={path=aR.path,mode=aR.mode}end;return aQ end;a.syscalls["loimgcreate"]=function(au)local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;if not au then error("EINVAL")end;if a.vfs.type(au)~="directory"then error("ENOTDIR: "..au)end;return at(au)end;a.syscalls["loimgwrite"]=function(aS,aT)local aL=a.currentTask;local aM=aL and(aL.euid or aL.uid)or a.uid;if aM~=0 then error("EPERM")end;if not aS or not aT then error("EINVAL")end;local d,aD=pcall(a.vfs.open,aT,"wb")if not d then d,aD=pcall(a.vfs.open,aT,"w")if not d then error("EIO: cannot write: "..tostring(aT))end end;local aF,aU=pcall(a.vfs.write,aD,aS)pcall(a.vfs.close,aD)if not aF then error("EIO: write failed: "..tostring(aU))end end;a.log("Loop device driver loaded (bind + BHFS binary image + legacy HFS compat)")