blob: 1205e2dea559d0806d7ac446bacdc3b5b3a6dc96 [file] [log] [blame]
module INotify
# Watchers monitor a single path for changes,
# specified by {INotify::Notifier#watch event flags}.
# A watcher is usually created via \{Notifier#watch}.
#
# One {Notifier} may have many {Watcher}s.
# The Notifier actually takes care of the checking for events,
# via \{Notifier#run #run} or \{Notifier#process #process}.
# The main purpose of having Watcher objects
# is to be able to disable them using \{#close}.
class Watcher
# The {Notifier} that this Watcher belongs to.
#
# @return [Notifier]
attr_reader :notifier
# The path that this Watcher is watching.
#
# @return [String]
attr_reader :path
# The {INotify::Notifier#watch flags}
# specifying the events that this Watcher is watching for,
# and potentially some options as well.
#
# @return [Array<Symbol>]
attr_reader :flags
# The id for this Watcher.
# Used to retrieve this Watcher from {Notifier#watchers}.
#
# @private
# @return [Fixnum]
attr_reader :id
# Calls this Watcher's callback with the given {Event}.
#
# @private
# @param event [Event]
def callback!(event)
@callback[event]
end
# Disables this Watcher, so that it doesn't fire any more events.
#
# @raise [SystemCallError] if the watch fails to be disabled for some reason
def close
if Native.inotify_rm_watch(@notifier.fd, @id) == 0
@notifier.watchers.delete(@id)
return
end
raise SystemCallError.new("Failed to stop watching #{path.inspect}",
FFI.errno)
end
# Creates a new {Watcher}.
#
# @private
# @see Notifier#watch
def initialize(notifier, path, *flags, &callback)
@notifier = notifier
@callback = callback || proc {}
@path = path
@flags = flags.freeze
@id = Native.inotify_add_watch(@notifier.fd, path.dup,
Native::Flags.to_mask(flags))
unless @id < 0
@notifier.watchers[@id] = self
return
end
raise SystemCallError.new(
"Failed to watch #{path.inspect}" +
case FFI.errno
when Errno::EACCES::Errno; ": read access to the given file is not permitted."
when Errno::EBADF::Errno; ": the given file descriptor is not valid."
when Errno::EFAULT::Errno; ": path points outside of the process's accessible address space."
when Errno::EINVAL::Errno; ": the given event mask contains no legal events; or fd is not an inotify file descriptor."
when Errno::ENOMEM::Errno; ": insufficient kernel memory was available."
when Errno::ENOSPC::Errno; ": The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."
else; ""
end,
FFI.errno)
end
end
end