summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilipp Gesang <phg@phi-gamma.net>2016-06-08 08:23:38 +0200
committerPhilipp Gesang <phg@phi-gamma.net>2016-06-08 08:23:43 +0200
commit37f8c42a1b560df3f1bc1444405c772f00340f88 (patch)
treeb04a709daa2929a82eb9497149610321f14dba43 /src
parent68f523b6660baaabd4fee994d5be79a3a9afda37 (diff)
downloadluaotfload-37f8c42a1b560df3f1bc1444405c772f00340f88.tar.gz
[db] resolve symlinks when traversing the file system
Addresses #359 and #325 To avoid duplicate entries, paths have to be resolved before collecting them. This necessitates loop detection of some sort, currently implemented naively as a flat table containing the directories already traversed.
Diffstat (limited to 'src')
-rw-r--r--src/luaotfload-database.lua72
1 files changed, 41 insertions, 31 deletions
diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua
index da2d5d0..5645b63 100644
--- a/src/luaotfload-database.lua
+++ b/src/luaotfload-database.lua
@@ -2033,7 +2033,7 @@ local locate_matching_pfb = function (afmfile, dir)
end
local process_dir_tree
-process_dir_tree = function (acc, dirs)
+process_dir_tree = function (acc, dirs, done)
if not next (dirs) then --- done
return acc
end
@@ -2042,46 +2042,56 @@ process_dir_tree = function (acc, dirs)
local dir = dirs[#dirs]
dirs[#dirs] = nil
- if lfschdir (dir) then
- lfschdir (pwd)
-
- local newfiles = { }
- local blacklist = names.blacklist
- for ent in lfsdir (dir) do
- --- filter right away
- if ent ~= "." and ent ~= ".." and not blacklist[ent] then
- local fullpath = dir .. "/" .. ent
- if lfsisdir (fullpath)
- and not lpegmatch (p_blacklist, fullpath)
- then
- dirs[#dirs+1] = fullpath
- elseif lfsisfile (fullpath) then
- ent = stringlower (ent)
-
- if lpegmatch (p_font_filter, ent) then
- newfiles[#newfiles+1] = fullpath
- if filesuffix (ent) == "afm" then
- local pfbpath = locate_matching_pfb (ent, dir)
- if pfbpath then
- newfiles[#newfiles+1] = pfbpath
- end
- else
- newfiles[#newfiles+1] = fullpath
+ if not lfschdir (dir) then
+ --- Cannot cd; skip.
+ return process_dir_tree (acc, dirs, done)
+ end
+
+ dir = lfscurrentdir () --- resolve symlinks
+ lfschdir (pwd)
+ if tablecontains (done, dir) then
+ --- Already traversed. Note that it’d be unsafe to rely on the
+ --- hash part above due to Lua only processing up to 32 bytes
+ --- of string data. The lookup shouldn’t impact performance too
+ --- much but we could check the performance of alternative data
+ --- structures at some point.
+ return process_dir_tree (acc, dirs, done)
+ end
+
+ local newfiles = { }
+ local blacklist = names.blacklist
+ for ent in lfsdir (dir) do
+ --- filter right away
+ if ent ~= "." and ent ~= ".." and not blacklist[ent] then
+ local fullpath = dir .. "/" .. ent
+ if lfsisdir (fullpath)
+ and not lpegmatch (p_blacklist, fullpath)
+ then
+ dirs[#dirs+1] = fullpath
+ elseif lfsisfile (fullpath) then
+ ent = stringlower (ent)
+ if lpegmatch (p_font_filter, ent) then
+ newfiles[#newfiles+1] = fullpath
+ if filesuffix (ent) == "afm" then
+ local pfbpath = locate_matching_pfb (ent, dir)
+ if pfbpath then
+ newfiles[#newfiles+1] = pfbpath
end
+ else
+ newfiles[#newfiles+1] = fullpath
end
-
end
end
end
- return process_dir_tree (tableappend (acc, newfiles), dirs)
end
- --- cannot cd; skip
- return process_dir_tree (acc, dirs)
+ done [#done + 1] = dir
+ return process_dir_tree (tableappend (acc, newfiles), dirs, done)
end
local process_dir = function (dir)
local pwd = lfscurrentdir ()
if lfschdir (dir) then
+ dir = lfscurrentdir () --- resolve symlinks
lfschdir (pwd)
local files = { }
@@ -2114,7 +2124,7 @@ end
local find_font_files = function (root, recurse)
if lfsisdir (root) then
if recurse == true then
- return process_dir_tree ({}, { root })
+ return process_dir_tree ({}, { root }, {})
else --- kpathsea already delivered the necessary subdirs
return process_dir (root)
end