fixing creation recursing

This commit is contained in:
Axel Kittenberger 2012-02-16 16:49:34 +01:00
parent 6faf99d952
commit 5e4fdba53a
3 changed files with 106 additions and 123 deletions

View File

@ -77,22 +77,20 @@ l_addwatch(lua_State *L)
uint32_t mask = standard_event_mask; uint32_t mask = standard_event_mask;
if (*imode) { if (*imode) {
if (!strcmp(imode, "Modify")) { if (!strcmp(imode, "Modify")) {
/* act on modify instead of closeWrite */ // act on modify instead of closeWrite
mask |= IN_MODIFY; mask |= IN_MODIFY;
mask &= ~IN_CLOSE_WRITE; mask &= ~IN_CLOSE_WRITE;
} else if (!strcmp(imode, "CloseWrite")) { } else if (!strcmp(imode, "CloseWrite")) {
/* default */ // default
} else if (!strcmp(imode, "CloseWrite or Modify")) { } else if (!strcmp(imode, "CloseWrite or Modify")) {
/* acts on modify and closeWrite */ // acts on modify and closeWrite
mask |= IN_MODIFY; mask |= IN_MODIFY;
} else if (!strcmp(imode, "CloseWrite after Modify")) { } else if (!strcmp(imode, "CloseWrite after Modify")) {
/* might be done in future */ // might be done in future
printlogf(L, "Error", printlogf(L, "Error", "'CloseWrite after Modify' not implemented.");
"'CloseWrite after Modify' not implemented.");
exit(-1); // ERRNO exit(-1); // ERRNO
} else { } else {
printlogf(L, "Error", printlogf(L, "Error", "'%s' not a valid inotfiyMode.", imode);
"'%s' not a valid inotfiyMode.", imode);
exit(-1); // ERRNO exit(-1); // ERRNO
} }
} }
@ -101,14 +99,11 @@ l_addwatch(lua_State *L)
int wd = inotify_add_watch(inotify_fd, path, mask); int wd = inotify_add_watch(inotify_fd, path, mask);
if (wd < 0) { if (wd < 0) {
if (errno == ENOSPC) { if (errno == ENOSPC) {
printlogf(L, "Error", printlogf(L, "Error", "Terminating since out of inotify watches.");
"Terminating since out of inotify watches."); printlogf(L, "Error", "Consider increasing /proc/sys/fs/inotify/max_user_watches");
printlogf(L, "Error",
"Consider increasing /proc/sys/fs/inotify/max_user_watches");
exit(-1); // ERRNO. exit(-1); // ERRNO.
} }
printlogf(L, "Inotify", "addwatch(%s)->%d; err=%d:%s", path, wd, printlogf(L, "Inotify", "addwatch(%s)->%d; err=%d:%s", path, wd, errno, strerror(errno));
errno, strerror(errno));
} else { } else {
printlogf(L, "Inotify", "addwatch(%s)->%d", path, wd); printlogf(L, "Inotify", "addwatch(%s)->%d", path, wd);
} }
@ -168,7 +163,7 @@ handle_event(lua_State *L,
{ {
const char *event_type = NULL; const char *event_type = NULL;
/* used to execute two events in case of unmatched MOVE_FROM buffer */ // used to execute two events in case of unmatched MOVE_FROM buffer
struct inotify_event *after_buf = NULL; struct inotify_event *after_buf = NULL;
if (event && (IN_Q_OVERFLOW & event->mask)) { if (event && (IN_Q_OVERFLOW & event->mask)) {
/* and overflow happened, tells the runner */ /* and overflow happened, tells the runner */
@ -180,27 +175,27 @@ handle_event(lua_State *L,
hup = 1; hup = 1;
return; return;
} }
/* cancel on ignored or resetting */ // cancel on ignored or resetting
if (event && (IN_IGNORED & event->mask)) { if (event && (IN_IGNORED & event->mask)) {
return; return;
} }
if (event && event->len == 0) { if (event && event->len == 0) {
/* sometimes inotify sends such strange events, // sometimes inotify sends such strange events,
* (e.g. when touching a dir */ // (e.g. when touching a dir
return; return;
} }
if (event == NULL) { if (event == NULL) {
/* a buffered MOVE_FROM is not followed by anything, // a buffered MOVE_FROM is not followed by anything,
thus it is unary */ // thus it is unary
event = move_event_buf; event = move_event_buf;
event_type = "Delete"; event_type = "Delete";
move_event = false; move_event = false;
} else if (move_event && } else if (move_event &&
( !(IN_MOVED_TO & event->mask) || ( !(IN_MOVED_TO & event->mask) ||
event->cookie != move_event_buf->cookie) ) { event->cookie != move_event_buf->cookie) ) {
/* there is a MOVE_FROM event in the buffer and this is not the match // there is a MOVE_FROM event in the buffer and this is not the match
* continue in this function iteration to handle the buffer instead */ // continue in this function iteration to handle the buffer instead */
logstring("Inotify", "icore, changing unary MOVE_FROM into DELETE") logstring("Inotify", "icore, changing unary MOVE_FROM into DELETE")
after_buf = event; after_buf = event;
event = move_event_buf; event = move_event_buf;
@ -209,13 +204,13 @@ handle_event(lua_State *L,
} else if ( move_event && } else if ( move_event &&
(IN_MOVED_TO & event->mask) && (IN_MOVED_TO & event->mask) &&
event->cookie == move_event_buf->cookie ) { event->cookie == move_event_buf->cookie ) {
/* this is indeed a matched move */ // this is indeed a matched move */
event_type = "Move"; event_type = "Move";
move_event = false; move_event = false;
} else if (IN_MOVED_FROM & event->mask) { } else if (IN_MOVED_FROM & event->mask) {
/* just the MOVE_FROM, buffers this event, and wait if next event is // just the MOVE_FROM, buffers this event, and wait if next event is
* a matching MOVED_TO of this was an unary move out of the watched // a matching MOVED_TO of this was an unary move out of the watched
* tree. */ // tree.
size_t el = sizeof(struct inotify_event) + event->len; size_t el = sizeof(struct inotify_event) + event->len;
if (move_event_buf_size < el) { if (move_event_buf_size < el) {
move_event_buf_size = el; move_event_buf_size = el;
@ -225,26 +220,26 @@ handle_event(lua_State *L,
move_event = true; move_event = true;
return; return;
} else if (IN_MOVED_TO & event->mask) { } else if (IN_MOVED_TO & event->mask) {
/* must be an unary move-to */ // must be an unary move-to
event_type = CREATE; event_type = CREATE;
} else if (IN_ATTRIB & event->mask) { } else if (IN_ATTRIB & event->mask) {
/* just attrib change */ // just attrib change
event_type = ATTRIB; event_type = ATTRIB;
} else if (IN_CLOSE_WRITE & event->mask) { } else if (IN_CLOSE_WRITE & event->mask) {
/* closed after written something */ // closed after written something
event_type = MODIFY; event_type = MODIFY;
} else if (IN_CREATE & event->mask) { } else if (IN_CREATE & event->mask) {
/* a new file */ // a new file
event_type = CREATE; event_type = CREATE;
} else if (IN_DELETE & event->mask) { } else if (IN_DELETE & event->mask) {
/* rm'ed */ // rm'ed
event_type = DELETE; event_type = DELETE;
} else { } else {
logstring("Inotify", "icore, skipped some inotify event."); logstring("Inotify", "icore, skipped some inotify event.");
return; return;
} }
/* and hands over to runner */ // and hands over to runner
load_runner_func(L, "inotifyEvent"); load_runner_func(L, "inotifyEvent");
if (!event_type) { if (!event_type) {
logstring("Error", "Internal: unknown event in handle_event()"); logstring("Error", "Internal: unknown event in handle_event()");
@ -272,7 +267,7 @@ handle_event(lua_State *L,
} }
lua_pop(L, 1); lua_pop(L, 1);
/* if there is a buffered event executes it */ // if there is a buffered event, executes it
if (after_buf) { if (after_buf) {
logstring("Inotify", "icore, handling buffered event."); logstring("Inotify", "icore, handling buffered event.");
handle_event(L, after_buf); handle_event(L, after_buf);
@ -304,23 +299,23 @@ inotify_ready(lua_State *L, struct observance *obs)
len = read (inotify_fd, readbuf, readbuf_size); len = read (inotify_fd, readbuf, readbuf_size);
err = errno; err = errno;
if (len < 0 && err == EINVAL) { if (len < 0 && err == EINVAL) {
/* kernel > 2.6.21 indicates that way that way that // kernel > 2.6.21 indicates that way that way that
* the buffer was too small to fit a filename. // the buffer was too small to fit a filename.
* double its size and try again. When using a lower // double its size and try again. When using a lower
* kernel and a filename > 2KB appears lsyncd // kernel and a filename > 2KB appears lsyncd
* will fail. (but does a 2KB filename really happen?) // will fail. (but does a 2KB filename really happen?)
*/ //
readbuf_size *= 2; readbuf_size *= 2;
readbuf = s_realloc(readbuf, readbuf_size); readbuf = s_realloc(readbuf, readbuf_size);
} }
} while(len < 0 && err == EINVAL); } while(len < 0 && err == EINVAL);
if (len == 0) { if (len == 0) {
/* nothing more inotify */ // nothing more inotify
break; break;
} }
if (len < 0) { if (len < 0) {
if (err == EAGAIN) { if (err == EAGAIN) {
/* nothing more inotify */ // nothing more inotify
break; break;
} else { } else {
printlogf(L, "Error", "Read fail on inotify"); printlogf(L, "Error", "Read fail on inotify");
@ -337,12 +332,12 @@ inotify_ready(lua_State *L, struct observance *obs)
} }
} }
if (!move_event) { if (!move_event) {
/* give it a pause if not endangering splitting a move */ // give it a pause if not endangering splitting a move
break; break;
} }
} }
/* checks if there is an unary MOVE_FROM left in the buffer */ // checks if there is an unary MOVE_FROM left in the buffer
if (move_event) { if (move_event) {
logstring("Inotify", "icore, handling unary move from."); logstring("Inotify", "icore, handling unary move from.");
handle_event(L, NULL); handle_event(L, NULL);

View File

@ -1245,7 +1245,7 @@ local Sync = (function()
-- --
local function delay(self, etype, time, path, path2) local function delay(self, etype, time, path, path2)
log('Function', 'delay(',self.config.name,', ',etype,', ',path,', ',path2,')') log('Function', 'delay(',self.config.name,', ',etype,', ',path,', ',path2,')')
-- TODO -- TODO
local function recurse() local function recurse()
if etype == 'Create' and path:byte(-1) == 47 then if etype == 'Create' and path:byte(-1) == 47 then
@ -1828,12 +1828,9 @@ local Inotify = (function()
-- --
-- @param path absolute path of directory to observe -- @param path absolute path of directory to observe
-- @param recurse true if recursing into subdirs -- @param recurse true if recursing into subdirs
-- @param raiseSync --X --
-- raiseTime if not nil sends create Events for all files/dirs
-- to this sync.
-- --
local function addWatch(path, recurse, raiseSync, raiseTime) local function addWatch(path)
log('Function','Inotify.addWatch(',path,', ',recurse,', ',raiseSync,', ',raiseTime,')') log('Function','Inotify.addWatch(',path,')')
if not Syncs.concerns(path) then if not Syncs.concerns(path) then
log('Inotify', 'not concerning "',path,'"') log('Inotify', 'not concerning "',path,'"')
@ -1862,9 +1859,6 @@ local Inotify = (function()
-- registers and adds watches for all subdirectories -- registers and adds watches for all subdirectories
-- and/or raises create events for all entries -- and/or raises create events for all entries
if not recurse and not raise then
return
end
local entries = lsyncd.readdir(path) local entries = lsyncd.readdir(path)
if not entries then return end if not entries then return end
@ -1872,15 +1866,8 @@ local Inotify = (function()
for dirname, isdir in pairs(entries) do for dirname, isdir in pairs(entries) do
local pd = path .. dirname local pd = path .. dirname
if isdir then pd = pd..'/' end if isdir then pd = pd..'/' end
-- creates a Create event for entry.
-- No longer needed? (TODO)
-- if raiseSync then
-- local relative = splitPath(pd, syncRoots[raiseSync])
-- if relative then raiseSync:delay('Create', raiseTime, relative) end
-- end
-- adds syncs for subdirs -- adds syncs for subdirs
if isdir then addWatch(pd, true, raiseSync, raiseTime) end if isdir then addWatch(pd) end
end end
end end
@ -1895,7 +1882,7 @@ local Inotify = (function()
error('duplicate sync in Inotify.addSync()') error('duplicate sync in Inotify.addSync()')
end end
syncRoots[sync] = rootdir syncRoots[sync] = rootdir
addWatch(rootdir, true) addWatch(rootdir)
end end
----- -----
@ -1965,18 +1952,19 @@ local Inotify = (function()
etyped = 'Create' etyped = 'Create'
end end
end end
sync:delay(etyped, time, relative, relative2)
if isdir then if isdir then
if etyped == 'Create' then if etyped == 'Create' then
addWatch(path, true, sync, time) addWatch(path)
elseif etyped == 'Delete' then elseif etyped == 'Delete' then
removeWatch(path, true) removeWatch(path, true)
elseif etyped == 'Move' then elseif etyped == 'Move' then
removeWatch(path, false) removeWatch(path, false)
addWatch(path2, true, sync, time) addWatch(path2)
end end
end end
sync:delay(etyped, time, relative, relative2)
until true end until true end
end end

View File

@ -1,115 +1,115 @@
#!/usr/bin/lua #!/usr/bin/lua
require("posix") require('posix')
dofile("tests/testlib.lua") dofile('tests/testlib.lua')
cwriteln("****************************************************************"); cwriteln('****************************************************************');
cwriteln(" Testing excludes "); cwriteln(' Testing excludes');
cwriteln("****************************************************************"); cwriteln('****************************************************************');
cwriteln(" (this test needs passwordless ssh localhost access "); cwriteln(' (this test needs passwordless ssh localhost access ');
cwriteln(" for current user)"); cwriteln(' for current user)');
local tdir, srcdir, trgdir = mktemps() local tdir, srcdir, trgdir = mktemps()
local logfile = tdir .. "log" local logfile = tdir .. 'log'
local cfgfile = tdir .. "config.lua" local cfgfile = tdir .. 'config.lua'
local range = 5 local range = 5
local log = {} local log = {}
log = {"-log", "all"} log = {'-log', 'all'}
writefile(cfgfile, [[ writefile(cfgfile, [[
settings = { settings = {
logfile = "]]..logfile..[[", logfile = ']]..logfile..[[',
nodaemon = true, nodaemon = true,
delay = 3, delay = 3,
} }
sync { sync {
default.rsyncssh, default.rsyncssh,
host = "localhost", host = 'localhost',
source = "]]..srcdir..[[", source = ']]..srcdir..[[',
targetdir = "]]..trgdir..[[", targetdir = ']]..trgdir..[[',
exclude = { exclude = {
"erf", 'erf',
"/eaf", '/eaf',
"erd/", 'erd/',
"/ead/", '/ead/',
}, },
}]]); }]]);
-- writes all files -- writes all files
local function writefiles() local function writefiles()
posix.mkdir(srcdir .. "d"); posix.mkdir(srcdir .. 'd');
writefile(srcdir .. "erf", "erf"); writefile(srcdir .. 'erf', 'erf');
writefile(srcdir .. "eaf", "erf"); writefile(srcdir .. 'eaf', 'erf');
writefile(srcdir .. "erd", "erd"); writefile(srcdir .. 'erd', 'erd');
writefile(srcdir .. "ead", "ead"); writefile(srcdir .. 'ead', 'ead');
writefile(srcdir .. "d/erf", "erf"); writefile(srcdir .. 'd/erf', 'erf');
writefile(srcdir .. "d/eaf", "erf"); writefile(srcdir .. 'd/eaf', 'erf');
writefile(srcdir .. "d/erd", "erd"); writefile(srcdir .. 'd/erd', 'erd');
writefile(srcdir .. "d/ead", "ead"); writefile(srcdir .. 'd/ead', 'ead');
end end
-- test if the filename exists, fails if this is different to expect -- test if the filename exists, fails if this is different to expect
local function testfile(filename, expect) local function testfile(filename, expect)
local stat, err = posix.stat(filename) local stat, err = posix.stat(filename)
if stat and not expect then if stat and not expect then
cwriteln("failure: ",filename," should be excluded"); cwriteln('failure: ',filename,' should be excluded');
os.exit(1); os.exit(1);
end end
if not stat and expect then if not stat and expect then
cwriteln("failure: ",filename," should not be excluded"); cwriteln('failure: ',filename,' should not be excluded');
os.exit(1); os.exit(1);
end end
end end
-- test all files -- test all files
local function testfiles() local function testfiles()
testfile(trgdir .. "erf", false); testfile(trgdir .. 'erf', false);
testfile(trgdir .. "eaf", false); testfile(trgdir .. 'eaf', false);
testfile(trgdir .. "erd", true); testfile(trgdir .. 'erd', true);
testfile(trgdir .. "ead", true); testfile(trgdir .. 'ead', true);
testfile(trgdir .. "d/erf", false); testfile(trgdir .. 'd/erf', false);
testfile(trgdir .. "d/eaf", true); testfile(trgdir .. 'd/eaf', true);
testfile(trgdir .. "d/erd", true); testfile(trgdir .. 'd/erd', true);
testfile(trgdir .. "d/ead", true); testfile(trgdir .. 'd/ead', true);
end end
cwriteln("testing startup excludes"); cwriteln('testing startup excludes');
writefiles(); writefiles();
cwriteln("starting Lsyncd"); cwriteln('starting Lsyncd');
local pid = spawn("./lsyncd", cfgfile, unpack(log)); local pid = spawn('./lsyncd', cfgfile, unpack(log));
cwriteln("waiting for Lsyncd to start"); cwriteln('waiting for Lsyncd to start');
posix.sleep(3) posix.sleep(10)
cwriteln("testing excludes after startup"); cwriteln('testing excludes after startup');
testfiles(); testfiles();
cwriteln("ok, removing sources"); cwriteln('ok, removing sources');
if srcdir:sub(1,4) ~= "/tmp" then if srcdir:sub(1,4) ~= '/tmp' then
-- just to make sure before rm -rf -- just to make sure before rm -rf
cwriteln("exist before drama, srcdir is '", srcdir, "'"); cwriteln('exist before drama, srcdir is "', srcdir, '"');
os.exit(1); os.exit(1);
end end
os.execute("rm -rf "..srcdir.."/*"); os.execute('rm -rf '..srcdir..'/*');
cwriteln("waiting for Lsyncd to remove destination"); cwriteln('waiting for Lsyncd to remove destination');
posix.sleep(5); posix.sleep(5);
if os.execute("diff -urN "..srcdir.." "..trgdir) ~= 0 then if os.execute('diff -urN '..srcdir..' '..trgdir) ~= 0 then
cwriteln("fail, target directory not empty!"); cwriteln('fail, target directory not empty!');
os.exit(1); os.exit(1);
end end
cwriteln("writing files after startup"); cwriteln('writing files after startup');
writefiles(); writefiles();
cwriteln("waiting for Lsyncd to transmit changes"); cwriteln('waiting for Lsyncd to transmit changes');
posix.sleep(5); posix.sleep(15);
testfiles(); testfiles();
cwriteln("killing started Lsyncd"); cwriteln('killing started Lsyncd');
posix.kill(pid); posix.kill(pid);
local _, exitmsg, lexitcode = posix.wait(lpid); local _, exitmsg, lexitcode = posix.wait(lpid);
cwriteln("Exitcode of Lsyncd = ", exitmsg, " ", lexitcode); cwriteln('Exitcode of Lsyncd = ', exitmsg, ' ', lexitcode);
posix.sleep(1); posix.sleep(1);
if lexitcode == 0 then if lexitcode == 0 then
cwriteln("OK"); cwriteln('OK');
end end
os.exit(lexitcode); os.exit(lexitcode);