Skip to content

add support for dirent related function#558

Closed
Mic92 wants to merge 1 commit into
nix-rust:masterfrom
Mic92:fdopendir
Closed

add support for dirent related function#558
Mic92 wants to merge 1 commit into
nix-rust:masterfrom
Mic92:fdopendir

Conversation

@Mic92

@Mic92 Mic92 commented Mar 17, 2017

Copy link
Copy Markdown
Contributor

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.

Comment thread src/dirent.rs Outdated
}

impl Dir {
pub fn read(&mut self) -> Result<Option<&libc::dirent>> {

@Mic92 Mic92 Mar 17, 2017

Copy link
Copy Markdown
Contributor Author

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.

Comment thread src/dirent.rs Outdated
use errno;

pub struct Dir {
pub handle: *mut DIR,

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Contributor Author

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.

@kamalmarhubi kamalmarhubi left a comment

Copy link
Copy Markdown
Member

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.

Thoughts @fiveop @posborne?

Comment thread Cargo.toml Outdated

[dependencies]
libc = { git = "https://github.com/rust-lang/libc" }
libc = { git = "https://github.com/Mic92/libc", branch = "master" }

Copy link
Copy Markdown
Member

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.

Comment thread src/dirent.rs Outdated
_ => Err(Error::last().into()),
}
} else {
Ok(Some(unsafe{&*dirent}))

Copy link
Copy Markdown
Member

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

Copy link
Copy Markdown
Contributor Author

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

@Mic92
Mic92 force-pushed the fdopendir branch 3 times, most recently from 1eb7cb7 to e498677 Compare March 20, 2017 12:42
@Mic92

Mic92 commented Mar 20, 2017

Copy link
Copy Markdown
Contributor Author

added seekdir/telldir

@Mic92
Mic92 force-pushed the fdopendir branch 2 times, most recently from 81ffa22 to 3ca111b Compare March 20, 2017 13:30
Comment thread src/dirent.rs
};
if dirent.is_null() {
match Errno::last() {
errno::UnknownErrno => Ok(None),

@kamalmarhubi kamalmarhubi Mar 20, 2017

Copy link
Copy Markdown
Member

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.

Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Member

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.

@kamalmarhubi kamalmarhubi left a comment

Copy link
Copy Markdown
Member

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.

@kamalmarhubi

Copy link
Copy Markdown
Member

Ah just noted that @Susurrus had mentioned {As,Into}RawFd already. Oh and there's also the changelog entry! :-)

@Mic92 Mic92 changed the title add support for fdopendir add support for dirent related function Mar 20, 2017
@Mic92

Mic92 commented Mar 20, 2017

Copy link
Copy Markdown
Contributor Author

I would leave adding the other functions open to someone else, as I currently only add functions, I need to proceed my project.

@kamalmarhubi

Copy link
Copy Markdown
Member

@Mic92 that's fair. Could you look at the CI failures? They seem legitimate.

@Mic92

Mic92 commented Mar 20, 2017

Copy link
Copy Markdown
Contributor Author

Order of .. and . seems to differ depending on platform

@Mic92
Mic92 force-pushed the fdopendir branch 6 times, most recently from d22cfb1 to 0cad72e Compare March 21, 2017 00:35
Comment thread src/dirent.rs Outdated
}
}

pub fn readdir<'a>(dir: &'a mut Dir) -> Result<Option<&'a libc::dirent>> {

Copy link
Copy Markdown
Contributor Author

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?

@Mic92

Mic92 commented Apr 8, 2017

Copy link
Copy Markdown
Contributor Author

This is ready for review.

@homu

homu commented Apr 15, 2017

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably #536) made this pull request unmergeable. Please resolve the merge conflicts.

@homu

homu commented May 17, 2017

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably ba5c837) made this pull request unmergeable. Please resolve the merge conflicts.

@Susurrus

Copy link
Copy Markdown
Contributor

@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 cargo doc --no-deps --open

Comment thread src/dirent.rs Outdated
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
use std::os::unix::io::RawFd;

pub struct Dir(*mut DIR);

Copy link
Copy Markdown
Contributor

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?

@Mic92 Mic92 Jul 6, 2017

Copy link
Copy Markdown
Contributor Author

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.

@Mic92
Mic92 force-pushed the fdopendir branch 2 times, most recently from 39cc8fd to 338d169 Compare July 6, 2017 23:58
@Mic92

Mic92 commented Jul 7, 2017

Copy link
Copy Markdown
Contributor Author

depends on rust-lang/libc#647

Comment thread test/test_dirent.rs Outdated
use std::path::Path;
use tempdir::TempDir;

fn test_readdir<OPEN>(open_fn: OPEN)

Copy link
Copy Markdown
Contributor

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.

Comment thread test/test_dirent.rs Outdated
assert_eq!(letter1, '.' as u8);

let pos = telldir(&mut dir);
seekdir(&mut dir, pos); // no-op

Copy link
Copy Markdown
Contributor

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.

Comment thread src/dirent.rs
}
}

/// Opens a directory stream corresponding to the directory name.

Copy link
Copy Markdown
Contributor

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.

Comment thread src/dirent.rs Outdated
}

/// Inode number
pub fn ino(&self) -> libc::ino_t {

Copy link
Copy Markdown
Contributor

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?

Comment thread src/dirent.rs
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
use std::os::unix::io::RawFd;

/// Directory Stream object

Copy link
Copy Markdown
Contributor

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?

Copy link
Copy Markdown
Contributor Author

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.

@Susurrus

Susurrus commented Jul 7, 2017

Copy link
Copy Markdown
Contributor

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.

@Mic92
Mic92 force-pushed the fdopendir branch 2 times, most recently from 8aa9e48 to 6ed79b0 Compare July 7, 2017 07:16
Comment thread src/dirent.rs
/// Consumes directory stream and return underlying directory pointer.
///
/// The pointer must be deallocated manually using `libc::closedir`
impl Into<*mut DIR> for DirectoryStream {

Copy link
Copy Markdown
Contributor

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.

Comment thread src/dirent.rs
///
/// 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) {

Copy link
Copy Markdown
Contributor

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.

Comment thread src/dirent.rs Outdated
}
}

/// Like `opendir()`, but returns a directory stream for the directory

Copy link
Copy Markdown
Contributor

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.

Comment thread test/test_dirent.rs Outdated
.unwrap()
.name()
.to_bytes()[0];
assert_eq!(letter3, '.' as u8);

Copy link
Copy Markdown
Contributor

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.

Comment thread test/test_dirent.rs

fn test_readdir<Open>(open_fn: Open)
where Open: Fn(&Path) -> DirectoryStream
{

Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Contributor

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.

@Susurrus

Susurrus commented Jul 7, 2017

Copy link
Copy Markdown
Contributor

Just saw you comment about the order of . and .. varying depending on platform. I do know many platforms don't guarantee returning things in alphabetical order. Maybe you should iterate through all the directories collecting their names into a sorted list and then compare that?

@Mic92
Mic92 force-pushed the fdopendir branch 4 times, most recently from db5380b to 1c570ea Compare July 7, 2017 21:28
@Susurrus

Copy link
Copy Markdown
Contributor

@Mic92 I'd still like to get this merged, can you resolve the lingering issues and rebase this?

@Mic92

Mic92 commented Aug 18, 2017

Copy link
Copy Markdown
Contributor Author

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.

@Mic92
Mic92 force-pushed the fdopendir branch 2 times, most recently from ce662b6 to 6035dd8 Compare September 1, 2017 10:28
@Mic92 Mic92 changed the title add support for dirent related function [WIP] add support for dirent related function Sep 1, 2017
@Mic92

Mic92 commented Sep 1, 2017

Copy link
Copy Markdown
Contributor Author

Can you restart the one failing test? Looks like a transient failure: https://travis-ci.org/nix-rust/nix/builds/270775924

@Mic92 Mic92 changed the title [WIP] add support for dirent related function add support for dirent related function Sep 1, 2017
@asomers

asomers commented Sep 1, 2017

Copy link
Copy Markdown
Member

offending test restarted

@Mic92

Mic92 commented Sep 6, 2017

Copy link
Copy Markdown
Contributor Author

if somebody is interested in dirfd and wants to make a pull request, feel free to cherry-pick from this branch: https://github.com/Mic92/nix/tree/dirfd

@Susurrus

Copy link
Copy Markdown
Contributor

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?

@Mic92

Mic92 commented Nov 13, 2017

Copy link
Copy Markdown
Contributor Author

Yes.

@Mic92 Mic92 closed this Nov 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants