rustix
rustix copied to clipboard
Consider adding a Dir::into_fd() method
Currently, once an OwnedFd has been passed to rustix::fs::Dir, there is no way to reuse it.
My usecase is to call rustix::fs::openat() and rustix::fs::statat() on it after I’m done with the iteration (or even during, I don’t think there is any issue with that since getdents64(2) is stateless).
My current solution is to call rustix::io::dup() on the fd before creating the Dir, but that shouldn’t be needed and wastes one fd. Another solution would be to rustix::fs::open() it again once the iteration is done, but that’s wasteful too.
rustix::fs::Dir::read_from has the same issue, it implements dup(2) manually by calling fcntl(4, F_GETFL) then openat(4, ".", …) with 4 being the fd being passed to it.
And since getdents64(2) is stateless, I believe there is no unsoundness issue with e.g. multiple rustix::fs::Dir being created around the same fd.
The tricky thing here is that rustix is aiming to have the same API across both the libc and linux-raw backends, and in the libc backend, it uses opendir/readdir/closedir. libc doesn't have a way to free a DIR object without closing the fd.
One option might be to have the libc backend implement into_fd by calling dup before calling closedir, however I'm not sure if it's too awkward if into_fd() has to be fallible.
Hello. So, my use case actually needs to reuse the dir file descriptor during iteration. This is because I need to remove a directory, and to do so I must recursively remove all its content. So the loop looks like:
for entry in dir.into_iter().flatten() {
let name = entry.file_name().to_bytes();
match name {
b"." | b".." => continue,
otherwise => {
// use statat to determine if the entry is a directory
// if it is, open it with openat and recursively delete it
// if not, use unlinkat directly
}
}
}
So I need access to the file descriptor while I am iterating. Right now I am getting around it by turning the file descriptor into a raw file descriptor, then using unsafe code to create a BorrowedFd from the raw file descriptor. However, I am not sure how portable this is (if at all). It seems to work on the linux backend, but I imagine there may be some issue with the libcbackend, since the documentation for fdopendir states the application should not use the file descriptor after passing it to fdopendir.
I believe libc has a dirfd function that allows us to get the file descriptor from a DIR handle. Could we use that somehow? This would allow me to use a while let Some(entry) = dir.read() loop and then call dir.fd() internally in the loop to make all the *at syscalls. This would also trivially solve @linkmauve's problem as a bonus.