Rust-Inotify rs: Idiomatic inotify wrapper for the Rust programming language.

inotify-rs crates.io Documentation Build Status

Idiomatic inotify wrapper for the Rust programming language.

extern crate inotify;


use std::env;

use inotify::{
    EventMask,
    WatchMask,
    Inotify,
};


fn main() {
    let mut inotify = Inotify::init()
        .expect("Failed to initialize inotify");

    let current_dir = env::current_dir()
        .expect("Failed to determine current directory");

    inotify
        .add_watch(
            current_dir,
            WatchMask::MODIFY | WatchMask::CREATE | WatchMask::DELETE,
        )
        .expect("Failed to add inotify watch");

    println!("Watching current directory for activity...");

    let mut buffer = [0u8; 4096];
    loop {
        let events = inotify
            .read_events_blocking(&mut buffer)
            .expect("Failed to read inotify events");

        for event in events {
            if event.mask.contains(EventMask::CREATE) {
                if event.mask.contains(EventMask::ISDIR) {
                    println!("Directory created: {:?}", event.name);
                } else {
                    println!("File created: {:?}", event.name);
                }
            } else if event.mask.contains(EventMask::DELETE) {
                if event.mask.contains(EventMask::ISDIR) {
                    println!("Directory deleted: {:?}", event.name);
                } else {
                    println!("File deleted: {:?}", event.name);
                }
            } else if event.mask.contains(EventMask::MODIFY) {
                if event.mask.contains(EventMask::ISDIR) {
                    println!("Directory modified: {:?}", event.name);
                } else {
                    println!("File modified: {:?}", event.name);
                }
            }
        }
    }
}

Usage

Include it in your Cargo.toml:

[dependencies]
inotify = "0.8"

Please refer to the documentation and the example above, for information on how to use it in your code.

Please note that inotify-rs is a relatively low-level wrapper around the original inotify API. And, of course, it is Linux-specific, just like inotify itself. If you are looking for a higher-level and platform-independent file system notification library, please consider notify.

If you need to access inotify in a way that this wrapper doesn't support, consider using inotify-sys instead.

Documentation

The most important piece of documentation for inotify-rs is the API reference, as it contains a thorough description of the complete API, as well as examples.

Additional examples can be found in the examples directory.

Please also make sure to read the inotify man page. Inotify use can be hard to get right, and this low-level wrapper won't protect you from all mistakes.

License

Copyright (c) Hanno Braun and contributors

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Comments

  • Multiple `EventStream`s can take each other's events
    Multiple `EventStream`s can take each other's events

    Aug 7, 2018

    It is possible to create multiple EventStreams from a single Inotify instance. Those streams will read from the same inotify file descriptor. Depending on the timing of the reads, one EventStream could end up with all the events, or both could end up with some of them. (Note: I haven't tested this. It's just my own reasoning).

    It would be possible to guarantee there is only one EventStream per Inotify instance, by consuming or mutably borrowing Inotify when creating an EventStream. However, both those solutions would make add_watch/rm_watch inaccessible.

    I have two ideas for how to solve this:

    1. Duplicate add_watch/rm_watch on EventStream. That way, EventStream would effectively become a replacement for Inotify that uses a different method for reading events.
    2. Split Inotify into two parts, one for managing watches, one for reading events.

    I don't think solution 1 is flexible enough. Stream has a lot of methods that move the stream, which would make add_watch/rm_watch inaccessible again. This isn't really a solution, it's just kicking the problem one step down the line.

    Solution 2 deserves a bit more elaboration:

    • Inotify would become a struct with two fields, watches and events.
    • watches would provide add_watch/rm_watch (which could be shortened to add/remove).
    • events would provide the various read_* methods.
    • events could be moved or borrowed when creating an EventStream, without affecting watches.

    Right now I'm unsure what to do, although I like solution 2. I'm going to let this issue sit for a while before attempting an implementation. In the meantime, feedback is highly welcome.

    enhancement 
    Reply
  • Consider unifying traditional and future-based APIs
    Consider unifying traditional and future-based APIs

    Aug 8, 2018

    Currently there are two parallel APIs: The original one, and the new future-based one. I think it would be ideal if we could unify those.

    One problem I see is efficiency. The stream-based API requires one additional heap allocation for every event that has a name. The reason for this are lifetime issues that probably can't be resolved, at least not in safe Rust.

    I think it's best for now to keep things as they are, while keeping a look at how futures developers. Feedback is very welcome!

    enhancement 
    Reply
  • Async/Await syntax support
    Async/Await syntax support

    Sep 25, 2018

    Futures 0.3 will support the Async/Await syntax. One it reaches GA, Tokio will be next. We should investigate what it will require of us to support the new syntax and prepare ourselves for it.

    Reply
  • Improve documentation of `Inotify::event_stream`
    Improve documentation of `Inotify::event_stream`

    Jun 23, 2019

    The documentation for Inotify::event_stream is out of date.

    1. It talks about using an internal buffer, but it no longer does.
    2. It could use examples showing the various usage scenarios.

    The examples should document what kinds of values can be passes as a buffer. See this comment in #124 and this comment in #125 for more information.

    good first issue help wanted 
    Reply
  • Async await support
    Async await support

    Sep 18, 2019

    (This includes changes from #134.)

    This adds an async Inotify type. It has an async fn read_events (close #121):

        pub async fn read_events<'a>(&mut self, buffer: &'a mut [u8])
                               -> io::Result<Events<'a>>
    

    that is basically the same as the original read_events function, but awaits on the read:

        {
            let num_bytes = self.fd.read(buffer).await?;
    
            if num_bytes == 0 {
                return Err(
                    io::Error::new(
                        io::ErrorKind::UnexpectedEof,
                        "`read` return `0`, signaling end-of-file"
                    )
                );
            }
    
            Ok(Events::new(Arc::downgrade(self.fd.get_ref()), buffer, num_bytes))
        }
    

    This addresses the efficiency concern in #112: no additional allocation is required.

    Reply
  • Update mio dependency
    Update mio dependency

    May 26, 2020

    mio version 0.6 depends on deprecated crate. Upgrade to version 0.7.

    good first issue help wanted 
    Reply
  • add: Hash trait for WatchDescriptor
    add: Hash trait for WatchDescriptor

    Jul 25, 2017

    I've made a new PR after breaking the previous one due to a clunky rebase/squash.

    I've added the Hash to the WatchDescriptor struct, to allow it to be used for HashMap lookup.

    Reply
  • refactor: Add FdGuard responsible for close-on-drop
    refactor: Add FdGuard responsible for close-on-drop

    Jun 7, 2018

    This commit improves the close-on-drop behaviour for file descriptors, by adding a FdGuard struct that wraps the file descriptor and is responsible for closing it when it is dropped. Rather than having an Inotify own an Arc<RawFd>, and be responsible for clsoing it, Inotify now owns an Arc<FdGuard>, and the FdGuard is responsible for closing the fd.

    This allows us to share the file descriptor between an Inotify and an EventStream, and close the file descriptor only when the Arc is dropped (i.e., when both the Inotify and the EventStream are dropped). This makes the Inotify::into_event_stream I added in #103 unnecessary, so I've gone ahead and deprecated it.

    Reply
  • `Eq` implementation of `WatchDescriptor` is wrong
    `Eq` implementation of `WatchDescriptor` is wrong

    Jul 26, 2017

    From Stack Overflow:

    As noted above, inotify watch descriptor values are scoped per parent inotify file descriptor. This makes the use of [derive(Eq)] on WatchDescriptor highly questionable. Looks like a straight-up bug.

    I haven't had the chance to look into the details myself so far, but this seems legit.

    bug 
    Reply
  • feat: Implement `EventStream` using `mio`
    feat: Implement `EventStream` using `mio`

    Jun 7, 2018

    This branch changes the implementation of Stream for EventStream to use mio and tokio_reactor to register interest in events on the Inotify file descriptor with the reactor, rather than using task::current().notify() to unpark the task in the executor when polling the fd would block.

    Since the reactor is intended to drive all IO resources (such as the inotify FD) and to be the bridge between tasks in the executor and events from the OS, using PollEvented is a more correct way to implement the stream.

    This branch shouldn't result in any noticeable changes in behaviour, but will hopefully allow tokio to manage Inotify's IO events more intelligently.

    Reply
  • feat: update to tokio 0.2 and futures 0.3
    feat: update to tokio 0.2 and futures 0.3

    Sep 18, 2019

    (Stability note: this feature depends on nightly rust and alpha releases of tokio 0.2 and futures 0.3. Maybe you want to hold off the merge until they are stable. In which case I will try to make sure that this PR is up to date.)

    This is a minimal and straightforward update to make inotify up to date with std::task, async-await syntax and next versions of tokio and futures.

    API changes

    • EventStream is now a futures 0.3 Stream

      A futures 0.3 Stream can be used with async-await directly (cc #121). See the stream example.

    • The buffer passed to the event_stream method is now required to be Unpin

    Other changes

    • Mandatory dependencies is minimized: only tokio-net, tokio-io and futures-core are mandatory dependencies. And for tokio-net unused features are disabled. The full tokio crate and futures-util are dev-dependencies.

    • The crate is updated to 2018 edition, so that related tests and examples can be written in async/await.

    • The CI config is modified to:

      • Run on nightly
      • Run with --no-default-features as well
    Reply
  • feat: support async polling via futures
    feat: support async polling via futures

    Feb 13, 2018

    Closes #49.


    No idea how idiomatic it is, but the test works :) .

    Reply