Fixed some issues with inotify and multiple events at the same time. (#872)
* Fixed some issues with inotify and multiple events at the same time. Seems to be working now. * Cleaned up and simplified function, and commented, and fixed a number of bugs. * Simplifying and fixing further. * Improved performance for skipping large amounts of files. * Added in extra checks, and changed paths. We should probably unify these path styles. * Fixed stutter. * Removed extraneous functions. * Cleaned up more, added more testing; dealt with multiple sequential events correctly.
This commit is contained in:
parent
52a47e0d73
commit
960b482061
|
@ -30,7 +30,7 @@ end
|
||||||
-- Should be called on every directory in a subdirectory.
|
-- Should be called on every directory in a subdirectory.
|
||||||
-- In windows, this is a no-op for anything underneath a top-level directory,
|
-- In windows, this is a no-op for anything underneath a top-level directory,
|
||||||
-- but code should be called anyway, so we can ensure that we have a proper
|
-- but code should be called anyway, so we can ensure that we have a proper
|
||||||
-- experience across all platforms.
|
-- experience across all platforms. Should be an absolute path.
|
||||||
function dirwatch:watch(directory, bool)
|
function dirwatch:watch(directory, bool)
|
||||||
if bool == false then return self:unwatch(directory) end
|
if bool == false then return self:unwatch(directory) end
|
||||||
if not self.watched[directory] and not self.scanned[directory] then
|
if not self.watched[directory] and not self.scanned[directory] then
|
||||||
|
@ -64,16 +64,17 @@ function dirwatch:watch(directory, bool)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- this should be an absolute path
|
||||||
function dirwatch:unwatch(directory)
|
function dirwatch:unwatch(directory)
|
||||||
if self.watched[directory] then
|
if self.watched[directory] then
|
||||||
if PLATFORM ~= "Windows" then
|
if PLATFORM ~= "Windows" then
|
||||||
self.monitor.unwatch(directory)
|
self.monitor:unwatch(self.watched[directory])
|
||||||
self.reverse_watched[self.watched[directory]] = nil
|
self.reverse_watched[directory] = nil
|
||||||
else
|
else
|
||||||
self.windows_watch_count = self.windows_watch_count - 1
|
self.windows_watch_count = self.windows_watch_count - 1
|
||||||
if self.windows_watch_count == 0 then
|
if self.windows_watch_count == 0 then
|
||||||
self.windows_watch_top = nil
|
self.windows_watch_top = nil
|
||||||
self.monitor.unwatch(directory)
|
self.monitor:unwatch(directory)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.watched[directory] = nil
|
self.watched[directory] = nil
|
||||||
|
@ -108,10 +109,6 @@ function dirwatch:check(change_callback, scan_time, wait_time)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function strip_leading_path(filename)
|
|
||||||
return filename:sub(2)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- inspect config.ignore_files patterns and prepare ready to use entries.
|
-- inspect config.ignore_files patterns and prepare ready to use entries.
|
||||||
local function compile_ignore_files()
|
local function compile_ignore_files()
|
||||||
local ipatterns = config.ignore_files
|
local ipatterns = config.ignore_files
|
||||||
|
@ -162,33 +159,36 @@ end
|
||||||
-- compute a file's info entry completed with "filename" to be used
|
-- compute a file's info entry completed with "filename" to be used
|
||||||
-- in project scan or falsy if it shouldn't appear in the list.
|
-- in project scan or falsy if it shouldn't appear in the list.
|
||||||
local function get_project_file_info(root, file, ignore_compiled)
|
local function get_project_file_info(root, file, ignore_compiled)
|
||||||
local info = system.get_file_info(root .. file)
|
local info = system.get_file_info(root .. PATHSEP .. file)
|
||||||
-- info can be not nil but info.type may be nil if is neither a file neither
|
-- info can be not nil but info.type may be nil if is neither a file neither
|
||||||
-- a directory, for example for /dev/* entries on linux.
|
-- a directory, for example for /dev/* entries on linux.
|
||||||
if info and info.type then
|
if info and info.type then
|
||||||
info.filename = strip_leading_path(file)
|
info.filename = file
|
||||||
return fileinfo_pass_filter(info, ignore_compiled) and info
|
return fileinfo_pass_filter(info, ignore_compiled) and info
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- "root" will by an absolute path without trailing '/'
|
-- "root" will by an absolute path without trailing '/'
|
||||||
-- "path" will be a path starting with '/' and without trailing '/'
|
-- "path" will be a path starting without '/' and without trailing '/'
|
||||||
-- or the empty string.
|
-- or the empty string.
|
||||||
-- It will identifies a sub-path within "root.
|
-- It will identifies a sub-path within "root.
|
||||||
-- The current path location will therefore always be: root .. path.
|
-- The current path location will therefore always be: root .. path.
|
||||||
-- When recursing "root" will always be the same, only "path" will change.
|
-- When recursing "root" will always be the same, only "path" will change.
|
||||||
-- Returns a list of file "items". In eash item the "filename" will be the
|
-- Returns a list of file "items". In each item the "filename" will be the
|
||||||
-- complete file path relative to "root" *without* the trailing '/'.
|
-- complete file path relative to "root" *without* the trailing '/', and without the starting '/'.
|
||||||
function dirwatch.get_directory_files(dir, root, path, t, entries_count, recurse_pred)
|
function dirwatch.get_directory_files(dir, root, path, t, entries_count, recurse_pred)
|
||||||
local t0 = system.get_time()
|
local t0 = system.get_time()
|
||||||
local all = system.list_dir(root .. path) or {}
|
|
||||||
local t_elapsed = system.get_time() - t0
|
local t_elapsed = system.get_time() - t0
|
||||||
local dirs, files = {}, {}
|
local dirs, files = {}, {}
|
||||||
local ignore_compiled = compile_ignore_files()
|
local ignore_compiled = compile_ignore_files()
|
||||||
|
|
||||||
for _, file in ipairs(all) do
|
|
||||||
local info = get_project_file_info(root, path .. PATHSEP .. file, ignore_compiled)
|
local all = system.list_dir(root .. PATHSEP .. path)
|
||||||
|
if not all then return nil end
|
||||||
|
|
||||||
|
for _, file in ipairs(all or {}) do
|
||||||
|
local info = get_project_file_info(root, (path ~= "" and (path .. PATHSEP) or "") .. file, ignore_compiled)
|
||||||
if info then
|
if info then
|
||||||
table.insert(info.type == "dir" and dirs or files, info)
|
table.insert(info.type == "dir" and dirs or files, info)
|
||||||
entries_count = entries_count + 1
|
entries_count = entries_count + 1
|
||||||
|
@ -200,7 +200,7 @@ function dirwatch.get_directory_files(dir, root, path, t, entries_count, recurse
|
||||||
for _, f in ipairs(dirs) do
|
for _, f in ipairs(dirs) do
|
||||||
table.insert(t, f)
|
table.insert(t, f)
|
||||||
if recurse_pred(dir, f.filename, entries_count, t_elapsed) then
|
if recurse_pred(dir, f.filename, entries_count, t_elapsed) then
|
||||||
local _, complete, n = dirwatch.get_directory_files(dir, root, PATHSEP .. f.filename, t, entries_count, recurse_pred)
|
local _, complete, n = dirwatch.get_directory_files(dir, root, f.filename, t, entries_count, recurse_pred)
|
||||||
recurse_complete = recurse_complete and complete
|
recurse_complete = recurse_complete and complete
|
||||||
entries_count = n
|
entries_count = n
|
||||||
else
|
else
|
||||||
|
|
|
@ -109,7 +109,6 @@ local function strip_trailing_slash(filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function core.project_subdir_is_shown(dir, filename)
|
function core.project_subdir_is_shown(dir, filename)
|
||||||
return not dir.files_limit or dir.shown_subdir[filename]
|
return not dir.files_limit or dir.shown_subdir[filename]
|
||||||
end
|
end
|
||||||
|
@ -127,80 +126,115 @@ local function show_max_files_warning(dir)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function file_search(files, info)
|
-- bisects the sorted file list to get to things in ln(n)
|
||||||
local filename, type = info.filename, info.type
|
local function file_bisect(files, is_superior, start_idx, end_idx)
|
||||||
local inf, sup = 1, #files
|
local inf, sup = start_idx or 1, end_idx or #files
|
||||||
while sup - inf > 8 do
|
while sup - inf > 8 do
|
||||||
local curr = math.floor((inf + sup) / 2)
|
local curr = math.floor((inf + sup) / 2)
|
||||||
if system.path_compare(filename, type, files[curr].filename, files[curr].type) then
|
if is_superior(files[curr]) then
|
||||||
sup = curr - 1
|
sup = curr - 1
|
||||||
else
|
else
|
||||||
inf = curr
|
inf = curr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
while inf <= sup and not system.path_compare(filename, type, files[inf].filename, files[inf].type) do
|
while inf <= sup and not is_superior(files[inf]) do
|
||||||
if files[inf].filename == filename then
|
|
||||||
return inf, true
|
|
||||||
end
|
|
||||||
inf = inf + 1
|
inf = inf + 1
|
||||||
end
|
end
|
||||||
return inf, false
|
return inf
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function file_search(files, info)
|
||||||
|
local idx = file_bisect(files, function(file)
|
||||||
|
return system.path_compare(info.filename, info.type, file.filename, file.type)
|
||||||
|
end)
|
||||||
|
if idx > 1 and files[idx-1].filename == info.filename then
|
||||||
|
return idx - 1, true
|
||||||
|
end
|
||||||
|
return idx, false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function files_info_equal(a, b)
|
local function files_info_equal(a, b)
|
||||||
return a.filename == b.filename and a.type == b.type
|
return (a == nil and b == nil) or (a and b and a.filename == b.filename and a.type == b.type)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- for "a" inclusive from i1 + 1 and i1 + n
|
|
||||||
local function files_list_match(a, i1, n, b)
|
local function project_subdir_bounds(dir, filename, start_index)
|
||||||
if n ~= #b then return false end
|
local found = true
|
||||||
for i = 1, n do
|
if not start_index then
|
||||||
if not files_info_equal(a[i1 + i], b[i]) then
|
start_index, found = file_search(dir.files, { type = "dir", filename = filename })
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return true
|
if found then
|
||||||
end
|
local end_index = file_bisect(dir.files, function(file)
|
||||||
|
return not common.path_belongs_to(file.filename, filename)
|
||||||
-- arguments like for files_list_match
|
end, start_index + 1)
|
||||||
local function files_list_replace(as, i1, n, bs, hook)
|
return start_index, end_index - start_index, dir.files[start_index]
|
||||||
local m = #bs
|
|
||||||
local i, j = 1, 1
|
|
||||||
while i <= m or i <= n do
|
|
||||||
local a, b = as[i1 + i], bs[j]
|
|
||||||
if i > n or (j <= m and not files_info_equal(a, b) and
|
|
||||||
not system.path_compare(a.filename, a.type, b.filename, b.type))
|
|
||||||
then
|
|
||||||
table.insert(as, i1 + i, b)
|
|
||||||
i, j, n = i + 1, j + 1, n + 1
|
|
||||||
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
|
|
||||||
i, j = i + 1, j + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local function project_subdir_bounds(dir, filename)
|
-- Should be called on any directory that registers a change, or on a directory we open if we're over the file limit.
|
||||||
local index, n = 0, #dir.files
|
-- Uses relative paths at the project root (i.e. target = "", target = "first-level-directory", target = "first-level-directory/second-level-directory")
|
||||||
for i, file in ipairs(dir.files) do
|
local function refresh_directory(topdir, target)
|
||||||
local file = dir.files[i]
|
local directory_start_idx, directory_end_idx = 1, #topdir.files
|
||||||
if file.filename == filename then
|
if target and target ~= "" then
|
||||||
index, n = i, #dir.files - i
|
directory_start_idx, directory_end_idx = project_subdir_bounds(topdir, target)
|
||||||
for j = 1, #dir.files - i do
|
directory_end_idx = directory_start_idx + directory_end_idx - 1
|
||||||
if not common.path_belongs_to(dir.files[i + j].filename, filename) then
|
directory_start_idx = directory_start_idx + 1
|
||||||
n = j - 1
|
end
|
||||||
break
|
|
||||||
|
local files = dirwatch.get_directory_files(topdir, topdir.name, (target or ""), {}, 0, function() return false end)
|
||||||
|
local change = false
|
||||||
|
|
||||||
|
-- If this file doesn't exist, we should be calling this on our parent directory, assume we'll do that.
|
||||||
|
-- Unwatch just in case.
|
||||||
|
if files == nil then
|
||||||
|
topdir.watch:unwatch(topdir.name .. PATHSEP .. (target or ""))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local new_idx, old_idx = 1, directory_start_idx
|
||||||
|
local new_directories = {}
|
||||||
|
-- Run through each sorted list and compare them. If we find a new entry, insert it and flag as new. If we're missing an entry
|
||||||
|
-- remove it and delete the entry from the list.
|
||||||
|
while old_idx <= directory_end_idx or new_idx <= #files do
|
||||||
|
local old_info, new_info = topdir.files[old_idx], files[new_idx]
|
||||||
|
if not files_info_equal(new_info, old_info) then
|
||||||
|
change = true
|
||||||
|
-- If we're a new file, and we exist *before* the other file in the list, then add to the list.
|
||||||
|
if not old_info or (new_info and system.path_compare(new_info.filename, new_info.type, old_info.filename, old_info.type)) then
|
||||||
|
table.insert(topdir.files, old_idx, new_info)
|
||||||
|
old_idx, new_idx = old_idx + 1, new_idx + 1
|
||||||
|
if new_info.type == "dir" then
|
||||||
|
table.insert(new_directories, new_info)
|
||||||
end
|
end
|
||||||
|
directory_end_idx = directory_end_idx + 1
|
||||||
|
else
|
||||||
|
-- If it's not there, remove the entry from the list as being out of order.
|
||||||
|
table.remove(topdir.files, old_idx)
|
||||||
|
if old_info.type == "dir" then
|
||||||
|
topdir.watch:unwatch(topdir.name .. PATHSEP .. old_info.filename)
|
||||||
|
end
|
||||||
|
directory_end_idx = directory_end_idx - 1
|
||||||
end
|
end
|
||||||
return index, n, file
|
else
|
||||||
|
-- If this file is a directory, determine in ln(n) the size of the directory, and skip every file in it.
|
||||||
|
local size = old_info and old_info.type == "dir" and select(2, project_subdir_bounds(topdir, old_info.filename, old_idx)) or 1
|
||||||
|
old_idx, new_idx = old_idx + size, new_idx + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
for i, v in ipairs(new_directories) do
|
||||||
|
topdir.watch:watch(topdir.name .. PATHSEP .. v.filename)
|
||||||
|
if not topdir.files_limit or core.project_subdir_is_shown(topdir, v.filename) then
|
||||||
|
refresh_directory(topdir, v.filename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if change then
|
||||||
|
core.redraw = true
|
||||||
|
topdir.is_dirty = true
|
||||||
|
end
|
||||||
|
return change
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,80 +247,6 @@ local function timed_max_files_pred(dir, filename, entries_count, t_elapsed)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Should be called on any directory that registers a change.
|
|
||||||
-- Uses relative paths at the project root.
|
|
||||||
local function refresh_directory(topdir, target, expanded)
|
|
||||||
local index, n, directory
|
|
||||||
if target == "" then
|
|
||||||
index, n = 1, #topdir.files
|
|
||||||
directory = ""
|
|
||||||
else
|
|
||||||
index, n = project_subdir_bounds(topdir, target)
|
|
||||||
index = index + 1
|
|
||||||
n = index + n - 1
|
|
||||||
directory = (PATHSEP .. target)
|
|
||||||
end
|
|
||||||
if index then
|
|
||||||
local files
|
|
||||||
local change = false
|
|
||||||
if topdir.files_limit then
|
|
||||||
-- If we have the folders literally open on the side panel.
|
|
||||||
files = expanded and dirwatch.get_directory_files(topdir, topdir.name, directory, {}, 0, core.project_subdir_is_shown) or {}
|
|
||||||
change = true
|
|
||||||
else
|
|
||||||
-- If we're expecting to keep track of everything, go through the list and iteratively deal with directories.
|
|
||||||
files = dirwatch.get_directory_files(topdir, topdir.name, directory, {}, 0, function() return false end)
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_idx, old_idx = 1, index
|
|
||||||
local new_directories = {}
|
|
||||||
local last_dir = nil
|
|
||||||
while old_idx <= n or new_idx <= #files do
|
|
||||||
local old_info, new_info = topdir.files[old_idx], files[new_idx]
|
|
||||||
if not new_info or not old_info or not last_dir or old_info.filename:sub(1, #last_dir + 1) ~= last_dir .. "/" then
|
|
||||||
if not new_info or not old_info or not files_info_equal(new_info, old_info) then
|
|
||||||
change = true
|
|
||||||
if not old_info or (new_info and system.path_compare(new_info.filename, new_info.type, old_info.filename, old_info.type)) then
|
|
||||||
table.insert(topdir.files, old_idx, new_info)
|
|
||||||
new_idx = new_idx + 1
|
|
||||||
old_idx = old_idx + 1
|
|
||||||
if new_info.type == "dir" then
|
|
||||||
table.insert(new_directories, new_info)
|
|
||||||
end
|
|
||||||
n = n + 1
|
|
||||||
else
|
|
||||||
table.remove(topdir.files, old_idx)
|
|
||||||
if old_info.type == "dir" then
|
|
||||||
topdir.watch:unwatch(target .. PATHSEP .. old_info.filename)
|
|
||||||
end
|
|
||||||
n = n - 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
new_idx = new_idx + 1
|
|
||||||
old_idx = old_idx + 1
|
|
||||||
end
|
|
||||||
if old_info and old_info.type == "dir" then
|
|
||||||
last_dir = old_info.filename
|
|
||||||
end
|
|
||||||
else
|
|
||||||
old_idx = old_idx + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i, v in ipairs(new_directories) do
|
|
||||||
topdir.watch:watch(target)
|
|
||||||
if refresh_directory(topdir, target .. PATHSEP .. v.filename) then
|
|
||||||
change = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if change then
|
|
||||||
core.redraw = true
|
|
||||||
topdir.is_dirty = true
|
|
||||||
end
|
|
||||||
return change
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function core.add_project_directory(path)
|
function core.add_project_directory(path)
|
||||||
-- top directories has a file-like "item" but the item.filename
|
-- top directories has a file-like "item" but the item.filename
|
||||||
-- will be simply the name of the directory, without its path.
|
-- will be simply the name of the directory, without its path.
|
||||||
|
@ -311,7 +271,7 @@ function core.add_project_directory(path)
|
||||||
topdir.slow_filesystem = not complete and (entries_count <= config.max_project_files)
|
topdir.slow_filesystem = not complete and (entries_count <= config.max_project_files)
|
||||||
topdir.files_limit = true
|
topdir.files_limit = true
|
||||||
show_max_files_warning(topdir)
|
show_max_files_warning(topdir)
|
||||||
refresh_directory(topdir, "", true)
|
refresh_directory(topdir)
|
||||||
else
|
else
|
||||||
for i,v in ipairs(t) do
|
for i,v in ipairs(t) do
|
||||||
if v.type == "dir" then topdir.watch:watch(path .. PATHSEP .. v.filename) end
|
if v.type == "dir" then topdir.watch:watch(path .. PATHSEP .. v.filename) end
|
||||||
|
@ -326,7 +286,7 @@ function core.add_project_directory(path)
|
||||||
topdir.watch_thread = core.add_thread(function()
|
topdir.watch_thread = core.add_thread(function()
|
||||||
while true do
|
while true do
|
||||||
topdir.watch:check(function(target)
|
topdir.watch:check(function(target)
|
||||||
if target == topdir.name then return refresh_directory(topdir, "", true) end
|
if target == topdir.name then return refresh_directory(topdir) end
|
||||||
local dirpath = target:sub(#topdir.name + 2)
|
local dirpath = target:sub(#topdir.name + 2)
|
||||||
local abs_dirpath = topdir.name .. PATHSEP .. dirpath
|
local abs_dirpath = topdir.name .. PATHSEP .. dirpath
|
||||||
if dirpath then
|
if dirpath then
|
||||||
|
@ -334,7 +294,7 @@ function core.add_project_directory(path)
|
||||||
local dir_index, dir_match = file_search(topdir.files, {filename = dirpath, type = "dir"})
|
local dir_index, dir_match = file_search(topdir.files, {filename = dirpath, type = "dir"})
|
||||||
if not dir_match or not core.project_subdir_is_shown(topdir, topdir.files[dir_index].filename) then return end
|
if not dir_match or not core.project_subdir_is_shown(topdir, topdir.files[dir_index].filename) then return end
|
||||||
end
|
end
|
||||||
return refresh_directory(topdir, dirpath, true)
|
return refresh_directory(topdir, dirpath)
|
||||||
end, 0.01, 0.01)
|
end, 0.01, 0.01)
|
||||||
coroutine.yield(0.05)
|
coroutine.yield(0.05)
|
||||||
end
|
end
|
||||||
|
@ -402,13 +362,7 @@ end
|
||||||
function core.update_project_subdir(dir, filename, expanded)
|
function core.update_project_subdir(dir, filename, expanded)
|
||||||
assert(dir.files_limit, "function should be called only when directory is in files limit mode")
|
assert(dir.files_limit, "function should be called only when directory is in files limit mode")
|
||||||
dir.shown_subdir[filename] = expanded
|
dir.shown_subdir[filename] = expanded
|
||||||
local index, n, file = project_subdir_bounds(dir, filename)
|
return refresh_directory(dir, filename)
|
||||||
if index then
|
|
||||||
local new_files = expanded and dirwatch.get_directory_files(dir, dir.name, PATHSEP .. filename, {}, 0, core.project_subdir_is_shown) or {}
|
|
||||||
files_list_replace(dir.files, index, n, new_files)
|
|
||||||
dir.is_dirty = true
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -93,14 +93,19 @@ int check_dirmonitor(struct dirmonitor* monitor, int (*change_callback)(int, con
|
||||||
return 0;
|
return 0;
|
||||||
#elif __linux__
|
#elif __linux__
|
||||||
char buf[PATH_MAX + sizeof(struct inotify_event)];
|
char buf[PATH_MAX + sizeof(struct inotify_event)];
|
||||||
|
ssize_t offset = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
ssize_t len = read(monitor->fd, buf, sizeof(buf));
|
ssize_t len = read(monitor->fd, &buf[offset], sizeof(buf) - offset);
|
||||||
if (len == -1 && errno != EAGAIN)
|
if (len == -1 && errno != EAGAIN)
|
||||||
return errno;
|
return errno;
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
for (char *ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + ((struct inotify_event*)ptr)->len)
|
while (len > sizeof(struct inotify_event) && len >= ((struct inotify_event*)buf)->len + sizeof(struct inotify_event)) {
|
||||||
change_callback(((const struct inotify_event *) ptr)->wd, NULL, data);
|
change_callback(((const struct inotify_event *)buf)->wd, NULL, data);
|
||||||
|
len -= sizeof(struct inotify_event) + ((struct inotify_event*)buf)->len;
|
||||||
|
memmove(buf, &buf[sizeof(struct inotify_event) + ((struct inotify_event*)buf)->len], len);
|
||||||
|
offset = len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
struct kevent event;
|
struct kevent event;
|
||||||
|
@ -146,6 +151,7 @@ void remove_dirmonitor(struct dirmonitor* monitor, int fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int f_check_dir_callback(int watch_id, const char* path, void* L) {
|
static int f_check_dir_callback(int watch_id, const char* path, void* L) {
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
char buffer[PATH_MAX*4];
|
char buffer[PATH_MAX*4];
|
||||||
int count = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)path, watch_id, buffer, PATH_MAX*4 - 1, NULL, NULL);
|
int count = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)path, watch_id, buffer, PATH_MAX*4 - 1, NULL, NULL);
|
||||||
|
@ -153,7 +159,7 @@ static int f_check_dir_callback(int watch_id, const char* path, void* L) {
|
||||||
#else
|
#else
|
||||||
lua_pushnumber(L, watch_id);
|
lua_pushnumber(L, watch_id);
|
||||||
#endif
|
#endif
|
||||||
lua_pcall(L, 1, 1, 0);
|
lua_call(L, 1, 1);
|
||||||
int result = lua_toboolean(L, -1);
|
int result = lua_toboolean(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return !result;
|
return !result;
|
||||||
|
|
Loading…
Reference in New Issue