summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastien Martini <seb@dbzteam.org>2010-01-03 15:04:28 +0100
committerSebastien Martini <seb@dbzteam.org>2010-01-03 15:04:28 +0100
commit7bbd6dab1c317314161567a6088076282100f736 (patch)
tree4e3ebc4039e88b505e6df5aad60020284b92cb6b
parenta8a70eeab092b89471435015196894ffb419bd97 (diff)
downloadpyinotify-7bbd6dab1c317314161567a6088076282100f736.tar.gz
- Removed custom glob functions, uses standard glob module directly.
- Modified exclusion filter mechanism, patterns still can be loaded from files but the syntax has changed see exclude.lst for more details. This new method is safer since the external file is not executed anymore, it is only parsed looking for patterns loaded as strings.
-rw-r--r--python2/examples/exclude.lst12
-rw-r--r--python2/examples/exclude.patterns16
-rw-r--r--python2/examples/exclude.py35
-rwxr-xr-xpython2/pyinotify.py111
-rwxr-xr-xpython3/pyinotify.py108
5 files changed, 80 insertions, 202 deletions
diff --git a/python2/examples/exclude.lst b/python2/examples/exclude.lst
new file mode 100644
index 0000000..7e81272
--- /dev/null
+++ b/python2/examples/exclude.lst
@@ -0,0 +1,12 @@
+# File associated to exclude.py
+#
+# List of patterns using regexps as defined into re standard module.
+# These regexps are matched against submitted paths with re.match().
+
+# Put only one pattern by line.
+^/etc/apache[2]?/
+^/etc/rc.*
+^/etc/hostname
+^/etc/hosts
+^/etc/(fs|m)tab
+^/etc/cron\..*
diff --git a/python2/examples/exclude.patterns b/python2/examples/exclude.patterns
deleted file mode 100644
index f519b15..0000000
--- a/python2/examples/exclude.patterns
+++ /dev/null
@@ -1,16 +0,0 @@
-# -*- mode: python; -*-
-
-# Patterns can use unrestricted regexps (see re module)
-# regexps are matched against submitted paths through match()
-
-excl_lst1 = ['^/etc/apache[2]?/',
- '^/etc/rc.*',
- '^/etc/hostname',
- '^/etc/hosts',
- '^/etc/(fs|m)tab',
- '^/etc/cron\..*']
-
-excl_lst2 = ['^/var/log/.*',
- '^/var/www/.*',
- '^/var/cache/.*',
- '^/var/spool/.*']
diff --git a/python2/examples/exclude.py b/python2/examples/exclude.py
index 850dbfe..4f12960 100644
--- a/python2/examples/exclude.py
+++ b/python2/examples/exclude.py
@@ -1,27 +1,30 @@
-# Example: excludes items from being monitored.
+# Example: exclude items from being monitored.
#
-import pyinotify
import os
-
-excl_file = os.path.join(os.getcwd(), 'exclude.patterns')
+import pyinotify
wm = pyinotify.WatchManager()
notifier = pyinotify.Notifier(wm)
-
### Method 1:
-# Exclude filter object
-excl = pyinotify.ExcludeFilter({excl_file: ('excl_lst1', 'excl_lst2')})
+# Exclude patterns from file
+excl_file = os.path.join(os.getcwd(), 'exclude.lst')
+excl = pyinotify.ExcludeFilter(excl_file)
# Add watches
-wm.add_watch(['/etc/*', '/var'], pyinotify.ALL_EVENTS,
- rec=True, do_glob=True, exclude_filter=excl)
-
+res = wm.add_watch(['/etc/hostname', '/etc/cups', '/etc/rc0.d'],
+ pyinotify.ALL_EVENTS, rec=True, exclude_filter=excl)
### Method 2 (Equivalent)
-wm.add_watch('/etc/*', pyinotify.ALL_EVENTS, rec=True, do_glob=True,
- exclude_filter=pyinotify.ExcludeFilter({excl_file:('excl_lst1',)}))
-wm.add_watch('/var', pyinotify.ALL_EVENTS, rec=True,
- exclude_filter=pyinotify.ExcludeFilter({excl_file:('excl_lst2',)}))
-
+# Exclude patterns from list
+excl_lst = ['^/etc/apache[2]?/',
+ '^/etc/rc.*',
+ '^/etc/hostname',
+ '^/etc/hosts',
+ '^/etc/(fs|m)tab',
+ '^/etc/cron\..*']
+excl = pyinotify.ExcludeFilter(excl_lst)
+# Add watches
+res = wm.add_watch(['/etc/hostname', '/etc/cups', '/etc/rc0.d'],
+ pyinotify.ALL_EVENTS, rec=True, exclude_filter=excl)
-notifier.loop()
+#notifier.loop()
diff --git a/python2/pyinotify.py b/python2/pyinotify.py
index 8a6111b..8cfe2ec 100755
--- a/python2/pyinotify.py
+++ b/python2/pyinotify.py
@@ -85,6 +85,7 @@ import re
import ctypes
import ctypes.util
import asyncore
+import glob
try:
from functools import reduce
@@ -183,10 +184,7 @@ def logger_init():
log = logger_init()
-
-### inotify's variables ###
-
-
+# inotify's variables
class SysCtlINotify:
"""
Access (read, write) inotify's variables through sysctl. Usually it
@@ -253,74 +251,6 @@ for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'):
globals()[attrname] = SysCtlINotify(attrname)
-
-### iglob ###
-
-
-# Code taken from standart Python Lib, slightly modified in order to work
-# with pyinotify (don't exclude dotted files/dirs like .foo).
-# Original version:
-# @see: http://svn.python.org/projects/python/trunk/Lib/glob.py
-
-def iglob(pathname):
- if not has_magic(pathname):
- if hasattr(os.path, 'lexists'):
- if os.path.lexists(pathname):
- yield pathname
- else:
- if os.path.islink(pathname) or os.path.exists(pathname):
- yield pathname
- return
- dirname, basename = os.path.split(pathname)
- # relative pathname
- if not dirname:
- return
- # absolute pathname
- if has_magic(dirname):
- dirs = iglob(dirname)
- else:
- dirs = [dirname]
- if has_magic(basename):
- glob_in_dir = glob1
- else:
- glob_in_dir = glob0
- for dirname in dirs:
- for name in glob_in_dir(dirname, basename):
- yield os.path.join(dirname, name)
-
-def glob1(dirname, pattern):
- if not dirname:
- dirname = os.curdir
- try:
- names = os.listdir(dirname)
- except os.error:
- return []
- return fnmatch.filter(names, pattern)
-
-def glob0(dirname, basename):
- if basename == '' and os.path.isdir(dirname):
- # `os.path.split()` returns an empty basename for paths ending with a
- # directory separator. 'q*x/' should match only directories.
- return [basename]
- if hasattr(os.path, 'lexists'):
- if os.path.lexists(os.path.join(dirname, basename)):
- return [basename]
- else:
- if (os.path.islink(os.path.join(dirname, basename)) or
- os.path.exists(os.path.join(dirname, basename))):
- return [basename]
- return []
-
-MAGIC_CHECK = re.compile('[*?[]')
-
-def has_magic(s):
- return MAGIC_CHECK.search(s) is not None
-
-
-
-### Core ###
-
-
class EventsCodes:
"""
Set of codes corresponding to each kind of events.
@@ -1501,14 +1431,20 @@ class ExcludeFilter:
"""
def __init__(self, arg_lst):
"""
+ Examples:
+ ef1 = ExcludeFilter(["^/etc/rc.*", "^/etc/hostname"])
+ ef2 = ExcludeFilter("/my/path/exclude.lst")
+ Where exclude.lst contains:
+ ^/etc/rc.*
+ ^/etc/hostname
+
@param arg_lst: is either a list or dict of patterns:
- [pattern1, ..., patternn]
- {'filename1': (list1, listn), ...} where list1 is
- a list of patterns
- @type arg_lst: list or dict
+ [pattern1, ..., patternn] or a filename from which
+ patterns will be loaded.
+ @type arg_lst: list(str) or str
"""
- if isinstance(arg_lst, dict):
- lst = self._load_patterns(arg_lst)
+ if isinstance(arg_lst, str):
+ lst = self._load_patterns_from_file(arg_lst)
elif isinstance(arg_lst, list):
lst = arg_lst
else:
@@ -1518,13 +1454,18 @@ class ExcludeFilter:
for regex in lst:
self._lregex.append(re.compile(regex, re.UNICODE))
- def _load_patterns(self, dct):
+ def _load_patterns_from_file(self, filename):
lst = []
- for path, varnames in dct.items():
- loc = {}
- execfile(path, {}, loc)
- for varname in varnames:
- lst.extend(loc.get(varname, []))
+ file_obj = file(filename, 'r')
+ try:
+ for line in file_obj.readlines():
+ # Trim leading an trailing whitespaces
+ pattern = line.strip()
+ if not pattern or pattern.startswith('#'):
+ continue
+ lst.append(pattern)
+ finally:
+ file_obj.close()
return lst
def _match(self, regex, path):
@@ -1656,7 +1597,7 @@ class WatchManager:
def __glob(self, path, do_glob):
if do_glob:
- return iglob(path)
+ return glob.iglob(path)
else:
return [path]
diff --git a/python3/pyinotify.py b/python3/pyinotify.py
index 2a5af1c..2596d43 100755
--- a/python3/pyinotify.py
+++ b/python3/pyinotify.py
@@ -86,6 +86,7 @@ import re
import ctypes
import ctypes.util
import asyncore
+import glob
try:
from functools import reduce
@@ -148,10 +149,7 @@ def logger_init():
log = logger_init()
-
-### inotify's variables ###
-
-
+# inotify's variables
class SysCtlINotify:
"""
Access (read, write) inotify's variables through sysctl. Usually it
@@ -218,74 +216,6 @@ for attrname in ('max_queued_events', 'max_user_instances', 'max_user_watches'):
globals()[attrname] = SysCtlINotify(attrname)
-
-### iglob ###
-
-
-# Code taken from standart Python Lib, slightly modified in order to work
-# with pyinotify (don't exclude dotted files/dirs like .foo).
-# Original version:
-# @see: http://svn.python.org/projects/python/trunk/Lib/glob.py
-
-def iglob(pathname):
- if not has_magic(pathname):
- if hasattr(os.path, 'lexists'):
- if os.path.lexists(pathname):
- yield pathname
- else:
- if os.path.islink(pathname) or os.path.exists(pathname):
- yield pathname
- return
- dirname, basename = os.path.split(pathname)
- # relative pathname
- if not dirname:
- return
- # absolute pathname
- if has_magic(dirname):
- dirs = iglob(dirname)
- else:
- dirs = [dirname]
- if has_magic(basename):
- glob_in_dir = glob1
- else:
- glob_in_dir = glob0
- for dirname in dirs:
- for name in glob_in_dir(dirname, basename):
- yield os.path.join(dirname, name)
-
-def glob1(dirname, pattern):
- if not dirname:
- dirname = os.curdir
- try:
- names = os.listdir(dirname)
- except os.error:
- return []
- return fnmatch.filter(names, pattern)
-
-def glob0(dirname, basename):
- if basename == '' and os.path.isdir(dirname):
- # `os.path.split()` returns an empty basename for paths ending with a
- # directory separator. 'q*x/' should match only directories.
- return [basename]
- if hasattr(os.path, 'lexists'):
- if os.path.lexists(os.path.join(dirname, basename)):
- return [basename]
- else:
- if (os.path.islink(os.path.join(dirname, basename)) or
- os.path.exists(os.path.join(dirname, basename))):
- return [basename]
- return []
-
-MAGIC_CHECK = re.compile('[*?[]')
-
-def has_magic(s):
- return MAGIC_CHECK.search(s) is not None
-
-
-
-### Core ###
-
-
class EventsCodes:
"""
Set of codes corresponding to each kind of events.
@@ -1459,14 +1389,20 @@ class ExcludeFilter:
"""
def __init__(self, arg_lst):
"""
+ Examples:
+ ef1 = ExcludeFilter(["^/etc/rc.*", "^/etc/hostname"])
+ ef2 = ExcludeFilter("/my/path/exclude.lst")
+ Where exclude.lst contains:
+ ^/etc/rc.*
+ ^/etc/hostname
+
@param arg_lst: is either a list or dict of patterns:
- [pattern1, ..., patternn]
- {'filename1': (list1, listn), ...} where list1 is
- a list of patterns
- @type arg_lst: list or dict
+ [pattern1, ..., patternn] or a filename from which
+ patterns will be loaded.
+ @type arg_lst: list(str) or str
"""
- if isinstance(arg_lst, dict):
- lst = self._load_patterns(arg_lst)
+ if isinstance(arg_lst, str):
+ lst = self._load_patterns_from_file(arg_lst)
elif isinstance(arg_lst, list):
lst = arg_lst
else:
@@ -1476,13 +1412,15 @@ class ExcludeFilter:
for regex in lst:
self._lregex.append(re.compile(regex, re.UNICODE))
- def _load_patterns(self, dct):
+ def _load_patterns_from_file(self, filename):
lst = []
- for path, varnames in dct.items():
- loc = {}
- execfile(path, {}, loc)
- for varname in varnames:
- lst.extend(loc.get(varname, []))
+ with open(filename, 'r') as file_obj:
+ for line in file_obj.readlines():
+ # Trim leading an trailing whitespaces
+ pattern = line.strip()
+ if not pattern or pattern.startswith('#'):
+ continue
+ lst.append(pattern)
return lst
def _match(self, regex, path):
@@ -1613,7 +1551,7 @@ class WatchManager:
def __glob(self, path, do_glob):
if do_glob:
- return iglob(path)
+ return glob.iglob(path)
else:
return [path]