Skip to content

Commit 060e2ab

Browse files
committed
Expose copy_file_range on FreeBSD
1 parent e756c96 commit 060e2ab

File tree

4 files changed

+62
-47
lines changed

4 files changed

+62
-47
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
99
([#1867](https://github.com/nix-rust/nix/pull/1867))
1010
- Added `nix::ucontext` module on `aarch64-unknown-linux-gnu`.
1111
(#[1662](https://github.com/nix-rust/nix/pull/1662))
12+
- Exposed `copy_file_range` on FreeBSD
13+
(#[???](https://github.com/nix-rust/nix/pull/???))
1214

1315
### Changed
1416

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ targets = [
2727
]
2828

2929
[dependencies]
30-
libc = { git = "https://github.com/rust-lang/libc", rev = "15d27952bfa93e5e4f419c603f275486f15a050c", features = [ "extra_traits" ] }
30+
libc = { version = "0.2.138", features = [ "extra_traits" ] }
3131
bitflags = "1.1"
3232
cfg-if = "1.0"
3333
pin-utils = { version = "0.1.0", optional = true }

src/fcntl.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::os::unix::io::RawFd;
88

99
#[cfg(feature = "fs")]
1010
use crate::{sys::stat::Mode, NixPath, Result};
11-
#[cfg(any(target_os = "android", target_os = "linux"))]
11+
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
1212
use std::ptr; // For splice and copy_file_range
1313

1414
#[cfg(any(
@@ -571,6 +571,11 @@ libc_bitflags! {
571571
feature! {
572572
#![feature = "zerocopy"]
573573

574+
#[cfg(any(target_os = "android", target_os = "linux"))]
575+
type type_of_off = libc::loff_t;
576+
#[cfg(target_os = "freebsd")]
577+
type type_of_off = libc::off_t;
578+
574579
/// Copy a range of data from one file to another
575580
///
576581
/// The `copy_file_range` system call performs an in-kernel copy between
@@ -587,24 +592,23 @@ feature! {
587592
///
588593
/// On successful completion the number of bytes actually copied will be
589594
/// returned.
590-
#[cfg(any(target_os = "android", target_os = "linux"))]
595+
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
591596
pub fn copy_file_range(
592597
fd_in: RawFd,
593-
off_in: Option<&mut libc::loff_t>,
598+
off_in: Option<&mut type_of_off>,
594599
fd_out: RawFd,
595-
off_out: Option<&mut libc::loff_t>,
600+
off_out: Option<&mut type_of_off>,
596601
len: usize,
597602
) -> Result<usize> {
598603
let off_in = off_in
599-
.map(|offset| offset as *mut libc::loff_t)
604+
.map(|offset| offset as *mut type_of_off)
600605
.unwrap_or(ptr::null_mut());
601606
let off_out = off_out
602-
.map(|offset| offset as *mut libc::loff_t)
607+
.map(|offset| offset as *mut type_of_off)
603608
.unwrap_or(ptr::null_mut());
604609

605610
let ret = unsafe {
606-
libc::syscall(
607-
libc::SYS_copy_file_range,
611+
libc::copy_file_range(
608612
fd_in,
609613
off_in,
610614
fd_out,

test/test_fcntl.rs

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::io::prelude::*;
2626
#[cfg(not(target_os = "redox"))]
2727
use std::os::unix::fs;
2828
#[cfg(not(target_os = "redox"))]
29-
use tempfile::{self, NamedTempFile};
29+
use tempfile::NamedTempFile;
3030

3131
#[test]
3232
#[cfg(not(target_os = "redox"))]
@@ -227,6 +227,51 @@ fn test_readlink() {
227227
);
228228
}
229229

230+
/// This test creates a temporary file containing the contents
231+
/// 'foobarbaz' and uses the `copy_file_range` call to transfer
232+
/// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
233+
/// resulting file is read and should contain the contents `bar`.
234+
/// The from_offset should be updated by the call to reflect
235+
/// the 3 bytes read (6).
236+
#[cfg(any(
237+
target_os = "linux",
238+
// Not available until FreeBSD 13.0
239+
all(target_os = "freebsd", fbsd14),
240+
target_os = "android"
241+
))]
242+
#[test]
243+
// QEMU does not support copy_file_range. Skip under qemu
244+
#[cfg_attr(qemu, ignore)]
245+
fn test_copy_file_range() {
246+
use std::os::unix::io::AsRawFd;
247+
use nix::fcntl::copy_file_range;
248+
249+
const CONTENTS: &[u8] = b"foobarbaz";
250+
251+
let mut tmp1 = tempfile::tempfile().unwrap();
252+
let mut tmp2 = tempfile::tempfile().unwrap();
253+
254+
tmp1.write_all(CONTENTS).unwrap();
255+
tmp1.flush().unwrap();
256+
257+
let mut from_offset: i64 = 3;
258+
copy_file_range(
259+
tmp1.as_raw_fd(),
260+
Some(&mut from_offset),
261+
tmp2.as_raw_fd(),
262+
None,
263+
3,
264+
)
265+
.unwrap();
266+
267+
let mut res: String = String::new();
268+
tmp2.rewind().unwrap();
269+
tmp2.read_to_string(&mut res).unwrap();
270+
271+
assert_eq!(res, String::from("bar"));
272+
assert_eq!(from_offset, 6);
273+
}
274+
230275
#[cfg(any(target_os = "linux", target_os = "android"))]
231276
mod linux_android {
232277
use libc::loff_t;
@@ -237,48 +282,12 @@ mod linux_android {
237282
use nix::fcntl::*;
238283
use nix::unistd::{close, pipe, read, write};
239284

240-
use tempfile::tempfile;
241285
#[cfg(any(target_os = "linux"))]
242286
use tempfile::NamedTempFile;
287+
use tempfile::tempfile;
243288

244289
use crate::*;
245290

246-
/// This test creates a temporary file containing the contents
247-
/// 'foobarbaz' and uses the `copy_file_range` call to transfer
248-
/// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
249-
/// resulting file is read and should contain the contents `bar`.
250-
/// The from_offset should be updated by the call to reflect
251-
/// the 3 bytes read (6).
252-
#[test]
253-
// QEMU does not support copy_file_range. Skip under qemu
254-
#[cfg_attr(qemu, ignore)]
255-
fn test_copy_file_range() {
256-
const CONTENTS: &[u8] = b"foobarbaz";
257-
258-
let mut tmp1 = tempfile().unwrap();
259-
let mut tmp2 = tempfile().unwrap();
260-
261-
tmp1.write_all(CONTENTS).unwrap();
262-
tmp1.flush().unwrap();
263-
264-
let mut from_offset: i64 = 3;
265-
copy_file_range(
266-
tmp1.as_raw_fd(),
267-
Some(&mut from_offset),
268-
tmp2.as_raw_fd(),
269-
None,
270-
3,
271-
)
272-
.unwrap();
273-
274-
let mut res: String = String::new();
275-
tmp2.rewind().unwrap();
276-
tmp2.read_to_string(&mut res).unwrap();
277-
278-
assert_eq!(res, String::from("bar"));
279-
assert_eq!(from_offset, 6);
280-
}
281-
282291
#[test]
283292
fn test_splice() {
284293
const CONTENTS: &[u8] = b"abcdef123456";

0 commit comments

Comments
 (0)