Repository: hannobraun/inotify-rs (language: rust)

Issue:
Build failure
Using `rustc 1.0.0-nightly (ea6f65c5f 2015-01-06 19:47:08 +0000)`, it fails to build:

``` sh
skyler at skyler-0345 in ~/src/rust/inotify-rs (master)
$ cargo build
   Compiling inotify v0.1.1 (file:///Users/skyler/src/rust/inotify-rs)
/Users/skyler/src/rust/inotify-rs/src/wrapper.rs:20:2: 20:9 error: unresolved import `std::c_str::CString`. Could not find `c_str` in `std`
/Users/skyler/src/rust/inotify-rs/src/wrapper.rs:20     CString,
                                                        ^~~~~~~
/Users/skyler/src/rust/inotify-rs/src/wrapper.rs:21:2: 21:8 error: unresolved import `std::c_str::ToCStr`. Could not find `c_str` in `std`
/Users/skyler/src/rust/inotify-rs/src/wrapper.rs:21     ToCStr,
                                                        ^~~~~~
error: aborting due to 2 previous errors
Could not compile `inotify`.

To learn more, run the command again with --verbose.
```



Discussion / hints:
Looks like the failure was caused by this change: https://github.com/rust-lang/rust/pull/20507

Thanks for reporting! I'll fix it on Monday. In the meantime, pull requests are very welcome.


Fix patch:
diff --git a/.gitignore b/.gitignore
index 577f31d..9ba8e7f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 /Cargo.lock
 /target
 *.sublime-workspace
+*.swp
diff --git a/src/ffi.rs b/src/ffi.rs
index 5e44142..8034ee9 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -31,9 +31,9 @@
 //! [inotify(7)]: http://man7.org/linux/man-pages/man7/inotify.7.html
 
 use libc::{
-	c_char,
-	c_int,
-	uint32_t };
+    c_char,
+    c_int,
+    uint32_t };
 
 
 pub use libc::close;
@@ -185,9 +185,9 @@ pub const IN_CLOSE: uint32_t = (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE);
 
 /// Event: Any event occured.
 pub const IN_ALL_EVENTS: uint32_t = (
-	IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_CLOSE_NOWRITE
-	| IN_OPEN | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE
-	| IN_DELETE_SELF | IN_MOVE_SELF);
+    IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | IN_CLOSE_NOWRITE
+    | IN_OPEN | IN_MOVED_FROM | IN_MOVED_TO | IN_CREATE | IN_DELETE
+    | IN_DELETE_SELF | IN_MOVE_SELF);
 
 /// Option: Don't watch children (if self is a directory).
 pub const IN_ONLYDIR    : uint32_t = 0x01000000;
@@ -257,64 +257,64 @@ pub const IN_IGNORED   : uint32_t = 0x00008000;
 /// [read(2)]: http://man7.org/linux/man-pages/man2/read.2.html
 /// [signal(7)]: http://man7.org/linux/man-pages/man2/read.2.html
 #[allow(non_camel_case_types)]
-#[allow(raw_pointer_deriving)]
+#[allow(raw_pointer_derive)]
 #[derive(Copy, Show)]
 pub struct inotify_event {
-	/// Identifies the watch for which this event occurs.
-	///
-	/// It is one of the watch descriptors returned by a previous call
-	/// to `inotify_add_watch()`.
-	pub wd    : c_int,
-
-	/// Contains bits that describe the event that occurred.
-	pub mask  : uint32_t,
-
-	/// A unique integer that connects related events.
-	///
-	/// Currently used only for rename events. A related pair of
-	/// IN_MOVED_FROM and IN_MOVED_TO events will have the same,
-	/// non-zero, cookie. For all other events, cookie is 0.
-	pub cookie: uint32_t,
-
-	/// The length of `name`.
-	///
-	/// Used to determine the size of this structure. When `name`
-	/// isn't present (`name` is only present when an event occurs
-	/// for a file inside a watched directory), it is 0. When `name`
-	/// *is* present, it counts all of `name`'s bytes, including `\0`.
-	///
-	/// > The `name` field is present only when an event is returned for
-	/// > a file inside a watched directory; it identifies the file
-	/// > pathname relative to the watched directory. This pathname is
-	/// > null-terminated, and may include further null bytes ('\0') to
-	/// > align subsequent reads to a suitable address boundary.
-	///
-	/// The `name` field must be ommited in this definition.
-	pub len   : uint32_t,
+    /// Identifies the watch for which this event occurs.
+    ///
+    /// It is one of the watch descriptors returned by a previous call
+    /// to `inotify_add_watch()`.
+    pub wd    : c_int,
+
+    /// Contains bits that describe the event that occurred.
+    pub mask  : uint32_t,
+
+    /// A unique integer that connects related events.
+    ///
+    /// Currently used only for rename events. A related pair of
+    /// IN_MOVED_FROM and IN_MOVED_TO events will have the same,
+    /// non-zero, cookie. For all other events, cookie is 0.
+    pub cookie: uint32_t,
+
+    /// The length of `name`.
+    ///
+    /// Used to determine the size of this structure. When `name`
+    /// isn't present (`name` is only present when an event occurs
+    /// for a file inside a watched directory), it is 0. When `name`
+    /// *is* present, it counts all of `name`'s bytes, including `\0`.
+    ///
+    /// > The `name` field is present only when an event is returned for
+    /// > a file inside a watched directory; it identifies the file
+    /// > pathname relative to the watched directory. This pathname is
+    /// > null-terminated, and may include further null bytes ('\0') to
+    /// > align subsequent reads to a suitable address boundary.
+    ///
+    /// The `name` field must be ommited in this definition.
+    pub len   : uint32_t,
 }
 
 
 extern {
-	/// Creates an inotify instance.
-	///
-	/// Returns a file descriptor referring to the inotify instance.
-	pub fn inotify_init() -> c_int;
-
-	/// Creates an inotify instance.
-	///
-	/// Also takes a bit mask of flags that provide access to extra
-	/// functionality. Returns a file descriptor.
-	pub fn inotify_init1(flags: c_int) -> c_int;
-
-	/// Manipulates the "watch list" associated with an inotify instance.
-	///
-	/// > Each item ("watch") in the watch list specifies the pathname of
-	/// > a file or directory, along with some set of events that the kernel
-	/// > should monitor for the file referred to by that pathname.
-	///
-	/// This function either creates a new watch, or modifies an existing one.
-	pub fn inotify_add_watch(fd: c_int, pathname: *const c_char, mask: uint32_t) -> c_int;
-
-	/// Removes an item from an inotify watch list.
-	pub fn inotify_rm_watch(fd: c_int, wd: c_int) -> c_int;
+    /// Creates an inotify instance.
+    ///
+    /// Returns a file descriptor referring to the inotify instance.
+    pub fn inotify_init() -> c_int;
+
+    /// Creates an inotify instance.
+    ///
+    /// Also takes a bit mask of flags that provide access to extra
+    /// functionality. Returns a file descriptor.
+    pub fn inotify_init1(flags: c_int) -> c_int;
+
+    /// Manipulates the "watch list" associated with an inotify instance.
+    ///
+    /// > Each item ("watch") in the watch list specifies the pathname of
+    /// > a file or directory, along with some set of events that the kernel
+    /// > should monitor for the file referred to by that pathname.
+    ///
+    /// This function either creates a new watch, or modifies an existing one.
+    pub fn inotify_add_watch(fd: c_int, pathname: *const c_char, mask: uint32_t) -> c_int;
+
+    /// Removes an item from an inotify watch list.
+    pub fn inotify_rm_watch(fd: c_int, wd: c_int) -> c_int;
 }
diff --git a/src/lib.rs b/src/lib.rs
index 75889f0..0172fba 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,6 +20,7 @@
 //! [wiki]: https://en.wikipedia.org/wiki/Inotify
 //! [inotify7]: http://man7.org/linux/man-pages/man7/inotify.7.html
 
+#[allow(unstable)]
 extern crate libc;
 
 pub use wrapper::INotify;
diff --git a/src/wrapper.rs b/src/wrapper.rs
index 71020e0..7db6f16 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -4,29 +4,28 @@
 //! Idiomatic wrapper for inotify
 
 use libc::{
-	EAGAIN,
-	EWOULDBLOCK,
-	F_GETFL,
-	F_SETFL,
-	O_NONBLOCK,
-	fcntl,
-	c_char,
-	c_int,
-	c_void,
-	size_t,
-	ssize_t
+    EAGAIN,
+    EWOULDBLOCK,
+    F_GETFL,
+    F_SETFL,
+    O_NONBLOCK,
+    fcntl,
+    c_int,
+    c_void,
+    size_t,
+    ssize_t
 };
-use std::c_str::{
-	CString,
-	ToCStr,
+use std::ffi::{
+    CString,
 };
 use std::mem;
 use std::io::{
-	EndOfFile,
-	IoError,
-	IoResult
+    EndOfFile,
+    IoError,
+    IoResult
 };
 use std::os::errno;
+use std::path::BytesContainer;
 
 use ffi;
 use ffi::inotify_event;
@@ -36,236 +35,235 @@ pub type Watch = c_int;
 
 #[derive(Clone)]
 pub struct INotify {
-	pub fd: c_int,
-	events: Vec<Event>,
+    pub fd: c_int,
+    events: Vec<Event>,
 }
 
 impl INotify {
-	pub fn init() -> IoResult<INotify> {
-		INotify::init_with_flags(0)
-	}
-
-	pub fn init_with_flags(flags: int) -> IoResult<INotify> {
-		let fd = unsafe { ffi::inotify_init1(flags as c_int) };
-
-		unsafe { fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) };
-
-		match fd {
-			-1 => Err(IoError::last_error()),
-			_  => Ok(INotify {
-				fd    : fd,
-				events: Vec::new(),
-			})
-		}
-	}
-
-	pub fn add_watch(&self, path: &Path, mask: u32) -> IoResult<Watch> {
-		let wd = unsafe {
-			ffi::inotify_add_watch(
-				self.fd,
-				path.to_c_str().into_inner(),
-				mask)
-		};
-
-		match wd {
-			-1 => Err(IoError::last_error()),
-			_  => Ok(wd)
-		}
-	}
-
-	pub fn rm_watch(&self, watch: Watch) -> IoResult<()> {
-		let result = unsafe { ffi::inotify_rm_watch(self.fd, watch) };
-		match result {
-			0  => Ok(()),
-			-1 => Err(IoError::last_error()),
-			_  => panic!(
-				"unexpected return code from inotify_rm_watch ({})", result)
-		}
-	}
-
-	/// Wait until events are available, then return them.
-	/// This function will block until events are available. If you want it to
-	/// return immediately, use `available_events`.
-	pub fn wait_for_events(&mut self) -> IoResult<&[Event]> {
-		let fd = self.fd;
-
-		unsafe {
-			fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & !O_NONBLOCK)
-		};
-		let result = self.available_events();
-		unsafe {
-			fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
-		};
-
-		result
-	}
-
-	/// Returns available inotify events.
-	/// If no events are available, this method will simply return a slice with
-	/// zero events. If you want to wait for events to become available, call
-	/// `wait_for_events`.
-	pub fn available_events(&mut self) -> IoResult<&[Event]> {
-		self.events.clear();
-
-		let mut buffer = [0u8; 1024];
-		let len = unsafe {
-			ffi::read(
-				self.fd,
-				buffer.as_mut_ptr() as *mut c_void,
-				buffer.len() as size_t
-			)
-		};
-
-		match len {
-			0 =>
-				return Err(IoError {
-					kind  : EndOfFile,
-					desc  : "end of file",
-					detail: None
-				}),
-			-1 => {
-				let error = errno();
-				if error == EAGAIN as uint || error == EWOULDBLOCK as uint {
-					return Ok(self.events.as_slice());
-				}
-				else {
-					return Err(IoError::from_errno(error, true));
-				}
-			},
-			_ =>
-				()
-		}
-
-		let event_size = mem::size_of::<inotify_event>();
-
-		let mut i = 0;
-		while i < len {
-			unsafe {
-				let slice = buffer.slice_from(i as uint);
-
-				let event = slice.as_ptr() as *const inotify_event;
-
-				let name = if (*event).len > 0 {
-					let c_str = CString::new(
-						event.offset(1) as *const c_char,
-						false);
-
-					match c_str.as_str() {
-						Some(string)
-							=> string.to_string(),
-						None =>
-							panic!("Failed to convert C string into Rust string")
-					}
-				}
-				else {
-					"".to_string()
-				};
-
-				self.events.push(Event::new(&*event, name));
-
-				i += (event_size + (*event).len as uint) as ssize_t;
-			}
-		}
-
-		Ok(self.events.as_slice())
-	}
-
-	pub fn close(&self) -> IoResult<()> {
-		let result = unsafe { ffi::close(self.fd) };
-		match result {
-			0 => Ok(()),
-			_ => Err(IoError::last_error())
-		}
-	}
+    pub fn init() -> IoResult<INotify> {
+        INotify::init_with_flags(0)
+    }
+
+    pub fn init_with_flags(flags: isize) -> IoResult<INotify> {
+        let fd = unsafe { ffi::inotify_init1(flags as c_int) };
+
+        unsafe { fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) };
+
+        match fd {
+            -1 => Err(IoError::last_error()),
+            _  => Ok(INotify {
+                fd    : fd,
+                events: Vec::new(),
+            })
+        }
+    }
+
+    pub fn add_watch(&self, path: &Path, mask: u32) -> IoResult<Watch> {
+        let wd = unsafe {
+            let path_c_str = CString::from_slice(path.container_as_bytes());
+            ffi::inotify_add_watch(
+                self.fd,
+                path_c_str.as_ptr(),
+                mask)
+        };
+
+        match wd {
+            -1 => Err(IoError::last_error()),
+            _  => Ok(wd)
+        }
+    }
+
+    pub fn rm_watch(&self, watch: Watch) -> IoResult<()> {
+        let result = unsafe { ffi::inotify_rm_watch(self.fd, watch) };
+        match result {
+            0  => Ok(()),
+            -1 => Err(IoError::last_error()),
+            _  => panic!(
+                "unexpected return code from inotify_rm_watch ({})", result)
+        }
+    }
+
+    /// Wait until events are available, then return them.
+    /// This function will block until events are available. If you want it to
+    /// return immediately, use `available_events`.
+    pub fn wait_for_events(&mut self) -> IoResult<&[Event]> {
+        let fd = self.fd;
+
+        unsafe {
+            fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & !O_NONBLOCK)
+        };
+        let result = self.available_events();
+        unsafe {
+            fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
+        };
+
+        result
+    }
+
+    /// Returns available inotify events.
+    /// If no events are available, this method will simply return a slice with
+    /// zero events. If you want to wait for events to become available, call
+    /// `wait_for_events`.
+    pub fn available_events(&mut self) -> IoResult<&[Event]> {
+        self.events.clear();
+
+        let mut buffer = [0u8; 1024];
+        let len = unsafe {
+            ffi::read(
+                self.fd,
+                buffer.as_mut_ptr() as *mut c_void,
+                buffer.len() as size_t
+            )
+        };
+
+        match len {
+            0 =>
+                return Err(IoError {
+                    kind  : EndOfFile,
+                    desc  : "end of file",
+                    detail: None
+                }),
+            -1 => {
+                let error = errno();
+                if error == EAGAIN as usize || error == EWOULDBLOCK as usize {
+                    return Ok(&self.events[]);
+                }
+                else {
+                    return Err(IoError::from_errno(error, true));
+                }
+            },
+            _ =>
+                ()
+        }
+
+        let event_size = mem::size_of::<inotify_event>();
+
+        let mut i = 0;
+        while i < len {
+            unsafe {
+                let slice = &buffer[i as usize..];
+
+                let event = slice.as_ptr() as *const inotify_event;
+
+                let name = if (*event).len > 0 {
+                    let c_str = CString::from_slice(slice);
+
+                    match c_str.container_as_str() {
+                        Some(string)
+                            => string.to_string(),
+                        None =>
+                            panic!("Failed to convert C string into Rust string")
+                    }
+                }
+                else {
+                    "".to_string()
+                };
+
+                self.events.push(Event::new(&*event, name));
+
+                i += (event_size + (*event).len as usize) as ssize_t;
+            }
+        }
+
+        Ok(&self.events[])
+    }
+
+    pub fn close(&self) -> IoResult<()> {
+        let result = unsafe { ffi::close(self.fd) };
+        match result {
+            0 => Ok(()),
+            _ => Err(IoError::last_error())
+        }
+    }
 }
 
 #[derive(Clone, Show)]
 pub struct Event {
-	pub wd    : i32,
-	pub mask  : u32,
-	pub cookie: u32,
-	pub name  : String,
+    pub wd    : i32,
+    pub mask  : u32,
+    pub cookie: u32,
+    pub name  : String,
 }
 
 impl Event {
-	fn new(event: &inotify_event, name: String) -> Event {
-		Event {
-			wd    : event.wd,
-			mask  : event.mask,
-			cookie: event.cookie,
-			name  : name,
-		}
-	}
-
-	pub fn is_access(&self) -> bool {
-		return self.mask & ffi::IN_ACCESS > 0;
-	}
-
-	pub fn is_modify(&self) -> bool {
-		return self.mask & ffi::IN_MODIFY > 0;
-	}
-
-	pub fn is_attrib(&self) -> bool {
-		return self.mask & ffi::IN_ATTRIB > 0;
-	}
-
-	pub fn is_close_write(&self) -> bool {
-		return self.mask & ffi::IN_CLOSE_WRITE > 0;
-	}
-
-	pub fn is_close_nowrite(&self) -> bool {
-		return self.mask & ffi::IN_CLOSE_NOWRITE > 0;
-	}
-
-	pub fn is_open(&self) -> bool {
-		return self.mask & ffi::IN_OPEN > 0;
-	}
-
-	pub fn is_moved_from(&self) -> bool {
-		return self.mask & ffi::IN_MOVED_FROM > 0;
-	}
-
-	pub fn is_moved_to(&self) -> bool {
-		return self.mask & ffi::IN_MOVED_TO > 0;
-	}
-
-	pub fn is_create(&self) -> bool {
-		return self.mask & ffi::IN_CREATE > 0;
-	}
-
-	pub fn is_delete(&self) -> bool {
-		return self.mask & ffi::IN_DELETE > 0;
-	}
-
-	pub fn is_delete_self(&self) -> bool {
-		return self.mask & ffi::IN_DELETE_SELF > 0;
-	}
-
-	pub fn is_move_self(&self) -> bool {
-		return self.mask & ffi::IN_MOVE_SELF > 0;
-	}
-
-	pub fn is_move(&self) -> bool {
-		return self.mask & ffi::IN_MOVE > 0;
-	}
-
-	pub fn is_close(&self) -> bool {
-		return self.mask & ffi::IN_CLOSE > 0;
-	}
-
-	pub fn is_dir(&self) -> bool {
-		return self.mask & ffi::IN_ISDIR > 0;
-	}
-
-	pub fn is_unmount(&self) -> bool {
-		return self.mask & ffi::IN_UNMOUNT > 0;
-	}
-
-	pub fn is_queue_overflow(&self) -> bool {
-		return self.mask & ffi::IN_Q_OVERFLOW > 0;
-	}
-
-	pub fn is_ignored(&self) -> bool {
-		return self.mask & ffi::IN_IGNORED > 0;
-	}
+    fn new(event: &inotify_event, name: String) -> Event {
+        Event {
+            wd    : event.wd,
+            mask  : event.mask,
+            cookie: event.cookie,
+            name  : name,
+        }
+    }
+
+    pub fn is_access(&self) -> bool {
+        return self.mask & ffi::IN_ACCESS > 0;
+    }
+
+    pub fn is_modify(&self) -> bool {
+        return self.mask & ffi::IN_MODIFY > 0;
+    }
+
+    pub fn is_attrib(&self) -> bool {
+        return self.mask & ffi::IN_ATTRIB > 0;
+    }
+
+    pub fn is_close_write(&self) -> bool {
+        return self.mask & ffi::IN_CLOSE_WRITE > 0;
+    }
+
+    pub fn is_close_nowrite(&self) -> bool {
+        return self.mask & ffi::IN_CLOSE_NOWRITE > 0;
+    }
+
+    pub fn is_open(&self) -> bool {
+        return self.mask & ffi::IN_OPEN > 0;
+    }
+
+    pub fn is_moved_from(&self) -> bool {
+        return self.mask & ffi::IN_MOVED_FROM > 0;
+    }
+
+    pub fn is_moved_to(&self) -> bool {
+        return self.mask & ffi::IN_MOVED_TO > 0;
+    }
+
+    pub fn is_create(&self) -> bool {
+        return self.mask & ffi::IN_CREATE > 0;
+    }
+
+    pub fn is_delete(&self) -> bool {
+        return self.mask & ffi::IN_DELETE > 0;
+    }
+
+    pub fn is_delete_self(&self) -> bool {
+        return self.mask & ffi::IN_DELETE_SELF > 0;
+    }
+
+    pub fn is_move_self(&self) -> bool {
+        return self.mask & ffi::IN_MOVE_SELF > 0;
+    }
+
+    pub fn is_move(&self) -> bool {
+        return self.mask & ffi::IN_MOVE > 0;
+    }
+
+    pub fn is_close(&self) -> bool {
+        return self.mask & ffi::IN_CLOSE > 0;
+    }
+
+    pub fn is_dir(&self) -> bool {
+        return self.mask & ffi::IN_ISDIR > 0;
+    }
+
+    pub fn is_unmount(&self) -> bool {
+        return self.mask & ffi::IN_UNMOUNT > 0;
+    }
+
+    pub fn is_queue_overflow(&self) -> bool {
+        return self.mask & ffi::IN_Q_OVERFLOW > 0;
+    }
+
+    pub fn is_ignored(&self) -> bool {
+        return self.mask & ffi::IN_IGNORED > 0;
+    }
 }


Test patch: