1 use crate::io
::prelude
::*;
3 use crate::fs
::{self, File, OpenOptions}
;
4 use crate::io
::{ErrorKind, SeekFrom}
;
7 use crate::sys_common
::io
::test
::{tmpdir, TempDir}
;
10 use rand
::{rngs::StdRng, RngCore, SeedableRng}
;
13 use crate::os
::unix
::fs
::symlink
as symlink_dir
;
15 use crate::os
::unix
::fs
::symlink
as symlink_file
;
17 use crate::os
::unix
::fs
::symlink
as symlink_junction
;
19 use crate::os
::windows
::fs
::{symlink_dir, symlink_file}
;
21 use crate::sys
::fs
::symlink_junction
;
22 #[cfg(target_os = "macos")]
23 use crate::sys
::weak
::weak
;
24 #[cfg(target_os = "macos")]
25 use libc
::{c_char, c_int}
;
31 Err(e
) => panic
!("{} failed with: {}", stringify
!($e
), e
),
38 ($e
:expr
, $s
:expr
) => {
40 Ok(_
) => panic
!("Unexpected success. Should've been: {:?}", $s
),
41 Err(ref err
) => assert
!(
42 err
.raw_os_error() == Some($s
),
43 format
!("`{}` did not have a code of `{}`", err
, $s
)
51 ($e
:expr
, $s
:expr
) => {
52 error_contains
!($e
, $s
)
56 macro_rules
! error_contains
{
57 ($e
:expr
, $s
:expr
) => {
59 Ok(_
) => panic
!("Unexpected success. Should've been: {:?}", $s
),
61 assert
!(err
.to_string().contains($s
), format
!("`{}` did not contain `{}`", err
, $s
))
67 // Several test fail on windows if the user does not have permission to
68 // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
69 // disabling these test on Windows, use this function to test whether we
70 // have permission, and return otherwise. This way, we still don't run these
71 // tests most of the time, but at least we do if the user has the right
73 pub fn got_symlink_permission(tmpdir
: &TempDir
) -> bool
{
77 let link
= tmpdir
.join("some_hopefully_unique_link_name");
79 match symlink_file(r
"nonexisting_target", link
) {
80 // ERROR_PRIVILEGE_NOT_HELD = 1314
81 Err(ref err
) if err
.raw_os_error() == Some(1314) => false,
82 Ok(_
) | Err(_
) => true,
86 #[cfg(target_os = "macos")]
87 fn able_to_not_follow_symlinks_while_hard_linking() -> bool
{
88 weak
!(fn linkat(c_int
, *const c_char
, c_int
, *const c_char
, c_int
) -> c_int
);
89 linkat
.get().is_some()
92 #[cfg(not(target_os = "macos"))]
93 fn able_to_not_follow_symlinks_while_hard_linking() -> bool
{
98 fn file_test_io_smoke_test() {
99 let message
= "it's alright. have a good time";
100 let tmpdir
= tmpdir();
101 let filename
= &tmpdir
.join("file_rt_io_file_test.txt");
103 let mut write_stream
= check
!(File
::create(filename
));
104 check
!(write_stream
.write(message
.as_bytes()));
107 let mut read_stream
= check
!(File
::open(filename
));
108 let mut read_buf
= [0; 1028];
109 let read_str
= match check
!(read_stream
.read(&mut read_buf
)) {
110 0 => panic
!("shouldn't happen"),
111 n
=> str::from_utf8(&read_buf
[..n
]).unwrap().to_string(),
113 assert_eq
!(read_str
, message
);
115 check
!(fs
::remove_file(filename
));
119 fn invalid_path_raises() {
120 let tmpdir
= tmpdir();
121 let filename
= &tmpdir
.join("file_that_does_not_exist.txt");
122 let result
= File
::open(filename
);
124 #[cfg(all(unix, not(target_os = "vxworks")))]
125 error
!(result
, "No such file or directory");
126 #[cfg(target_os = "vxworks")]
127 error
!(result
, "no such file or directory");
129 error
!(result
, 2); // ERROR_FILE_NOT_FOUND
133 fn file_test_iounlinking_invalid_path_should_raise_condition() {
134 let tmpdir
= tmpdir();
135 let filename
= &tmpdir
.join("file_another_file_that_does_not_exist.txt");
137 let result
= fs
::remove_file(filename
);
139 #[cfg(all(unix, not(target_os = "vxworks")))]
140 error
!(result
, "No such file or directory");
141 #[cfg(target_os = "vxworks")]
142 error
!(result
, "no such file or directory");
144 error
!(result
, 2); // ERROR_FILE_NOT_FOUND
148 fn file_test_io_non_positional_read() {
149 let message
: &str = "ten-four";
150 let mut read_mem
= [0; 8];
151 let tmpdir
= tmpdir();
152 let filename
= &tmpdir
.join("file_rt_io_file_test_positional.txt");
154 let mut rw_stream
= check
!(File
::create(filename
));
155 check
!(rw_stream
.write(message
.as_bytes()));
158 let mut read_stream
= check
!(File
::open(filename
));
160 let read_buf
= &mut read_mem
[0..4];
161 check
!(read_stream
.read(read_buf
));
164 let read_buf
= &mut read_mem
[4..8];
165 check
!(read_stream
.read(read_buf
));
168 check
!(fs
::remove_file(filename
));
169 let read_str
= str::from_utf8(&read_mem
).unwrap();
170 assert_eq
!(read_str
, message
);
174 fn file_test_io_seek_and_tell_smoke_test() {
175 let message
= "ten-four";
176 let mut read_mem
= [0; 4];
177 let set_cursor
= 4 as u64;
178 let tell_pos_pre_read
;
179 let tell_pos_post_read
;
180 let tmpdir
= tmpdir();
181 let filename
= &tmpdir
.join("file_rt_io_file_test_seeking.txt");
183 let mut rw_stream
= check
!(File
::create(filename
));
184 check
!(rw_stream
.write(message
.as_bytes()));
187 let mut read_stream
= check
!(File
::open(filename
));
188 check
!(read_stream
.seek(SeekFrom
::Start(set_cursor
)));
189 tell_pos_pre_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
190 check
!(read_stream
.read(&mut read_mem
));
191 tell_pos_post_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
193 check
!(fs
::remove_file(filename
));
194 let read_str
= str::from_utf8(&read_mem
).unwrap();
195 assert_eq
!(read_str
, &message
[4..8]);
196 assert_eq
!(tell_pos_pre_read
, set_cursor
);
197 assert_eq
!(tell_pos_post_read
, message
.len() as u64);
201 fn file_test_io_seek_and_write() {
202 let initial_msg
= "food-is-yummy";
203 let overwrite_msg
= "-the-bar!!";
204 let final_msg
= "foo-the-bar!!";
206 let mut read_mem
= [0; 13];
207 let tmpdir
= tmpdir();
208 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_and_write.txt");
210 let mut rw_stream
= check
!(File
::create(filename
));
211 check
!(rw_stream
.write(initial_msg
.as_bytes()));
212 check
!(rw_stream
.seek(SeekFrom
::Start(seek_idx
)));
213 check
!(rw_stream
.write(overwrite_msg
.as_bytes()));
216 let mut read_stream
= check
!(File
::open(filename
));
217 check
!(read_stream
.read(&mut read_mem
));
219 check
!(fs
::remove_file(filename
));
220 let read_str
= str::from_utf8(&read_mem
).unwrap();
221 assert
!(read_str
== final_msg
);
225 fn file_test_io_seek_shakedown() {
227 let initial_msg
= "qwer-asdf-zxcv";
228 let chunk_one
: &str = "qwer";
229 let chunk_two
: &str = "asdf";
230 let chunk_three
: &str = "zxcv";
231 let mut read_mem
= [0; 4];
232 let tmpdir
= tmpdir();
233 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_shakedown.txt");
235 let mut rw_stream
= check
!(File
::create(filename
));
236 check
!(rw_stream
.write(initial_msg
.as_bytes()));
239 let mut read_stream
= check
!(File
::open(filename
));
241 check
!(read_stream
.seek(SeekFrom
::End(-4)));
242 check
!(read_stream
.read(&mut read_mem
));
243 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_three
);
245 check
!(read_stream
.seek(SeekFrom
::Current(-9)));
246 check
!(read_stream
.read(&mut read_mem
));
247 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_two
);
249 check
!(read_stream
.seek(SeekFrom
::Start(0)));
250 check
!(read_stream
.read(&mut read_mem
));
251 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_one
);
253 check
!(fs
::remove_file(filename
));
257 fn file_test_io_eof() {
258 let tmpdir
= tmpdir();
259 let filename
= tmpdir
.join("file_rt_io_file_test_eof.txt");
260 let mut buf
= [0; 256];
262 let oo
= OpenOptions
::new().create_new(true).write(true).read(true).clone();
263 let mut rw
= check
!(oo
.open(&filename
));
264 assert_eq
!(check
!(rw
.read(&mut buf
)), 0);
265 assert_eq
!(check
!(rw
.read(&mut buf
)), 0);
267 check
!(fs
::remove_file(&filename
));
272 fn file_test_io_read_write_at() {
273 use crate::os
::unix
::fs
::FileExt
;
275 let tmpdir
= tmpdir();
276 let filename
= tmpdir
.join("file_rt_io_file_test_read_write_at.txt");
277 let mut buf
= [0; 256];
279 let write2
= "qwer-";
280 let write3
= "-zxcv";
281 let content
= "qwer-asdf-zxcv";
283 let oo
= OpenOptions
::new().create_new(true).write(true).read(true).clone();
284 let mut rw
= check
!(oo
.open(&filename
));
285 assert_eq
!(check
!(rw
.write_at(write1
.as_bytes(), 5)), write1
.len());
286 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 0);
287 assert_eq
!(check
!(rw
.read_at(&mut buf
, 5)), write1
.len());
288 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
289 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 0);
290 assert_eq
!(check
!(rw
.read_at(&mut buf
[..write2
.len()], 0)), write2
.len());
291 assert_eq
!(str::from_utf8(&buf
[..write2
.len()]), Ok("\0\0\0\0\0"));
292 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 0);
293 assert_eq
!(check
!(rw
.write(write2
.as_bytes())), write2
.len());
294 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 5);
295 assert_eq
!(check
!(rw
.read(&mut buf
)), write1
.len());
296 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
297 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
298 assert_eq
!(check
!(rw
.read_at(&mut buf
[..write2
.len()], 0)), write2
.len());
299 assert_eq
!(str::from_utf8(&buf
[..write2
.len()]), Ok(write2
));
300 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
301 assert_eq
!(check
!(rw
.write_at(write3
.as_bytes(), 9)), write3
.len());
302 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
305 let mut read
= check
!(File
::open(&filename
));
306 assert_eq
!(check
!(read
.read_at(&mut buf
, 0)), content
.len());
307 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
308 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 0);
309 assert_eq
!(check
!(read
.seek(SeekFrom
::End(-5))), 9);
310 assert_eq
!(check
!(read
.read_at(&mut buf
, 0)), content
.len());
311 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
312 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 9);
313 assert_eq
!(check
!(read
.read(&mut buf
)), write3
.len());
314 assert_eq
!(str::from_utf8(&buf
[..write3
.len()]), Ok(write3
));
315 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
316 assert_eq
!(check
!(read
.read_at(&mut buf
, 0)), content
.len());
317 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
318 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
319 assert_eq
!(check
!(read
.read_at(&mut buf
, 14)), 0);
320 assert_eq
!(check
!(read
.read_at(&mut buf
, 15)), 0);
321 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
323 check
!(fs
::remove_file(&filename
));
328 fn set_get_unix_permissions() {
329 use crate::os
::unix
::fs
::PermissionsExt
;
331 let tmpdir
= tmpdir();
332 let filename
= &tmpdir
.join("set_get_unix_permissions");
333 check
!(fs
::create_dir(filename
));
336 check
!(fs
::set_permissions(filename
, fs
::Permissions
::from_mode(0)));
337 let metadata0
= check
!(fs
::metadata(filename
));
338 assert_eq
!(mask
& metadata0
.permissions().mode(), 0);
340 check
!(fs
::set_permissions(filename
, fs
::Permissions
::from_mode(0o1777)));
341 let metadata1
= check
!(fs
::metadata(filename
));
342 #[cfg(all(unix, not(target_os = "vxworks")))]
343 assert_eq
!(mask
& metadata1
.permissions().mode(), 0o1777);
344 #[cfg(target_os = "vxworks")]
345 assert_eq
!(mask
& metadata1
.permissions().mode(), 0o0777);
350 fn file_test_io_seek_read_write() {
351 use crate::os
::windows
::fs
::FileExt
;
353 let tmpdir
= tmpdir();
354 let filename
= tmpdir
.join("file_rt_io_file_test_seek_read_write.txt");
355 let mut buf
= [0; 256];
357 let write2
= "qwer-";
358 let write3
= "-zxcv";
359 let content
= "qwer-asdf-zxcv";
361 let oo
= OpenOptions
::new().create_new(true).write(true).read(true).clone();
362 let mut rw
= check
!(oo
.open(&filename
));
363 assert_eq
!(check
!(rw
.seek_write(write1
.as_bytes(), 5)), write1
.len());
364 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
365 assert_eq
!(check
!(rw
.seek_read(&mut buf
, 5)), write1
.len());
366 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
367 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
368 assert_eq
!(check
!(rw
.seek(SeekFrom
::Start(0))), 0);
369 assert_eq
!(check
!(rw
.write(write2
.as_bytes())), write2
.len());
370 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 5);
371 assert_eq
!(check
!(rw
.read(&mut buf
)), write1
.len());
372 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
373 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
374 assert_eq
!(check
!(rw
.seek_read(&mut buf
[..write2
.len()], 0)), write2
.len());
375 assert_eq
!(str::from_utf8(&buf
[..write2
.len()]), Ok(write2
));
376 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 5);
377 assert_eq
!(check
!(rw
.seek_write(write3
.as_bytes(), 9)), write3
.len());
378 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 14);
381 let mut read
= check
!(File
::open(&filename
));
382 assert_eq
!(check
!(read
.seek_read(&mut buf
, 0)), content
.len());
383 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
384 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
385 assert_eq
!(check
!(read
.seek(SeekFrom
::End(-5))), 9);
386 assert_eq
!(check
!(read
.seek_read(&mut buf
, 0)), content
.len());
387 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
388 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
389 assert_eq
!(check
!(read
.seek(SeekFrom
::End(-5))), 9);
390 assert_eq
!(check
!(read
.read(&mut buf
)), write3
.len());
391 assert_eq
!(str::from_utf8(&buf
[..write3
.len()]), Ok(write3
));
392 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
393 assert_eq
!(check
!(read
.seek_read(&mut buf
, 0)), content
.len());
394 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
395 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
396 assert_eq
!(check
!(read
.seek_read(&mut buf
, 14)), 0);
397 assert_eq
!(check
!(read
.seek_read(&mut buf
, 15)), 0);
399 check
!(fs
::remove_file(&filename
));
403 fn file_test_stat_is_correct_on_is_file() {
404 let tmpdir
= tmpdir();
405 let filename
= &tmpdir
.join("file_stat_correct_on_is_file.txt");
407 let mut opts
= OpenOptions
::new();
408 let mut fs
= check
!(opts
.read(true).write(true).create(true).open(filename
));
410 fs
.write(msg
.as_bytes()).unwrap();
412 let fstat_res
= check
!(fs
.metadata());
413 assert
!(fstat_res
.is_file());
415 let stat_res_fn
= check
!(fs
::metadata(filename
));
416 assert
!(stat_res_fn
.is_file());
417 let stat_res_meth
= check
!(filename
.metadata());
418 assert
!(stat_res_meth
.is_file());
419 check
!(fs
::remove_file(filename
));
423 fn file_test_stat_is_correct_on_is_dir() {
424 let tmpdir
= tmpdir();
425 let filename
= &tmpdir
.join("file_stat_correct_on_is_dir");
426 check
!(fs
::create_dir(filename
));
427 let stat_res_fn
= check
!(fs
::metadata(filename
));
428 assert
!(stat_res_fn
.is_dir());
429 let stat_res_meth
= check
!(filename
.metadata());
430 assert
!(stat_res_meth
.is_dir());
431 check
!(fs
::remove_dir(filename
));
435 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
436 let tmpdir
= tmpdir();
437 let dir
= &tmpdir
.join("fileinfo_false_on_dir");
438 check
!(fs
::create_dir(dir
));
439 assert
!(!dir
.is_file());
440 check
!(fs
::remove_dir(dir
));
444 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
445 let tmpdir
= tmpdir();
446 let file
= &tmpdir
.join("fileinfo_check_exists_b_and_a.txt");
447 check
!(check
!(File
::create(file
)).write(b
"foo"));
448 assert
!(file
.exists());
449 check
!(fs
::remove_file(file
));
450 assert
!(!file
.exists());
454 fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
455 let tmpdir
= tmpdir();
456 let dir
= &tmpdir
.join("before_and_after_dir");
457 assert
!(!dir
.exists());
458 check
!(fs
::create_dir(dir
));
459 assert
!(dir
.exists());
460 assert
!(dir
.is_dir());
461 check
!(fs
::remove_dir(dir
));
462 assert
!(!dir
.exists());
466 fn file_test_directoryinfo_readdir() {
467 let tmpdir
= tmpdir();
468 let dir
= &tmpdir
.join("di_readdir");
469 check
!(fs
::create_dir(dir
));
472 let f
= dir
.join(&format
!("{}.txt", n
));
473 let mut w
= check
!(File
::create(&f
));
474 let msg_str
= format
!("{}{}", prefix
, n
.to_string());
475 let msg
= msg_str
.as_bytes();
476 check
!(w
.write(msg
));
478 let files
= check
!(fs
::read_dir(dir
));
479 let mut mem
= [0; 4];
481 let f
= f
.unwrap().path();
483 let n
= f
.file_stem().unwrap();
484 check
!(check
!(File
::open(&f
)).read(&mut mem
));
485 let read_str
= str::from_utf8(&mem
).unwrap();
486 let expected
= format
!("{}{}", prefix
, n
.to_str().unwrap());
487 assert_eq
!(expected
, read_str
);
489 check
!(fs
::remove_file(&f
));
491 check
!(fs
::remove_dir(dir
));
495 fn file_create_new_already_exists_error() {
496 let tmpdir
= tmpdir();
497 let file
= &tmpdir
.join("file_create_new_error_exists");
498 check
!(fs
::File
::create(file
));
499 let e
= fs
::OpenOptions
::new().write(true).create_new(true).open(file
).unwrap_err();
500 assert_eq
!(e
.kind(), ErrorKind
::AlreadyExists
);
504 fn mkdir_path_already_exists_error() {
505 let tmpdir
= tmpdir();
506 let dir
= &tmpdir
.join("mkdir_error_twice");
507 check
!(fs
::create_dir(dir
));
508 let e
= fs
::create_dir(dir
).unwrap_err();
509 assert_eq
!(e
.kind(), ErrorKind
::AlreadyExists
);
513 fn recursive_mkdir() {
514 let tmpdir
= tmpdir();
515 let dir
= tmpdir
.join("d1/d2");
516 check
!(fs
::create_dir_all(&dir
));
517 assert
!(dir
.is_dir())
521 fn recursive_mkdir_failure() {
522 let tmpdir
= tmpdir();
523 let dir
= tmpdir
.join("d1");
524 let file
= dir
.join("f1");
526 check
!(fs
::create_dir_all(&dir
));
527 check
!(File
::create(&file
));
529 let result
= fs
::create_dir_all(&file
);
531 assert
!(result
.is_err());
535 fn concurrent_recursive_mkdir() {
538 let mut dir
= dir
.join("a");
542 let mut join
= vec
![];
544 let dir
= dir
.clone();
545 join
.push(thread
::spawn(move || {
546 check
!(fs
::create_dir_all(&dir
));
550 // No `Display` on result of `join()`
551 join
.drain(..).map(|join
| join
.join().unwrap()).count();
556 fn recursive_mkdir_slash() {
557 check
!(fs
::create_dir_all(Path
::new("/")));
561 fn recursive_mkdir_dot() {
562 check
!(fs
::create_dir_all(Path
::new(".")));
566 fn recursive_mkdir_empty() {
567 check
!(fs
::create_dir_all(Path
::new("")));
571 fn recursive_rmdir() {
572 let tmpdir
= tmpdir();
573 let d1
= tmpdir
.join("d1");
574 let dt
= d1
.join("t");
575 let dtt
= dt
.join("t");
576 let d2
= tmpdir
.join("d2");
577 let canary
= d2
.join("do_not_delete");
578 check
!(fs
::create_dir_all(&dtt
));
579 check
!(fs
::create_dir_all(&d2
));
580 check
!(check
!(File
::create(&canary
)).write(b
"foo"));
581 check
!(symlink_junction(&d2
, &dt
.join("d2")));
582 let _
= symlink_file(&canary
, &d1
.join("canary"));
583 check
!(fs
::remove_dir_all(&d1
));
585 assert
!(!d1
.is_dir());
586 assert
!(canary
.exists());
590 fn recursive_rmdir_of_symlink() {
591 // test we do not recursively delete a symlink but only dirs.
592 let tmpdir
= tmpdir();
593 let link
= tmpdir
.join("d1");
594 let dir
= tmpdir
.join("d2");
595 let canary
= dir
.join("do_not_delete");
596 check
!(fs
::create_dir_all(&dir
));
597 check
!(check
!(File
::create(&canary
)).write(b
"foo"));
598 check
!(symlink_junction(&dir
, &link
));
599 check
!(fs
::remove_dir_all(&link
));
601 assert
!(!link
.is_dir());
602 assert
!(canary
.exists());
606 // only Windows makes a distinction between file and directory symlinks.
608 fn recursive_rmdir_of_file_symlink() {
609 let tmpdir
= tmpdir();
610 if !got_symlink_permission(&tmpdir
) {
614 let f1
= tmpdir
.join("f1");
615 let f2
= tmpdir
.join("f2");
616 check
!(check
!(File
::create(&f1
)).write(b
"foo"));
617 check
!(symlink_file(&f1
, &f2
));
618 match fs
::remove_dir_all(&f2
) {
619 Ok(..) => panic
!("wanted a failure"),
625 fn unicode_path_is_dir() {
626 assert
!(Path
::new(".").is_dir());
627 assert
!(!Path
::new("test/stdtest/fs.rs").is_dir());
629 let tmpdir
= tmpdir();
631 let mut dirpath
= tmpdir
.path().to_path_buf();
632 dirpath
.push("test-가一ー你好");
633 check
!(fs
::create_dir(&dirpath
));
634 assert
!(dirpath
.is_dir());
636 let mut filepath
= dirpath
;
637 filepath
.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
638 check
!(File
::create(&filepath
)); // ignore return; touch only
639 assert
!(!filepath
.is_dir());
640 assert
!(filepath
.exists());
644 fn unicode_path_exists() {
645 assert
!(Path
::new(".").exists());
646 assert
!(!Path
::new("test/nonexistent-bogus-path").exists());
648 let tmpdir
= tmpdir();
649 let unicode
= tmpdir
.path();
650 let unicode
= unicode
.join("test-각丁ー再见");
651 check
!(fs
::create_dir(&unicode
));
652 assert
!(unicode
.exists());
653 assert
!(!Path
::new("test/unicode-bogus-path-각丁ー再见").exists());
657 fn copy_file_does_not_exist() {
658 let from
= Path
::new("test/nonexistent-bogus-path");
659 let to
= Path
::new("test/other-bogus-path");
661 match fs
::copy(&from
, &to
) {
664 assert
!(!from
.exists());
665 assert
!(!to
.exists());
671 fn copy_src_does_not_exist() {
672 let tmpdir
= tmpdir();
673 let from
= Path
::new("test/nonexistent-bogus-path");
674 let to
= tmpdir
.join("out.txt");
675 check
!(check
!(File
::create(&to
)).write(b
"hello"));
676 assert
!(fs
::copy(&from
, &to
).is_err());
677 assert
!(!from
.exists());
678 let mut v
= Vec
::new();
679 check
!(check
!(File
::open(&to
)).read_to_end(&mut v
));
680 assert_eq
!(v
, b
"hello");
685 let tmpdir
= tmpdir();
686 let input
= tmpdir
.join("in.txt");
687 let out
= tmpdir
.join("out.txt");
689 check
!(check
!(File
::create(&input
)).write(b
"hello"));
690 check
!(fs
::copy(&input
, &out
));
691 let mut v
= Vec
::new();
692 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
693 assert_eq
!(v
, b
"hello");
695 assert_eq
!(check
!(input
.metadata()).permissions(), check
!(out
.metadata()).permissions());
699 fn copy_file_dst_dir() {
700 let tmpdir
= tmpdir();
701 let out
= tmpdir
.join("out");
703 check
!(File
::create(&out
));
704 match fs
::copy(&*out
, tmpdir
.path()) {
711 fn copy_file_dst_exists() {
712 let tmpdir
= tmpdir();
713 let input
= tmpdir
.join("in");
714 let output
= tmpdir
.join("out");
716 check
!(check
!(File
::create(&input
)).write("foo".as_bytes()));
717 check
!(check
!(File
::create(&output
)).write("bar".as_bytes()));
718 check
!(fs
::copy(&input
, &output
));
720 let mut v
= Vec
::new();
721 check
!(check
!(File
::open(&output
)).read_to_end(&mut v
));
722 assert_eq
!(v
, b
"foo".to_vec());
726 fn copy_file_src_dir() {
727 let tmpdir
= tmpdir();
728 let out
= tmpdir
.join("out");
730 match fs
::copy(tmpdir
.path(), &out
) {
734 assert
!(!out
.exists());
738 fn copy_file_preserves_perm_bits() {
739 let tmpdir
= tmpdir();
740 let input
= tmpdir
.join("in.txt");
741 let out
= tmpdir
.join("out.txt");
743 let attr
= check
!(check
!(File
::create(&input
)).metadata());
744 let mut p
= attr
.permissions();
745 p
.set_readonly(true);
746 check
!(fs
::set_permissions(&input
, p
));
747 check
!(fs
::copy(&input
, &out
));
748 assert
!(check
!(out
.metadata()).permissions().readonly());
749 check
!(fs
::set_permissions(&input
, attr
.permissions()));
750 check
!(fs
::set_permissions(&out
, attr
.permissions()));
755 fn copy_file_preserves_streams() {
757 check
!(check
!(File
::create(tmp
.join("in.txt:bunny"))).write("carrot".as_bytes()));
758 assert_eq
!(check
!(fs
::copy(tmp
.join("in.txt"), tmp
.join("out.txt"))), 0);
759 assert_eq
!(check
!(tmp
.join("out.txt").metadata()).len(), 0);
760 let mut v
= Vec
::new();
761 check
!(check
!(File
::open(tmp
.join("out.txt:bunny"))).read_to_end(&mut v
));
762 assert_eq
!(v
, b
"carrot".to_vec());
766 fn copy_file_returns_metadata_len() {
768 let in_path
= tmp
.join("in.txt");
769 let out_path
= tmp
.join("out.txt");
770 check
!(check
!(File
::create(&in_path
)).write(b
"lettuce"));
772 check
!(check
!(File
::create(tmp
.join("in.txt:bunny"))).write(b
"carrot"));
773 let copied_len
= check
!(fs
::copy(&in_path
, &out_path
));
774 assert_eq
!(check
!(out_path
.metadata()).len(), copied_len
);
778 fn copy_file_follows_dst_symlink() {
780 if !got_symlink_permission(&tmp
) {
784 let in_path
= tmp
.join("in.txt");
785 let out_path
= tmp
.join("out.txt");
786 let out_path_symlink
= tmp
.join("out_symlink.txt");
788 check
!(fs
::write(&in_path
, "foo"));
789 check
!(fs
::write(&out_path
, "bar"));
790 check
!(symlink_file(&out_path
, &out_path_symlink
));
792 check
!(fs
::copy(&in_path
, &out_path_symlink
));
794 assert
!(check
!(out_path_symlink
.symlink_metadata()).file_type().is_symlink());
795 assert_eq
!(check
!(fs
::read(&out_path_symlink
)), b
"foo".to_vec());
796 assert_eq
!(check
!(fs
::read(&out_path
)), b
"foo".to_vec());
801 let tmpdir
= tmpdir();
802 if !got_symlink_permission(&tmpdir
) {
806 let input
= tmpdir
.join("in.txt");
807 let out
= tmpdir
.join("out.txt");
809 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
810 check
!(symlink_file(&input
, &out
));
811 assert
!(check
!(out
.symlink_metadata()).file_type().is_symlink());
812 assert_eq
!(check
!(fs
::metadata(&out
)).len(), check
!(fs
::metadata(&input
)).len());
813 let mut v
= Vec
::new();
814 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
815 assert_eq
!(v
, b
"foobar".to_vec());
819 fn symlink_noexist() {
820 // Symlinks can point to things that don't exist
821 let tmpdir
= tmpdir();
822 if !got_symlink_permission(&tmpdir
) {
826 // Use a relative path for testing. Symlinks get normalized by Windows,
827 // so we may not get the same path back for absolute paths
828 check
!(symlink_file(&"foo", &tmpdir
.join("bar")));
829 assert_eq
!(check
!(fs
::read_link(&tmpdir
.join("bar"))).to_str().unwrap(), "foo");
837 check
!(fs
::read_link(r
"C:\Users\All Users")).to_str().unwrap(),
842 check
!(fs
::read_link(r
"C:\Users\Default User")).to_str().unwrap(),
845 // junction with special permissions
847 check
!(fs
::read_link(r
"C:\Documents and Settings\")).to_str().unwrap(),
851 let tmpdir
= tmpdir();
852 let link
= tmpdir
.join("link");
853 if !got_symlink_permission(&tmpdir
) {
856 check
!(symlink_file(&"foo", &link
));
857 assert_eq
!(check
!(fs
::read_link(&link
)).to_str().unwrap(), "foo");
861 fn readlink_not_symlink() {
862 let tmpdir
= tmpdir();
863 match fs
::read_link(tmpdir
.path()) {
864 Ok(..) => panic
!("wanted a failure"),
871 let tmpdir
= tmpdir();
872 let input
= tmpdir
.join("in.txt");
873 let out
= tmpdir
.join("out.txt");
875 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
876 check
!(fs
::hard_link(&input
, &out
));
877 assert_eq
!(check
!(fs
::metadata(&out
)).len(), check
!(fs
::metadata(&input
)).len());
878 assert_eq
!(check
!(fs
::metadata(&out
)).len(), check
!(input
.metadata()).len());
879 let mut v
= Vec
::new();
880 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
881 assert_eq
!(v
, b
"foobar".to_vec());
883 // can't link to yourself
884 match fs
::hard_link(&input
, &input
) {
885 Ok(..) => panic
!("wanted a failure"),
888 // can't link to something that doesn't exist
889 match fs
::hard_link(&tmpdir
.join("foo"), &tmpdir
.join("bar")) {
890 Ok(..) => panic
!("wanted a failure"),
897 let tmpdir
= tmpdir();
898 let file
= tmpdir
.join("in.txt");
900 check
!(File
::create(&file
));
901 let attr
= check
!(fs
::metadata(&file
));
902 assert
!(!attr
.permissions().readonly());
903 let mut p
= attr
.permissions();
904 p
.set_readonly(true);
905 check
!(fs
::set_permissions(&file
, p
.clone()));
906 let attr
= check
!(fs
::metadata(&file
));
907 assert
!(attr
.permissions().readonly());
909 match fs
::set_permissions(&tmpdir
.join("foo"), p
.clone()) {
910 Ok(..) => panic
!("wanted an error"),
914 p
.set_readonly(false);
915 check
!(fs
::set_permissions(&file
, p
));
920 let tmpdir
= tmpdir();
921 let path
= tmpdir
.join("in.txt");
923 let file
= check
!(File
::create(&path
));
924 let attr
= check
!(fs
::metadata(&path
));
925 assert
!(!attr
.permissions().readonly());
926 let mut p
= attr
.permissions();
927 p
.set_readonly(true);
928 check
!(file
.set_permissions(p
.clone()));
929 let attr
= check
!(fs
::metadata(&path
));
930 assert
!(attr
.permissions().readonly());
932 p
.set_readonly(false);
933 check
!(file
.set_permissions(p
));
937 fn sync_doesnt_kill_anything() {
938 let tmpdir
= tmpdir();
939 let path
= tmpdir
.join("in.txt");
941 let mut file
= check
!(File
::create(&path
));
942 check
!(file
.sync_all());
943 check
!(file
.sync_data());
944 check
!(file
.write(b
"foo"));
945 check
!(file
.sync_all());
946 check
!(file
.sync_data());
950 fn truncate_works() {
951 let tmpdir
= tmpdir();
952 let path
= tmpdir
.join("in.txt");
954 let mut file
= check
!(File
::create(&path
));
955 check
!(file
.write(b
"foo"));
956 check
!(file
.sync_all());
958 // Do some simple things with truncation
959 assert_eq
!(check
!(file
.metadata()).len(), 3);
960 check
!(file
.set_len(10));
961 assert_eq
!(check
!(file
.metadata()).len(), 10);
962 check
!(file
.write(b
"bar"));
963 check
!(file
.sync_all());
964 assert_eq
!(check
!(file
.metadata()).len(), 10);
966 let mut v
= Vec
::new();
967 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
968 assert_eq
!(v
, b
"foobar\0\0\0\0".to_vec());
970 // Truncate to a smaller length, don't seek, and then write something.
971 // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
972 // past the end of the file).
973 check
!(file
.set_len(2));
974 assert_eq
!(check
!(file
.metadata()).len(), 2);
975 check
!(file
.write(b
"wut"));
976 check
!(file
.sync_all());
977 assert_eq
!(check
!(file
.metadata()).len(), 9);
978 let mut v
= Vec
::new();
979 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
980 assert_eq
!(v
, b
"fo\0\0\0\0wut".to_vec());
985 use crate::fs
::OpenOptions
as OO
;
986 fn c
<T
: Clone
>(t
: &T
) -> T
{
990 let tmpdir
= tmpdir();
992 let mut r
= OO
::new();
994 let mut w
= OO
::new();
996 let mut rw
= OO
::new();
997 rw
.read(true).write(true);
998 let mut a
= OO
::new();
1000 let mut ra
= OO
::new();
1001 ra
.read(true).append(true);
1004 let invalid_options
= 87; // ERROR_INVALID_PARAMETER
1005 #[cfg(all(unix, not(target_os = "vxworks")))]
1006 let invalid_options
= "Invalid argument";
1007 #[cfg(target_os = "vxworks")]
1008 let invalid_options
= "invalid argument";
1010 // Test various combinations of creation modes and access modes.
1013 // creation mode | read | write | read-write | append | read-append |
1014 // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
1015 // not set (open existing) | X | X | X | X | X |
1016 // create | | X | X | X | X |
1017 // truncate | | X | X | | |
1018 // create and truncate | | X | X | | |
1019 // create_new | | X | X | X | X |
1021 // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
1024 check
!(c(&w
).create_new(true).open(&tmpdir
.join("a")));
1025 check
!(c(&w
).create(true).truncate(true).open(&tmpdir
.join("a")));
1026 check
!(c(&w
).truncate(true).open(&tmpdir
.join("a")));
1027 check
!(c(&w
).create(true).open(&tmpdir
.join("a")));
1028 check
!(c(&w
).open(&tmpdir
.join("a")));
1031 error
!(c(&r
).create_new(true).open(&tmpdir
.join("b")), invalid_options
);
1032 error
!(c(&r
).create(true).truncate(true).open(&tmpdir
.join("b")), invalid_options
);
1033 error
!(c(&r
).truncate(true).open(&tmpdir
.join("b")), invalid_options
);
1034 error
!(c(&r
).create(true).open(&tmpdir
.join("b")), invalid_options
);
1035 check
!(c(&r
).open(&tmpdir
.join("a"))); // try opening the file created with write_only
1038 check
!(c(&rw
).create_new(true).open(&tmpdir
.join("c")));
1039 check
!(c(&rw
).create(true).truncate(true).open(&tmpdir
.join("c")));
1040 check
!(c(&rw
).truncate(true).open(&tmpdir
.join("c")));
1041 check
!(c(&rw
).create(true).open(&tmpdir
.join("c")));
1042 check
!(c(&rw
).open(&tmpdir
.join("c")));
1045 check
!(c(&a
).create_new(true).open(&tmpdir
.join("d")));
1046 error
!(c(&a
).create(true).truncate(true).open(&tmpdir
.join("d")), invalid_options
);
1047 error
!(c(&a
).truncate(true).open(&tmpdir
.join("d")), invalid_options
);
1048 check
!(c(&a
).create(true).open(&tmpdir
.join("d")));
1049 check
!(c(&a
).open(&tmpdir
.join("d")));
1052 check
!(c(&ra
).create_new(true).open(&tmpdir
.join("e")));
1053 error
!(c(&ra
).create(true).truncate(true).open(&tmpdir
.join("e")), invalid_options
);
1054 error
!(c(&ra
).truncate(true).open(&tmpdir
.join("e")), invalid_options
);
1055 check
!(c(&ra
).create(true).open(&tmpdir
.join("e")));
1056 check
!(c(&ra
).open(&tmpdir
.join("e")));
1058 // Test opening a file without setting an access mode
1059 let mut blank
= OO
::new();
1060 error
!(blank
.create(true).open(&tmpdir
.join("f")), invalid_options
);
1063 check
!(check
!(File
::create(&tmpdir
.join("h"))).write("foobar".as_bytes()));
1065 // Test write fails for read-only
1066 check
!(r
.open(&tmpdir
.join("h")));
1068 let mut f
= check
!(r
.open(&tmpdir
.join("h")));
1069 assert
!(f
.write("wut".as_bytes()).is_err());
1072 // Test write overwrites
1074 let mut f
= check
!(c(&w
).open(&tmpdir
.join("h")));
1075 check
!(f
.write("baz".as_bytes()));
1078 let mut f
= check
!(c(&r
).open(&tmpdir
.join("h")));
1079 let mut b
= vec
![0; 6];
1080 check
!(f
.read(&mut b
));
1081 assert_eq
!(b
, "bazbar".as_bytes());
1084 // Test truncate works
1086 let mut f
= check
!(c(&w
).truncate(true).open(&tmpdir
.join("h")));
1087 check
!(f
.write("foo".as_bytes()));
1089 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
1091 // Test append works
1092 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
1094 let mut f
= check
!(c(&a
).open(&tmpdir
.join("h")));
1095 check
!(f
.write("bar".as_bytes()));
1097 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 6);
1099 // Test .append(true) equals .write(true).append(true)
1101 let mut f
= check
!(c(&w
).append(true).open(&tmpdir
.join("h")));
1102 check
!(f
.write("baz".as_bytes()));
1104 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 9);
1108 fn _assert_send_sync() {
1109 fn _assert_send_sync
<T
: Send
+ Sync
>() {}
1110 _assert_send_sync
::<OpenOptions
>();
1115 let mut bytes
= [0; 1024];
1116 StdRng
::from_entropy().fill_bytes(&mut bytes
);
1118 let tmpdir
= tmpdir();
1120 check
!(check
!(File
::create(&tmpdir
.join("test"))).write(&bytes
));
1121 let mut v
= Vec
::new();
1122 check
!(check
!(File
::open(&tmpdir
.join("test"))).read_to_end(&mut v
));
1123 assert
!(v
== &bytes
[..]);
1127 fn write_then_read() {
1128 let mut bytes
= [0; 1024];
1129 StdRng
::from_entropy().fill_bytes(&mut bytes
);
1131 let tmpdir
= tmpdir();
1133 check
!(fs
::write(&tmpdir
.join("test"), &bytes
[..]));
1134 let v
= check
!(fs
::read(&tmpdir
.join("test")));
1135 assert
!(v
== &bytes
[..]);
1137 check
!(fs
::write(&tmpdir
.join("not-utf8"), &[0xFF]));
1139 fs
::read_to_string(&tmpdir
.join("not-utf8")),
1140 "stream did not contain valid UTF-8"
1144 check
!(fs
::write(&tmpdir
.join("utf8"), s
.as_bytes()));
1145 let string
= check
!(fs
::read_to_string(&tmpdir
.join("utf8")));
1146 assert_eq
!(string
, s
);
1150 fn file_try_clone() {
1151 let tmpdir
= tmpdir();
1154 check
!(OpenOptions
::new().read(true).write(true).create(true).open(&tmpdir
.join("test")));
1155 let mut f2
= check
!(f1
.try_clone());
1157 check
!(f1
.write_all(b
"hello world"));
1158 check
!(f1
.seek(SeekFrom
::Start(2)));
1160 let mut buf
= vec
![];
1161 check
!(f2
.read_to_end(&mut buf
));
1162 assert_eq
!(buf
, b
"llo world");
1165 check
!(f1
.write_all(b
"!"));
1169 #[cfg(not(windows))]
1170 fn unlink_readonly() {
1171 let tmpdir
= tmpdir();
1172 let path
= tmpdir
.join("file");
1173 check
!(File
::create(&path
));
1174 let mut perm
= check
!(fs
::metadata(&path
)).permissions();
1175 perm
.set_readonly(true);
1176 check
!(fs
::set_permissions(&path
, perm
));
1177 check
!(fs
::remove_file(&path
));
1181 fn mkdir_trailing_slash() {
1182 let tmpdir
= tmpdir();
1183 let path
= tmpdir
.join("file");
1184 check
!(fs
::create_dir_all(&path
.join("a/")));
1188 fn canonicalize_works_simple() {
1189 let tmpdir
= tmpdir();
1190 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
1191 let file
= tmpdir
.join("test");
1192 File
::create(&file
).unwrap();
1193 assert_eq
!(fs
::canonicalize(&file
).unwrap(), file
);
1197 fn realpath_works() {
1198 let tmpdir
= tmpdir();
1199 if !got_symlink_permission(&tmpdir
) {
1203 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
1204 let file
= tmpdir
.join("test");
1205 let dir
= tmpdir
.join("test2");
1206 let link
= dir
.join("link");
1207 let linkdir
= tmpdir
.join("test3");
1209 File
::create(&file
).unwrap();
1210 fs
::create_dir(&dir
).unwrap();
1211 symlink_file(&file
, &link
).unwrap();
1212 symlink_dir(&dir
, &linkdir
).unwrap();
1214 assert
!(link
.symlink_metadata().unwrap().file_type().is_symlink());
1216 assert_eq
!(fs
::canonicalize(&tmpdir
).unwrap(), tmpdir
);
1217 assert_eq
!(fs
::canonicalize(&file
).unwrap(), file
);
1218 assert_eq
!(fs
::canonicalize(&link
).unwrap(), file
);
1219 assert_eq
!(fs
::canonicalize(&linkdir
).unwrap(), dir
);
1220 assert_eq
!(fs
::canonicalize(&linkdir
.join("link")).unwrap(), file
);
1224 fn realpath_works_tricky() {
1225 let tmpdir
= tmpdir();
1226 if !got_symlink_permission(&tmpdir
) {
1230 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
1231 let a
= tmpdir
.join("a");
1232 let b
= a
.join("b");
1233 let c
= b
.join("c");
1234 let d
= a
.join("d");
1235 let e
= d
.join("e");
1236 let f
= a
.join("f");
1238 fs
::create_dir_all(&b
).unwrap();
1239 fs
::create_dir_all(&d
).unwrap();
1240 File
::create(&f
).unwrap();
1241 if cfg
!(not(windows
)) {
1242 symlink_file("../d/e", &c
).unwrap();
1243 symlink_file("../f", &e
).unwrap();
1246 symlink_file(r
"..\d\e", &c
).unwrap();
1247 symlink_file(r
"..\f", &e
).unwrap();
1250 assert_eq
!(fs
::canonicalize(&c
).unwrap(), f
);
1251 assert_eq
!(fs
::canonicalize(&e
).unwrap(), f
);
1255 fn dir_entry_methods() {
1256 let tmpdir
= tmpdir();
1258 fs
::create_dir_all(&tmpdir
.join("a")).unwrap();
1259 File
::create(&tmpdir
.join("b")).unwrap();
1261 for file
in tmpdir
.path().read_dir().unwrap().map(|f
| f
.unwrap()) {
1262 let fname
= file
.file_name();
1263 match fname
.to_str() {
1265 assert
!(file
.file_type().unwrap().is_dir());
1266 assert
!(file
.metadata().unwrap().is_dir());
1269 assert
!(file
.file_type().unwrap().is_file());
1270 assert
!(file
.metadata().unwrap().is_file());
1272 f
=> panic
!("unknown file name: {:?}", f
),
1278 fn dir_entry_debug() {
1279 let tmpdir
= tmpdir();
1280 File
::create(&tmpdir
.join("b")).unwrap();
1281 let mut read_dir
= tmpdir
.path().read_dir().unwrap();
1282 let dir_entry
= read_dir
.next().unwrap().unwrap();
1283 let actual
= format
!("{:?}", dir_entry
);
1284 let expected
= format
!("DirEntry({:?})", dir_entry
.0.path());
1285 assert_eq
!(actual
, expected
);
1289 fn read_dir_not_found() {
1290 let res
= fs
::read_dir("/path/that/does/not/exist");
1291 assert_eq
!(res
.err().unwrap().kind(), ErrorKind
::NotFound
);
1295 fn create_dir_all_with_junctions() {
1296 let tmpdir
= tmpdir();
1297 let target
= tmpdir
.join("target");
1299 let junction
= tmpdir
.join("junction");
1300 let b
= junction
.join("a/b");
1302 let link
= tmpdir
.join("link");
1303 let d
= link
.join("c/d");
1305 fs
::create_dir(&target
).unwrap();
1307 check
!(symlink_junction(&target
, &junction
));
1308 check
!(fs
::create_dir_all(&b
));
1309 // the junction itself is not a directory, but `is_dir()` on a Path
1311 assert
!(junction
.is_dir());
1312 assert
!(b
.exists());
1314 if !got_symlink_permission(&tmpdir
) {
1317 check
!(symlink_dir(&target
, &link
));
1318 check
!(fs
::create_dir_all(&d
));
1319 assert
!(link
.is_dir());
1320 assert
!(d
.exists());
1324 fn metadata_access_times() {
1325 let tmpdir
= tmpdir();
1327 let b
= tmpdir
.join("b");
1328 File
::create(&b
).unwrap();
1330 let a
= check
!(fs
::metadata(&tmpdir
.path()));
1331 let b
= check
!(fs
::metadata(&b
));
1333 assert_eq
!(check
!(a
.accessed()), check
!(a
.accessed()));
1334 assert_eq
!(check
!(a
.modified()), check
!(a
.modified()));
1335 assert_eq
!(check
!(b
.accessed()), check
!(b
.modified()));
1337 if cfg
!(target_os
= "macos") || cfg
!(target_os
= "windows") {
1338 check
!(a
.created());
1339 check
!(b
.created());
1342 if cfg
!(target_os
= "linux") {
1343 // Not always available
1344 match (a
.created(), b
.created()) {
1345 (Ok(t1
), Ok(t2
)) => assert
!(t1
<= t2
),
1347 if e1
.kind() == ErrorKind
::Uncategorized
1348 && e2
.kind() == ErrorKind
::Uncategorized
1349 || e1
.kind() == ErrorKind
::Unsupported
1350 && e2
.kind() == ErrorKind
::Unsupported
=> {}
1352 panic
!("creation time must be always supported or not supported: {:?} {:?}", a
, b
,)
1358 /// Test creating hard links to symlinks.
1360 fn symlink_hard_link() {
1361 let tmpdir
= tmpdir();
1362 if !got_symlink_permission(&tmpdir
) {
1365 if !able_to_not_follow_symlinks_while_hard_linking() {
1369 // Create "file", a file.
1370 check
!(fs
::File
::create(tmpdir
.join("file")));
1372 // Create "symlink", a symlink to "file".
1373 check
!(symlink_file("file", tmpdir
.join("symlink")));
1375 // Create "hard_link", a hard link to "symlink".
1376 check
!(fs
::hard_link(tmpdir
.join("symlink"), tmpdir
.join("hard_link")));
1378 // "hard_link" should appear as a symlink.
1379 assert
!(check
!(fs
::symlink_metadata(tmpdir
.join("hard_link"))).file_type().is_symlink());
1381 // We sould be able to open "file" via any of the above names.
1382 let _
= check
!(fs
::File
::open(tmpdir
.join("file")));
1383 assert
!(fs
::File
::open(tmpdir
.join("file.renamed")).is_err());
1384 let _
= check
!(fs
::File
::open(tmpdir
.join("symlink")));
1385 let _
= check
!(fs
::File
::open(tmpdir
.join("hard_link")));
1387 // Rename "file" to "file.renamed".
1388 check
!(fs
::rename(tmpdir
.join("file"), tmpdir
.join("file.renamed")));
1390 // Now, the symlink and the hard link should be dangling.
1391 assert
!(fs
::File
::open(tmpdir
.join("file")).is_err());
1392 let _
= check
!(fs
::File
::open(tmpdir
.join("file.renamed")));
1393 assert
!(fs
::File
::open(tmpdir
.join("symlink")).is_err());
1394 assert
!(fs
::File
::open(tmpdir
.join("hard_link")).is_err());
1396 // The symlink and the hard link should both still point to "file".
1397 assert
!(fs
::read_link(tmpdir
.join("file")).is_err());
1398 assert
!(fs
::read_link(tmpdir
.join("file.renamed")).is_err());
1399 assert_eq
!(check
!(fs
::read_link(tmpdir
.join("symlink"))), Path
::new("file"));
1400 assert_eq
!(check
!(fs
::read_link(tmpdir
.join("hard_link"))), Path
::new("file"));
1402 // Remove "file.renamed".
1403 check
!(fs
::remove_file(tmpdir
.join("file.renamed")));
1405 // Now, we can't open the file by any name.
1406 assert
!(fs
::File
::open(tmpdir
.join("file")).is_err());
1407 assert
!(fs
::File
::open(tmpdir
.join("file.renamed")).is_err());
1408 assert
!(fs
::File
::open(tmpdir
.join("symlink")).is_err());
1409 assert
!(fs
::File
::open(tmpdir
.join("hard_link")).is_err());
1411 // "hard_link" should still appear as a symlink.
1412 assert
!(check
!(fs
::symlink_metadata(tmpdir
.join("hard_link"))).file_type().is_symlink());