initial pkgfs work, seems functional

This commit is contained in:
Izaya 2020-06-05 12:10:48 +10:00
parent 58c9a5492e
commit 0f1b324cc4
2 changed files with 221 additions and 0 deletions

112
lib/libmtar.lua Normal file
View File

@ -0,0 +1,112 @@
local mtar = {}
-- detect OS hopefully
if _OSVERSION then
if _OSVERSION:sub(1,8) == "OpenOS" then
OPENOS = true
elseif _OSVERSION:sub(1,9) == "PsychOS" then
PSYCHOS = true
end
else
LINUX = true
end
local function mkdir(dir)
if OPENOS or LINUX then
os.execute("mkdir "..dest.."/"..dir.." &> /dev/null")
elseif PSYCHOS then
-- todo: write PsychOS support
end
end
local function toint(s)
local n = 0
local i = 1
for p in s:gmatch(".") do
n = n << 8
n = n | string.byte(p)
i=i+1
end
return n
end
local function cint(n,l)
local t={}
for i = 0, 7 do
t[i+1] = (n >> (i * 8)) & 0xFF
end
return string.reverse(string.char(table.unpack(t)):sub(1,l))
end
local function cleanPath(path)
local pt = {}
for segment in path:gmatch("[^/]+") do
if segment == ".." then
pt[#pt] = nil
elseif segment ~= "." then
pt[#pt+1] = segment
end
end
return table.concat(pt,"/")
end
function mtar.genHeader(fname,len) -- generate a header for file *fname* when provided with file length *len*
return string.format("%s%s%s",cint(fname:len(),2),fname,cint(len,2))
end
function mtar.iter(stream) -- table -- function -- Given buffer *stream*, returns an iterator suitable for use with *for* that returns, for each iteration, the file name, a function to read from the file, and the length of the file.
local remain = 0
local function read(n)
local rb = stream:read(math.min(n,remain))
remain = remain - rb:len()
return rb
end
return function()
stream:read(remain)
local nlen = toint(stream:read(2) or "\0\0")
if nlen == 0 then
return
end
local name = cleanPath(stream:read(nlen))
local fsize = toint(stream:read(2))
remain = fsize
return name, read, fsize
end
end
function mtar.unarchive(stream,dest,verbose) -- Extract mtar archive read from *stream* to *dest*. If *verbose*, print status.
dest = dest or "."
while true do
local nlen = toint(stream:read(2) or "\0\0")
if nlen == 0 then
break
end
local name = cleanPath(stream:read(nlen))
local fsize = toint(stream:read(2))
if verbose then
io.write(name.." "..tostring(fsize).."... ")
end
local dir = name:match("(.+)/.*%.?.+")
if (dir) then
mkdir(dir)
end
local f = io.open(dest.."/"..name,"wb")
local rsize,buf = fsize, ""
if f then
repeat
buf = stream:read(math.min(rsize,2048))
f:write(buf)
rsize = rsize - buf:len()
if verbose then
io.write(tostring(rsize).." ")
end
until rsize <= 1
f:close()
end
if verbose then
print("done.")
end
end
end
return mtar

109
lib/pkgfs.lua Normal file
View File

@ -0,0 +1,109 @@
local mtar = require "libmtar"
local w, lz16 = pcall(require, "liblz16")
if not w then lz16 = nil end
pkgfs = {}
local findex = {}
local handles = {}
local hc = 0
local function rfalse()
return false
end
local function rzero()
return 0
end
pkgfs.component = {seek = rfalse, makeDirectory = rfalse, write = rfalse, rename = rfalse, setlabel = rfalse, spaceUsed = rzero, spaceTotal = rzero, lastModified = rzero}
local function fopen(path,comp)
local f
if comp and lz16 then
f = lz16.open(path,"rb")
else
f = io.open(path,"rb")
end
return f
end
local function fnormalize(s)
return table.concat(fs.segments(s),"/")
end
function pkgfs.component.list(path)
path = fnormalize(path).."/"
local ft,rt = {},{}
for k,v in pairs(findex) do
k="/"..k
if k:match(path.."([^/]+)/.+") then
ft[k:match(path.."([^/]+)/.+").."/"] = true
elseif k:match(path.."([^/]+)") then
ft[k:match(path.."([^/]+)")] = true
end
end
for k,v in pairs(ft) do
rt[#rt+1] = k
end
return rt
end
function pkgfs.component.isDirectory(path)
path = fnormalize(path).."/"
for k,v in pairs(findex) do
k="/"..k
if k:match(path.."([^/]+)/.+") then
return true
end
end
return false
end
function pkgfs.component.size(path)
path=fnormalize(path)
if not findex[path] then return false end
local f = fopen(findex[path][1], findex[path][2])
for fname, read, fsize in mtar.iter(f) do
if fname == path then
return fsize
end
end
return false
end
function pkgfs.component.open(path,mode)
path=fnormalize(path)
if mode:find("w") or mode:find("a") or not findex[path] then
return false
end
local f = fopen(findex[path][1],findex[path][2])
for fname,read,fsize in mtar.iter(f) do
if fname == path then
hc = hc + 1
handles[hc] = {read, f}
return hc
end
end
end
function pkgfs.component.read(handle, n)
if not handles[handle] then return false end
local rv = handles[handle][1](n)
if not rv then return nil end
if rv:len() < 1 then return nil end
return rv
end
function pkgfs.component.close(handle)
if not handles[handle] then return false end
handles[handle][2]:close()
handles[handle] = nil
return true
end
function pkgfs.add(fname,comp)
local f = fopen(fname,comp)
for name, read, fsize in mtar.iter(f) do
findex[fnormalize(name)] = {fname,comp}
end
f:close()
end
return pkgfs