diff options
author | Hisham Muhammad <hisham@gobolinux.org> | 2010-12-21 20:33:07 -0200 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2010-12-21 20:33:07 -0200 |
commit | 9f6ff4c8564e721e26faa7cff1bc2e0923f809e9 (patch) | |
tree | c9101814fed2a8de573075a47d8779540aecbd16 | |
parent | 3f9a19ca94f9238d5ec897d0bf2cdac8eb6d763e (diff) | |
download | luarocks-9f6ff4c8564e721e26faa7cff1bc2e0923f809e9.tar.gz luarocks-9f6ff4c8564e721e26faa7cff1bc2e0923f809e9.tar.bz2 luarocks-9f6ff4c8564e721e26faa7cff1bc2e0923f809e9.zip |
Fix bug with paths causing LuaRocks to break on Windows when using LuaFileSystem.
(Bug reported by Cosmin Apreutesei)
-rw-r--r-- | src/luarocks/fs/lua.lua | 101 |
1 files changed, 60 insertions, 41 deletions
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index 5b3efd94..a9fca7b4 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua | |||
@@ -38,6 +38,10 @@ function Q(arg) | |||
38 | return "'" .. arg:gsub("\\", "\\\\"):gsub("'", "'\\''") .. "'" | 38 | return "'" .. arg:gsub("\\", "\\\\"):gsub("'", "'\\''") .. "'" |
39 | end | 39 | end |
40 | 40 | ||
41 | local function normalize(name) | ||
42 | return name:gsub("\\", "/"):gsub("/$", "") | ||
43 | end | ||
44 | |||
41 | --- Test is file/dir is writable. | 45 | --- Test is file/dir is writable. |
42 | -- Warning: testing if a file/dir is writable does not guarantee | 46 | -- Warning: testing if a file/dir is writable does not guarantee |
43 | -- that it will remain writable and therefore it is no replacement | 47 | -- that it will remain writable and therefore it is no replacement |
@@ -46,9 +50,10 @@ end | |||
46 | -- @return boolean: true if file exists, false otherwise. | 50 | -- @return boolean: true if file exists, false otherwise. |
47 | function is_writable(file) | 51 | function is_writable(file) |
48 | assert(file) | 52 | assert(file) |
53 | file = normalize(file) | ||
49 | local result | 54 | local result |
50 | if fs.is_dir(file) then | 55 | if fs.is_dir(file) then |
51 | local file2 = file .. '/.tmpluarockstestwritable' | 56 | local file2 = dir.path(file, '.tmpluarockstestwritable') |
52 | local fh = io.open(file2, 'wb') | 57 | local fh = io.open(file2, 'wb') |
53 | result = fh ~= nil | 58 | result = fh ~= nil |
54 | if fh then fh:close() end | 59 | if fh then fh:close() end |
@@ -67,8 +72,8 @@ end | |||
67 | -- @return string or nil: name of temporary directory or nil on failure. | 72 | -- @return string or nil: name of temporary directory or nil on failure. |
68 | function make_temp_dir(name) | 73 | function make_temp_dir(name) |
69 | assert(type(name) == "string") | 74 | assert(type(name) == "string") |
75 | name = normalize(name) | ||
70 | 76 | ||
71 | name = name:gsub("\\", "/") | ||
72 | local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) | 77 | local temp_dir = (os.getenv("TMP") or "/tmp") .. "/luarocks_" .. name:gsub(dir.separator, "_") .. "-" .. tostring(math.floor(math.random() * 10000)) |
73 | if fs.make_dir(temp_dir) then | 78 | if fs.make_dir(temp_dir) then |
74 | return temp_dir | 79 | return temp_dir |
@@ -100,6 +105,7 @@ end | |||
100 | -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not | 105 | -- @return boolean: true if the MD5 checksum for 'file' equals 'md5sum', false if not |
101 | -- or if it could not perform the check for any reason. | 106 | -- or if it could not perform the check for any reason. |
102 | function check_md5(file, md5sum) | 107 | function check_md5(file, md5sum) |
108 | file = normalize(file) | ||
103 | local computed = fs.get_md5(file) | 109 | local computed = fs.get_md5(file) |
104 | if not computed then | 110 | if not computed then |
105 | return false | 111 | return false |
@@ -144,6 +150,7 @@ end | |||
144 | -- @param d string: The directory to switch to. | 150 | -- @param d string: The directory to switch to. |
145 | function change_dir(d) | 151 | function change_dir(d) |
146 | table.insert(dir_stack, lfs.currentdir()) | 152 | table.insert(dir_stack, lfs.currentdir()) |
153 | d = normalize(d) | ||
147 | lfs.chdir(d) | 154 | lfs.chdir(d) |
148 | end | 155 | end |
149 | 156 | ||
@@ -175,7 +182,7 @@ end | |||
175 | -- @return boolean: true on success, false on failure. | 182 | -- @return boolean: true on success, false on failure. |
176 | function make_dir(directory) | 183 | function make_dir(directory) |
177 | assert(type(directory) == "string") | 184 | assert(type(directory) == "string") |
178 | directory = directory:gsub("\\", "/") | 185 | directory = normalize(directory) |
179 | local path = nil | 186 | local path = nil |
180 | if directory:sub(2, 2) == ":" then | 187 | if directory:sub(2, 2) == ":" then |
181 | path = directory:sub(1, 2) | 188 | path = directory:sub(1, 2) |
@@ -205,6 +212,7 @@ end | |||
205 | -- @param d string: pathname of directory to remove. | 212 | -- @param d string: pathname of directory to remove. |
206 | function remove_dir_if_empty(d) | 213 | function remove_dir_if_empty(d) |
207 | assert(d) | 214 | assert(d) |
215 | d = normalize(d) | ||
208 | lfs.rmdir(d) | 216 | lfs.rmdir(d) |
209 | end | 217 | end |
210 | 218 | ||
@@ -214,6 +222,7 @@ end | |||
214 | -- @param d string: pathname of directory to remove. | 222 | -- @param d string: pathname of directory to remove. |
215 | function remove_dir_tree_if_empty(d) | 223 | function remove_dir_tree_if_empty(d) |
216 | assert(d) | 224 | assert(d) |
225 | d = normalize(d) | ||
217 | for i=1,10 do | 226 | for i=1,10 do |
218 | lfs.rmdir(d) | 227 | lfs.rmdir(d) |
219 | d = dir.dir_name(d) | 228 | d = dir.dir_name(d) |
@@ -227,6 +236,8 @@ end | |||
227 | -- plus an error message. | 236 | -- plus an error message. |
228 | function copy(src, dest) | 237 | function copy(src, dest) |
229 | assert(src and dest) | 238 | assert(src and dest) |
239 | src = normalize(src) | ||
240 | dest = normalize(dest) | ||
230 | local destmode = lfs.attributes(dest, "mode") | 241 | local destmode = lfs.attributes(dest, "mode") |
231 | if destmode == "directory" then | 242 | if destmode == "directory" then |
232 | dest = dir.path(dest, dir.base_name(src)) | 243 | dest = dir.path(dest, dir.base_name(src)) |
@@ -248,6 +259,7 @@ function copy(src, dest) | |||
248 | end | 259 | end |
249 | 260 | ||
250 | --- Implementation function for recursive copy of directory contents. | 261 | --- Implementation function for recursive copy of directory contents. |
262 | -- Assumes paths are normalized. | ||
251 | -- @param src string: Pathname of source | 263 | -- @param src string: Pathname of source |
252 | -- @param dest string: Pathname of destination | 264 | -- @param dest string: Pathname of destination |
253 | -- @return boolean or (boolean, string): true on success, false on failure | 265 | -- @return boolean or (boolean, string): true on success, false on failure |
@@ -277,6 +289,8 @@ end | |||
277 | -- plus an error message. | 289 | -- plus an error message. |
278 | function copy_contents(src, dest) | 290 | function copy_contents(src, dest) |
279 | assert(src and dest) | 291 | assert(src and dest) |
292 | src = normalize(src) | ||
293 | dest = normalize(dest) | ||
280 | assert(lfs.attributes(src, "mode") == "directory") | 294 | assert(lfs.attributes(src, "mode") == "directory") |
281 | 295 | ||
282 | for file in lfs.dir(src) do | 296 | for file in lfs.dir(src) do |
@@ -291,35 +305,34 @@ function copy_contents(src, dest) | |||
291 | end | 305 | end |
292 | 306 | ||
293 | --- Implementation function for recursive removal of directories. | 307 | --- Implementation function for recursive removal of directories. |
294 | -- @param src string: Pathname of source | 308 | -- Assumes paths are normalized. |
295 | -- @param dest string: Pathname of destination | 309 | -- @param name string: Pathname of file |
296 | -- @return boolean or (boolean, string): true on success, | 310 | -- @return boolean or (boolean, string): true on success, |
297 | -- or nil and an error message on failure. | 311 | -- or nil and an error message on failure. |
298 | local function recursive_delete(src) | 312 | local function recursive_delete(name) |
299 | local srcmode = lfs.attributes(src, "mode") | 313 | local mode = lfs.attributes(name, "mode") |
300 | 314 | ||
301 | if srcmode == "file" then | 315 | if mode == "file" then |
302 | return os.remove(src) | 316 | return os.remove(name) |
303 | elseif srcmode == "directory" then | 317 | elseif mode == "directory" then |
304 | for file in lfs.dir(src) do | 318 | for file in lfs.dir(name) do |
305 | if file ~= "." and file ~= ".." then | 319 | if file ~= "." and file ~= ".." then |
306 | local ok, err = recursive_delete(dir.path(src, file)) | 320 | local ok, err = recursive_delete(dir.path(name, file)) |
307 | if not ok then return nil, err end | 321 | if not ok then return nil, err end |
308 | end | 322 | end |
309 | end | 323 | end |
310 | local ok, err = lfs.rmdir(src) | 324 | local ok, err = lfs.rmdir(name) |
311 | if not ok then return nil, err end | 325 | if not ok then return nil, err end |
312 | end | 326 | end |
313 | return true | 327 | return true |
314 | end | 328 | end |
315 | 329 | ||
316 | --- Delete a file or a directory and all its contents. | 330 | --- Delete a file or a directory and all its contents. |
317 | -- For safety, this only accepts absolute paths. | 331 | -- @param name string: Pathname of source |
318 | -- @param arg string: Pathname of source | ||
319 | -- @return boolean: true on success, false on failure. | 332 | -- @return boolean: true on success, false on failure. |
320 | function delete(arg) | 333 | function delete(name) |
321 | assert(arg) | 334 | name = normalize(name) |
322 | return recursive_delete(arg) or false | 335 | return recursive_delete(name) or false |
323 | end | 336 | end |
324 | 337 | ||
325 | --- List the contents of a directory. | 338 | --- List the contents of a directory. |
@@ -332,6 +345,7 @@ function list_dir(at) | |||
332 | if not at then | 345 | if not at then |
333 | at = fs.current_dir() | 346 | at = fs.current_dir() |
334 | end | 347 | end |
348 | at = normalize(at) | ||
335 | if not fs.is_dir(at) then | 349 | if not fs.is_dir(at) then |
336 | return {} | 350 | return {} |
337 | end | 351 | end |
@@ -345,6 +359,7 @@ function list_dir(at) | |||
345 | end | 359 | end |
346 | 360 | ||
347 | --- Implementation function for recursive find. | 361 | --- Implementation function for recursive find. |
362 | -- Assumes paths are normalized. | ||
348 | -- @param cwd string: Current working directory in recursion. | 363 | -- @param cwd string: Current working directory in recursion. |
349 | -- @param prefix string: Auxiliary prefix string to form pathname. | 364 | -- @param prefix string: Auxiliary prefix string to form pathname. |
350 | -- @param result table: Array of strings where results are collected. | 365 | -- @param result table: Array of strings where results are collected. |
@@ -371,6 +386,7 @@ function find(at) | |||
371 | if not at then | 386 | if not at then |
372 | at = fs.current_dir() | 387 | at = fs.current_dir() |
373 | end | 388 | end |
389 | at = normalize(at) | ||
374 | if not fs.is_dir(at) then | 390 | if not fs.is_dir(at) then |
375 | return {} | 391 | return {} |
376 | end | 392 | end |
@@ -384,7 +400,8 @@ end | |||
384 | -- @return boolean: true if file exists, false otherwise. | 400 | -- @return boolean: true if file exists, false otherwise. |
385 | function exists(file) | 401 | function exists(file) |
386 | assert(file) | 402 | assert(file) |
387 | return type(lfs.attributes(file)) == "table" | 403 | file = normalize(file) |
404 | return type(file) == "table" | ||
388 | end | 405 | end |
389 | 406 | ||
390 | --- Test is pathname is a directory. | 407 | --- Test is pathname is a directory. |
@@ -392,6 +409,7 @@ end | |||
392 | -- @return boolean: true if it is a directory, false otherwise. | 409 | -- @return boolean: true if it is a directory, false otherwise. |
393 | function is_dir(file) | 410 | function is_dir(file) |
394 | assert(file) | 411 | assert(file) |
412 | file = normalize(file) | ||
395 | return lfs.attributes(file, "mode") == "directory" | 413 | return lfs.attributes(file, "mode") == "directory" |
396 | end | 414 | end |
397 | 415 | ||
@@ -400,10 +418,12 @@ end | |||
400 | -- @return boolean: true if it is a file, false otherwise. | 418 | -- @return boolean: true if it is a file, false otherwise. |
401 | function is_file(file) | 419 | function is_file(file) |
402 | assert(file) | 420 | assert(file) |
421 | file = normalize(file) | ||
403 | return lfs.attributes(file, "mode") == "file" | 422 | return lfs.attributes(file, "mode") == "file" |
404 | end | 423 | end |
405 | 424 | ||
406 | function set_time(file, time) | 425 | function set_time(file, time) |
426 | file = normalize(file) | ||
407 | return lfs.touch(file, time) | 427 | return lfs.touch(file, time) |
408 | end | 428 | end |
409 | 429 | ||
@@ -426,27 +446,27 @@ if unzip_ok then | |||
426 | -- @param zipfile string: pathname of .zip archive to be extracted. | 446 | -- @param zipfile string: pathname of .zip archive to be extracted. |
427 | -- @return boolean: true on success, false on failure. | 447 | -- @return boolean: true on success, false on failure. |
428 | function unzip(zipfile) | 448 | function unzip(zipfile) |
429 | local zipfile, err = luazip.open(zipfile) | 449 | local zipfile, err = luazip.open(zipfile) |
430 | if not zipfile then return nil, err end | 450 | if not zipfile then return nil, err end |
431 | local files = zipfile:files() | 451 | local files = zipfile:files() |
432 | local file = files() | 452 | local file = files() |
433 | repeat | 453 | repeat |
434 | if file.filename:sub(#file.filename) == "/" then | 454 | if file.filename:sub(#file.filename) == "/" then |
435 | fs.make_dir(dir.path(fs.current_dir(), file.filename)) | 455 | fs.make_dir(dir.path(fs.current_dir(), file.filename)) |
436 | else | 456 | else |
437 | local rf, err = zipfile:open(file.filename) | 457 | local rf, err = zipfile:open(file.filename) |
438 | if not rf then zipfile:close(); return nil, err end | 458 | if not rf then zipfile:close(); return nil, err end |
439 | local contents = rf:read("*a") | 459 | local contents = rf:read("*a") |
440 | rf:close() | 460 | rf:close() |
441 | local wf, err = io.open(dir.path(fs.current_dir(), file.filename), "wb") | 461 | local wf, err = io.open(dir.path(fs.current_dir(), file.filename), "wb") |
442 | if not wf then zipfile:close(); return nil, err end | 462 | if not wf then zipfile:close(); return nil, err end |
443 | wf:write(contents) | 463 | wf:write(contents) |
444 | wf:close() | 464 | wf:close() |
445 | end | 465 | end |
446 | file = files() | 466 | file = files() |
447 | until not file | 467 | until not file |
448 | zipfile:close() | 468 | zipfile:close() |
449 | return true | 469 | return true |
450 | end | 470 | end |
451 | 471 | ||
452 | end | 472 | end |
@@ -457,7 +477,6 @@ end | |||
457 | 477 | ||
458 | if socket_ok then | 478 | if socket_ok then |
459 | 479 | ||
460 | |||
461 | local ltn12 = require("ltn12") | 480 | local ltn12 = require("ltn12") |
462 | 481 | ||
463 | --- Download a remote file. | 482 | --- Download a remote file. |