This file is indexed.

/usr/share/pyshared/coherence/extern/inotify.py is in python-coherence 0.6.6.2-8.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php

# Copyright 2006-2009 Frank Scholz <coherence@beebits.net>
# Modified by Colin Laplace, added is_watched() function
# Copyright 2008 Adroll.com and Valentino Volonghi <dialtone@adroll.com>
# Modified by Valentino Volonghi.
#  * Increased isWatched efficiency, now it's O(1)
#  * Code reorganization, added docstrings, Twisted coding style
#  * Introduced an hack to partially solve a race condition in auto_add.
#  * Removed code that didn't use libc 2.4 but magic hacks
#    -> reverted, as it might still be needed somewhere (fs)
#  * Used fdesc.readFromFD to read during doRead

import os
import struct

try:
    import ctypes
    import ctypes.util
except ImportError:
    raise SystemError("ctypes not detected on this system, can't use INotify")

from twisted.internet import reactor
from twisted.internet.abstract import FileDescriptor
from twisted.internet import fdesc
from twisted.python.filepath import FilePath

# from /usr/src/linux/include/linux/inotify.h

IN_ACCESS =         0x00000001L     # File was accessed
IN_MODIFY =         0x00000002L     # File was modified
IN_ATTRIB =         0x00000004L     # Metadata changed
IN_CLOSE_WRITE =    0x00000008L     # Writtable file was closed
IN_CLOSE_NOWRITE =  0x00000010L     # Unwrittable file closed
IN_OPEN =           0x00000020L     # File was opened
IN_MOVED_FROM =     0x00000040L     # File was moved from X
IN_MOVED_TO =       0x00000080L     # File was moved to Y
IN_CREATE =         0x00000100L     # Subfile was created
IN_DELETE =         0x00000200L     # Subfile was delete
IN_DELETE_SELF =    0x00000400L     # Self was deleted
IN_MOVE_SELF =      0x00000800L     # Self was moved
IN_UNMOUNT =        0x00002000L     # Backing fs was unmounted
IN_Q_OVERFLOW =     0x00004000L     # Event queued overflowed
IN_IGNORED =        0x00008000L     # File was ignored

IN_ONLYDIR =         0x01000000      # only watch the path if it is a directory
IN_DONT_FOLLOW =     0x02000000      # don't follow a sym link
IN_MASK_ADD =        0x20000000      # add to the mask of an already existing watch
IN_ISDIR =           0x40000000      # event occurred against dir
IN_ONESHOT =         0x80000000      # only send event once

IN_CLOSE =      IN_CLOSE_WRITE | IN_CLOSE_NOWRITE   # closes
IN_MOVED =      IN_MOVED_FROM | IN_MOVED_TO         # moves
IN_CHANGED =    IN_MODIFY | IN_ATTRIB               # changes

IN_WATCH_MASK = IN_MODIFY | IN_ATTRIB | \
                IN_CREATE | IN_DELETE | \
                IN_DELETE_SELF | IN_MOVE_SELF | \
                IN_UNMOUNT | IN_MOVED_FROM | IN_MOVED_TO


_FLAG_TO_HUMAN = {
    IN_ACCESS: 'access',
    IN_MODIFY: 'modify',
    IN_ATTRIB: 'attrib',
    IN_CLOSE_WRITE: 'close_write',
    IN_CLOSE_NOWRITE: 'close_nowrite',
    IN_OPEN: 'open',
    IN_MOVED_FROM: 'moved_from',
    IN_MOVED_TO: 'moved_to',
    IN_CREATE: 'create',
    IN_DELETE: 'delete',
    IN_DELETE_SELF: 'delete_self',
    IN_MOVE_SELF: 'move_self',
    IN_UNMOUNT: 'unmount',
    IN_Q_OVERFLOW: 'queue_overflow',
    IN_IGNORED: 'ignored',
    IN_ONLYDIR: 'only_dir',
    IN_DONT_FOLLOW: 'dont_follow',
    IN_MASK_ADD: 'mask_add',
    IN_ISDIR: 'is_dir',
    IN_ONESHOT: 'one_shot'
}

# system call numbers are architecture-specific
# see /usr/include/linux/asm/unistd.h and look for inotify
_inotify_syscalls = { 'i386': (291,292,293),  # FIXME, there has to be a better way for this
                      'i486': (291,292,293),
                      'i586': (291,292,293),
                      'i686': (291,292,293),
                      'x86_64': (253,254,255), # gotten from FC-6 and F-7
                      'armv6l':(316,317,318),              # Nokia N800
                      'armv5tej1':(316,317,318),           # Nokia N770
                      'ppc': (275,276,277),                # PPC, like PS3
                      }

def flag_to_human(mask):
    """
    Auxiliary function that converts an hexadecimal mask into a series
    of human readable flags.
    """
    s = []
    for (k, v) in _FLAG_TO_HUMAN.iteritems():
        if k & mask:
            s.append(v)
    return s


class Watch(object):
    """
    Watch object that represents a Watch point in the filesystem.

    @ivar path: The path over which this watch point is monitoring
    @ivar mask: The events monitored by this watchpoint
    @ivar auto_add: Flag that determines whether this watch point
                    should automatically add created subdirectories
    @ivar callbacks: C{list} of C{tuples} of callbacks that should be
                     called synchronously on the events monitored.
    """
    def __init__(self, path, mask=IN_WATCH_MASK, auto_add=False, callbacks=[]):
        self.path = path
        self.mask = mask
        self.auto_add = auto_add
        self.callbacks = []
        if not isinstance(callbacks, list):
            callbacks = [callbacks]
        self.callbacks = callbacks

    def addCallback(self, callback, args=None):
        """
        Add a new callback to the list with the given auxiliary
        optional argument.
        """
        self.callbacks.append((callback, args))

    def notify(self, filename, events):
        """
        Callback function used by L{INotify} to dispatch an event.
        """
        for callback in self.callbacks:
            if callback is not None:
                #wrap that so our loop isn't aborted by a faulty callback
                try:
                    callback[0](self, filename, events, callback[1])
                except:
                    import traceback
                    traceback.print_exc()


class INotify(FileDescriptor, object):
    """
    The INotify file descriptor, it basically does everything related
    to INotify, from reading to notifying watch points.
    """
    _instance_ = None  # Singleton

    def __new__(cls, *args, **kwargs):
        obj = getattr(cls, '_instance_', None)
        if obj is not None:
            return obj
        else:
            obj = super(INotify, cls).__new__(cls, *args, **kwargs)

            # Check inotify support by checking for the required functions
            obj.libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))
            if len([function for function in "inotify_add_watch inotify_init inotify_rm_watch".split() if hasattr(obj.libc, function)]) == 3:
                obj.inotify_init = obj.libc.inotify_init
                obj.inotify_add_watch = obj.libc_inotify_add_watch
                obj.inotify_rm_watch = obj.libc_inotify_rm_watch
            else:
                print("inotify.py - can't use libc6, 2.4 or higher needed")
                import platform
                if platform.system() != 'Linux':
                    raise SystemError, "unknown system '%r', INotify support disabled" % platform.uname()
                machine = platform.machine()
                try:
                    obj._init_syscall_id = _inotify_syscalls[machine][0]
                    obj._add_watch_syscall_id = _inotify_syscalls[machine][1]
                    obj._rm_watch_syscall_id = _inotify_syscalls[machine][2]

                    obj.inotify_init = obj._inotify_init
                    obj.inotify_add_watch = obj._inotify_add_watch
                    obj.inotify_rm_watch = obj._inotify_rm_watch
                except:
                    raise SystemError, "unknown system '%s', INotify support disabled" % machine

            FileDescriptor.__init__(obj)

            obj._fd = obj.inotify_init()
            if obj._fd < 0:
                raise SystemError("INotify initialization error.")
            fdesc.setNonBlocking(obj._fd)
            reactor.addReader(obj)

            obj._buffer = ''
            # Mapping from wds to Watch objects
            obj._watchpoints = {}
            # Mapping from paths to wds
            obj._watchpaths = {}
            cls._instance_ = obj
            return obj

    def _addWatch(self, path, mask, auto_add, callbacks):
        """
        Private helpers that abstract the use of ctypes and help
        managing state related to those calls.
        """
        wd = self.inotify_add_watch(
            os.path.normpath(path),
            mask
        )

        if wd < 0:
            raise IOError("Failed to add watch on '%r' - (%r)" % (path, wd))

        iwp = Watch(path, mask, auto_add, callbacks)

        self._watchpoints[wd] = iwp
        self._watchpaths[path] = wd

        return wd

    def _rmWatch(self, wd):
        """
        Private helpers that abstract the use of ctypes and help
        managing state related to those calls.
        """
        self.inotify_rm_watch(wd)
        iwp = self._watchpoints.pop(wd)
        self._watchpaths.pop(iwp.path)
        del iwp


    def _inotify_init(self):
        return self.libc.syscall(self._init_syscall_id)

    def _inotify_add_watch(self, path, mask):
        if type(path) is unicode:
            path = path.encode('utf-8')
            self.libc.syscall.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_int]
        else:
            self.libc.syscall.argtypes = None
        return self.libc.syscall(self._add_watch_syscall_id, self._fd, path, mask)

    def _inotify_rm_watch(self, wd):
        return self.libc.syscall(self._rm_watch_syscall_id, self._fd, wd)

    def libc_inotify_add_watch(self, path, mask):
        if type(path) is unicode:
            path = path.encode('utf-8')
            self.libc.inotify_add_watch.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int]
        else:
            self.libc.inotify_add_watch.argtypes = None
        return self.libc.inotify_add_watch(self._fd, path, mask)

    def libc_inotify_rm_watch(self, wd):
        return self.libc.inotify_rm_watch(self._fd, wd)

    def release(self):
        """
        Release the inotify file descriptor and do the necessary cleanup
        """
        reactor.removeReader(self)
        if hasattr(self, '_fd') and self._fd >= 0:
            try:
                os.close(self._fd)
            except OSError:
                pass

        if hasattr(INotify, '_instance_'):
            del INotify._instance_

    # I'd rather not have this...
    __del__ = release

    def fileno(self):
        """
        Get the underlying file descriptor from this inotify observer.
        """
        return self._fd

    def notify(self, iwp, filename, mask, *args):
        """
        A simple callback that you can use for tests
        """
        print "event %s on %s %s" % (
            ', '.join(flag_to_human(mask)), iwp.path, filename)

    def doRead(self):
        """
        Read some data from the observed file descriptors
        """
        fdesc.readFromFD(self._fd, self._doRead)

    def _doRead(self, in_):
        """
        Work on the data just read from the file descriptor.
        """
        self._buffer += in_
        while True:
            if len(self._buffer) < 16:
                break

            wd, mask, cookie, size = struct.unpack("=LLLL", self._buffer[0:16])

            if size:
                name = self._buffer[16:16+size].rstrip('\0')
            else:
                name = None

            self._buffer = self._buffer[16+size:]

            try:
                iwp = self._watchpoints[wd]
            except:
                continue # can this happen?

            path = iwp.path
            if name:
                path = os.path.join(path, name)
                iwp.notify(name, mask)
            else:
                iwp.notify(path, mask)

            if (iwp.auto_add and mask & IN_ISDIR and mask & IN_CREATE):
                # Note that this is a fricking hack... it's because we
                # cannot be fast enough in adding a watch to a directory
                # and so we basically end up getting here too late if
                # some operations have already been going on in the
                # subdir, we basically need to catchup.
                # This eventually ends up meaning that we generate
                # double events, your app must be resistant.
                def _addChildren(iwp):
                    try:
                        listdir = os.listdir(iwp.path)
                    except OSError:
                        # Somebody or something (like a test)
                        # removed this directory while we were in the
                        # callLater(0...) waiting. It doesn't make
                        # sense to process it anymore
                        return

                    # note that it's true that listdir will only see
                    # the subdirs inside path at the moment of the call
                    # but path is monitored already so if something is
                    # created we will receive an event.
                    for f in listdir:
                        inner = os.path.join(iwp.path, f)

                        # It's a directory, watch it and then add its
                        # children
                        if os.path.isdir(inner):
                            wd = self.watch(
                                inner, mask=iwp.mask, auto_add=True,
                                callbacks=iwp.callbacks
                            )
                            iwp.notify(f, IN_ISDIR|IN_CREATE)
                            # now inner is watched, we can add its children
                            # the callLater is to avoid recursion
                            reactor.callLater(0,
                                _addChildren, self._watchpoints[wd])

                        # It's a file and we notify it.
                        if os.path.isfile(inner):
                            iwp.notify(f, IN_CREATE|IN_CLOSE_WRITE)

                if os.path.isdir(path):
                    new_wd = self.watch(
                        path, mask=iwp.mask, auto_add=True,
                        callbacks=iwp.callbacks
                    )
                    # This is very very very hacky and I'd rather
                    # not do this but we have no other alternative
                    # that is less hacky other than surrender
                    # We use callLater because we don't want to have
                    # too many events waiting while we process these
                    # subdirs, we must always answer events as fast
                    # as possible or the overflow might come.
                    reactor.callLater(0,
                        _addChildren, self._watchpoints[new_wd])
            if mask & IN_DELETE_SELF:
                self._rmWatch(wd)

    def watch(self, path, mask=IN_WATCH_MASK, auto_add=None, callbacks=[], recursive=False):
        """
        Watch the 'mask' events in given path.

        @param path: The path needing monitoring
        @type path: L{FilePath} or C{str} or C{unicode}

        @param mask: The events that should be watched
        @type mask: C{hex}

        @param auto_add: if True automatically add newly created
                        subdirectories
        @type auto_add: C{boolean}

        @param callbacks: A list of callbacks that should be called
                          when an event happens in the given path.
        @type callbacks: C{list} of C{tuples}

        @param recursive: Also add all the subdirectories in this path
        @type recursive: C{boolean}
        """
        if isinstance(path, FilePath):
            path = path.path
        if type(path) is unicode:
            path = path.encode('utf-8')
        path = os.path.realpath(path)

        if recursive:
            for root, dirs, files in os.walk(path):
                self.watch(root, mask, auto_add, callbacks, False)
        else:
            wd = self.isWatched(path)
            if wd:
                return wd

            mask = mask | IN_DELETE_SELF

            return self._addWatch(path, mask, auto_add, callbacks)

    def ignore(self, path):
        """
        Remove the watch point monitoring the given path

        @param path: The path that should be ignored
        @type path: L{FilePath} or C{unicode} or C{str}
        """
        if isinstance(path, FilePath):
            path = path.path
        if type(path) is unicode:
            path = path.encode('utf-8')
        path = os.path.realpath(path)
        wd = self.isWatched(path)
        if wd:
            self._rmWatch(wd)

    def isWatched(self, path):
        """
        Helper function that checks if the path is already monitored
        and returns its watchdescriptor if so.

        @param path: The path that should be checked
        @type path: L{FilePath} or C{unicode} or C{str}
        """
        if isinstance(path, FilePath):
            path = path.path
        if type(path) is unicode:
            path = path.encode('utf-8')
        return self._watchpaths.get(path, False)

    def flag_to_human(self,mask):
        return flag_to_human(mask)

if __name__ == '__main__':

    i = INotify()
    print i
    i.watch(unicode('/tmp'), auto_add=True, callbacks=(i.notify,None), recursive=True)

    i2 = INotify()
    print i2
    i2.watch('/', auto_add=True, callbacks=(i2.notify,None), recursive=False)

    reactor.run()