ENH(+possibly BF): for FilterPoll rely not only on mtime but also ino and size to assess if file was modified

mtime alone is a poor measure here as many of our tests shown -- on older Pythons and some file systems
mtime might be reported only with precision up to a second.  If file gets rotated fast, or there are new
modifications within the same second, fail2ban might miss them with Polling backend if judging only by
mtime.  With this modification we will track also inode and size which are all indicative of a file
change.
pull/280/head
Yaroslav Halchenko 12 years ago
parent 8c125b6053
commit f340e5c0f5

@ -57,7 +57,7 @@ class FilterPoll(FileFilter):
FileFilter.__init__(self, jail) FileFilter.__init__(self, jail)
self.__modified = False self.__modified = False
## The time of the last modification of the file. ## The time of the last modification of the file.
self.__lastModTime = dict() self.__prevStats = dict()
self.__file404Cnt = dict() self.__file404Cnt = dict()
logSys.debug("Created FilterPoll") logSys.debug("Created FilterPoll")
@ -67,7 +67,7 @@ class FilterPoll(FileFilter):
# @param path log file path # @param path log file path
def _addLogPath(self, path): def _addLogPath(self, path):
self.__lastModTime[path] = 0 self.__prevStats[path] = (0, None, None) # mtime, ino, size
self.__file404Cnt[path] = 0 self.__file404Cnt[path] = 0
## ##
@ -76,7 +76,7 @@ class FilterPoll(FileFilter):
# @param path the log file to delete # @param path the log file to delete
def _delLogPath(self, path): def _delLogPath(self, path):
del self.__lastModTime[path] del self.__prevStats[path]
del self.__file404Cnt[path] del self.__file404Cnt[path]
## ##
@ -126,18 +126,20 @@ class FilterPoll(FileFilter):
def isModified(self, filename): def isModified(self, filename):
try: try:
logStats = os.stat(filename) logStats = os.stat(filename)
stats = logStats.st_mtime, logStats.st_ino, logStats.st_size
pstats = self.__prevStats[filename]
self.__file404Cnt[filename] = 0 self.__file404Cnt[filename] = 0
if logSys.getEffectiveLevel() <= 7: if logSys.getEffectiveLevel() <= 7:
# we do not want to waste time on strftime etc if not necessary # we do not want to waste time on strftime etc if not necessary
dt = logStats.st_mtime - self.__lastModTime[filename] dt = logStats.st_mtime - pstats[0]
logSys.log(7, "Checking %s for being modified. Previous/current mtimes: %s / %s. dt: %s", logSys.log(7, "Checking %s for being modified. Previous/current stats: %s / %s. dt: %s",
filename, _ctime(self.__lastModTime[filename]), _ctime(logStats.st_mtime), dt) filename, pstats, stats, dt)
# os.system("stat %s | grep Modify" % filename) # os.system("stat %s | grep Modify" % filename)
if self.__lastModTime[filename] == logStats.st_mtime: if pstats == stats:
return False return False
else: else:
logSys.debug(filename + " has been modified") logSys.debug("%s has been modified", filename)
self.__lastModTime[filename] = logStats.st_mtime self.__prevStats[filename] = stats
return True return True
except OSError, e: except OSError, e:
logSys.error("Unable to get stat on %s because of: %s" logSys.error("Unable to get stat on %s because of: %s"

Loading…
Cancel
Save