From 869a628bec218b94b4b312fadcedf13262fa5b03 Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Thu, 25 Jul 2019 14:56:28 -0300 Subject: fs: use Unix fork-free versions of is_file/is_dir in Linux and macOS only The Unix fork-free version relies on non-standard behaviors. It works on Linux, but it took a while for it to work properly in macOS, and it turns out that you can't really properly detect a directory in FreeBSD using io.open() because it can actually open a directory. To avoid filling in platform-specific tricks in luarocks/fs/unix.lua, which was never the goal, it's better to move the fork-free operations to Linux and macOS specific backends, and keep other Unices using the 'test' command. --- src/luarocks/core/cfg.lua | 1 + src/luarocks/fs/linux.lua | 50 ++++++++++++++++++++++++++++++++++++++++++ src/luarocks/fs/macosx.lua | 50 ++++++++++++++++++++++++++++++++++++++++++ src/luarocks/fs/unix.lua | 43 ------------------------------------ src/luarocks/fs/unix/tools.lua | 24 ++++++++++++++++++++ 5 files changed, 125 insertions(+), 43 deletions(-) create mode 100644 src/luarocks/fs/linux.lua create mode 100644 src/luarocks/fs/macosx.lua (limited to 'src') diff --git a/src/luarocks/core/cfg.lua b/src/luarocks/core/cfg.lua index 8c11d408..0505b11d 100644 --- a/src/luarocks/core/cfg.lua +++ b/src/luarocks/core/cfg.lua @@ -370,6 +370,7 @@ local function make_defaults(lua_version, target_cpu, platforms, home) defaults.variables.LD = "gcc" defaults.gcc_rpath = true defaults.variables.LIBFLAG = "-shared" + defaults.variables.TEST = "test" defaults.external_deps_patterns = { bin = { "?" }, diff --git a/src/luarocks/fs/linux.lua b/src/luarocks/fs/linux.lua new file mode 100644 index 00000000..c1b057c2 --- /dev/null +++ b/src/luarocks/fs/linux.lua @@ -0,0 +1,50 @@ +--- Linux-specific implementation of filesystem and platform abstractions. +local linux = {} + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +function linux.is_dir(file) + file = fs.absolute_name(file) + file = dir.normalize(file) .. "/." + local fd, _, code = io.open(file, "r") + if code == 2 then -- "No such file or directory" + return false + end + if code == 20 then -- "Not a directory", regardless of permissions + return false + end + if code == 13 then -- "Permission denied", but is a directory + return true + end + if fd then + local _, _, ecode = fd:read(1) + fd:close() + if ecode == 21 then -- "Is a directory" + return true + end + end + return false +end + +function linux.is_file(file) + file = fs.absolute_name(file) + if fs.is_dir(file) then + return false + end + file = dir.normalize(file) + local fd, _, code = io.open(file, "r") + if code == 2 then -- "No such file or directory" + return false + end + if code == 13 then -- "Permission denied", but it exists + return true + end + if fd then + fd:close() + return true + end + return false +end + +return linux diff --git a/src/luarocks/fs/macosx.lua b/src/luarocks/fs/macosx.lua new file mode 100644 index 00000000..b71e7f12 --- /dev/null +++ b/src/luarocks/fs/macosx.lua @@ -0,0 +1,50 @@ +--- macOS-specific implementation of filesystem and platform abstractions. +local macosx = {} + +local fs = require("luarocks.fs") +local dir = require("luarocks.dir") + +function macosx.is_dir(file) + file = fs.absolute_name(file) + file = dir.normalize(file) .. "/." + local fd, _, code = io.open(file, "r") + if code == 2 then -- "No such file or directory" + return false + end + if code == 20 then -- "Not a directory", regardless of permissions + return false + end + if code == 13 then -- "Permission denied", but is a directory + return true + end + if fd then + local _, _, ecode = fd:read(1) + fd:close() + if ecode == 21 then -- "Is a directory" + return true + end + end + return false +end + +function macosx.is_file(file) + file = fs.absolute_name(file) + if fs.is_dir(file) then + return false + end + file = dir.normalize(file) + local fd, _, code = io.open(file, "r") + if code == 2 then -- "No such file or directory" + return false + end + if code == 13 then -- "Permission denied", but it exists + return true + end + if fd then + fd:close() + return true + end + return false +end + +return macosx diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua index 3e05fbf3..92a2dd91 100644 --- a/src/luarocks/fs/unix.lua +++ b/src/luarocks/fs/unix.lua @@ -206,49 +206,6 @@ function unix._unix_moderate_permissions(perms) return moderated_perms end -function unix.is_dir(file) - file = fs.absolute_name(file) - file = dir.normalize(file) .. "/." - local fd, _, code = io.open(file, "r") - if code == 2 then -- "No such file or directory" - return false - end - if code == 20 then -- "Not a directory", regardless of permissions - return false - end - if code == 13 then -- "Permission denied", but is a directory - return true - end - if fd then - local _, _, ecode = fd:read(1) - fd:close() - if ecode == 21 then -- "Is a directory" - return true - end - end - return false -end - -function unix.is_file(file) - file = fs.absolute_name(file) - if fs.is_dir(file) then - return false - end - file = dir.normalize(file) - local fd, _, code = io.open(file, "r") - if code == 2 then -- "No such file or directory" - return false - end - if code == 13 then -- "Permission denied", but it exists - return true - end - if fd then - fd:close() - return true - end - return false -end - function unix.system_cache_dir() if fs.is_dir("/var/cache") then return "/var/cache" diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua index 65b5681c..2e46c19b 100644 --- a/src/luarocks/fs/unix/tools.lua +++ b/src/luarocks/fs/unix/tools.lua @@ -273,4 +273,28 @@ function tools.make_temp_dir(name_pattern) return nil, "Failed to create temporary directory "..tostring(dirname) end +--- Test is file/directory exists +-- @param file string: filename to test +-- @return boolean: true if file exists, false otherwise. +function tools.exists(file) + assert(file) + return fs.execute(vars.TEST, "-e", file) +end + +--- Test is pathname is a directory. +-- @param file string: pathname to test +-- @return boolean: true if it is a directory, false otherwise. +function tools.is_dir(file) + assert(file) + return fs.execute(vars.TEST, "-d", file) +end + +--- Test is pathname is a regular file. +-- @param file string: pathname to test +-- @return boolean: true if it is a regular file, false otherwise. +function tools.is_file(file) + assert(file) + return fs.execute(vars.TEST, "-f", file) +end + return tools -- cgit v1.2.3-55-g6feb