You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If you want a guarantee that a rename() operation has been committed to disk, you need to call fsync() on all the directories that were involved, which of course means you need file descriptors referring to those directories. I was hoping I could use openat::Dir to abstract over the process of acquiring those fds, and just write this in my code:
use std::io;
use std::os::fd::AsRawFd;
use openat::Dir;
fn sync_dir(d: &Dir) -> io::Result<()> {
// SAFETY: trusts you to supply a valid fd, manual error checking required
let status = unsafe { libc::fsync(d.as_raw_fd()) };
if status != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
Unfortunately, this doesn't work; the fsync() call fails with code EBADF. The problem appears to be that openat::Dir wraps a fd that was opened with O_PATH, and to use fsync you instead need a fd that was opened with O_RDONLY|O_DIRECTORY. A C program that demonstrates this requirement is attached.
As far as I know, the only other differences between O_PATH and O_RDONLY|O_DIRECTORY, when applied to a directory, are that in the latter case you need read permission on the directory, and, if it succeeds, you are then allowed to read the contents of the directory (readdir in C, getdents at the syscall level). Thus, the Right Thing™, in my opinion, would be, on Linux, to attempt an open call first with O_RDONLY|O_DIRECTORY and then fall back to O_PATH|O_DIRECTORY if that fails with EPERM. This change would fix my problem and should also fix #34.
In my fork (openat_ct) I added a DirFlags builder which allows to specify the flags for creating Dir's. I just noticed that the documentation is wrong there in a earlier implementation i forced O_PATH flags, that's not there anymore. Eventually i should go over it and fix the doc and bring that crate up to date (remove the build.rs). A sync() -> Result<(), CanNotSync> method on a Dir could be nice, PR welcome.
zackw
added a commit
to zackw/openat
that referenced
this issue
Dec 12, 2023
It calls fsync() on the file descriptor. This is necessary with some
operating systems and/or file systems to ensure that changes to the
contents of the directory make it to persistent storage — for the same
reason it is sometimes necessary to use `std::fs::File::sync_{all,contents}`.
Note that this method will fail if used on a `Dir` opened with `O_PATH`.
(Same issue as `list_dir`; see tailhook#34.)
Closestailhook#47.
If you want a guarantee that a rename() operation has been committed to disk, you need to call fsync() on all the directories that were involved, which of course means you need file descriptors referring to those directories. I was hoping I could use openat::Dir to abstract over the process of acquiring those fds, and just write this in my code:
Unfortunately, this doesn't work; the fsync() call fails with code EBADF. The problem appears to be that openat::Dir wraps a fd that was opened with
O_PATH
, and to use fsync you instead need a fd that was opened withO_RDONLY|O_DIRECTORY
. A C program that demonstrates this requirement is attached.As far as I know, the only other differences between
O_PATH
andO_RDONLY|O_DIRECTORY
, when applied to a directory, are that in the latter case you need read permission on the directory, and, if it succeeds, you are then allowed to read the contents of the directory (readdir
in C,getdents
at the syscall level). Thus, the Right Thing™, in my opinion, would be, on Linux, to attempt an open call first withO_RDONLY|O_DIRECTORY
and then fall back toO_PATH|O_DIRECTORY
if that fails with EPERM. This change would fix my problem and should also fix #34.fsync_dir_requires_o_directory.c
The text was updated successfully, but these errors were encountered: