moved the unarchive function out of libmtar, making it significantly simpler and more compact, and allowing implementations to deal with the implementation details
This commit is contained in:
parent
f20719f3cb
commit
235684b979
@ -1,5 +1,6 @@
|
|||||||
local shell = require "shell"
|
local shell = require "shell"
|
||||||
local mtar = require "libmtar"
|
local mtar = require "libmtar"
|
||||||
|
local fs = require "filesystem"
|
||||||
|
|
||||||
local args, opts = shell.parse(...)
|
local args, opts = shell.parse(...)
|
||||||
|
|
||||||
@ -30,43 +31,78 @@ local function vp(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if opts.x then
|
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 unarchive(stream,dest,verbose,csize)
|
||||||
|
csize = csize or 2048
|
||||||
|
function vwrite(...)
|
||||||
|
if verbose then
|
||||||
|
io.write(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for fname, read, len in mtar.iter(stream) do
|
||||||
|
local written = 0
|
||||||
|
fname = cleanPath(fname)
|
||||||
|
vwrite(string.format("%s %i... ",fname,len))
|
||||||
|
local dir = fname:match("(.+)/.*%.?.+")
|
||||||
|
if dir then
|
||||||
|
if dir:sub(1,1) ~= "/" then
|
||||||
|
dir = os.getenv("PWD").."/"..dir
|
||||||
|
end
|
||||||
|
fs.makeDirectory(dest.."/"..dir)
|
||||||
|
end
|
||||||
|
local f = io.open(dest.."/"..fname,"wb")
|
||||||
|
if f then
|
||||||
|
repeat
|
||||||
|
local rb = read(csize)
|
||||||
|
written = written + rb:len()
|
||||||
|
f:write(rb)
|
||||||
|
vwrite(written)
|
||||||
|
vwrite(" ")
|
||||||
|
until written == len
|
||||||
|
f:close()
|
||||||
|
vwrite("done\n")
|
||||||
|
else
|
||||||
|
vwrite("failed to open "..fname.."\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function open(fn,mode)
|
||||||
local f
|
local f
|
||||||
if opts.z then
|
if opts.z then
|
||||||
f = lz16.open(args[1],"rb")
|
f = lz16.open(fn, mode)
|
||||||
else
|
else
|
||||||
f = io.open(args[1],"rb")
|
f = io.open(fn, mode)
|
||||||
end
|
end
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts.x then
|
||||||
|
local f = open(args[1],"rb")
|
||||||
if not f then error("unable to open file") end
|
if not f then error("unable to open file") end
|
||||||
local w, r = mtar.unarchive(f,args[2] or ".",opts.v)
|
local w, r = unarchive(f,args[2] or ".",opts.v)
|
||||||
f:close()
|
f:close()
|
||||||
elseif opts.t then
|
elseif opts.t then
|
||||||
local f
|
local f = open(args[1],"rb")
|
||||||
if opts.z then
|
|
||||||
f = lz16.open(args[1],"rb")
|
|
||||||
else
|
|
||||||
f = io.open(args[1],"rb")
|
|
||||||
end
|
|
||||||
if not f then error("unable to open file") end
|
if not f then error("unable to open file") end
|
||||||
while true do
|
for name, _, fsize in mtar.iter(f) do
|
||||||
local nlen = toint(f:read(2))
|
|
||||||
if nlen == 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
local name = f:read(nlen)
|
|
||||||
local fsize = toint(f:read(2) or "\0\0")
|
|
||||||
f:read(fsize)
|
|
||||||
print(name..": "..tostring(fsize))
|
print(name..": "..tostring(fsize))
|
||||||
end
|
end
|
||||||
f:close()
|
f:close()
|
||||||
elseif opts.c then
|
elseif opts.c then
|
||||||
local mode = (opts.r and "ab") or "wb"
|
local mode = (opts.r and "ab") or "wb"
|
||||||
local f
|
local f = open(args[1],mode)
|
||||||
if opts.z then
|
|
||||||
f = lz16.open(args[1],mode)
|
|
||||||
else
|
|
||||||
f = io.open(args[1],mode)
|
|
||||||
end
|
|
||||||
if not f then error("unable to open file") end
|
if not f then error("unable to open file") end
|
||||||
table.remove(args,1)
|
table.remove(args,1)
|
||||||
local fs = require "filesystem"
|
local fs = require "filesystem"
|
||||||
@ -122,5 +158,6 @@ Operations:
|
|||||||
t: list contents of archive
|
t: list contents of archive
|
||||||
Flags:
|
Flags:
|
||||||
v: be verbose
|
v: be verbose
|
||||||
z: use LZSS compression (requires liblz16)]])
|
z: use LZSS compression (requires liblz16)
|
||||||
|
r: append rather than overwrite]])
|
||||||
end
|
end
|
||||||
|
@ -1,24 +1,5 @@
|
|||||||
local mtar = {}
|
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 function toint(s)
|
||||||
local n = 0
|
local n = 0
|
||||||
local i = 1
|
local i = 1
|
||||||
@ -38,18 +19,6 @@ local function cint(n,l)
|
|||||||
return string.reverse(string.char(table.unpack(t)):sub(1,l))
|
return string.reverse(string.char(table.unpack(t)):sub(1,l))
|
||||||
end
|
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*
|
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))
|
return string.format("%s%s%s",cint(fname:len(),2),fname,cint(len,2))
|
||||||
end
|
end
|
||||||
@ -67,46 +36,11 @@ function mtar.iter(stream) -- table -- function -- Given buffer *stream*, return
|
|||||||
if nlen == 0 then
|
if nlen == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local name = cleanPath(stream:read(nlen))
|
local name = stream:read(nlen)
|
||||||
local fsize = toint(stream:read(2))
|
local fsize = toint(stream:read(2))
|
||||||
remain = fsize
|
remain = fsize
|
||||||
return name, read, fsize
|
return name, read, fsize
|
||||||
end
|
end
|
||||||
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
|
return mtar
|
||||||
|
Loading…
Reference in New Issue
Block a user