1use std::fs::File;
2use std::io;
3use std::os::fd::AsRawFd;
4use std::path::Path;
5
6pub fn clone_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dest: Q) -> io::Result<()> {
14 let src_file = File::open(src)?;
15 let dest_file = File::options()
16 .write(true)
17 .create(true)
18 .truncate(true)
19 .open(dest)?;
20
21 match unsafe { ioctl::ficlone(dest_file.as_raw_fd(), src_file.as_raw_fd() as u64) } {
22 Ok(_) => Ok(()),
23 Err(_) => Err(io::Error::last_os_error()),
24 }
25}
26
27pub fn clone_file_range<P: AsRef<Path>, Q: AsRef<Path>>(
38 src: P,
39 src_offset: u64,
40 src_length: u64,
41 dest: Q,
42 dest_offset: u64,
43) -> io::Result<()> {
44 let src_file = File::open(src)?;
45 let dest_file = File::options().write(true).create(true).open(dest)?;
46
47 let args = ioctl::FileCloneRange {
48 src_fd: src_file.as_raw_fd() as i64,
49 src_offset,
50 src_length,
51 dest_offset,
52 };
53
54 match unsafe { ioctl::ficlonerange(dest_file.as_raw_fd(), &args) } {
55 Ok(_) => Ok(()),
56 Err(_) => Err(io::Error::last_os_error()),
57 }
58}
59
60mod ioctl {
61 pub struct FileCloneRange {
62 pub src_fd: i64,
63 pub src_offset: u64,
64 pub src_length: u64,
65 pub dest_offset: u64,
66 }
67
68 nix::ioctl_write_int!(ficlone, 0x94, 9);
69 nix::ioctl_write_ptr!(ficlonerange, 0x94, 13, FileCloneRange);
70}