Skip to content

Commit c7827ce

Browse files
committed
Expose copy_file_range on FreeBSD
1 parent c42b649 commit c7827ce

File tree

3 files changed

+61
-46
lines changed

3 files changed

+61
-46
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1414
- Added `mq_timedreceive` to `::nix::mqueue`.
1515
([#1966])(https://github.com/nix-rust/nix/pull/1966)
1616
- Added `LocalPeerPid` to `nix::sys::socket::sockopt` for macOS. ([#1967](https://github.com/nix-rust/nix/pull/1967))
17+
- Exposed `copy_file_range` on FreeBSD
18+
(#[???](https://github.com/nix-rust/nix/pull/???))
1719

1820
### Changed
1921

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(
@@ -605,6 +605,11 @@ libc_bitflags! {
605605
feature! {
606606
#![feature = "zerocopy"]
607607

608+
#[cfg(any(target_os = "android", target_os = "linux"))]
609+
type type_of_off = libc::loff_t;
610+
#[cfg(target_os = "freebsd")]
611+
type type_of_off = libc::off_t;
612+
608613
/// Copy a range of data from one file to another
609614
///
610615
/// The `copy_file_range` system call performs an in-kernel copy between
@@ -621,24 +626,23 @@ feature! {
621626
///
622627
/// On successful completion the number of bytes actually copied will be
623628
/// returned.
624-
#[cfg(any(target_os = "android", target_os = "linux"))]
629+
#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))]
625630
pub fn copy_file_range(
626631
fd_in: RawFd,
627-
off_in: Option<&mut libc::loff_t>,
632+
off_in: Option<&mut type_of_off>,
628633
fd_out: RawFd,
629-
off_out: Option<&mut libc::loff_t>,
634+
off_out: Option<&mut type_of_off>,
630635
len: usize,
631636
) -> Result<usize> {
632637
let off_in = off_in
633-
.map(|offset| offset as *mut libc::loff_t)
638+
.map(|offset| offset as *mut type_of_off)
634639
.unwrap_or(ptr::null_mut());
635640
let off_out = off_out
636-
.map(|offset| offset as *mut libc::loff_t)
641+
.map(|offset| offset as *mut type_of_off)
637642
.unwrap_or(ptr::null_mut());
638643

639644
let ret = unsafe {
640-
libc::syscall(
641-
libc::SYS_copy_file_range,
645+
libc::copy_file_range(
642646
fd_in,
643647
off_in,
644648
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)