-
Notifications
You must be signed in to change notification settings - Fork 683
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add support for dirent related function #558
Conversation
src/dirent.rs
Outdated
} | ||
|
||
impl Dir { | ||
pub fn read(&mut self) -> Result<Option<&libc::dirent>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
borrowing mutually Dir is required here as the dirent reference might get overwritten by subsequent calls.
src/dirent.rs
Outdated
use errno; | ||
|
||
pub struct Dir { | ||
pub handle: *mut DIR, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this field should be public. Instead I'd propose implementing AsRawFd
and IntoRawFd
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe Into<*mut DIR>
because AsRawFd is for file descriptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, you're right. Into<*mut DIR>
is what you'd want to do.
There is also dirfd
which you could use to implement the *RawFd
traits if you wanted to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I currently leave it private as I have implemented all functions, where the dir pointer is useful. If it turns out, that I missed a use case, it can be still added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! While here, it seems like you should also add opendir(3)
. We'd also need something in the changelog.
However, I'm trying to decide on what the best way to expose this is. At one end, we could have fdopendir(3)
and opendir(3)
as here, and instead of Dir::read
, we have readdir
as a free function. At the other end, we expose readdir(3)
as an iterator. And somewhere in between is the approach here.
Cargo.toml
Outdated
@@ -21,7 +21,7 @@ preadv_pwritev = [] | |||
signalfd = [] | |||
|
|||
[dependencies] | |||
libc = { git = "https://github.com/rust-lang/libc" } | |||
libc = { git = "https://github.com/Mic92/libc", branch = "master" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will wait till this hits libc upstream.
src/dirent.rs
Outdated
_ => Err(Error::last().into()), | ||
} | ||
} else { | ||
Ok(Some(unsafe{&*dirent})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you annotate the lifetime in the signature so we're sure that this reference has the correct lifetime:
pub fn read<'a>(&'a mut self) -> Result<Option<&'a libc::dirent>>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched back to readdir
1eb7cb7
to
e498677
Compare
added seekdir/telldir |
81ffa22
to
3ca111b
Compare
src/dirent.rs
Outdated
}; | ||
if dirent.is_null() { | ||
match Errno::last() { | ||
errno::UnknownErrno => Ok(None), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this right? It seems that on error, -1
is returned, not NULL
. NULL
indicates end of stream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from readdir(3):
If the end of the directory stream is reached, NULL is returned and
errno is not changed. If an error occurs, NULL is returned and errno
is set appropriately. To distinguish end of stream and from an error,
set errno to zero before calling readdir() and then check the value of
errno if NULL is returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right you are! I must have had one of the other functions' man pages open.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks ofr the update! If you're adding the whole family, could you also include closedir(3)
, rewinddir(3)
, scandir(3)
, and dirfd(3)
? Either that or update the commit message.
It would also make sense to implement AsRawFd
and IntoRawFd
for Dir
using dirfd(3)
, but I'm happy to have that in a later PR.
Ah just noted that @Susurrus had mentioned |
I would leave adding the other functions open to someone else, as I currently only add functions, I need to proceed my project. |
@Mic92 that's fair. Could you look at the CI failures? They seem legitimate. |
Order of |
d22cfb1
to
0cad72e
Compare
src/dirent.rs
Outdated
} | ||
} | ||
|
||
pub fn readdir<'a>(dir: &'a mut Dir) -> Result<Option<&'a libc::dirent>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To obtain d_name
I use:
let name = OsStr::from_bytes(unsafe {
&mem::transmute::<[i8; 256], [u8; 256]>(entry.d_name)
});
any idea how I could how add a convenience wrapper to this library?
This is ready for review. |
☔ The latest upstream changes (presumably #536) made this pull request unmergeable. Please resolve the merge conflicts. |
☔ The latest upstream changes (presumably ba5c837) made this pull request unmergeable. Please resolve the merge conflicts. |
@Mic92 Can you add comments for every function based on their man pages? We're trying to have complete documentation coverage for all PRs moving forward. You can see where things are lacking when you run |
src/dirent.rs
Outdated
#[cfg(not(any(target_os = "ios", target_os = "macos")))] | ||
use std::os::unix::io::RawFd; | ||
|
||
pub struct Dir(*mut DIR); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe name this DirStream
so it's a little more clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer Dir
as it it closer to the underlying API and matches the function names better, which all end in dir.
39cc8fd
to
338d169
Compare
depends on rust-lang/libc#647 |
test/test_dirent.rs
Outdated
use std::path::Path; | ||
use tempdir::TempDir; | ||
|
||
fn test_readdir<OPEN>(open_fn: OPEN) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use all-caps here for a type name. Maybe just use O
.
test/test_dirent.rs
Outdated
assert_eq!(letter1, '.' as u8); | ||
|
||
let pos = telldir(&mut dir); | ||
seekdir(&mut dir, pos); // no-op |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we have a test where we seek back a directory and check that the same directory is read twice (so that we no seekdir
worked? I'd like to have a non-nop test of it.
} | ||
} | ||
|
||
/// Opens a directory stream corresponding to the directory name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you run cargo doc --no-deps --open
locally with this code and make sure the first sentence shows up nicely on the page listing all the functions here? I'm certain that some of these sentences are too long and that you need an empty ///
on the next line to make them show up nicely.
src/dirent.rs
Outdated
} | ||
|
||
/// Inode number | ||
pub fn ino(&self) -> libc::ino_t { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to call this inode
here for a little more clarity?
#[cfg(not(any(target_os = "ios", target_os = "macos")))] | ||
use std::os::unix::io::RawFd; | ||
|
||
/// Directory Stream object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we call this DirectoryStream
or DirStream
instead of Dir
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also renamed Dirent
to DirectoryEntry
for consistency.
This is looking pretty good. Mostly some minor changes here. I would love to have more comprehensive module documentation, but I think linking to the man pages should be fine. |
8aa9e48
to
6ed79b0
Compare
/// Consumes directory stream and return underlying directory pointer. | ||
/// | ||
/// The pointer must be deallocated manually using `libc::closedir` | ||
impl Into<*mut DIR> for DirectoryStream { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A convention in std
is to use a method named into_raw
here when you're unwrapping a type. I'd suggest using that here instead of Into<*mut DIR>
. I don't see this used anywhere, however. Can you either remove it if it's unnecessary, or if it's necessary add it to the test or use it in an example.
/// | ||
/// The `loc` argument should be a value returned by a previous call to `telldir` | ||
#[cfg(not(any(target_os = "android")))] | ||
pub fn seekdir<'a>(dir: &'a mut DirectoryStream, loc: c_long) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking a newtype around c_long
for use as the return value of telldir
and the 2nd argument of seekdir
would be good, since that's an invariant that should be embedded in the type system. I can't think of a good name for it, hopefully you can, but I think we should definitely do it.
src/dirent.rs
Outdated
} | ||
} | ||
|
||
/// Like `opendir()`, but returns a directory stream for the directory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make the first line all one line. You can go out to 99 characters with your comments.
test/test_dirent.rs
Outdated
.unwrap() | ||
.name() | ||
.to_bytes()[0]; | ||
assert_eq!(letter3, '.' as u8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be more clear if you compared letter2
and letter3
directly if that's what should be happening here.
|
||
fn test_readdir<Open>(open_fn: Open) | ||
where Open: Fn(&Path) -> DirectoryStream | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check the full name of the directory? It's confusing that you're checking just the first character of the filename. It'd also be helpful if you created a directory in the tempdir you made so you have 3 directories, then you iterate through all of them checking their names, and then seek back to check that seeking works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no guarantee on the order of directory entries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think it's worth checking their names, we can treat it as a set, where the order doesn't matter but the contents should still be the same. We'd expect to encounter both "." and "..", but we aren't certain of the order, but that's fine, we can still do that check.
Just saw you comment about the order of |
db5380b
to
1c570ea
Compare
@Mic92 I'd still like to get this merged, can you resolve the lingering issues and rebase this? |
Next week - this week I am on holiday. Maybe CHANGELOG.md should not be modified by pull requests at all. It creates to much merge conflicts and could be easily added from the pull request description after a merge. |
ce662b6
to
6035dd8
Compare
Can you restart the one failing test? Looks like a transient failure: https://travis-ci.org/nix-rust/nix/builds/270775924 |
offending test restarted |
if somebody is interested in |
Looks like there are legitimate test failures here. @Mic92 Are you interested in pushing this PR through to be merged? Based on your last comment, it sounds like you aren't interested in continuing to work on this PR. Is that correct? |
Yes. |
This pr is currently work in progress, as it depends on an outstanding pull request for fdopendir in libc. I wanted to know if this function and DIR wrapper I added fit into the scope of the nix crate.