Updated installer
This commit is contained in:
157
misc/cct/installdata/tarbad
Normal file
157
misc/cct/installdata/tarbad
Normal file
@@ -0,0 +1,157 @@
|
||||
local function octal_to_number(str)
|
||||
str = str:gsub("%z", ""):match("^%s*(.-)%s*$")
|
||||
return tonumber(str, 8) or 0
|
||||
end
|
||||
|
||||
local function dedupe_path(path)
|
||||
|
||||
local parts = {}
|
||||
for p in path:gmatch("[^/]+") do table.insert(parts, p) end
|
||||
|
||||
for prefix_len = 1, math.floor(#parts / 2) do
|
||||
local ok = true
|
||||
for i = 1, prefix_len do
|
||||
if parts[i] ~= parts[i + prefix_len] then
|
||||
ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if ok then
|
||||
local cleaned = {}
|
||||
for i = 1, #parts - prefix_len do
|
||||
cleaned[#cleaned + 1] = parts[i + prefix_len]
|
||||
end
|
||||
return table.concat(cleaned, "/")
|
||||
end
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
|
||||
local function make_dirs(root, path)
|
||||
local cur = root
|
||||
for part in path:gmatch("([^/]+)/") do
|
||||
if not cur[part] then
|
||||
cur[part] = { __type = "dir", __entries = {} }
|
||||
end
|
||||
cur = cur[part].__entries
|
||||
end
|
||||
return cur
|
||||
end
|
||||
|
||||
local function flatten(node, prefix)
|
||||
local out = {}
|
||||
prefix = prefix or ""
|
||||
|
||||
for name, obj in pairs(node) do
|
||||
local full = prefix .. name
|
||||
if obj.__type == "file" then
|
||||
out[#out+1] = {
|
||||
name = full,
|
||||
type = "file",
|
||||
contents = obj.__contents
|
||||
}
|
||||
elseif obj.__type == "dir" then
|
||||
out[#out+1] = {
|
||||
name = full .. "/",
|
||||
type = "dir",
|
||||
contents = flatten(obj.__entries, full .. "/")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local function unpack_tar(tarstr)
|
||||
local i = 1
|
||||
local len = #tarstr
|
||||
local root = {}
|
||||
|
||||
while i + 512 <= len do
|
||||
local header = tarstr:sub(i, i + 511)
|
||||
|
||||
if header:match("^\0+$") then break end
|
||||
|
||||
local name_raw = header:sub(1, 100):gsub("%z.*", "")
|
||||
local prefix_raw = header:sub(346, 500):gsub("%z.*", "")
|
||||
|
||||
local name
|
||||
if prefix_raw ~= "" then
|
||||
name = prefix_raw .. "/" .. name_raw
|
||||
else
|
||||
name = name_raw
|
||||
end
|
||||
|
||||
name = name:gsub("^%./", ""):gsub("/+", "/")
|
||||
|
||||
name = dedupe_path(name)
|
||||
|
||||
local size = octal_to_number(header:sub(125,136))
|
||||
local typeflag = header:sub(157,157)
|
||||
|
||||
i = i + 512
|
||||
|
||||
local contents = tarstr:sub(i, i + size - 1)
|
||||
local pad = (512 - (size % 512)) % 512
|
||||
i = i + size + pad
|
||||
|
||||
if name ~= "" then
|
||||
|
||||
local is_dir = typeflag == "5" or name:sub(-1) == "/"
|
||||
local clean_name = name:gsub("/$", "")
|
||||
|
||||
if clean_name ~= "" then
|
||||
|
||||
local parent_path = clean_name:match("(.+)/")
|
||||
local fname = clean_name:match("([^/]+)$")
|
||||
if not fname then
|
||||
|
||||
local parent = root
|
||||
if parent_path then
|
||||
parent = make_dirs(root, parent_path .. "/")
|
||||
end
|
||||
|
||||
if is_dir then
|
||||
parent[fname] = parent[fname] or { __type = "dir", __entries = {} }
|
||||
else
|
||||
parent[fname] = { __type = "file", __contents = contents }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return flatten(root)
|
||||
end
|
||||
|
||||
local function write_directory(prefix, items)
|
||||
for _, v in ipairs(items) do
|
||||
if v.type == "dir" then
|
||||
fs.makeDir(prefix..v.name)
|
||||
write_directory(prefix, v.contents)
|
||||
elseif v.type == "file" then
|
||||
local file = fs.open(prefix..v.name, "w")
|
||||
file.write(v.contents)
|
||||
file.close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local in_tar = ({...})[1]
|
||||
local out_dir = ({...})[2]
|
||||
|
||||
if not in_tar or not out_dir then
|
||||
print("Usage: unpack_tar <tarfile> <output_dir>")
|
||||
return
|
||||
end
|
||||
|
||||
local f = fs.open(in_tar, "r")
|
||||
local tarstr = f.readAll()
|
||||
f.close()
|
||||
|
||||
local list = unpack_tar(tarstr)
|
||||
write_directory(out_dir, list)
|
||||
|
||||
print("TAR extracted into: " .. out_dir)
|
||||
Reference in New Issue
Block a user