zeek/scripts/base/utils/dir.bro
Bernhard Amann 4b0ee2e7ca Fix the dir module.
Internally, Dir kept track of the files in directory
by storing all inode numbers in a set. However, when a file
is deleted and a new file is created in a directory, the old
file may get the same inode number as the old one. In this
case, bro did not notice the new file.

The patch simply changes the indexing of files - now files
are indexed by inode and creation time.

This should fix the scripts.base.utils.dir test failures.
2013-10-25 18:01:46 -07:00

67 lines
2 KiB
Text

@load base/utils/exec
@load base/frameworks/reporter
@load base/utils/paths
module Dir;
export {
## The default interval this module checks for files in directories when
## using the :bro:see:`Dir::monitor` function.
const polling_interval = 30sec &redef;
## Register a directory to monitor with a callback that is called
## every time a previously unseen file is seen. If a file is deleted
## and seen to be gone, then the file is available for being seen again
## in the future.
##
## dir: The directory to monitor for files.
##
## callback: Callback that gets executed with each file name
## that is found. Filenames are provided with the full path.
##
## poll_interval: An interval at which to check for new files.
global monitor: function(dir: string, callback: function(fname: string),
poll_interval: interval &default=polling_interval);
}
event Dir::monitor_ev(dir: string, last_files: set[string],
callback: function(fname: string),
poll_interval: interval)
{
# the command lists all file in the directory in the form [inode]-[ctime] [filename]
when ( local result = Exec::run([$cmd=fmt("find \"%s\" -depth 1 -exec stat -f \"%%i-%%c %%N\" {} \\;", str_shell_escape(dir))]) )
{
if ( result$exit_code != 0 )
{
Reporter::warning(fmt("Requested monitoring of non-existent directory (%s).", dir));
return;
}
local current_files: set[string] = set();
local files: vector of string = vector();
if ( result?$stdout )
files = result$stdout;
for ( i in files )
{
local parts = split1(files[i], / /);
if ( parts[1] !in last_files )
callback(build_path_compressed(dir, parts[2]));
add current_files[parts[1]];
}
schedule poll_interval
{
Dir::monitor_ev(dir, current_files, callback, poll_interval)
};
}
}
function monitor(dir: string, callback: function(fname: string),
poll_interval: interval &default=polling_interval)
{
event Dir::monitor_ev(dir, set(), callback, poll_interval);
}