Idiomatic inotify wrapper for the Rust programming language

Overview

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.9"

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
  • feat: update to tokio 0.2 and futures 0.3

    feat: update to tokio 0.2 and futures 0.3

    (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
    opened by sopium 15
  • feat: Implement `EventStream` using `mio`

    feat: Implement `EventStream` using `mio`

    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.

    opened by hawkw 13
  • `Eq` implementation of `WatchDescriptor` is wrong

    `Eq` implementation of `WatchDescriptor` is wrong

    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 
    opened by hannobraun 12
  • refactor: Add FdGuard responsible for close-on-drop

    refactor: Add FdGuard responsible for close-on-drop

    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.

    opened by hawkw 10
  • Implement ToOwned for `Event<&'a OsStr>`

    Implement ToOwned for `Event<&'a OsStr>`

    I am using inotify with calloop and one issue I've noticed is the lack of ability to easily convert an event from the methods into an owned event to pass to calloop. Calloop gets kinda messy when an Event in an event source has a lifetime, so getting an owned copy is typically the best way around this issue.

    I noticed the presence of into_ownedthat is only available with the streams api, I think we could convert this to delegate to an implementation of ToOwned and made always available.

    enhancement status: blocked 
    opened by i509VCB 9
  • add: Hash trait for WatchDescriptor

    add: Hash trait for WatchDescriptor

    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.

    opened by arsalan86 8
  • Fixed deprecated syntax

    Fixed deprecated syntax

    [0, ..1024] syntax is now deprecated. Fixed using std::iter::repeat.

    I tried out Vec::with_capacity instead and passing buffer.capacity() instead of buffer.len() to get rid of initializing the vec with zeros, but got a failed assertion from slice.rs, so I guess the initialization is necessary.

    opened by Detegr 8
  • deriving traits for WatchDescriptor

    deriving traits for WatchDescriptor

    I've derived the Hash trait for WatchDescriptor, so it can be added to HashMaps and used for lookup.

    I ran into difficulties while implementing inotify-rs in a project that watches a large number of files. Not being able to match an inotify::Event to a file in a database is crippling for me.

    opened by arsalan86 7
  • Base API on futures-rs

    Base API on futures-rs

    The current API offers both synchronous and asynchronous operation, but it would be better to do that based on futures-rs. I've looked into it, but decided to hold off for the moment, until I had a chance to learn a bit more about futures-rs and experience it from a user's perspective (as opposed to that of a library author).

    enhancement 
    opened by hannobraun 7
  • Look into automatic changelog generation

    Look into automatic changelog generation

    I've heard of projects, for example Hyper, automatically generating changelogs from Git commits. I haven't looked into the details yet, but I understand that GitCop can be used to enforce the commit message format that's required for that.

    enhancement 
    opened by hannobraun 7
  • Allow asynchronous closing.

    Allow asynchronous closing.

    Alright, I'm by no means done, but I thought I'd give you a chance to weigh in earlier, rather than later.

    Changes

    • INotify is no longer cloneable. Therefore the API is essentially single-threaded, enforced by ownership semantics.
    • A new method closer() is introduced. Its return value enables asynchronous closing of the inotify fd.
      • To avoid any races, the actual closing is still done by whoever owns the corresponding INotify.
      • This only happens when wait_for_events() is called.
      • To allow wait_for_events() to react to asynchronous closing, it spins in an epoll loop with a smallish timeout.

    TODO

    • [ ] Look at available_events() wrt asynchronous closing. Currently it does not make sense, because the caller can't determine if the inotify fd was closed without calling a blocking method. Maybe expose the state?
    • [ ] Figure out a good epoll timeout (10ms seems a bit high).
    • [x] Go over all the unwrap() calls and figure out how to deal with the potential error conditions.
    • [ ] More tests
    • [ ] Documentation

    (ref #28)

    opened by benschulz 7
  • panic when call event_stream

    panic when call event_stream

    panic info:

       5: std::panicking::begin_panic
                 at ~/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:505:12
       6: tokio::io::driver::Handle::current
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.3.5/src/io/driver/mod.rs:277:13
       7: tokio::io::async_fd::AsyncFd<T>::with_interest
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.3.5/src/io/async_fd.rs:99:51
       8: tokio::io::async_fd::AsyncFd<T>::new
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.3.5/src/io/async_fd.rs:89:9
       9: inotify::stream::EventStream<T>::new
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/inotify-0.9.1/src/stream.rs:35:17
      10: inotify::inotify::Inotify::event_stream
                 at ~/.cargo/registry/src/github.com-1ecc6299db9ec823/inotify-0.9.1/src/inotify.rs:406:9
      11: controller::sync::Notifier::watch::{{closure}}
                 at ~/work/github/cita-cloud/controller_poc/src/sync.rs:128:26
    

    related source code:

            let mut inotify = Inotify::init().expect("Failed to initialize inotify");
    
            let root_path = Path::new(&self.root);
            let mut wds = Vec::new();
            for dir in SYNC_FOLDERS.iter() {
                let path = root_path.join(dir);
                let wd = inotify.add_watch(path, WatchMask::MOVED_TO).unwrap();
                wds.push(wd);
            }
    
            let mut buffer = vec![0u8; 4096];
            let mut stream = inotify.event_stream(&mut buffer).unwrap();
    
            while let Some(event_or_error) = stream.next().await {
    

    This happend when upgrade inotify to latest version (v0.9.1). After back to v0.8.3, it's ok.

    bug help wanted 
    opened by rink1969 1
  • Async await support

    Async await support

    (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.

    opened by sopium 6
  • Improve documentation of `Inotify::event_stream`

    Improve documentation of `Inotify::event_stream`

    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.

    help wanted good first issue 
    opened by hannobraun 0
  • Async/Await syntax support

    Async/Await syntax support

    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.

    opened by thedrow 2
  • Consider unifying traditional and future-based APIs

    Consider unifying traditional and future-based APIs

    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 develop. Feedback is very welcome!

    enhancement 
    opened by hannobraun 4
  • add a read_events_with_timeout()

    add a read_events_with_timeout()

    That would imply to use a select on the inotify's fd waiting for data in the fd or the timeout.

    The workaround would be to use the nix crate with Inotify's RawFD and do the select in the application.

    enhancement help wanted 
    opened by ceyusa 10
Owner
Hanno Braun
Self-employed software developer with a focus on embedded software development in Rust.
Hanno Braun
nginx bindings for Rust

nginx-rs This crate provides nginx bindings for Rust. Currently, only Linux is supported. How to Use Add nginx crate to Cargo.toml [dependencies] ngin

ArvanCloud 104 Jan 2, 2023
Rust bindings for iptables

Rust iptables This crate provides bindings for iptables application in Linux (inspired by go-iptables). This crate uses iptables binary to manipulate

Navid 63 Nov 17, 2022
Rust friendly bindings to *nix APIs

Rust bindings to *nix APIs Documentation (Releases) Nix seeks to provide friendly bindings to various *nix platform APIs (Linux, Darwin, ...). The goa

null 2k Jan 4, 2023
Rust library for filesystems in userspace (FUSE)

Rust FUSE - Filesystem in Userspace About fuse-rs is a Rust library crate for easy implementation of FUSE filesystems in userspace. fuse-rs does not j

Andreas Neuhaus 916 Jan 9, 2023
Rust bindings to Windows API

winapi-rs Documentation Official communication channel: #windows-dev on the Rust Community Discord This crate provides raw FFI bindings to all of Wind

Peter Atashian 1.6k Jan 1, 2023
Rust implementation of a FreeBSD jail library

libjail-rs libjail-rs aims to be a rust implementation of the FreeBSD jail(3) library. While feature parity is a goal, a one-to-one implementation of

fubarnetes 38 Sep 27, 2022
Rust bindings for the FreeBSD capsicum framework

capsicum Contain the awesome! Rust bindings for the FreeBSD capsicum framework for OS capability and sandboxing Prerequisites Rust, Cargo, and FreeBSD

Dan Robertson 52 Dec 5, 2022
Idiomatic inotify wrapper for the Rust programming language

inotify-rs Idiomatic inotify wrapper for the Rust programming language. extern crate inotify; use std::env; use inotify::{ EventMask, Watch

Hanno Braun 220 Dec 26, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
GLFW3 bindings and idiomatic wrapper for Rust.

glfw-rs GLFW bindings and wrapper for The Rust Programming Language. Example extern crate glfw; use glfw::{Action, Context, Key}; fn main() { le

PistonDevelopers 546 Jan 3, 2023
ODBC wrapper for safe idiomatic Rust

ODBC wrapper for safe idiomatic Rust Library for writing ODBC applications in Rust. If you're looking for raw ODBC FFI bindings check odbc-safe and od

Konstantin V. Salikhov 91 Dec 10, 2022
prelate-rs is an idiomatic, asynchronous Rust wrapper around the aoe4world API. Very much a WIP at this stage.

prelate-rs is an idiomatic, asynchronous Rust wrapper around the aoe4world API. Very much a WIP at this stage. Project Status We currently support the

William Findlay 4 Dec 29, 2022
An Interpreter for Brainfuck programming language implemented in the Rust programming language with zero dependencies.

Brainfuck Hello, Visitor! Hey there, welcome to my project showcase website! It's great to have you here. I hope you're ready to check out some awesom

Syed Vilayat Ali Rizvi 7 Mar 31, 2023
The Devils' Programming Language (Quantum Programming Language)

devilslang has roots in Scheme and ML-flavored languages: it's the culmination of everything I expect from a programming language, including the desire to keep everything as minimalistic and concise as possible. At its core, devilslang is lambda-calculus with pattern-matching, structural types, fiber-based concurrency, and syntactic extension.

Devils' Language 2 Aug 26, 2022
Idiomatic Rust bindings for OpenAL 1.1 and extensions (including EFX).

alto alto provides idiomatic Rust bindings for OpenAL 1.1 and extensions (including EFX). WARNING Because Alto interacts with global C state via dynam

null 80 Aug 7, 2022
Idiomatic, GTK+-based, GUI library, inspired by Elm, written in Rust

Relm Asynchronous, GTK+-based, GUI library, inspired by Elm, written in Rust. This library is in beta stage: it has not been thoroughly tested and its

null 2.2k Dec 31, 2022
A peer-reviewed collection of articles/talks/repos which teach concise, idiomatic Rust.

This repository collects resources for writing clean, idiomatic Rust code. Please bring your own. ?? Idiomatic coding means following the conventions

Matthias 4.2k Dec 30, 2022
Rust-idiomatic, compliant, flexible and performant BIP21 crate

Rust implementation of BIP21 Rust-idiomatic, compliant, flexible and performant BIP21 crate. About Important: while lot of work went into polishing th

Martin Habovštiak 6 Dec 15, 2022
Idiomatic Rust bindings for Pdfium

Idiomatic Rust bindings for Pdfium pdfium-render provides an idiomatic high-level Rust interface around the low-level bindings to Pdfium exposed by th

Alastair Carey 65 Jan 8, 2023
alto provides idiomatic Rust bindings for OpenAL 1.1 and extensions (including EFX).

alto alto provides idiomatic Rust bindings for OpenAL 1.1 and extensions (including EFX). WARNING Because Alto interacts with global C state via dynam

null 80 Aug 7, 2022