@@ -23,3 +23,60 @@ fn test_ioctl_ficlone() {
2323 Err ( err) => panic ! ( "{:?}" , err) ,
2424 }
2525}
26+
27+ #[ cfg( all( linux_kernel, not( any( target_arch = "sparc" , target_arch = "sparc64" ) ) ) ) ]
28+ #[ test]
29+ fn test_ioctl_ficlonerange ( ) {
30+ use rustix:: io;
31+
32+ let src = std:: fs:: File :: open ( "Cargo.toml" ) . unwrap ( ) ;
33+ let dest = tempfile:: tempfile ( ) . unwrap ( ) ;
34+
35+ // Often the temporary directory is on a different filesystem (like tmpfs),
36+ // which means the test to clone some data doesn't do anything interesting,
37+ // singe the ioctl simply returns failure.
38+ // Uncomment the line below to use a file in the same directory as the source,
39+ // which guarantees they are on the same filesystem.
40+ // let dest = std::fs::File::options()
41+ // .create(true)
42+ // .truncate(true)
43+ // .read(true)
44+ // .write(true)
45+ // .open("test_ficlonerange").unwrap();
46+
47+ let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
48+ let dir = std:: fs:: File :: open ( dir. path ( ) ) . unwrap ( ) ;
49+
50+ // `src` isn't opened for writing, so passing it as the output fails.
51+ assert_eq ! (
52+ rustix:: fs:: ioctl_ficlonerange( & src, & src, 0 , 4096 , 0 ) ,
53+ Err ( io:: Errno :: BADF )
54+ ) ;
55+
56+ // `FICLONERANGE` operates on regular files, not directories.
57+ assert_eq ! (
58+ rustix:: fs:: ioctl_ficlonerange( & dir, & dir, 0 , 4096 , 0 ) ,
59+ Err ( io:: Errno :: ISDIR )
60+ ) ;
61+
62+ // Now try something that might succeed, though be prepared for filesystems
63+ // that don't support this.
64+ // Copy 4096 bytes from offset 4096 in src to offset 8192 in dest.
65+ match rustix:: fs:: ioctl_ficlonerange ( & dest, & src, 4096 , 4096 , 8192 ) {
66+ Ok ( ( ) ) => {
67+ use std:: os:: unix:: fs:: FileExt ;
68+
69+ let mut expected_buf = vec ! [ 0u8 ; 4096 ] ;
70+ let mut actual_buf = vec ! [ 0u8 ; 4096 ] ;
71+ src. read_exact_at ( expected_buf. as_mut_slice ( ) , 4096 )
72+ . unwrap ( ) ;
73+ dest. read_exact_at ( actual_buf. as_mut_slice ( ) , 8192 ) . unwrap ( ) ;
74+
75+ assert_eq ! ( expected_buf, actual_buf) ;
76+ }
77+
78+ Err ( io:: Errno :: OPNOTSUPP ) => ( ) ,
79+ Err ( e) if e == io:: Errno :: from_raw_os_error ( 0x12 ) => ( ) ,
80+ Err ( err) => panic ! ( "{:?}" , err) ,
81+ }
82+ }
0 commit comments