Skip to content

Commit

Permalink
Fix quoting in luacheck.lua_fs.get_mode, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mpeterv committed Apr 26, 2017
1 parent 773e299 commit 946742a
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 4 deletions.
49 changes: 48 additions & 1 deletion spec/fs_spec.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
local lfs = require "lfs"

local fs = require "luacheck.fs"
local utils = require "luacheck.utils"
local P = fs.normalize

describe("fs", function()
Expand Down Expand Up @@ -51,9 +54,10 @@ describe("fs", function()
end)

describe("get_current_dir", function()
it("returns absolute path to current directory", function()
it("returns absolute path to current directory with trailing directory separator", function()
local current_dir = fs.get_current_dir()
assert.string(current_dir)
assert.matches(utils.dir_sep .. "$", current_dir)
assert.not_equal("", (fs.split_base(current_dir)))
assert.is_true(fs.is_file(current_dir .. "spec/folder/foo"))
end)
Expand All @@ -76,3 +80,46 @@ describe("fs", function()
end)
end)
end)

for _, fs_name in ipairs({"lua_fs", "lfs_fs"}) do
local base_fs = require("luacheck." .. fs_name)

describe(fs_name, function()
describe("get_current_dir", function()
it("returns absolute path to current directory", function()
local current_dir = base_fs.get_current_dir()
assert.string(current_dir)
assert.not_equal("", (fs.split_base(current_dir)))
assert.is_true(fs.is_file(fs.join(current_dir, "spec/folder/foo")))
end)
end)

describe("get_mode", function()
local tricky_path = "spec/'"

it("returns 'file' for a file", function()
assert(io.open(tricky_path, "w"))
finally(function() assert(os.remove(tricky_path)) end)
assert.equal("file", base_fs.get_mode(tricky_path))
end)

it("returns 'directory' for a directory", function()
assert(lfs.mkdir(tricky_path))
finally(function() assert(lfs.rmdir(tricky_path)) end)
assert.equal("directory", base_fs.get_mode(tricky_path))
end)

it("returns not 'file' or 'directory' if path doesn't point to a file or a directory", function()
local mode = base_fs.get_mode(tricky_path)
assert.not_equal("file", mode)
assert.not_equal("directory", mode)
end)

it("returns not 'file' or 'directory' if path is bad", function()
local mode = base_fs.get_mode('"^<>!|&%')
assert.not_equal("file", mode)
assert.not_equal("directory", mode)
end)
end)
end)
end
35 changes: 32 additions & 3 deletions src/luacheck/lua_fs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,45 @@ local utils = require "luacheck.utils"

local lua_fs = {}

-- Quotes an argument for a command for os.execute or io.popen.
-- Same code has been contributed to pl.
local function quote_arg(argument)
if utils.is_windows then
if argument == "" or argument:find('[ \f\t\v]') then
-- Need to quote the argument.
-- Quotes need to be escaped with backslashes;
-- additionally, backslashes before a quote, escaped or not,
-- need to be doubled.
-- See documentation for CommandLineToArgvW Windows function.
argument = '"' .. argument:gsub([[(\*)"]], [[%1%1\"]]):gsub([[\+$]], "%0%0") .. '"'
end

-- os.execute() uses system() C function, which on Windows passes command
-- to cmd.exe. Escape its special characters.
return (argument:gsub('["^<>!|&%%]', "^%0"))
else
if argument == "" or argument:find('[^a-zA-Z0-9_@%+=:,./-]') then
-- To quote arguments on posix-like systems use single quotes.
-- To represent an embedded single quote close quoted string ('),
-- add escaped quote (\'), open quoted string again (').
argument = "'" .. argument:gsub("'", [['\'']]) .. "'"
end

return argument
end
end

local mode_cmd_template

if utils.is_windows then
mode_cmd_template = [[if exist "%s\*" (echo directory) else (if exist "%s" echo "file")]]
mode_cmd_template = [[if exist %s\* (echo directory) else (if exist %s echo file)]]
else
mode_cmd_template = [[if [ -d '%s' ]; then echo directory; elif [ -f '%s' ]; then echo file; fi]]
mode_cmd_template = [[if [ -d %s ]; then echo directory; elif [ -f %s ]; then echo file; fi]]
end

function lua_fs.get_mode(path)
local fh = assert(io.popen(mode_cmd_template:format(path, path)))
local quoted_path = quote_arg(path)
local fh = assert(io.popen(mode_cmd_template:format(quoted_path, quoted_path)))
local mode = fh:read("*a"):match("^(%S*)")
fh:close()
return mode
Expand Down

0 comments on commit 946742a

Please sign in to comment.