@@ -16,6 +16,10 @@ mod utils;
16
16
fn main ( ) {
17
17
test_dup_stdout_stderr ( ) ;
18
18
test_canonicalize_too_long ( ) ;
19
+ test_rename ( ) ;
20
+ test_ftruncate :: < libc:: off_t > ( libc:: ftruncate) ;
21
+ #[ cfg( target_os = "linux" ) ]
22
+ test_ftruncate :: < libc:: off64_t > ( libc:: ftruncate64) ;
19
23
test_readlink ( ) ;
20
24
test_file_open_unix_allow_two_args ( ) ;
21
25
test_file_open_unix_needs_three_args ( ) ;
@@ -133,6 +137,65 @@ fn test_readlink() {
133
137
assert_eq ! ( Error :: last_os_error( ) . kind( ) , ErrorKind :: NotFound ) ;
134
138
}
135
139
140
+ fn test_rename ( ) {
141
+ let path1 = prepare ( "miri_test_libc_fs_source.txt" ) ;
142
+ let path2 = prepare ( "miri_test_libc_fs_rename_destination.txt" ) ;
143
+
144
+ let file = File :: create ( & path1) . unwrap ( ) ;
145
+ drop ( file) ;
146
+
147
+ let c_path1 = CString :: new ( path1. as_os_str ( ) . as_bytes ( ) ) . expect ( "CString::new failed" ) ;
148
+ let c_path2 = CString :: new ( path2. as_os_str ( ) . as_bytes ( ) ) . expect ( "CString::new failed" ) ;
149
+
150
+ // Renaming should succeed
151
+ unsafe { libc:: rename ( c_path1. as_ptr ( ) , c_path2. as_ptr ( ) ) } ;
152
+ // Check that old file path isn't present
153
+ assert_eq ! ( ErrorKind :: NotFound , path1. metadata( ) . unwrap_err( ) . kind( ) ) ;
154
+ // Check that the file has moved successfully
155
+ assert ! ( path2. metadata( ) . unwrap( ) . is_file( ) ) ;
156
+
157
+ // Renaming a nonexistent file should fail
158
+ let res = unsafe { libc:: rename ( c_path1. as_ptr ( ) , c_path2. as_ptr ( ) ) } ;
159
+ assert_eq ! ( res, -1 ) ;
160
+ assert_eq ! ( Error :: last_os_error( ) . kind( ) , ErrorKind :: NotFound ) ;
161
+
162
+ remove_file ( & path2) . unwrap ( ) ;
163
+ }
164
+
165
+ fn test_ftruncate < T : From < i32 > > (
166
+ ftruncate : unsafe extern "C" fn ( fd : libc:: c_int , length : T ) -> libc:: c_int ,
167
+ ) {
168
+ // libc::off_t is i32 in target i686-unknown-linux-gnu
169
+ // https://docs.rs/libc/latest/i686-unknown-linux-gnu/libc/type.off_t.html
170
+
171
+ let bytes = b"hello" ;
172
+ let path = prepare ( "miri_test_libc_fs_ftruncate.txt" ) ;
173
+ let mut file = File :: create ( & path) . unwrap ( ) ;
174
+ file. write ( bytes) . unwrap ( ) ;
175
+ file. sync_all ( ) . unwrap ( ) ;
176
+ assert_eq ! ( file. metadata( ) . unwrap( ) . len( ) , 5 ) ;
177
+
178
+ let c_path = CString :: new ( path. as_os_str ( ) . as_bytes ( ) ) . expect ( "CString::new failed" ) ;
179
+ let fd = unsafe { libc:: open ( c_path. as_ptr ( ) , libc:: O_RDWR ) } ;
180
+
181
+ // Truncate to a bigger size
182
+ let mut res = unsafe { ftruncate ( fd, T :: from ( 10 ) ) } ;
183
+ assert_eq ! ( res, 0 ) ;
184
+ assert_eq ! ( file. metadata( ) . unwrap( ) . len( ) , 10 ) ;
185
+
186
+ // Write after truncate
187
+ file. write ( b"dup" ) . unwrap ( ) ;
188
+ file. sync_all ( ) . unwrap ( ) ;
189
+ assert_eq ! ( file. metadata( ) . unwrap( ) . len( ) , 10 ) ;
190
+
191
+ // Truncate to smaller size
192
+ res = unsafe { ftruncate ( fd, T :: from ( 2 ) ) } ;
193
+ assert_eq ! ( res, 0 ) ;
194
+ assert_eq ! ( file. metadata( ) . unwrap( ) . len( ) , 2 ) ;
195
+
196
+ remove_file ( & path) . unwrap ( ) ;
197
+ }
198
+
136
199
#[ cfg( target_os = "linux" ) ]
137
200
fn test_o_tmpfile_flag ( ) {
138
201
use std:: fs:: { create_dir, OpenOptions } ;
0 commit comments