update
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
local http=require("http")
|
||||
local ok,err = xpcall(http.get, debug.traceback, "http://localhost:8000/spm.json")
|
||||
if not ok then
|
||||
print(err)
|
||||
else
|
||||
print(err.body)
|
||||
end
|
||||
@@ -1,11 +1,6 @@
|
||||
--:Minify:--
|
||||
local fs={}
|
||||
|
||||
-- "open" : open
|
||||
-- "read" : read
|
||||
-- "write" : write
|
||||
-- "close" : close
|
||||
|
||||
function fs.open(path, mode)
|
||||
local fd=syscall.open(path,mode)
|
||||
local ret={
|
||||
@@ -140,4 +135,12 @@ function fs.isDir(path)
|
||||
return syscall.type(path) == "directory"
|
||||
end
|
||||
|
||||
function fs.symlink(target, path)
|
||||
return syscall.syslink(target, path)
|
||||
end
|
||||
|
||||
function fs.readlink(path)
|
||||
return syscall.readlink(path)
|
||||
end
|
||||
|
||||
return fs
|
||||
@@ -463,7 +463,12 @@ local ok, err = xpcall(function()
|
||||
getTextColor = function()
|
||||
return fg
|
||||
end,
|
||||
enable=function() end,
|
||||
enable=function()
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1, 1)
|
||||
end
|
||||
end,
|
||||
disable=function() end
|
||||
},
|
||||
architecture="cct",
|
||||
|
||||
@@ -220,9 +220,6 @@ local function newtty(obj, id, ev)
|
||||
gbgc=function()
|
||||
return bg
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
||||
end,
|
||||
isvirt=function()
|
||||
return false
|
||||
end,
|
||||
@@ -269,6 +266,9 @@ kernel.devfs.data["input"]["keyboard1"] = function(op, mode)
|
||||
return rv
|
||||
end,
|
||||
write=function(content)
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
||||
end
|
||||
}
|
||||
if mode=="rw" then
|
||||
|
||||
@@ -7,10 +7,10 @@ local disks=EFI.disks
|
||||
local arch=EFI.architecture
|
||||
local kernel = {}
|
||||
kernel.LOG_Text=""
|
||||
kernel.version="HyperionOS V1.2.4-dev_5"
|
||||
kernel.tag="1.2.4-dev_5"
|
||||
kernel.version="HyperionOS V1.2.4"
|
||||
kernel.tag="1.2.4"
|
||||
kernel.process = "Kernel"
|
||||
kernel.users={[0]="root",[1]="User"}
|
||||
kernel.users={[0]="root",[1000]="User"}
|
||||
kernel.hostname = "hyperion"
|
||||
kernel.groups = {}
|
||||
kernel.uid = 0
|
||||
|
||||
@@ -23,6 +23,7 @@ function string.split(str, delim, maxResultCountOrNil)
|
||||
assert(#delim == 1, "only delim len 1 supported for now")
|
||||
if not str then return false end
|
||||
maxResultCountOrNil = (maxResultCountOrNil or 0) - 1
|
||||
if str == "" then return {} end
|
||||
local rv = {}
|
||||
local buf = ""
|
||||
for i = 1, #str do
|
||||
|
||||
@@ -124,7 +124,7 @@ end
|
||||
|
||||
local function validateComponent(comp)
|
||||
local lower = comp:lower()
|
||||
if not lower:match(SAFE_COMPONENT_PATTERN) then
|
||||
if not comp:match(SAFE_COMPONENT_PATTERN) then
|
||||
error("EINVAL: illegal characters in path component: " .. comp, 3)
|
||||
end
|
||||
if lower == ".meta" then
|
||||
@@ -276,7 +276,7 @@ local function namei(path, noFollow, symDepth)
|
||||
|
||||
else
|
||||
validateComponent(comp)
|
||||
local lname = comp:lower()
|
||||
local lname = comp
|
||||
|
||||
local curPath = "/" .. table.concat(stack, "/")
|
||||
|
||||
@@ -374,7 +374,7 @@ local function normalizePath(path)
|
||||
table.remove(stack)
|
||||
end
|
||||
else
|
||||
table.insert(stack, comp:lower())
|
||||
table.insert(stack, comp)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -184,11 +184,16 @@ function socket.sockshutdown(fd)
|
||||
return true
|
||||
end
|
||||
|
||||
function socket.socketendpoints()
|
||||
return table.keys(socket.handlers)
|
||||
end
|
||||
|
||||
sys.socket = socket.socket
|
||||
sys.connect = socket.connect
|
||||
sys.listen = socket.listen
|
||||
sys.send = socket.send
|
||||
sys.recv = socket.recv
|
||||
sys.sockshutdown = socket.sockshutdown
|
||||
sys.socketendpoints = socket.socketendpoints
|
||||
|
||||
kernel.log("Loaded socket module")
|
||||
@@ -19,4 +19,25 @@ function printInline(...)
|
||||
for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
|
||||
output = output:sub(1, -2)
|
||||
syscall.write(1, output)
|
||||
end
|
||||
|
||||
function userinput(fd, helpstr, replacestr, fdo)
|
||||
local str = ""
|
||||
if helpstr then print(helpstr) end
|
||||
while true do
|
||||
local inp = syscall.read(fd)
|
||||
if inp~="" and inp~=nil then
|
||||
if inp~="\n" then
|
||||
if replacestr then
|
||||
syscall.write(fdo, replacestr)
|
||||
else
|
||||
syscall.write(fdo, inp)
|
||||
end
|
||||
str = inp
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return str
|
||||
end
|
||||
@@ -315,7 +315,9 @@ end
|
||||
|
||||
-- CRC-16/CRC-32 computation
|
||||
local band, bnot, xor, lshift, rshift
|
||||
|
||||
local bit32
|
||||
local ok, temp = pcall(require, "bit32")
|
||||
if ok then bit32=temp end
|
||||
if bit ~= nil then
|
||||
band = bit.band
|
||||
bnot = bit.bnot
|
||||
|
||||
@@ -1211,9 +1211,9 @@ local function runCommand(command)
|
||||
|
||||
local proc = syscall.spawn(function()
|
||||
-- Open standard fds so programs that don't do it themselves work correctly.
|
||||
syscall.open("/dev/input/keyboard1", "r") -- fd 0 stdin
|
||||
syscall.open("/dev/tty/1", "w") -- fd 1 stdout
|
||||
syscall.open("/dev/null", "w") -- fd 2 stderr
|
||||
syscall.open("/proc/self/parent/fd/0", "r") -- fd 0 stdin
|
||||
syscall.open("/proc/self/parent/fd/1", "w") -- fd 1 stdout
|
||||
syscall.open("/proc/self/parent/fd/2", "w") -- fd 2 stderr
|
||||
-- exec replaces this coroutine's code with a fresh isolated environment
|
||||
-- compiled from disk by the kernel (via loadExecutable -> freshUserEnv),
|
||||
-- so the child cannot share any upvalue or syscall table state with hysh.
|
||||
|
||||
+310
-48
@@ -1,68 +1,330 @@
|
||||
local args={...}
|
||||
--:Minify:--
|
||||
local spm = function(...)
|
||||
if syscall.geteuid()~=0 then print("Permission denied") return end
|
||||
local inpArgs = { ... }
|
||||
local args = {}
|
||||
local cloptions = {
|
||||
S = false,
|
||||
y = false,
|
||||
u = false,
|
||||
R = false,
|
||||
h = false,
|
||||
r = false,
|
||||
Q = false,
|
||||
l = false,
|
||||
o = false,
|
||||
i = false,
|
||||
e = false,
|
||||
t = false,
|
||||
sysroot = "",
|
||||
init = false,
|
||||
help = false,
|
||||
source = false
|
||||
}
|
||||
|
||||
-- local test repo
|
||||
local rootRepo="http://localhost:8000/spm.json"
|
||||
--local rootRepo="https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm.json"
|
||||
local i = 1
|
||||
local fs = require("fs")
|
||||
local http = require("http")
|
||||
local json = require("json")
|
||||
local tar = require("tar")
|
||||
local deflate = require("deflate")
|
||||
local httpcache = {}
|
||||
|
||||
local json = require("json")
|
||||
local http = require("http")
|
||||
local deflate = require("deflate")
|
||||
|
||||
local function checkRepo(repo)
|
||||
local resp = http.get(repo)
|
||||
if resp.code ~= 200 then
|
||||
return false
|
||||
local function get(url)
|
||||
if httpcache[url] then return httpcache[url] end
|
||||
local ret = http.get(url)
|
||||
httpcache[url] = ret
|
||||
return ret
|
||||
end
|
||||
local repojson = json.decode(resp.body)
|
||||
if not repojson then
|
||||
return false
|
||||
|
||||
while i <= #inpArgs do
|
||||
local v = inpArgs[i]
|
||||
|
||||
if v:sub(1, 2) == "--" then
|
||||
local opt, value = v:match("^%-%-(.-)=(.*)$")
|
||||
|
||||
if not opt then
|
||||
opt = v:sub(3)
|
||||
end
|
||||
|
||||
if cloptions[opt] == nil then
|
||||
print("spm: unrecognized option '" .. v .. "'.")
|
||||
print("try 'spm --help' for more information.")
|
||||
return
|
||||
end
|
||||
|
||||
if type(cloptions[opt]) == "boolean" then
|
||||
cloptions[opt] = true
|
||||
else
|
||||
if value == nil then
|
||||
i = i + 1
|
||||
value = inpArgs[i]
|
||||
end
|
||||
|
||||
if value == nil then
|
||||
print("spm: option '--" .. opt .. "' requires an argument.")
|
||||
return
|
||||
end
|
||||
|
||||
cloptions[opt] = value
|
||||
end
|
||||
|
||||
elseif v:sub(1, 1) == "-" then
|
||||
for j = 2, #v do
|
||||
local opt = v:sub(j, j)
|
||||
|
||||
if cloptions[opt] == nil then
|
||||
print("spm: invalid option '-" .. opt .. "'.")
|
||||
print("try 'spm --help' for more information.")
|
||||
return
|
||||
end
|
||||
|
||||
if type(cloptions[opt]) ~= "boolean" then
|
||||
print("spm: option '-" .. opt .. "' requires the long form '--" .. opt .. "=value'.")
|
||||
return
|
||||
end
|
||||
|
||||
cloptions[opt] = true
|
||||
end
|
||||
|
||||
else
|
||||
table.insert(args, v)
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
return true, repojson
|
||||
end
|
||||
|
||||
local function getRepos(root)
|
||||
local repos = {}
|
||||
local visited = {}
|
||||
if cloptions.sysroot=="" then
|
||||
syscall.chdir("/")
|
||||
else
|
||||
syscall.chdir(cloptions.sysroot)
|
||||
end
|
||||
|
||||
local queue = {root}
|
||||
local head = 1
|
||||
if cloptions.init then
|
||||
fs.mkdir("var/spm/cache/")
|
||||
fs.mkdir("var/spm/db/")
|
||||
fs.writeAllText("var/spm/db/repos.list","")
|
||||
fs.mkdir("var/spm/db/installed/")
|
||||
fs.mkdir("etc/spm/")
|
||||
fs.writeAllText("etc/spm/sources.list","https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm.json\nhttp://localhost:8000/spm.json")
|
||||
end
|
||||
|
||||
while head <= #queue do
|
||||
local url = queue[head]
|
||||
head = head + 1
|
||||
if not fs.exists("var/spm/") or not fs.exists("etc/spm/") then
|
||||
print("spm not initialized run \"spm --init\"")
|
||||
return
|
||||
end
|
||||
|
||||
if not visited[url] then
|
||||
visited[url] = true
|
||||
local repodb = string.split(fs.readAllText("var/spm/db/repos.list"), "\n")
|
||||
local sourcelist = string.split(fs.readAllText("etc/spm/sources.list"), "\n")
|
||||
local pkgdblist = fs.list("var/spm/db/installed/")
|
||||
local pkgdb = {}
|
||||
|
||||
local ok, repo = checkRepo(url)
|
||||
if ok then
|
||||
table.insert(repos, {
|
||||
url = url,
|
||||
data = repo
|
||||
})
|
||||
for _,v in ipairs(pkgdblist) do
|
||||
local file = fs.readAllText("var/spm/db/installed/"..v)
|
||||
pkgdb[v] = json.decode(file)
|
||||
end
|
||||
|
||||
if repo.refs then
|
||||
for _, ref in ipairs(repo.refs) do
|
||||
if not visited[ref] then
|
||||
queue[#queue + 1] = ref
|
||||
local function printpkgs(list)
|
||||
local colWidth=0
|
||||
local tmp = syscall.devctl(1, "size")
|
||||
local sizeX, sizeY = tonumber(tmp:sub(1, tmp:find(";")-1)), tonumber(tmp:sub(tmp:find(";")+1))
|
||||
for _, v in ipairs(list) do
|
||||
if #v + 2 > colWidth then colWidth = #v + 2 end
|
||||
end
|
||||
local numCols = math.max(1, math.floor(sizeX / colWidth))
|
||||
|
||||
for i, v in ipairs(list) do
|
||||
printInline(v.id)
|
||||
printInline((" "):rep(colWidth - #v))
|
||||
if i % numCols == 0 then print("") end
|
||||
end
|
||||
if #list % numCols ~= 0 then print("") end
|
||||
end
|
||||
|
||||
local function checkRepo(repo)
|
||||
local resp = get(repo)
|
||||
if not resp then return false end
|
||||
if resp.code ~= 200 then
|
||||
return false
|
||||
end
|
||||
local repojson = json.decode(resp.body)
|
||||
if not repojson then
|
||||
return false
|
||||
end
|
||||
return true, repojson
|
||||
end
|
||||
|
||||
local function getRepos(root)
|
||||
local repos = {}
|
||||
local visited = {}
|
||||
|
||||
local queue = table.values(root)
|
||||
local head = 1
|
||||
|
||||
while head <= #queue do
|
||||
local url = queue[head]
|
||||
head = head + 1
|
||||
|
||||
if not visited[url] then
|
||||
visited[url] = true
|
||||
|
||||
print("GET:"..tostring(head-1).." "..url)
|
||||
|
||||
local ok, repo = checkRepo(url)
|
||||
if ok then
|
||||
table.insert(repos, url)
|
||||
|
||||
if repo.refs then
|
||||
for _, ref in ipairs(repo.refs) do
|
||||
if not visited[ref] then
|
||||
queue[#queue + 1] = ref
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return repos
|
||||
end
|
||||
|
||||
return repos
|
||||
end
|
||||
local function getPkg(name)
|
||||
for _, url in ipairs(repodb) do
|
||||
local ok, repo = checkRepo(url)
|
||||
if not ok then
|
||||
print("Failed to contact repository:")
|
||||
print(url)
|
||||
print("Consider running 'spm -Sy' to remove broken repositories.")
|
||||
else
|
||||
if repo.packages then
|
||||
if repo.packages[name] then
|
||||
local pkgurl = repo.packages[name]
|
||||
local resp = get(pkgurl)
|
||||
if not resp then
|
||||
print("Repository: "..url)
|
||||
print("Has broken package: "..name)
|
||||
print("Ignoring")
|
||||
else
|
||||
if resp.code ~= 200 then
|
||||
print("Repository: "..url)
|
||||
print("Has broken package: "..name)
|
||||
print("Ignoring")
|
||||
else
|
||||
local pkgjson = json.decode(resp.body)
|
||||
if not pkgjson then
|
||||
print("Repository: "..url)
|
||||
print("Has broken package: "..name)
|
||||
print("Ignoring")
|
||||
else
|
||||
return {
|
||||
url=pkgurl,
|
||||
tar=pkgjson.tarball,
|
||||
hash=pkgjson.hash,
|
||||
id=pkgjson.id,
|
||||
deps=pkgjson.dependencies,
|
||||
desc=pkgjson.description,
|
||||
auth=pkgjson.authors,
|
||||
ver=pkgjson.version
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false, "target not found: "..name
|
||||
end
|
||||
|
||||
local function getPkg(name)
|
||||
|
||||
end
|
||||
if cloptions.S then
|
||||
if cloptions.y then
|
||||
print("Updating repositories...")
|
||||
repodb={}
|
||||
for _,v in ipairs(getRepos(sourcelist)) do
|
||||
repodb[#repodb+1]=v
|
||||
end
|
||||
print("Writing new data...")
|
||||
local str = ""
|
||||
for _,v in ipairs(repodb) do
|
||||
str=str..v.."\n"
|
||||
end
|
||||
fs.writeAllText("var/spm/db/repos.list", str)
|
||||
end
|
||||
if cloptions.i then
|
||||
-- info remote
|
||||
end
|
||||
local needed = {}
|
||||
local found = {}
|
||||
for i,v in ipairs(args) do
|
||||
local pkg, err = getPkg(v)
|
||||
if not pkg then print(err) syscall.exit(1) end
|
||||
needed[#needed+1] = pkg
|
||||
found[v]=true
|
||||
end
|
||||
if cloptions.u then
|
||||
for i,v in ipairs(table.keys(pkgdb)) do
|
||||
local pkg, err = getPkg(v)
|
||||
if pkg then
|
||||
needed[#needed+1] = pkg
|
||||
found[v]=true
|
||||
end
|
||||
end
|
||||
end
|
||||
local head = 0
|
||||
while head<#needed do
|
||||
head=head+1
|
||||
for i,v in ipairs(needed[head].deps) do
|
||||
if not found[v] and not pkgdb[v] then
|
||||
local pkg, err = getPkg(v)
|
||||
if pkg then
|
||||
needed[#needed+1] = pkg
|
||||
found[v]=true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if #needed==0 then
|
||||
syscall.exit()
|
||||
end
|
||||
print("")
|
||||
print("Packages("..tostring(#needed).."):")
|
||||
printpkgs(needed)
|
||||
print("")
|
||||
while true do
|
||||
local text = userinput(0, "Proceed with download [Y/n]", nil, 1)
|
||||
if text=="" then
|
||||
break
|
||||
elseif text:lower()=="y" then
|
||||
break
|
||||
elseif text:lower()=="n" then
|
||||
syscall.exit()
|
||||
end
|
||||
end
|
||||
|
||||
if args[1] == "install" then
|
||||
local pkg=getPkg(args[2])
|
||||
elseif args[1] == "sync" then
|
||||
error("not implemented")
|
||||
elseif args[1] == "remove" then
|
||||
error("not implemented")
|
||||
local files = {}
|
||||
for _,v in ipairs(needed) do
|
||||
local file = http.get(v.tar)
|
||||
|
||||
end
|
||||
|
||||
elseif cloptions.R then
|
||||
-- remove tree
|
||||
elseif cloptions.Q then
|
||||
if cloptions.l then
|
||||
-- list installed files
|
||||
elseif cloptions.o then
|
||||
-- get package file arg[1] is from
|
||||
elseif cloptions.e then
|
||||
-- list installed manually
|
||||
elseif cloptions.i then
|
||||
-- list installed info
|
||||
elseif cloptions.t then
|
||||
-- list orphans
|
||||
end
|
||||
end
|
||||
end
|
||||
local ok,err = xpcall(spm, debug.traceback, ...)
|
||||
if not ok then
|
||||
print("Fatal error in spm:")
|
||||
print(err)
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
tar
|
||||
deflate
|
||||
json
|
||||
minify
|
||||
@@ -0,0 +1,2 @@
|
||||
Hyperion
|
||||
Astronand
|
||||
@@ -0,0 +1,201 @@
|
||||
local LibDeflate = require("LibDeflate")
|
||||
local tar = {}
|
||||
|
||||
local function pad512(n)
|
||||
return math.ceil(n / 512) * 512
|
||||
end
|
||||
|
||||
local function octal(n, size)
|
||||
local s = string.format("%0" .. (size - 1) .. "o", n)
|
||||
return s .. "\0"
|
||||
end
|
||||
|
||||
local function header(name, size, typeflag, link)
|
||||
local h = string.rep("\0", 512)
|
||||
|
||||
local function put(pos, len, value)
|
||||
h = h:sub(1, pos - 1) ..
|
||||
value ..
|
||||
h:sub(pos + len)
|
||||
end
|
||||
|
||||
put(1, 100, name)
|
||||
put(101, 8, octal(0, 8))
|
||||
put(109, 8, octal(0, 8))
|
||||
put(117, 8, octal(0, 8))
|
||||
put(125, 12, octal(size, 12))
|
||||
put(137, 12, octal(os.time(), 12))
|
||||
put(149, 8, " ")
|
||||
put(157, 1, typeflag)
|
||||
|
||||
if link then
|
||||
put(158, 100, link)
|
||||
end
|
||||
|
||||
put(257, 6, "ustar\0")
|
||||
put(263, 2, "00")
|
||||
|
||||
local sum = 0
|
||||
for i = 1, 512 do
|
||||
sum = sum + h:byte(i)
|
||||
end
|
||||
|
||||
put(149, 8, string.format("%06o\0 ", sum))
|
||||
|
||||
return h
|
||||
end
|
||||
|
||||
local function add(out, node, prefix)
|
||||
local path = prefix and (prefix .. "/" .. node.name)
|
||||
or node.name
|
||||
|
||||
if node.type == "dir" then
|
||||
table.insert(out, header(path .. "/", 0, "5"))
|
||||
|
||||
for _, child in ipairs(node.content) do
|
||||
add(out, child, path)
|
||||
end
|
||||
|
||||
elseif node.type == "file" then
|
||||
local data = node.content or ""
|
||||
|
||||
table.insert(out, header(path, #data, "0"))
|
||||
table.insert(out, data)
|
||||
|
||||
local padding = pad512(#data) - #data
|
||||
if padding > 0 then
|
||||
table.insert(out, string.rep("\0", padding))
|
||||
end
|
||||
|
||||
elseif node.type == "symlink" then
|
||||
table.insert(out,
|
||||
header(path, 0, "2", node.content)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function tar.pack(tree, gzip)
|
||||
local out = {}
|
||||
|
||||
add(out, tree)
|
||||
|
||||
table.insert(out, string.rep("\0", 1024))
|
||||
|
||||
local data = table.concat(out)
|
||||
|
||||
if gzip then
|
||||
return LibDeflate:CompressGzip(data)
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
local function read_octal(s)
|
||||
s = s:gsub("\0.*", "")
|
||||
return tonumber(s, 8) or 0
|
||||
end
|
||||
|
||||
function tar.unpack(data)
|
||||
if data:sub(1,2) == "\31\139" then
|
||||
data = assert(LibDeflate:DecompressGzip(data))
|
||||
end
|
||||
|
||||
local root = {
|
||||
type = "dir",
|
||||
name = "",
|
||||
content = {}
|
||||
}
|
||||
|
||||
local function add_path(parts, node)
|
||||
local current = root
|
||||
|
||||
for i = 1, #parts - 1 do
|
||||
local name = parts[i]
|
||||
local found
|
||||
|
||||
for _, child in ipairs(current.content) do
|
||||
if child.name == name and child.type == "dir" then
|
||||
found = child
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
found = {
|
||||
type = "dir",
|
||||
name = name,
|
||||
content = {}
|
||||
}
|
||||
table.insert(current.content, found)
|
||||
end
|
||||
|
||||
current = found
|
||||
end
|
||||
|
||||
table.insert(current.content, node)
|
||||
end
|
||||
|
||||
local pos = 1
|
||||
|
||||
while pos + 511 <= #data do
|
||||
local h = data:sub(pos, pos + 511)
|
||||
|
||||
if h == string.rep("\0", 512) then
|
||||
break
|
||||
end
|
||||
|
||||
local name = h:sub(1,100):gsub("\0.*", "")
|
||||
local size = read_octal(h:sub(125,136))
|
||||
local kind = h:sub(157,157)
|
||||
|
||||
local skip = false
|
||||
|
||||
-- Ignore PAX headers and GNU long filename records
|
||||
if kind == "x" or kind == "g" or kind == "L" then
|
||||
skip = true
|
||||
end
|
||||
|
||||
if not skip then
|
||||
local node
|
||||
|
||||
if kind == "5" then
|
||||
node = {
|
||||
type = "dir",
|
||||
name = name:gsub("/$", ""),
|
||||
content = {}
|
||||
}
|
||||
|
||||
elseif kind == "2" then
|
||||
node = {
|
||||
type = "symlink",
|
||||
name = name,
|
||||
content =
|
||||
h:sub(158,257):gsub("\0.*", "")
|
||||
}
|
||||
|
||||
else
|
||||
node = {
|
||||
type = "file",
|
||||
name = name,
|
||||
content =
|
||||
data:sub(pos + 512,
|
||||
pos + 511 + size)
|
||||
}
|
||||
end
|
||||
|
||||
local parts = {}
|
||||
|
||||
for part in node.name:gmatch("[^/]+") do
|
||||
table.insert(parts, part)
|
||||
end
|
||||
|
||||
add_path(parts, node)
|
||||
end
|
||||
|
||||
pos = pos + 512 + pad512(size)
|
||||
end
|
||||
|
||||
return root
|
||||
end
|
||||
|
||||
return tar
|
||||
Reference in New Issue
Block a user