aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorV1K1NGbg <victor@ilchev.com>2024-08-03 16:25:31 +0300
committerV1K1NGbg <victor@ilchev.com>2024-08-05 20:51:31 +0300
commite45c52d01f8e0abffebbfb4a0ac8a72b8f0f62ba (patch)
treea715869e949d60101e3f98197a35d548fff04e96 /src
parent908303e675ed95591f1b80ff0051c724f893969f (diff)
downloadluarocks-e45c52d01f8e0abffebbfb4a0ac8a72b8f0f62ba.tar.gz
luarocks-e45c52d01f8e0abffebbfb4a0ac8a72b8f0f62ba.tar.bz2
luarocks-e45c52d01f8e0abffebbfb4a0ac8a72b8f0f62ba.zip
tar
Diffstat (limited to 'src')
-rw-r--r--src/luarocks/fs.d.tl2
-rw-r--r--src/luarocks/tools/tar-original.lua191
-rw-r--r--src/luarocks/tools/tar.lua109
-rw-r--r--src/luarocks/tools/tar.tl59
-rw-r--r--src/luarocks/tools/zip.tl3
5 files changed, 298 insertions, 66 deletions
diff --git a/src/luarocks/fs.d.tl b/src/luarocks/fs.d.tl
index a2218cd6..eec2b6a2 100644
--- a/src/luarocks/fs.d.tl
+++ b/src/luarocks/fs.d.tl
@@ -29,6 +29,8 @@ local record fs
29 set_permissions: function(string, string, string) 29 set_permissions: function(string, string, string)
30 -- patch 30 -- patch
31 absolute_name: function(string, ?string): string 31 absolute_name: function(string, ?string): string
32 -- tar
33 set_time: function(string, number)
32end 34end
33 35
34return fs 36return fs
diff --git a/src/luarocks/tools/tar-original.lua b/src/luarocks/tools/tar-original.lua
new file mode 100644
index 00000000..bac7b2a9
--- /dev/null
+++ b/src/luarocks/tools/tar-original.lua
@@ -0,0 +1,191 @@
1
2--- A pure-Lua implementation of untar (unpacking .tar archives)
3local tar = {}
4
5local fs = require("luarocks.fs")
6local dir = require("luarocks.dir")
7local fun = require("luarocks.fun")
8
9local blocksize = 512
10
11local function get_typeflag(flag)
12 if flag == "0" or flag == "\0" then return "file"
13 elseif flag == "1" then return "link"
14 elseif flag == "2" then return "symlink" -- "reserved" in POSIX, "symlink" in GNU
15 elseif flag == "3" then return "character"
16 elseif flag == "4" then return "block"
17 elseif flag == "5" then return "directory"
18 elseif flag == "6" then return "fifo"
19 elseif flag == "7" then return "contiguous" -- "reserved" in POSIX, "contiguous" in GNU
20 elseif flag == "x" then return "next file"
21 elseif flag == "g" then return "global extended header"
22 elseif flag == "L" then return "long name"
23 elseif flag == "K" then return "long link name"
24 end
25 return "unknown"
26end
27
28local function octal_to_number(octal)
29 local exp = 0
30 local number = 0
31 octal = octal:gsub("%s", "")
32 for i = #octal,1,-1 do
33 local digit = tonumber(octal:sub(i,i))
34 if not digit then
35 break
36 end
37 number = number + (digit * 8^exp)
38 exp = exp + 1
39 end
40 return number
41end
42
43local function checksum_header(block)
44 local sum = 256
45
46 if block:byte(1) == 0 then
47 return 0
48 end
49
50 for i = 1,148 do
51 local b = block:byte(i) or 0
52 sum = sum + b
53 end
54 for i = 157,500 do
55 local b = block:byte(i) or 0
56 sum = sum + b
57 end
58
59 return sum
60end
61
62local function nullterm(s)
63 return s:match("^[^%z]*")
64end
65
66local function read_header_block(block)
67 local header = {}
68 header.name = nullterm(block:sub(1,100))
69 header.mode = nullterm(block:sub(101,108)):gsub(" ", "")
70 header.uid = octal_to_number(nullterm(block:sub(109,116)))
71 header.gid = octal_to_number(nullterm(block:sub(117,124)))
72 header.size = octal_to_number(nullterm(block:sub(125,136)))
73 header.mtime = octal_to_number(nullterm(block:sub(137,148)))
74 header.chksum = octal_to_number(nullterm(block:sub(149,156)))
75 header.typeflag = get_typeflag(block:sub(157,157))
76 header.linkname = nullterm(block:sub(158,257))
77 header.magic = block:sub(258,263)
78 header.version = block:sub(264,265)
79 header.uname = nullterm(block:sub(266,297))
80 header.gname = nullterm(block:sub(298,329))
81 header.devmajor = octal_to_number(nullterm(block:sub(330,337)))
82 header.devminor = octal_to_number(nullterm(block:sub(338,345)))
83 header.prefix = block:sub(346,500)
84
85 -- if header.magic ~= "ustar " and header.magic ~= "ustar\0" then
86 -- return false, ("Invalid header magic %6x"):format(bestring_to_number(header.magic))
87 -- end
88 -- if header.version ~= "00" and header.version ~= " \0" then
89 -- return false, "Unknown version "..header.version
90 -- end
91 if header.typeflag == "unknown" then
92 if checksum_header(block) ~= header.chksum then
93 return false, "Failed header checksum"
94 end
95 end
96 return header
97end
98
99function tar.untar(filename, destdir)
100 assert(type(filename) == "string")
101 assert(type(destdir) == "string")
102
103 local tar_handle = io.open(filename, "rb")
104 if not tar_handle then return nil, "Error opening file "..filename end
105
106 local long_name, long_link_name
107 local ok, err
108 local make_dir = fun.memoize(fs.make_dir)
109 while true do
110 local block
111 repeat
112 block = tar_handle:read(blocksize)
113 until (not block) or block:byte(1) > 0
114 if not block then break end
115 if #block < blocksize then
116 ok, err = nil, "Invalid block size -- corrupted file?"
117 break
118 end
119
120 local header
121 header, err = read_header_block(block)
122 if not header then
123 ok = false
124 break
125 end
126
127 local file_data = ""
128 if header.size > 0 then
129 local nread = math.ceil(header.size / blocksize) * blocksize
130 file_data = tar_handle:read(header.size)
131 if nread > header.size then
132 tar_handle:seek("cur", nread - header.size)
133 end
134 end
135
136 if header.typeflag == "long name" then
137 long_name = nullterm(file_data)
138 elseif header.typeflag == "long link name" then
139 long_link_name = nullterm(file_data)
140 else
141 if long_name then
142 header.name = long_name
143 long_name = nil
144 end
145 if long_link_name then
146 header.name = long_link_name
147 long_link_name = nil
148 end
149 end
150 local pathname = dir.path(destdir, header.name)
151 pathname = fs.absolute_name(pathname)
152 if header.typeflag == "directory" then
153 ok, err = make_dir(pathname)
154 if not ok then
155 break
156 end
157 elseif header.typeflag == "file" then
158 local dirname = dir.dir_name(pathname)
159 if dirname ~= "" then
160 ok, err = make_dir(dirname)
161 if not ok then
162 break
163 end
164 end
165 local file_handle
166 file_handle, err = io.open(pathname, "wb")
167 if not file_handle then
168 ok = nil
169 break
170 end
171 file_handle:write(file_data)
172 file_handle:close()
173 fs.set_time(pathname, header.mtime)
174 if header.mode:match("[75]") then
175 fs.set_permissions(pathname, "exec", "all")
176 else
177 fs.set_permissions(pathname, "read", "all")
178 end
179 end
180 --[[
181 for k,v in pairs(header) do
182 util.printout("[\""..tostring(k).."\"] = "..(type(v)=="number" and v or "\""..v:gsub("%z", "\\0").."\""))
183 end
184 util.printout()
185 --]]
186 end
187 tar_handle:close()
188 return ok, err
189end
190
191return tar
diff --git a/src/luarocks/tools/tar.lua b/src/luarocks/tools/tar.lua
index bac7b2a9..e95b85d0 100644
--- a/src/luarocks/tools/tar.lua
+++ b/src/luarocks/tools/tar.lua
@@ -1,22 +1,43 @@
1local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local io = _tl_compat and _tl_compat.io or io; local math = _tl_compat and _tl_compat.math or math; local string = _tl_compat and _tl_compat.string or string
2
3local tar = {Header = {}, }
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1 22
2--- A pure-Lua implementation of untar (unpacking .tar archives)
3local tar = {}
4 23
5local fs = require("luarocks.fs") 24local fs = require("luarocks.fs")
6local dir = require("luarocks.dir") 25local dir = require("luarocks.dir")
7local fun = require("luarocks.fun") 26local fun = require("luarocks.fun")
8 27
28
29
9local blocksize = 512 30local blocksize = 512
10 31
11local function get_typeflag(flag) 32local function get_typeflag(flag)
12 if flag == "0" or flag == "\0" then return "file" 33 if flag == "0" or flag == "\0" then return "file"
13 elseif flag == "1" then return "link" 34 elseif flag == "1" then return "link"
14 elseif flag == "2" then return "symlink" -- "reserved" in POSIX, "symlink" in GNU 35 elseif flag == "2" then return "symlink"
15 elseif flag == "3" then return "character" 36 elseif flag == "3" then return "character"
16 elseif flag == "4" then return "block" 37 elseif flag == "4" then return "block"
17 elseif flag == "5" then return "directory" 38 elseif flag == "5" then return "directory"
18 elseif flag == "6" then return "fifo" 39 elseif flag == "6" then return "fifo"
19 elseif flag == "7" then return "contiguous" -- "reserved" in POSIX, "contiguous" in GNU 40 elseif flag == "7" then return "contiguous"
20 elseif flag == "x" then return "next file" 41 elseif flag == "x" then return "next file"
21 elseif flag == "g" then return "global extended header" 42 elseif flag == "g" then return "global extended header"
22 elseif flag == "L" then return "long name" 43 elseif flag == "L" then return "long name"
@@ -29,12 +50,12 @@ local function octal_to_number(octal)
29 local exp = 0 50 local exp = 0
30 local number = 0 51 local number = 0
31 octal = octal:gsub("%s", "") 52 octal = octal:gsub("%s", "")
32 for i = #octal,1,-1 do 53 for i = #octal, 1, -1 do
33 local digit = tonumber(octal:sub(i,i)) 54 local digit = tonumber(octal:sub(i, i))
34 if not digit then 55 if not digit then
35 break 56 break
36 end 57 end
37 number = number + (digit * 8^exp) 58 number = number + (digit * 8 ^ exp)
38 exp = exp + 1 59 exp = exp + 1
39 end 60 end
40 return number 61 return number
@@ -47,11 +68,11 @@ local function checksum_header(block)
47 return 0 68 return 0
48 end 69 end
49 70
50 for i = 1,148 do 71 for i = 1, 148 do
51 local b = block:byte(i) or 0 72 local b = block:byte(i) or 0
52 sum = sum + b 73 sum = sum + b
53 end 74 end
54 for i = 157,500 do 75 for i = 157, 500 do
55 local b = block:byte(i) or 0 76 local b = block:byte(i) or 0
56 sum = sum + b 77 sum = sum + b
57 end 78 end
@@ -65,29 +86,29 @@ end
65 86
66local function read_header_block(block) 87local function read_header_block(block)
67 local header = {} 88 local header = {}
68 header.name = nullterm(block:sub(1,100)) 89 header.name = nullterm(block:sub(1, 100))
69 header.mode = nullterm(block:sub(101,108)):gsub(" ", "") 90 header.mode = nullterm(block:sub(101, 108)):gsub(" ", "")
70 header.uid = octal_to_number(nullterm(block:sub(109,116))) 91 header.uid = octal_to_number(nullterm(block:sub(109, 116)))
71 header.gid = octal_to_number(nullterm(block:sub(117,124))) 92 header.gid = octal_to_number(nullterm(block:sub(117, 124)))
72 header.size = octal_to_number(nullterm(block:sub(125,136))) 93 header.size = octal_to_number(nullterm(block:sub(125, 136)))
73 header.mtime = octal_to_number(nullterm(block:sub(137,148))) 94 header.mtime = octal_to_number(nullterm(block:sub(137, 148)))
74 header.chksum = octal_to_number(nullterm(block:sub(149,156))) 95 header.chksum = octal_to_number(nullterm(block:sub(149, 156)))
75 header.typeflag = get_typeflag(block:sub(157,157)) 96 header.typeflag = get_typeflag(block:sub(157, 157))
76 header.linkname = nullterm(block:sub(158,257)) 97 header.linkname = nullterm(block:sub(158, 257))
77 header.magic = block:sub(258,263) 98 header.magic = block:sub(258, 263)
78 header.version = block:sub(264,265) 99 header.version = block:sub(264, 265)
79 header.uname = nullterm(block:sub(266,297)) 100 header.uname = nullterm(block:sub(266, 297))
80 header.gname = nullterm(block:sub(298,329)) 101 header.gname = nullterm(block:sub(298, 329))
81 header.devmajor = octal_to_number(nullterm(block:sub(330,337))) 102 header.devmajor = octal_to_number(nullterm(block:sub(330, 337)))
82 header.devminor = octal_to_number(nullterm(block:sub(338,345))) 103 header.devminor = octal_to_number(nullterm(block:sub(338, 345)))
83 header.prefix = block:sub(346,500) 104 header.prefix = block:sub(346, 500)
84 105
85 -- if header.magic ~= "ustar " and header.magic ~= "ustar\0" then 106
86 -- return false, ("Invalid header magic %6x"):format(bestring_to_number(header.magic)) 107
87 -- end 108
88 -- if header.version ~= "00" and header.version ~= " \0" then 109
89 -- return false, "Unknown version "..header.version 110
90 -- end 111
91 if header.typeflag == "unknown" then 112 if header.typeflag == "unknown" then
92 if checksum_header(block) ~= header.chksum then 113 if checksum_header(block) ~= header.chksum then
93 return false, "Failed header checksum" 114 return false, "Failed header checksum"
@@ -97,11 +118,9 @@ local function read_header_block(block)
97end 118end
98 119
99function tar.untar(filename, destdir) 120function tar.untar(filename, destdir)
100 assert(type(filename) == "string")
101 assert(type(destdir) == "string")
102 121
103 local tar_handle = io.open(filename, "rb") 122 local tar_handle = io.open(filename, "rb")
104 if not tar_handle then return nil, "Error opening file "..filename end 123 if not tar_handle then return nil, "Error opening file " .. filename end
105 124
106 local long_name, long_link_name 125 local long_name, long_link_name
107 local ok, err 126 local ok, err
@@ -117,13 +136,13 @@ function tar.untar(filename, destdir)
117 break 136 break
118 end 137 end
119 138
120 local header 139 local headerp
121 header, err = read_header_block(block) 140 headerp, err = read_header_block(block)
122 if not header then 141 if not headerp then
123 ok = false 142 ok = false
124 break 143 break
125 end 144 end
126 145 local header = headerp
127 local file_data = "" 146 local file_data = ""
128 if header.size > 0 then 147 if header.size > 0 then
129 local nread = math.ceil(header.size / blocksize) * blocksize 148 local nread = math.ceil(header.size / blocksize) * blocksize
@@ -177,12 +196,12 @@ function tar.untar(filename, destdir)
177 fs.set_permissions(pathname, "read", "all") 196 fs.set_permissions(pathname, "read", "all")
178 end 197 end
179 end 198 end
180 --[[ 199
181 for k,v in pairs(header) do 200
182 util.printout("[\""..tostring(k).."\"] = "..(type(v)=="number" and v or "\""..v:gsub("%z", "\\0").."\"")) 201
183 end 202
184 util.printout() 203
185 --]] 204
186 end 205 end
187 tar_handle:close() 206 tar_handle:close()
188 return ok, err 207 return ok, err
diff --git a/src/luarocks/tools/tar.tl b/src/luarocks/tools/tar.tl
index bac7b2a9..9a7ce8e6 100644
--- a/src/luarocks/tools/tar.tl
+++ b/src/luarocks/tools/tar.tl
@@ -1,14 +1,35 @@
1 1
2--- A pure-Lua implementation of untar (unpacking .tar archives) 2--- A pure-Lua implementation of untar (unpacking .tar archives)
3local tar = {} 3local record tar
4 record Header
5 name: string
6 mode: string
7 uid: number
8 gid: number
9 size: number
10 mtime: number
11 chksum: number
12 typeflag: string
13 linkname: string
14 magic: string
15 version: string
16 uname: string
17 gname: string
18 devmajor: number
19 devminor: number
20 prefix: string
21 end
22end
4 23
5local fs = require("luarocks.fs") 24local fs = require("luarocks.fs")
6local dir = require("luarocks.dir") 25local dir = require("luarocks.dir")
7local fun = require("luarocks.fun") 26local fun = require("luarocks.fun")
8 27
28local type Header = tar.Header
29
9local blocksize = 512 30local blocksize = 512
10 31
11local function get_typeflag(flag) 32local function get_typeflag(flag: string): string
12 if flag == "0" or flag == "\0" then return "file" 33 if flag == "0" or flag == "\0" then return "file"
13 elseif flag == "1" then return "link" 34 elseif flag == "1" then return "link"
14 elseif flag == "2" then return "symlink" -- "reserved" in POSIX, "symlink" in GNU 35 elseif flag == "2" then return "symlink" -- "reserved" in POSIX, "symlink" in GNU
@@ -25,9 +46,9 @@ local function get_typeflag(flag)
25 return "unknown" 46 return "unknown"
26end 47end
27 48
28local function octal_to_number(octal) 49local function octal_to_number(octal: string): number
29 local exp = 0 50 local exp = 0
30 local number = 0 51 local number: number = 0
31 octal = octal:gsub("%s", "") 52 octal = octal:gsub("%s", "")
32 for i = #octal,1,-1 do 53 for i = #octal,1,-1 do
33 local digit = tonumber(octal:sub(i,i)) 54 local digit = tonumber(octal:sub(i,i))
@@ -40,7 +61,7 @@ local function octal_to_number(octal)
40 return number 61 return number
41end 62end
42 63
43local function checksum_header(block) 64local function checksum_header(block: string): number
44 local sum = 256 65 local sum = 256
45 66
46 if block:byte(1) == 0 then 67 if block:byte(1) == 0 then
@@ -59,12 +80,12 @@ local function checksum_header(block)
59 return sum 80 return sum
60end 81end
61 82
62local function nullterm(s) 83local function nullterm(s: string): string
63 return s:match("^[^%z]*") 84 return s:match("^[^%z]*")
64end 85end
65 86
66local function read_header_block(block) 87local function read_header_block(block: string): boolean | Header, string
67 local header = {} 88 local header: Header = {}
68 header.name = nullterm(block:sub(1,100)) 89 header.name = nullterm(block:sub(1,100))
69 header.mode = nullterm(block:sub(101,108)):gsub(" ", "") 90 header.mode = nullterm(block:sub(101,108)):gsub(" ", "")
70 header.uid = octal_to_number(nullterm(block:sub(109,116))) 91 header.uid = octal_to_number(nullterm(block:sub(109,116)))
@@ -96,18 +117,16 @@ local function read_header_block(block)
96 return header 117 return header
97end 118end
98 119
99function tar.untar(filename, destdir) 120function tar.untar(filename: string, destdir: string): boolean, string
100 assert(type(filename) == "string")
101 assert(type(destdir) == "string")
102 121
103 local tar_handle = io.open(filename, "rb") 122 local tar_handle = io.open(filename, "rb")
104 if not tar_handle then return nil, "Error opening file "..filename end 123 if not tar_handle then return nil, "Error opening file "..filename end
105 124
106 local long_name, long_link_name 125 local long_name, long_link_name: string, string
107 local ok, err 126 local ok, err: boolean, string
108 local make_dir = fun.memoize(fs.make_dir) 127 local make_dir = fun.memoize(fs.make_dir)
109 while true do 128 while true do
110 local block 129 local block: string
111 repeat 130 repeat
112 block = tar_handle:read(blocksize) 131 block = tar_handle:read(blocksize)
113 until (not block) or block:byte(1) > 0 132 until (not block) or block:byte(1) > 0
@@ -117,19 +136,19 @@ function tar.untar(filename, destdir)
117 break 136 break
118 end 137 end
119 138
120 local header 139 local headerp: boolean | Header
121 header, err = read_header_block(block) 140 headerp, err = read_header_block(block)
122 if not header then 141 if not headerp then
123 ok = false 142 ok = false
124 break 143 break
125 end 144 end
126 145 local header: Header = headerp as Header --! cast
127 local file_data = "" 146 local file_data = ""
128 if header.size > 0 then 147 if header.size > 0 then
129 local nread = math.ceil(header.size / blocksize) * blocksize 148 local nread = math.ceil(header.size / blocksize) * blocksize
130 file_data = tar_handle:read(header.size) 149 file_data = tar_handle:read(header.size)
131 if nread > header.size then 150 if nread > header.size then
132 tar_handle:seek("cur", nread - header.size) 151 tar_handle:seek("cur", nread - header.size as integer) --! cast to integer
133 end 152 end
134 end 153 end
135 154
@@ -162,7 +181,7 @@ function tar.untar(filename, destdir)
162 break 181 break
163 end 182 end
164 end 183 end
165 local file_handle 184 local file_handle: FILE
166 file_handle, err = io.open(pathname, "wb") 185 file_handle, err = io.open(pathname, "wb")
167 if not file_handle then 186 if not file_handle then
168 ok = nil 187 ok = nil
diff --git a/src/luarocks/tools/zip.tl b/src/luarocks/tools/zip.tl
index 82d582fa..849a8180 100644
--- a/src/luarocks/tools/zip.tl
+++ b/src/luarocks/tools/zip.tl
@@ -1,7 +1,8 @@
1 1
2--- A Lua implementation of .zip and .gz file compression and decompression, 2--- A Lua implementation of .zip and .gz file compression and decompression,
3-- using only lzlib or lua-lzib. 3-- using only lzlib or lua-lzib.
4local zip = {} 4local record zip
5end
5 6
6local zlib = require("zlib") 7local zlib = require("zlib")
7local fs = require("luarocks.fs") 8local fs = require("luarocks.fs")