diff --git a/lib/rb-inotify/native/flags.rb b/lib/rb-inotify/native/flags.rb index 5640130..bc59607 100644 --- a/lib/rb-inotify/native/flags.rb +++ b/lib/rb-inotify/native/flags.rb @@ -11,31 +11,31 @@ module Flags IN_ATTRIB = 0x00000004 # Writtable file was closed. IN_CLOSE_WRITE = 0x00000008 - # File was modified. - IN_MODIFY = 0x00000002 # Unwrittable file closed. IN_CLOSE_NOWRITE = 0x00000010 - # File was opened. - IN_OPEN = 0x00000020 - # File was moved from X. - IN_MOVED_FROM = 0x00000040 - # File was moved to Y. - IN_MOVED_TO = 0x00000080 # Subfile was created. IN_CREATE = 0x00000100 # Subfile was deleted. IN_DELETE = 0x00000200 # Self was deleted. IN_DELETE_SELF = 0x00000400 + # File was modified. + IN_MODIFY = 0x00000002 # Self was moved. IN_MOVE_SELF = 0x00000800 + # File was moved from X. + IN_MOVED_FROM = 0x00000040 + # File was moved to Y. + IN_MOVED_TO = 0x00000080 + # File was opened. + IN_OPEN = 0x00000020 ## Helper events. - # Close. - IN_CLOSE = (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) # Moves. IN_MOVE = (IN_MOVED_FROM | IN_MOVED_TO) + # Close. + IN_CLOSE = (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) # All events which a program can wait on. IN_ALL_EVENTS = (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | @@ -44,26 +44,35 @@ module Flags ## Special flags. - # Only watch the path if it is a directory. - IN_ONLYDIR = 0x01000000 - # Do not follow a sym link. + # Do not follow a sym link + # available since Linux 2.6.15, causes EINVAL othervise IN_DONT_FOLLOW = 0x02000000 + # Exclude events on unlinked objects. + # available since Linux 2.6.36, causes EINVAL othervise + IN_EXCL_UNLINK = 0x04000000 # Add to the mask of an already existing watch. IN_MASK_ADD = 0x20000000 # Only send event once. IN_ONESHOT = 0x80000000 - + # Only watch the path if it is a directory. + # available since Linux 2.6.15, causes EINVAL othervise + IN_ONLYDIR = 0x01000000 + # Only create watches. + # available since Linux 4.18, causes EINVAL othervise + IN_MASK_CREATE = 0x10000000 ## Events sent by the kernel. - # Backing fs was unmounted. - IN_UNMOUNT = 0x00002000 - # Event queued overflowed. - IN_Q_OVERFLOW = 0x00004000 # File was ignored. IN_IGNORED = 0x00008000 # Event occurred against dir. IN_ISDIR = 0x40000000 + # Event queued overflowed. + IN_Q_OVERFLOW = 0x00004000 + # Backing fs was unmounted. + IN_UNMOUNT = 0x00002000 + + EVENT_ONLY_FLAGS = IN_IGNORED | IN_ISDIR | IN_UNMOUNT | IN_Q_OVERFLOW ## fpathconf Macros @@ -75,10 +84,23 @@ module Flags # @param flags [Array] # @return [Fixnum] def self.to_mask(flags) - flags.map {|flag| const_get("IN_#{flag.to_s.upcase}")}. + flags.map {|flag| to_add_watch_flag(flag) }. inject(0) {|mask, flag| mask | flag} end + # Converts a flag to the value that can be used in inotify_add_watch + # + # @param flag [Symbol] + # @return [Fixnum] + # @raise [NameError] if the flag is not supported + # @raise [ArgumentError] if the flag is defined, but can't be used in inotify_add_watch + def self.to_add_watch_flag(flag) + res = const_get("IN_#{flag.to_s.upcase}") + raise ArgumentError, "Invalid flag: #{flag}" if EVENT_ONLY_FLAGS & res != 0 + + res + end + # Converts a bitmask from the C API into a list of flags. # # @param mask [Fixnum] diff --git a/lib/rb-inotify/notifier.rb b/lib/rb-inotify/notifier.rb index 398ef99..5c8ecb4 100644 --- a/lib/rb-inotify/notifier.rb +++ b/lib/rb-inotify/notifier.rb @@ -164,10 +164,16 @@ def to_io # Instead, they specify options for the watcher. # # `:onlydir` - # : Only watch the path if it's a directory. + # : Only watch the path if it's a directory; since Linux 2.6.15. # # `:dont_follow` - # : Don't follow symlinks. + # : Don't follow symlinks; since Linux 2.6.15. + # + # `:excl_unlink` + # : Exclude events on unlinked objects; since Linux 2.6.36. + # + # `:mask_create` + # : Watch pathname only if it does not already have a watch associated with it, Errno::EEXIST is raised otherwise; since Linux 4.18. # # `:mask_add` # : Add these flags to the pre-existing flags for this path. diff --git a/spec/notifier_spec.rb b/spec/notifier_spec.rb index 8370151..41b1bad 100644 --- a/spec/notifier_spec.rb +++ b/spec/notifier_spec.rb @@ -41,6 +41,26 @@ expect(events.first.absolute_name).to eq(dir.join("test.txt").to_s) end + it "ensures that new watches do not modify existing ones" do + recording(dir, :create, :oneshot, :mask_create) + expect do + recording(dir, :create, :oneshot, :mask_create) + end.to raise_error(Errno::EEXIST) + dir.join("test.txt").write("hello world") + expect do + recording(dir, :create, :oneshot, :mask_create) + end.not_to raise_error + end + + it "fails if flags are not supported" do + expect do + recording(dir, :create, :oneshot, :unknown_flag) + end.to raise_error(NameError, 'uninitialized constant INotify::Native::Flags::IN_UNKNOWN_FLAG') + expect do + recording(dir, :create, :isdir) + end.to raise_error(ArgumentError, 'Invalid flag: isdir') + end + it "gets simultaneous events" do events = recording(dir, :create)