diff --git a/mtar/OpenOS/usr/bin/mtar.lua b/mtar/OpenOS/usr/bin/mtar.lua index 791da33..78f29f9 100644 --- a/mtar/OpenOS/usr/bin/mtar.lua +++ b/mtar/OpenOS/usr/bin/mtar.lua @@ -1,5 +1,6 @@ local shell = require "shell" local mtar = require "libmtar" +local fs = require "filesystem" local args, opts = shell.parse(...) @@ -30,43 +31,78 @@ local function vp(...) 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 if opts.z then - f = lz16.open(args[1],"rb") + f = lz16.open(fn, mode) else - f = io.open(args[1],"rb") + f = io.open(fn, mode) end + return f +end + +if opts.x then + local f = open(args[1],"rb") 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() elseif opts.t then - local f - if opts.z then - f = lz16.open(args[1],"rb") - else - f = io.open(args[1],"rb") - end + local f = open(args[1],"rb") if not f then error("unable to open file") end - while true 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) + for name, _, fsize in mtar.iter(f) do print(name..": "..tostring(fsize)) end f:close() elseif opts.c then local mode = (opts.r and "ab") or "wb" - local f - if opts.z then - f = lz16.open(args[1],mode) - else - f = io.open(args[1],mode) - end + local f = open(args[1],mode) if not f then error("unable to open file") end table.remove(args,1) local fs = require "filesystem" @@ -122,5 +158,6 @@ Operations: t: list contents of archive Flags: v: be verbose - z: use LZSS compression (requires liblz16)]]) + z: use LZSS compression (requires liblz16) + r: append rather than overwrite]]) end diff --git a/mtar/libmtar.lua b/mtar/libmtar.lua index 0da8f7d..75bf9e2 100644 --- a/mtar/libmtar.lua +++ b/mtar/libmtar.lua @@ -1,24 +1,5 @@ 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 @@ -38,18 +19,6 @@ local function cint(n,l) 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 @@ -67,46 +36,11 @@ function mtar.iter(stream) -- table -- function -- Given buffer *stream*, return if nlen == 0 then return end - local name = cleanPath(stream:read(nlen)) + local name = 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