1
0
mirror of https://github.com/AR2000AR/openComputers_codes.git synced 2025-09-08 14:41:14 +02:00

[tar] misc fox and partial extraction

This commit is contained in:
2023-04-05 21:59:58 +02:00
parent 2f647560c7
commit 08a8ae07d8

View File

@@ -2,6 +2,24 @@ local filesystem = require("filesystem")
local shell = require("shell") local shell = require("shell")
local io = require("io") local io = require("io")
---@class tarHeader
---@field name any
---@field mode any
---@field uid any
---@field gid any
---@field size any
---@field mtime any
---@field chksum any
---@field typeflag any
---@field linkname any
---@field magic any
---@field version any
---@field uname any
---@field gname any
---@field devmajor any
---@field devminor any
---@field prefix any
---https://github.com/luarocks/luarocks/blob/master/src/luarocks/core/dir.lua ---https://github.com/luarocks/luarocks/blob/master/src/luarocks/core/dir.lua
local function unquote(c) local function unquote(c)
local first, last = c:sub(1, 1), c:sub(-1) local first, last = c:sub(1, 1), c:sub(-1)
@@ -114,6 +132,7 @@ local function read_header_block(block)
return header return header
end end
function tar.untar(filename, destdir) function tar.untar(filename, destdir)
checkArg(1, filename, "string") checkArg(1, filename, "string")
checkArg(2, destdir, "string") checkArg(2, destdir, "string")
@@ -160,20 +179,11 @@ function tar.untar(filename, destdir)
local pathname = dir.path(destdir, header.name) local pathname = dir.path(destdir, header.name)
pathname = filesystem.canonical(pathname) pathname = filesystem.canonical(pathname)
if header.typeflag == "directory" then if header.typeflag == "directory" then
ok, err = make_dir(pathname) make_dir(pathname)
if not ok then
require("event").onError("[tar]" .. err)
break
end
elseif header.typeflag == "file" then elseif header.typeflag == "file" then
require("event").onError(pathname)
local dirname = filesystem.path(pathname) local dirname = filesystem.path(pathname)
if dirname ~= "" then if dirname ~= "" then
ok, err = make_dir(dirname) make_dir(dirname)
if not ok then
require("event").onError("[tar]" .. err)
--break
end
end end
local file_handle local file_handle
file_handle, err = io.open(pathname, "wb") file_handle, err = io.open(pathname, "wb")
@@ -182,8 +192,7 @@ function tar.untar(filename, destdir)
require("event").onError("[tar]" .. err) require("event").onError("[tar]" .. err)
break break
end end
file_handle:write(file_data) file_handle:write(file_data):close()
file_handle:close()
end end
end end
tar_handle:close() tar_handle:close()
@@ -194,7 +203,7 @@ end
---Retrun the headers ---Retrun the headers
---@param filename string ---@param filename string
---@return table?, string? reason ---@return table<number,tarHeader>?, string? reason
function tar.list(filename) function tar.list(filename)
checkArg(1, filename, 'string') checkArg(1, filename, 'string')
local tar_handle = io.open(filename, "rb") local tar_handle = io.open(filename, "rb")
@@ -233,22 +242,59 @@ function tar.list(filename)
long_link_name = nil long_link_name = nil
end end
end end
table.insert(files, header) if (header.typeflag == "file" or header.typeflag == "directory") then
table.insert(files, header)
end
end end
tar_handle:close() tar_handle:close()
return files, err return files, err
end end
function tar.extract(tarname, filename, destdir) ---Extract files that match filename `fineNameInArchive:match("^"..filename)
---@param tarname string
---@param filename? string|table
---@param overwrite boolean overwrite existing files.
---@param ignore? string|table
---@param destdir string
---@param newRoot? string
function tar.extract(tarname, destdir, overwrite, filename, ignore, newRoot)
checkArg(1, tarname, "string") checkArg(1, tarname, "string")
checkArg(2, filename, "string") checkArg(2, destdir, "string")
checkArg(3, destdir, "string") checkArg(3, overwrite, "boolean")
checkArg(4, filename, "string", "table", 'nil')
checkArg(5, ignore, "string", "table", 'nil')
checkArg(6, destdir, "string")
checkArg(7, newRoot, "string", "nil")
---@param name string
---@return boolean
local function shouldExtractFile(name)
local ok = true
if (filename and type(filename) == "string") then
if (not name:match("^" .. filename)) then ok = false end
end
if (filename and type(filename) == "table") then
for _, fname in pairs(filename) do
if (not name:match("^" .. fname)) then ok = false end
end
end
if (ignore and type(ignore) == "string") then
if (name:match("^" .. ignore)) then ok = false end
end
if (ignore and type(ignore) == "table") then
for _, fname in pairs(ignore) do
if (name:match("^" .. fname)) then ok = false end
end
end
return ok
end
local tar_handle = io.open(tarname, "rb") local tar_handle = io.open(tarname, "rb")
if not tar_handle then return nil, "Error opening file " .. tarname end if not tar_handle then return nil, "Error opening file " .. tarname end
local long_name, long_link_name local long_name, long_link_name
local ok, err ---@type boolean?, string?
local ok, err = true, nil
local make_dir = filesystem.makeDirectory local make_dir = filesystem.makeDirectory
while true do while true do
local block local block
@@ -283,34 +329,37 @@ function tar.extract(tarname, filename, destdir)
long_link_name = nil long_link_name = nil
end end
end end
local pathname = dir.path(destdir, header.name)
pathname = filesystem.canonical(pathname)
if header.typeflag == "file" and header.name == filename then
require("event").onError(pathname) if (shouldExtractFile(header.name)) then
local dirname = filesystem.path(pathname) local pathname = dir.path(destdir, header.name)
if dirname ~= "" then if (newRoot) then --change the archive root
ok, err = make_dir(dirname) pathname = pathname:gsub(newRoot, "")
if not ok then end
require("event").onError("[tar]" .. err) pathname = filesystem.canonical(pathname)
--break
if header.typeflag == "directory" then
make_dir(pathname)
elseif header.typeflag == "file" then
local dirname = filesystem.path(pathname)
if dirname ~= "" then
make_dir(dirname)
end
if (overwrite or not (filesystem.exists(pathname) and not filesystem.isDirectory(pathname))) then
local file_handle
file_handle, err = io.open(pathname, "wb")
if not file_handle then
ok = nil
require("event").onError("[tar]" .. err)
break
end
file_handle:write(file_data):close()
end end
end end
local file_handle
file_handle, err = io.open(pathname, "wb")
if not file_handle then
ok = nil
require("event").onError("[tar]" .. err)
break
end
file_handle:write(file_data)
file_handle:close()
tar_handle:close()
return pathname, err
end end
end end
tar_handle:close() tar_handle:close()
return ok, "file not found in archive" return ok, err
end end
return tar return tar