2020-03-06 22:10:16 +11:00
|
|
|
local shell = require "shell"
|
|
|
|
local mtar = require "libmtar"
|
2020-05-30 09:51:47 +10:00
|
|
|
local fs = require "filesystem"
|
2020-03-06 22:10:16 +11:00
|
|
|
|
|
|
|
local args, opts = shell.parse(...)
|
|
|
|
|
|
|
|
local w, lz16 = pcall(require, "liblz16")
|
|
|
|
if not w then lz16 = nil end
|
|
|
|
|
|
|
|
local function vw(s)
|
|
|
|
if opts.v and s then
|
|
|
|
io.write(tostring(s))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function vp(...)
|
|
|
|
for k,v in ipairs({...}) do
|
|
|
|
vw(tostring(v).."\n")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-05-30 09:51:47 +10:00
|
|
|
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)
|
2020-03-06 22:10:16 +11:00
|
|
|
local f
|
|
|
|
if opts.z then
|
2020-05-30 09:51:47 +10:00
|
|
|
f = lz16.open(fn, mode)
|
2021-05-26 17:49:42 +10:00
|
|
|
if mode == "w" and tonumber(opts.csize) then
|
|
|
|
f.bufferSize = tonumber(opts.csize)
|
|
|
|
end
|
2020-03-06 22:10:16 +11:00
|
|
|
else
|
2020-05-30 09:51:47 +10:00
|
|
|
f = io.open(fn, mode)
|
2020-03-06 22:10:16 +11:00
|
|
|
end
|
2020-05-30 09:51:47 +10:00
|
|
|
return f
|
|
|
|
end
|
|
|
|
|
|
|
|
if opts.x then
|
|
|
|
local f = open(args[1],"rb")
|
2020-03-06 22:10:16 +11:00
|
|
|
if not f then error("unable to open file") end
|
2020-05-30 09:51:47 +10:00
|
|
|
local w, r = unarchive(f,args[2] or ".",opts.v)
|
2020-03-06 22:10:16 +11:00
|
|
|
f:close()
|
|
|
|
elseif opts.t then
|
2020-05-30 09:51:47 +10:00
|
|
|
local f = open(args[1],"rb")
|
2020-03-06 22:10:16 +11:00
|
|
|
if not f then error("unable to open file") end
|
2020-05-30 09:51:47 +10:00
|
|
|
for name, _, fsize in mtar.iter(f) do
|
2020-03-06 22:10:16 +11:00
|
|
|
print(name..": "..tostring(fsize))
|
|
|
|
end
|
|
|
|
f:close()
|
|
|
|
elseif opts.c then
|
|
|
|
local mode = (opts.r and "ab") or "wb"
|
2020-05-30 09:51:47 +10:00
|
|
|
local f = open(args[1],mode)
|
2020-03-06 22:10:16 +11:00
|
|
|
if not f then error("unable to open file") end
|
|
|
|
table.remove(args,1)
|
|
|
|
local fs = require "filesystem"
|
|
|
|
for k,v in pairs(args) do
|
|
|
|
local ap = true
|
|
|
|
if v:sub(1,1) ~= "/" then
|
|
|
|
ap = false
|
|
|
|
v = os.getenv("PWD") .. "/" .. v
|
|
|
|
end
|
|
|
|
v=fs.canonical(v)
|
|
|
|
vw(v.."... ")
|
|
|
|
if fs.isDirectory(v) then
|
|
|
|
vp("directory.")
|
|
|
|
for file in fs.list(v) do
|
|
|
|
if ap then
|
|
|
|
args[#args+1] = v.."/"..file
|
|
|
|
else
|
|
|
|
args[#args+1] = v:sub(os.getenv("PWD"):len()+2).."/"..file
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
local fsize = fs.size(v)
|
|
|
|
local inputf = io.open(v,"rb")
|
|
|
|
if fsize and inputf then
|
|
|
|
local c = 0
|
|
|
|
if ap then
|
|
|
|
f:write(mtar.genHeader(v,fsize))
|
|
|
|
else
|
|
|
|
f:write(mtar.genHeader(v:sub(os.getenv("PWD"):len()+2),fsize))
|
|
|
|
end
|
|
|
|
while true do
|
|
|
|
local ib = inputf:read(4096)
|
|
|
|
if ib then
|
|
|
|
c=c+ib:len()
|
|
|
|
f:write(ib)
|
|
|
|
else
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2023-11-13 23:12:18 +11:00
|
|
|
inputf:close()
|
2020-03-06 22:10:16 +11:00
|
|
|
vp(c)
|
|
|
|
else
|
|
|
|
vp("failed to open.")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
f:close()
|
|
|
|
else
|
|
|
|
print([[Usage:
|
2021-05-26 17:49:42 +10:00
|
|
|
mtar -[crtxvz] <archivefile> [otherfile] [otherfile] [--csize=blocksize]
|
2020-03-06 22:10:16 +11:00
|
|
|
Operations:
|
|
|
|
x: extract archive
|
|
|
|
c: create archive
|
|
|
|
t: list contents of archive
|
|
|
|
Flags:
|
|
|
|
v: be verbose
|
2020-05-30 09:51:47 +10:00
|
|
|
z: use LZSS compression (requires liblz16)
|
2021-05-26 17:49:42 +10:00
|
|
|
r: append rather than overwrite
|
|
|
|
Extended options:
|
|
|
|
csize: compression input block size]])
|
2020-03-06 22:10:16 +11:00
|
|
|
end
|