From b8a2710a2cefbddc5e6b494db186014b341412e4 Mon Sep 17 00:00:00 2001 From: Aleksei Volkov Date: Tue, 31 Oct 2023 01:39:43 +0300 Subject: Fix problems in path normalisation algorithm (#1541) Current implementation of path normalisation contains various flaws: - Trailing `.` and `..` at the end of path don't get normalised, - Path `/` turns into an empty string after normalisation. This patch changes implementation of normalisation to fix these. --- spec/dir_spec.lua | 8 ++++++++ src/luarocks/core/dir.lua | 11 +++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/spec/dir_spec.lua b/spec/dir_spec.lua index 9f05c664..f6ef172e 100644 --- a/spec/dir_spec.lua +++ b/spec/dir_spec.lua @@ -52,12 +52,20 @@ describe("luarocks.dir #unit", function() it("strips unneeded /../ and /./", function() assert.are.same("/some/dir/file.txt", dir.normalize("/../../../some/./foo/bar/.././../dir/bla/../file.txt")) assert.are.same("/some/dir/file.txt", dir.normalize("/../../../some/./foo/bar/.././../dir/bla/../file.txt")) + assert.are.same("/some/dir", dir.normalize("/../../../some/./foo/bar/.././../dir/./some/subdir/../..")) + assert.are.same("/some/dir", dir.normalize("/../../../some/./foo/bar/.././../dir/./.")) end) it("respects relative paths", function() + assert.are.same(".", dir.normalize(".")) assert.are.same("boo", dir.normalize("./boo")) assert.are.same("/boo", dir.normalize("/./boo")) assert.are.same("../../../../boo", dir.normalize("../../../hello/world/../../../boo")) end) + it("respects root directory", function() + assert.are.same("/", dir.normalize("/")) + assert.are.same("/", dir.normalize("/////")) + assert.are.same("/", dir.normalize("/a/b/.././../c/./../../")) + end) end) end) diff --git a/src/luarocks/core/dir.lua b/src/luarocks/core/dir.lua index 0da88997..46dbeafd 100644 --- a/src/luarocks/core/dir.lua +++ b/src/luarocks/core/dir.lua @@ -63,6 +63,7 @@ function dir.normalize(name) if pathname:match("^.:") then drive, pathname = pathname:match("^(.:)(.*)$") end + pathname = pathname .. "/" for piece in pathname:gmatch("(.-)/") do if piece == ".." then local prev = pieces[#pieces] @@ -75,11 +76,13 @@ function dir.normalize(name) table.insert(pieces, piece) end end - local basename = pathname:match("[^/]+$") - if basename then - table.insert(pieces, basename) + if #pieces == 0 then + pathname = drive .. "." + elseif #pieces == 1 and pieces[1] == "" then + pathname = drive .. "/" + else + pathname = drive .. table.concat(pieces, "/") end - pathname = drive .. table.concat(pieces, "/") if protocol ~= "file" then pathname = protocol .."://"..pathname end return pathname end -- cgit v1.2.3-55-g6feb