diff options
author | Philipp Gesang <phg@phi-gamma.net> | 2016-06-08 08:23:38 +0200 |
---|---|---|
committer | Philipp Gesang <phg@phi-gamma.net> | 2016-06-08 08:23:43 +0200 |
commit | 37f8c42a1b560df3f1bc1444405c772f00340f88 (patch) | |
tree | b04a709daa2929a82eb9497149610321f14dba43 /src | |
parent | 68f523b6660baaabd4fee994d5be79a3a9afda37 (diff) | |
download | luaotfload-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.lua | 72 |
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 |