From 37f8c42a1b560df3f1bc1444405c772f00340f88 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 8 Jun 2016 08:23:38 +0200 Subject: [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. --- src/luaotfload-database.lua | 72 ++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 31 deletions(-) (limited to 'src') 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 -- cgit v1.2.3