From 955f0ddb9db33947a3fc806d9d3f2fcbb9a3b08f Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 21 Sep 2021 08:59:17 -0400 Subject: [PATCH] repo: Expose dfd_as_file() The `dfd()` API returns just an integer. Add a safe API that makes a copy of the fd. What we really want here is `BorrowedFd` from https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md but that isn't here yet. --- rust-bindings/rust/src/repo.rs | 17 +++++++++++++++++ rust-bindings/rust/tests/repo/mod.rs | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/rust-bindings/rust/src/repo.rs b/rust-bindings/rust/src/repo.rs index d6ffeb41..3b4961cf 100644 --- a/rust-bindings/rust/src/repo.rs +++ b/rust-bindings/rust/src/repo.rs @@ -40,6 +40,23 @@ impl Repo { Repo::new(&gio::File::for_path(path.as_ref())) } + /// Return a copy of the directory file descriptor for this repository. + #[cfg(any(feature = "v2016_4", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v2016_4")))] + pub fn dfd_as_file(&self) -> std::io::Result { + use std::os::unix::prelude::FromRawFd; + use std::os::unix::prelude::IntoRawFd; + unsafe { + // A temporary owned file instance + let dfd = std::fs::File::from_raw_fd(self.dfd()); + // So we can call dup() on it + let copy = dfd.try_clone(); + // Now release our temporary ownership of the original + let _ = dfd.into_raw_fd(); + Ok(copy?) + } + } + /// Find all objects reachable from a commit. pub fn traverse_commit>( &self, diff --git a/rust-bindings/rust/tests/repo/mod.rs b/rust-bindings/rust/tests/repo/mod.rs index 6bf045b6..6f3100aa 100644 --- a/rust-bindings/rust/tests/repo/mod.rs +++ b/rust-bindings/rust/tests/repo/mod.rs @@ -106,6 +106,17 @@ fn should_write_content_to_repo() { } } +#[test] +#[cfg(feature = "v2016_4")] +fn repo_file() { + use std::os::unix::fs::MetadataExt; + let test_repo = TestRepo::new(); + let m1 = test_repo.repo.dfd_as_file().unwrap().metadata().unwrap(); + let m2 = test_repo.repo.dfd_as_file().unwrap().metadata().unwrap(); + assert_eq!(m1.dev(), m2.dev()); + assert_eq!(m1.ino(), m2.ino()); +} + fn copy_file(src: &TestRepo, dest: &TestRepo, obj: &ObjectName) { let (stream, len) = src .repo