4
4
#![ feature( io_error_more) ]
5
5
#![ feature( io_error_uncategorized) ]
6
6
7
- use std:: ffi:: CString ;
7
+ use std:: ffi:: { CStr , CString , OsString } ;
8
8
use std:: fs:: { canonicalize, remove_dir_all, remove_file, File } ;
9
9
use std:: io:: { Error , ErrorKind , Write } ;
10
10
use std:: os:: unix:: ffi:: OsStrExt ;
11
+ use std:: os:: unix:: io:: AsRawFd ;
11
12
use std:: path:: PathBuf ;
12
13
13
14
#[ path = "../../utils/mod.rs" ]
@@ -27,6 +28,14 @@ fn main() {
27
28
#[ cfg( target_os = "linux" ) ]
28
29
test_o_tmpfile_flag ( ) ;
29
30
test_posix_mkstemp ( ) ;
31
+ test_posix_realpath_alloc ( ) ;
32
+ test_posix_realpath_noalloc ( ) ;
33
+ test_posix_realpath_errors ( ) ;
34
+ #[ cfg( target_os = "linux" ) ]
35
+ test_posix_fadvise ( ) ;
36
+ #[ cfg( target_os = "linux" ) ]
37
+ test_sync_file_range ( ) ;
38
+ test_isatty ( ) ;
30
39
}
31
40
32
41
/// Prepare: compute filename and make sure the file does not exist.
@@ -256,3 +265,166 @@ fn test_posix_mkstemp() {
256
265
assert_eq ! ( e. kind( ) , std:: io:: ErrorKind :: InvalidInput ) ;
257
266
}
258
267
}
268
+
269
+ /// Test allocating variant of `realpath`.
270
+ fn test_posix_realpath_alloc ( ) {
271
+ use std:: os:: unix:: ffi:: OsStrExt ;
272
+ use std:: os:: unix:: ffi:: OsStringExt ;
273
+
274
+ let buf;
275
+ let path = utils:: tmp ( ) . join ( "miri_test_libc_posix_realpath_alloc" ) ;
276
+ let c_path = CString :: new ( path. as_os_str ( ) . as_bytes ( ) ) . expect ( "CString::new failed" ) ;
277
+
278
+ // Cleanup before test.
279
+ remove_file ( & path) . ok ( ) ;
280
+ // Create file.
281
+ drop ( File :: create ( & path) . unwrap ( ) ) ;
282
+ unsafe {
283
+ let r = libc:: realpath ( c_path. as_ptr ( ) , std:: ptr:: null_mut ( ) ) ;
284
+ assert ! ( !r. is_null( ) ) ;
285
+ buf = CStr :: from_ptr ( r) . to_bytes ( ) . to_vec ( ) ;
286
+ libc:: free ( r as * mut _ ) ;
287
+ }
288
+ let canonical = PathBuf :: from ( OsString :: from_vec ( buf) ) ;
289
+ assert_eq ! ( path. file_name( ) , canonical. file_name( ) ) ;
290
+
291
+ // Cleanup after test.
292
+ remove_file ( & path) . unwrap ( ) ;
293
+ }
294
+
295
+ /// Test non-allocating variant of `realpath`.
296
+ fn test_posix_realpath_noalloc ( ) {
297
+ use std:: ffi:: { CStr , CString } ;
298
+ use std:: os:: unix:: ffi:: OsStrExt ;
299
+
300
+ let path = utils:: tmp ( ) . join ( "miri_test_libc_posix_realpath_noalloc" ) ;
301
+ let c_path = CString :: new ( path. as_os_str ( ) . as_bytes ( ) ) . expect ( "CString::new failed" ) ;
302
+
303
+ let mut v = vec ! [ 0 ; libc:: PATH_MAX as usize ] ;
304
+
305
+ // Cleanup before test.
306
+ remove_file ( & path) . ok ( ) ;
307
+ // Create file.
308
+ drop ( File :: create ( & path) . unwrap ( ) ) ;
309
+ unsafe {
310
+ let r = libc:: realpath ( c_path. as_ptr ( ) , v. as_mut_ptr ( ) ) ;
311
+ assert ! ( !r. is_null( ) ) ;
312
+ }
313
+ let c = unsafe { CStr :: from_ptr ( v. as_ptr ( ) ) } ;
314
+ let canonical = PathBuf :: from ( c. to_str ( ) . expect ( "CStr to str" ) ) ;
315
+
316
+ assert_eq ! ( path. file_name( ) , canonical. file_name( ) ) ;
317
+
318
+ // Cleanup after test.
319
+ remove_file ( & path) . unwrap ( ) ;
320
+ }
321
+
322
+ /// Test failure cases for `realpath`.
323
+ fn test_posix_realpath_errors ( ) {
324
+ use std:: ffi:: CString ;
325
+ use std:: io:: ErrorKind ;
326
+
327
+ // Test nonexistent path returns an error.
328
+ let c_path = CString :: new ( "./nothing_to_see_here" ) . expect ( "CString::new failed" ) ;
329
+ let r = unsafe { libc:: realpath ( c_path. as_ptr ( ) , std:: ptr:: null_mut ( ) ) } ;
330
+ assert ! ( r. is_null( ) ) ;
331
+ let e = std:: io:: Error :: last_os_error ( ) ;
332
+ assert_eq ! ( e. raw_os_error( ) , Some ( libc:: ENOENT ) ) ;
333
+ assert_eq ! ( e. kind( ) , ErrorKind :: NotFound ) ;
334
+ }
335
+
336
+ #[ cfg( target_os = "linux" ) ]
337
+ fn test_posix_fadvise ( ) {
338
+ use std:: io:: Write ;
339
+
340
+ let path = utils:: tmp ( ) . join ( "miri_test_libc_posix_fadvise.txt" ) ;
341
+ // Cleanup before test
342
+ remove_file ( & path) . ok ( ) ;
343
+
344
+ // Set up an open file
345
+ let mut file = File :: create ( & path) . unwrap ( ) ;
346
+ let bytes = b"Hello, World!\n " ;
347
+ file. write ( bytes) . unwrap ( ) ;
348
+
349
+ // Test calling posix_fadvise on a file.
350
+ let result = unsafe {
351
+ libc:: posix_fadvise (
352
+ file. as_raw_fd ( ) ,
353
+ 0 ,
354
+ bytes. len ( ) . try_into ( ) . unwrap ( ) ,
355
+ libc:: POSIX_FADV_DONTNEED ,
356
+ )
357
+ } ;
358
+ drop ( file) ;
359
+ remove_file ( & path) . unwrap ( ) ;
360
+ assert_eq ! ( result, 0 ) ;
361
+ }
362
+
363
+ #[ cfg( target_os = "linux" ) ]
364
+ fn test_sync_file_range ( ) {
365
+ use std:: io:: Write ;
366
+
367
+ let path = utils:: tmp ( ) . join ( "miri_test_libc_sync_file_range.txt" ) ;
368
+ // Cleanup before test.
369
+ remove_file ( & path) . ok ( ) ;
370
+
371
+ // Write to a file.
372
+ let mut file = File :: create ( & path) . unwrap ( ) ;
373
+ let bytes = b"Hello, World!\n " ;
374
+ file. write ( bytes) . unwrap ( ) ;
375
+
376
+ // Test calling sync_file_range on the file.
377
+ let result_1 = unsafe {
378
+ libc:: sync_file_range (
379
+ file. as_raw_fd ( ) ,
380
+ 0 ,
381
+ 0 ,
382
+ libc:: SYNC_FILE_RANGE_WAIT_BEFORE
383
+ | libc:: SYNC_FILE_RANGE_WRITE
384
+ | libc:: SYNC_FILE_RANGE_WAIT_AFTER ,
385
+ )
386
+ } ;
387
+ drop ( file) ;
388
+
389
+ // Test calling sync_file_range on a file opened for reading.
390
+ let file = File :: open ( & path) . unwrap ( ) ;
391
+ let result_2 = unsafe {
392
+ libc:: sync_file_range (
393
+ file. as_raw_fd ( ) ,
394
+ 0 ,
395
+ 0 ,
396
+ libc:: SYNC_FILE_RANGE_WAIT_BEFORE
397
+ | libc:: SYNC_FILE_RANGE_WRITE
398
+ | libc:: SYNC_FILE_RANGE_WAIT_AFTER ,
399
+ )
400
+ } ;
401
+ drop ( file) ;
402
+
403
+ remove_file ( & path) . unwrap ( ) ;
404
+ assert_eq ! ( result_1, 0 ) ;
405
+ assert_eq ! ( result_2, 0 ) ;
406
+ }
407
+
408
+ fn test_isatty ( ) {
409
+ // Testing whether our isatty shim returns the right value would require controlling whether
410
+ // these streams are actually TTYs, which is hard.
411
+ // For now, we just check that these calls are supported at all.
412
+ unsafe {
413
+ libc:: isatty ( libc:: STDIN_FILENO ) ;
414
+ libc:: isatty ( libc:: STDOUT_FILENO ) ;
415
+ libc:: isatty ( libc:: STDERR_FILENO ) ;
416
+
417
+ // But when we open a file, it is definitely not a TTY.
418
+ let path = utils:: tmp ( ) . join ( "notatty.txt" ) ;
419
+ // Cleanup before test.
420
+ remove_file ( & path) . ok ( ) ;
421
+ let file = File :: create ( & path) . unwrap ( ) ;
422
+
423
+ assert_eq ! ( libc:: isatty( file. as_raw_fd( ) ) , 0 ) ;
424
+ assert_eq ! ( std:: io:: Error :: last_os_error( ) . raw_os_error( ) . unwrap( ) , libc:: ENOTTY ) ;
425
+
426
+ // Cleanup after test.
427
+ drop ( file) ;
428
+ remove_file ( & path) . unwrap ( ) ;
429
+ }
430
+ }
0 commit comments