aboutsummaryrefslogtreecommitdiffhomepage
path: root/core/lfs_ext.lua
diff options
context:
space:
mode:
authorGravatar mitchell <70453897+orbitalquark@users.noreply.github.com>2020-10-25 00:43:25 -0400
committerGravatar mitchell <70453897+orbitalquark@users.noreply.github.com>2020-10-25 00:43:25 -0400
commite82eddd9e007597e8283922653de0e5abb94c0dc (patch)
treea96d8d761ad9a28aeaf3bbc5e5718b4aa269cb41 /core/lfs_ext.lua
parent677b204c8fa3541b7ddfc176be69a68451436fde (diff)
Handle recursive symlinks in `lfs.walk()`.
Diffstat (limited to 'core/lfs_ext.lua')
-rw-r--r--core/lfs_ext.lua17
1 files changed, 11 insertions, 6 deletions
diff --git a/core/lfs_ext.lua b/core/lfs_ext.lua
index c24ee2e9..5bbe609a 100644
--- a/core/lfs_ext.lua
+++ b/core/lfs_ext.lua
@@ -19,9 +19,14 @@ module('lfs')]]
lfs.default_filter = {--[[Extensions]]'!.a','!.bmp','!.bz2','!.class','!.dll','!.exe','!.gif','!.gz','!.jar','!.jpeg','!.jpg','!.o','!.pdf','!.png','!.so','!.tar','!.tgz','!.tif','!.tiff','!.xz','!.zip',--[[Directories]]'!/%.bzr$','!/%.git$','!/%.hg$','!/%.svn$','!/_FOSSIL_$','!/node_modules$'}
-- Documentation is in `lfs.walk()`.
+-- @param seen Utility table that holds directories seen. If there is a
+-- duplicate, stop walking down that path (it's probably a recursive symlink).
-- @param level Utility value indicating the directory level this function is
-- at.
-local function walk(dir, filter, n, include_dirs, level)
+local function walk(dir, filter, n, include_dirs, seen, level)
+ local sep = not WIN32 and '/' or '\\'
+ local os_dir = not WIN32 and dir or dir:gsub('/', sep)
+ seen[os_dir], seen[os_dir .. sep] = true, true
for basename in lfs.dir(dir) do
if basename:find('^%.%.?$') then goto continue end -- ignore . and ..
local filename = dir .. (dir ~= '/' and '/' or '') .. basename
@@ -42,14 +47,14 @@ local function walk(dir, filter, n, include_dirs, level)
include = include or (not patt:find('^!') and filename:find(patt))
end
if not include then goto continue end
- local sep = not WIN32 and '/' or '\\'
local os_filename = not WIN32 and filename or filename:gsub('/', sep)
if mode == 'file' then
coroutine.yield(os_filename)
- elseif mode == 'directory' then
+ elseif mode == 'directory' and
+ not seen[lfs.symlinkattributes(filename, 'target')] then
if include_dirs then coroutine.yield(os_filename .. sep) end
if n and (level or 0) >= n then goto continue end
- walk(filename, filter, n, include_dirs, (level or 0) + 1)
+ walk(filename, filter, n, include_dirs, seen, (level or 0) + 1)
end
::continue::
end
@@ -77,7 +82,7 @@ end
-- @see filter
-- @name walk
function lfs.walk(dir, filter, n, include_dirs)
- assert_type(dir, 'string', 1)
+ dir = assert_type(dir, 'string', 1):match('^(.-)[/\\]?$')
if not assert_type(filter, 'string/table/nil', 2) then
filter = lfs.default_filter
end
@@ -104,7 +109,7 @@ function lfs.walk(dir, filter, n, include_dirs)
end
end
local co = coroutine.create(
- function() walk(dir, processed_filter, n, include_dirs) end)
+ function() walk(dir, processed_filter, n, include_dirs, {}) end)
return function() return select(2, coroutine.resume(co)) end
end