From ae1890d29a6aeb28be698fcafd3180e63a085de5 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Mon, 10 Jan 2022 16:26:39 +0100 Subject: [PATCH] Fix project files reading with symlink --- data/core/init.lua | 64 +++++++++++++++++++++++++++++++--------------- src/api/system.c | 8 ++++++ 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/data/core/init.lua b/data/core/init.lua index 7a44f0ae..315f8c95 100644 --- a/data/core/init.lua +++ b/data/core/init.lua @@ -278,20 +278,6 @@ local function file_search(files, info) end -local function project_scan_add_entry(dir, fileinfo) - assert(not dir.force_rescan, "should be used on when force_rescan is unset") - local index, match = file_search(dir.files, fileinfo) - if not match then - table.insert(dir.files, index, fileinfo) - if fileinfo.type == "dir" and not dir.files_limit then - -- ASSUMPTION: dir.force_rescan is FALSE - system.watch_dir_add(dir.watch_id, dir.name .. PATHSEP .. fileinfo.filename) - end - dir.is_dirty = true - end -end - - local function files_info_equal(a, b) return a.filename == b.filename and a.type == b.type end @@ -308,7 +294,7 @@ local function files_list_match(a, i1, n, b) end -- arguments like for files_list_match -local function files_list_replace(as, i1, n, bs, insert_hook) +local function files_list_replace(as, i1, n, bs, hook) local m = #bs local i, j = 1, 1 while i <= m or i <= n do @@ -318,8 +304,9 @@ local function files_list_replace(as, i1, n, bs, insert_hook) then table.insert(as, i1 + i, b) i, j, n = i + 1, j + 1, n + 1 - if insert_hook then insert_hook(b) end + if hook and hook.insert then hook.insert(b) end elseif j > m or system.path_compare(a.filename, a.type, b.filename, b.type) then + if hook and hook.remove then hook.remove(as[i1 + i]) end table.remove(as, i1 + i) n = n - 1 else @@ -328,6 +315,29 @@ local function files_list_replace(as, i1, n, bs, insert_hook) end end + +local function project_scan_add_entry(dir, fileinfo) + assert(not dir.force_rescan, "should be used only when force_rescan is false") + local index, match = file_search(dir.files, fileinfo) + if not match then + table.insert(dir.files, index, fileinfo) + if fileinfo.type == "dir" and not dir.files_limit then + -- ASSUMPTION: dir.force_rescan is FALSE + system.watch_dir_add(dir.watch_id, dir.name .. PATHSEP .. fileinfo.filename) + if fileinfo.symlink then + local new_files = get_directory_files(dir, dir.name, PATHSEP .. fileinfo.filename, {}, nil, 0, core.project_subdir_is_shown) + files_list_replace(dir.files, index, 0, new_files, {insert = function(info) + if info.type == "dir" then + system.watch_dir_add(dir.watch_id, dir.name .. PATHSEP .. info.filename) + end + end}) + end + end + dir.is_dirty = true + end +end + + local function project_subdir_bounds(dir, filename) local index, n = 0, #dir.files for i, file in ipairs(dir.files) do @@ -362,11 +372,11 @@ local function rescan_project_subdir(dir, filename_rooted) -- we missed some directory creation event from the directory monitoring which -- almost never happens. With inotify is at least theoretically possible. local need_subdir_watches = not dir.files_limit and not dir.force_rescan - files_list_replace(dir.files, index, n, new_files, need_subdir_watches and function(fileinfo) + files_list_replace(dir.files, index, n, new_files, need_subdir_watches and {insert = function(fileinfo) if fileinfo.type == "dir" then system.watch_dir_add(dir.watch_id, dir.name .. PATHSEP .. fileinfo.filename) end - end) + end}) dir.is_dirty = true return true end @@ -624,10 +634,22 @@ local function project_scan_remove_file(dir, filepath) fileinfo.type = filetype local index, match = file_search(dir.files, fileinfo) if match then - table.remove(dir.files, index) - if dir.files_limit and filetype == "dir" then - dir.shown_subdir[filepath] = nil + if filetype == "dir" then + -- If the directory is a symlink it may get deleted and we will + -- never get dirmonitor events for the removal the files it contains. + -- We proceed to remove all the files that belong to the directory. + local _, n_subdir = project_subdir_bounds(dir, filepath) + files_list_replace(dir.files, index, n_subdir, {}, { + remove= function(fileinfo) + if fileinfo.type == "dir" then + system.watch_dir_rm(dir.watch_id, dir.name .. PATHSEP .. filepath) + end + end}) + if dir.files_limit then + dir.shown_subdir[filepath] = nil + end end + table.remove(dir.files, index) dir.is_dirty = true return end diff --git a/src/api/system.c b/src/api/system.c index 4e134e91..10288eba 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -544,6 +544,14 @@ static int f_get_file_info(lua_State *L) { } lua_setfield(L, -2, "type"); +#if __linux__ + if (S_ISDIR(s.st_mode)) { + if (lstat(path, &s) == 0) { + lua_pushboolean(L, S_ISLNK(s.st_mode)); + lua_setfield(L, -2, "symlink"); + } + } +#endif return 1; }