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
;
27 Err(e
) => panic
!("{} failed with: {}", stringify
!($e
), e
),
34 ($e
:expr
, $s
:expr
) => {
36 Ok(_
) => panic
!("Unexpected success. Should've been: {:?}", $s
),
37 Err(ref err
) => assert
!(
38 err
.raw_os_error() == Some($s
),
39 format
!("`{}` did not have a code of `{}`", err
, $s
)
47 ($e
:expr
, $s
:expr
) => {
48 error_contains
!($e
, $s
)
52 macro_rules
! error_contains
{
53 ($e
:expr
, $s
:expr
) => {
55 Ok(_
) => panic
!("Unexpected success. Should've been: {:?}", $s
),
57 assert
!(err
.to_string().contains($s
), format
!("`{}` did not contain `{}`", err
, $s
))
63 // Several test fail on windows if the user does not have permission to
64 // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
65 // disabling these test on Windows, use this function to test whether we
66 // have permission, and return otherwise. This way, we still don't run these
67 // tests most of the time, but at least we do if the user has the right
69 pub fn got_symlink_permission(tmpdir
: &TempDir
) -> bool
{
73 let link
= tmpdir
.join("some_hopefully_unique_link_name");
75 match symlink_file(r
"nonexisting_target", link
) {
76 // ERROR_PRIVILEGE_NOT_HELD = 1314
77 Err(ref err
) if err
.raw_os_error() == Some(1314) => false,
78 Ok(_
) | Err(_
) => true,
83 fn file_test_io_smoke_test() {
84 let message
= "it's alright. have a good time";
85 let tmpdir
= tmpdir();
86 let filename
= &tmpdir
.join("file_rt_io_file_test.txt");
88 let mut write_stream
= check
!(File
::create(filename
));
89 check
!(write_stream
.write(message
.as_bytes()));
92 let mut read_stream
= check
!(File
::open(filename
));
93 let mut read_buf
= [0; 1028];
94 let read_str
= match check
!(read_stream
.read(&mut read_buf
)) {
95 0 => panic
!("shouldn't happen"),
96 n
=> str::from_utf8(&read_buf
[..n
]).unwrap().to_string(),
98 assert_eq
!(read_str
, message
);
100 check
!(fs
::remove_file(filename
));
104 fn invalid_path_raises() {
105 let tmpdir
= tmpdir();
106 let filename
= &tmpdir
.join("file_that_does_not_exist.txt");
107 let result
= File
::open(filename
);
109 #[cfg(all(unix, not(target_os = "vxworks")))]
110 error
!(result
, "No such file or directory");
111 #[cfg(target_os = "vxworks")]
112 error
!(result
, "no such file or directory");
114 error
!(result
, 2); // ERROR_FILE_NOT_FOUND
118 fn file_test_iounlinking_invalid_path_should_raise_condition() {
119 let tmpdir
= tmpdir();
120 let filename
= &tmpdir
.join("file_another_file_that_does_not_exist.txt");
122 let result
= fs
::remove_file(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_io_non_positional_read() {
134 let message
: &str = "ten-four";
135 let mut read_mem
= [0; 8];
136 let tmpdir
= tmpdir();
137 let filename
= &tmpdir
.join("file_rt_io_file_test_positional.txt");
139 let mut rw_stream
= check
!(File
::create(filename
));
140 check
!(rw_stream
.write(message
.as_bytes()));
143 let mut read_stream
= check
!(File
::open(filename
));
145 let read_buf
= &mut read_mem
[0..4];
146 check
!(read_stream
.read(read_buf
));
149 let read_buf
= &mut read_mem
[4..8];
150 check
!(read_stream
.read(read_buf
));
153 check
!(fs
::remove_file(filename
));
154 let read_str
= str::from_utf8(&read_mem
).unwrap();
155 assert_eq
!(read_str
, message
);
159 fn file_test_io_seek_and_tell_smoke_test() {
160 let message
= "ten-four";
161 let mut read_mem
= [0; 4];
162 let set_cursor
= 4 as u64;
163 let tell_pos_pre_read
;
164 let tell_pos_post_read
;
165 let tmpdir
= tmpdir();
166 let filename
= &tmpdir
.join("file_rt_io_file_test_seeking.txt");
168 let mut rw_stream
= check
!(File
::create(filename
));
169 check
!(rw_stream
.write(message
.as_bytes()));
172 let mut read_stream
= check
!(File
::open(filename
));
173 check
!(read_stream
.seek(SeekFrom
::Start(set_cursor
)));
174 tell_pos_pre_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
175 check
!(read_stream
.read(&mut read_mem
));
176 tell_pos_post_read
= check
!(read_stream
.seek(SeekFrom
::Current(0)));
178 check
!(fs
::remove_file(filename
));
179 let read_str
= str::from_utf8(&read_mem
).unwrap();
180 assert_eq
!(read_str
, &message
[4..8]);
181 assert_eq
!(tell_pos_pre_read
, set_cursor
);
182 assert_eq
!(tell_pos_post_read
, message
.len() as u64);
186 fn file_test_io_seek_and_write() {
187 let initial_msg
= "food-is-yummy";
188 let overwrite_msg
= "-the-bar!!";
189 let final_msg
= "foo-the-bar!!";
191 let mut read_mem
= [0; 13];
192 let tmpdir
= tmpdir();
193 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_and_write.txt");
195 let mut rw_stream
= check
!(File
::create(filename
));
196 check
!(rw_stream
.write(initial_msg
.as_bytes()));
197 check
!(rw_stream
.seek(SeekFrom
::Start(seek_idx
)));
198 check
!(rw_stream
.write(overwrite_msg
.as_bytes()));
201 let mut read_stream
= check
!(File
::open(filename
));
202 check
!(read_stream
.read(&mut read_mem
));
204 check
!(fs
::remove_file(filename
));
205 let read_str
= str::from_utf8(&read_mem
).unwrap();
206 assert
!(read_str
== final_msg
);
210 fn file_test_io_seek_shakedown() {
212 let initial_msg
= "qwer-asdf-zxcv";
213 let chunk_one
: &str = "qwer";
214 let chunk_two
: &str = "asdf";
215 let chunk_three
: &str = "zxcv";
216 let mut read_mem
= [0; 4];
217 let tmpdir
= tmpdir();
218 let filename
= &tmpdir
.join("file_rt_io_file_test_seek_shakedown.txt");
220 let mut rw_stream
= check
!(File
::create(filename
));
221 check
!(rw_stream
.write(initial_msg
.as_bytes()));
224 let mut read_stream
= check
!(File
::open(filename
));
226 check
!(read_stream
.seek(SeekFrom
::End(-4)));
227 check
!(read_stream
.read(&mut read_mem
));
228 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_three
);
230 check
!(read_stream
.seek(SeekFrom
::Current(-9)));
231 check
!(read_stream
.read(&mut read_mem
));
232 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_two
);
234 check
!(read_stream
.seek(SeekFrom
::Start(0)));
235 check
!(read_stream
.read(&mut read_mem
));
236 assert_eq
!(str::from_utf8(&read_mem
).unwrap(), chunk_one
);
238 check
!(fs
::remove_file(filename
));
242 fn file_test_io_eof() {
243 let tmpdir
= tmpdir();
244 let filename
= tmpdir
.join("file_rt_io_file_test_eof.txt");
245 let mut buf
= [0; 256];
247 let oo
= OpenOptions
::new().create_new(true).write(true).read(true).clone();
248 let mut rw
= check
!(oo
.open(&filename
));
249 assert_eq
!(check
!(rw
.read(&mut buf
)), 0);
250 assert_eq
!(check
!(rw
.read(&mut buf
)), 0);
252 check
!(fs
::remove_file(&filename
));
257 fn file_test_io_read_write_at() {
258 use crate::os
::unix
::fs
::FileExt
;
260 let tmpdir
= tmpdir();
261 let filename
= tmpdir
.join("file_rt_io_file_test_read_write_at.txt");
262 let mut buf
= [0; 256];
264 let write2
= "qwer-";
265 let write3
= "-zxcv";
266 let content
= "qwer-asdf-zxcv";
268 let oo
= OpenOptions
::new().create_new(true).write(true).read(true).clone();
269 let mut rw
= check
!(oo
.open(&filename
));
270 assert_eq
!(check
!(rw
.write_at(write1
.as_bytes(), 5)), write1
.len());
271 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 0);
272 assert_eq
!(check
!(rw
.read_at(&mut buf
, 5)), write1
.len());
273 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
274 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 0);
275 assert_eq
!(check
!(rw
.read_at(&mut buf
[..write2
.len()], 0)), write2
.len());
276 assert_eq
!(str::from_utf8(&buf
[..write2
.len()]), Ok("\0\0\0\0\0"));
277 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 0);
278 assert_eq
!(check
!(rw
.write(write2
.as_bytes())), write2
.len());
279 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 5);
280 assert_eq
!(check
!(rw
.read(&mut buf
)), write1
.len());
281 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
282 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
283 assert_eq
!(check
!(rw
.read_at(&mut buf
[..write2
.len()], 0)), write2
.len());
284 assert_eq
!(str::from_utf8(&buf
[..write2
.len()]), Ok(write2
));
285 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
286 assert_eq
!(check
!(rw
.write_at(write3
.as_bytes(), 9)), write3
.len());
287 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
290 let mut read
= check
!(File
::open(&filename
));
291 assert_eq
!(check
!(read
.read_at(&mut buf
, 0)), content
.len());
292 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
293 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 0);
294 assert_eq
!(check
!(read
.seek(SeekFrom
::End(-5))), 9);
295 assert_eq
!(check
!(read
.read_at(&mut buf
, 0)), content
.len());
296 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
297 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 9);
298 assert_eq
!(check
!(read
.read(&mut buf
)), write3
.len());
299 assert_eq
!(str::from_utf8(&buf
[..write3
.len()]), Ok(write3
));
300 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
301 assert_eq
!(check
!(read
.read_at(&mut buf
, 0)), content
.len());
302 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
303 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
304 assert_eq
!(check
!(read
.read_at(&mut buf
, 14)), 0);
305 assert_eq
!(check
!(read
.read_at(&mut buf
, 15)), 0);
306 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
308 check
!(fs
::remove_file(&filename
));
313 fn set_get_unix_permissions() {
314 use crate::os
::unix
::fs
::PermissionsExt
;
316 let tmpdir
= tmpdir();
317 let filename
= &tmpdir
.join("set_get_unix_permissions");
318 check
!(fs
::create_dir(filename
));
321 check
!(fs
::set_permissions(filename
, fs
::Permissions
::from_mode(0)));
322 let metadata0
= check
!(fs
::metadata(filename
));
323 assert_eq
!(mask
& metadata0
.permissions().mode(), 0);
325 check
!(fs
::set_permissions(filename
, fs
::Permissions
::from_mode(0o1777)));
326 let metadata1
= check
!(fs
::metadata(filename
));
327 #[cfg(all(unix, not(target_os = "vxworks")))]
328 assert_eq
!(mask
& metadata1
.permissions().mode(), 0o1777);
329 #[cfg(target_os = "vxworks")]
330 assert_eq
!(mask
& metadata1
.permissions().mode(), 0o0777);
335 fn file_test_io_seek_read_write() {
336 use crate::os
::windows
::fs
::FileExt
;
338 let tmpdir
= tmpdir();
339 let filename
= tmpdir
.join("file_rt_io_file_test_seek_read_write.txt");
340 let mut buf
= [0; 256];
342 let write2
= "qwer-";
343 let write3
= "-zxcv";
344 let content
= "qwer-asdf-zxcv";
346 let oo
= OpenOptions
::new().create_new(true).write(true).read(true).clone();
347 let mut rw
= check
!(oo
.open(&filename
));
348 assert_eq
!(check
!(rw
.seek_write(write1
.as_bytes(), 5)), write1
.len());
349 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
350 assert_eq
!(check
!(rw
.seek_read(&mut buf
, 5)), write1
.len());
351 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
352 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
353 assert_eq
!(check
!(rw
.seek(SeekFrom
::Start(0))), 0);
354 assert_eq
!(check
!(rw
.write(write2
.as_bytes())), write2
.len());
355 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 5);
356 assert_eq
!(check
!(rw
.read(&mut buf
)), write1
.len());
357 assert_eq
!(str::from_utf8(&buf
[..write1
.len()]), Ok(write1
));
358 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 9);
359 assert_eq
!(check
!(rw
.seek_read(&mut buf
[..write2
.len()], 0)), write2
.len());
360 assert_eq
!(str::from_utf8(&buf
[..write2
.len()]), Ok(write2
));
361 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 5);
362 assert_eq
!(check
!(rw
.seek_write(write3
.as_bytes(), 9)), write3
.len());
363 assert_eq
!(check
!(rw
.seek(SeekFrom
::Current(0))), 14);
366 let mut read
= check
!(File
::open(&filename
));
367 assert_eq
!(check
!(read
.seek_read(&mut buf
, 0)), content
.len());
368 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
369 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
370 assert_eq
!(check
!(read
.seek(SeekFrom
::End(-5))), 9);
371 assert_eq
!(check
!(read
.seek_read(&mut buf
, 0)), content
.len());
372 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
373 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
374 assert_eq
!(check
!(read
.seek(SeekFrom
::End(-5))), 9);
375 assert_eq
!(check
!(read
.read(&mut buf
)), write3
.len());
376 assert_eq
!(str::from_utf8(&buf
[..write3
.len()]), Ok(write3
));
377 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
378 assert_eq
!(check
!(read
.seek_read(&mut buf
, 0)), content
.len());
379 assert_eq
!(str::from_utf8(&buf
[..content
.len()]), Ok(content
));
380 assert_eq
!(check
!(read
.seek(SeekFrom
::Current(0))), 14);
381 assert_eq
!(check
!(read
.seek_read(&mut buf
, 14)), 0);
382 assert_eq
!(check
!(read
.seek_read(&mut buf
, 15)), 0);
384 check
!(fs
::remove_file(&filename
));
388 fn file_test_stat_is_correct_on_is_file() {
389 let tmpdir
= tmpdir();
390 let filename
= &tmpdir
.join("file_stat_correct_on_is_file.txt");
392 let mut opts
= OpenOptions
::new();
393 let mut fs
= check
!(opts
.read(true).write(true).create(true).open(filename
));
395 fs
.write(msg
.as_bytes()).unwrap();
397 let fstat_res
= check
!(fs
.metadata());
398 assert
!(fstat_res
.is_file());
400 let stat_res_fn
= check
!(fs
::metadata(filename
));
401 assert
!(stat_res_fn
.is_file());
402 let stat_res_meth
= check
!(filename
.metadata());
403 assert
!(stat_res_meth
.is_file());
404 check
!(fs
::remove_file(filename
));
408 fn file_test_stat_is_correct_on_is_dir() {
409 let tmpdir
= tmpdir();
410 let filename
= &tmpdir
.join("file_stat_correct_on_is_dir");
411 check
!(fs
::create_dir(filename
));
412 let stat_res_fn
= check
!(fs
::metadata(filename
));
413 assert
!(stat_res_fn
.is_dir());
414 let stat_res_meth
= check
!(filename
.metadata());
415 assert
!(stat_res_meth
.is_dir());
416 check
!(fs
::remove_dir(filename
));
420 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
421 let tmpdir
= tmpdir();
422 let dir
= &tmpdir
.join("fileinfo_false_on_dir");
423 check
!(fs
::create_dir(dir
));
424 assert
!(!dir
.is_file());
425 check
!(fs
::remove_dir(dir
));
429 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
430 let tmpdir
= tmpdir();
431 let file
= &tmpdir
.join("fileinfo_check_exists_b_and_a.txt");
432 check
!(check
!(File
::create(file
)).write(b
"foo"));
433 assert
!(file
.exists());
434 check
!(fs
::remove_file(file
));
435 assert
!(!file
.exists());
439 fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
440 let tmpdir
= tmpdir();
441 let dir
= &tmpdir
.join("before_and_after_dir");
442 assert
!(!dir
.exists());
443 check
!(fs
::create_dir(dir
));
444 assert
!(dir
.exists());
445 assert
!(dir
.is_dir());
446 check
!(fs
::remove_dir(dir
));
447 assert
!(!dir
.exists());
451 fn file_test_directoryinfo_readdir() {
452 let tmpdir
= tmpdir();
453 let dir
= &tmpdir
.join("di_readdir");
454 check
!(fs
::create_dir(dir
));
457 let f
= dir
.join(&format
!("{}.txt", n
));
458 let mut w
= check
!(File
::create(&f
));
459 let msg_str
= format
!("{}{}", prefix
, n
.to_string());
460 let msg
= msg_str
.as_bytes();
461 check
!(w
.write(msg
));
463 let files
= check
!(fs
::read_dir(dir
));
464 let mut mem
= [0; 4];
466 let f
= f
.unwrap().path();
468 let n
= f
.file_stem().unwrap();
469 check
!(check
!(File
::open(&f
)).read(&mut mem
));
470 let read_str
= str::from_utf8(&mem
).unwrap();
471 let expected
= format
!("{}{}", prefix
, n
.to_str().unwrap());
472 assert_eq
!(expected
, read_str
);
474 check
!(fs
::remove_file(&f
));
476 check
!(fs
::remove_dir(dir
));
480 fn file_create_new_already_exists_error() {
481 let tmpdir
= tmpdir();
482 let file
= &tmpdir
.join("file_create_new_error_exists");
483 check
!(fs
::File
::create(file
));
484 let e
= fs
::OpenOptions
::new().write(true).create_new(true).open(file
).unwrap_err();
485 assert_eq
!(e
.kind(), ErrorKind
::AlreadyExists
);
489 fn mkdir_path_already_exists_error() {
490 let tmpdir
= tmpdir();
491 let dir
= &tmpdir
.join("mkdir_error_twice");
492 check
!(fs
::create_dir(dir
));
493 let e
= fs
::create_dir(dir
).unwrap_err();
494 assert_eq
!(e
.kind(), ErrorKind
::AlreadyExists
);
498 fn recursive_mkdir() {
499 let tmpdir
= tmpdir();
500 let dir
= tmpdir
.join("d1/d2");
501 check
!(fs
::create_dir_all(&dir
));
502 assert
!(dir
.is_dir())
506 fn recursive_mkdir_failure() {
507 let tmpdir
= tmpdir();
508 let dir
= tmpdir
.join("d1");
509 let file
= dir
.join("f1");
511 check
!(fs
::create_dir_all(&dir
));
512 check
!(File
::create(&file
));
514 let result
= fs
::create_dir_all(&file
);
516 assert
!(result
.is_err());
520 fn concurrent_recursive_mkdir() {
523 let mut dir
= dir
.join("a");
527 let mut join
= vec
![];
529 let dir
= dir
.clone();
530 join
.push(thread
::spawn(move || {
531 check
!(fs
::create_dir_all(&dir
));
535 // No `Display` on result of `join()`
536 join
.drain(..).map(|join
| join
.join().unwrap()).count();
541 fn recursive_mkdir_slash() {
542 check
!(fs
::create_dir_all(Path
::new("/")));
546 fn recursive_mkdir_dot() {
547 check
!(fs
::create_dir_all(Path
::new(".")));
551 fn recursive_mkdir_empty() {
552 check
!(fs
::create_dir_all(Path
::new("")));
556 fn recursive_rmdir() {
557 let tmpdir
= tmpdir();
558 let d1
= tmpdir
.join("d1");
559 let dt
= d1
.join("t");
560 let dtt
= dt
.join("t");
561 let d2
= tmpdir
.join("d2");
562 let canary
= d2
.join("do_not_delete");
563 check
!(fs
::create_dir_all(&dtt
));
564 check
!(fs
::create_dir_all(&d2
));
565 check
!(check
!(File
::create(&canary
)).write(b
"foo"));
566 check
!(symlink_junction(&d2
, &dt
.join("d2")));
567 let _
= symlink_file(&canary
, &d1
.join("canary"));
568 check
!(fs
::remove_dir_all(&d1
));
570 assert
!(!d1
.is_dir());
571 assert
!(canary
.exists());
575 fn recursive_rmdir_of_symlink() {
576 // test we do not recursively delete a symlink but only dirs.
577 let tmpdir
= tmpdir();
578 let link
= tmpdir
.join("d1");
579 let dir
= tmpdir
.join("d2");
580 let canary
= dir
.join("do_not_delete");
581 check
!(fs
::create_dir_all(&dir
));
582 check
!(check
!(File
::create(&canary
)).write(b
"foo"));
583 check
!(symlink_junction(&dir
, &link
));
584 check
!(fs
::remove_dir_all(&link
));
586 assert
!(!link
.is_dir());
587 assert
!(canary
.exists());
591 // only Windows makes a distinction between file and directory symlinks.
593 fn recursive_rmdir_of_file_symlink() {
594 let tmpdir
= tmpdir();
595 if !got_symlink_permission(&tmpdir
) {
599 let f1
= tmpdir
.join("f1");
600 let f2
= tmpdir
.join("f2");
601 check
!(check
!(File
::create(&f1
)).write(b
"foo"));
602 check
!(symlink_file(&f1
, &f2
));
603 match fs
::remove_dir_all(&f2
) {
604 Ok(..) => panic
!("wanted a failure"),
610 fn unicode_path_is_dir() {
611 assert
!(Path
::new(".").is_dir());
612 assert
!(!Path
::new("test/stdtest/fs.rs").is_dir());
614 let tmpdir
= tmpdir();
616 let mut dirpath
= tmpdir
.path().to_path_buf();
617 dirpath
.push("test-가一ー你好");
618 check
!(fs
::create_dir(&dirpath
));
619 assert
!(dirpath
.is_dir());
621 let mut filepath
= dirpath
;
622 filepath
.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
623 check
!(File
::create(&filepath
)); // ignore return; touch only
624 assert
!(!filepath
.is_dir());
625 assert
!(filepath
.exists());
629 fn unicode_path_exists() {
630 assert
!(Path
::new(".").exists());
631 assert
!(!Path
::new("test/nonexistent-bogus-path").exists());
633 let tmpdir
= tmpdir();
634 let unicode
= tmpdir
.path();
635 let unicode
= unicode
.join("test-각丁ー再见");
636 check
!(fs
::create_dir(&unicode
));
637 assert
!(unicode
.exists());
638 assert
!(!Path
::new("test/unicode-bogus-path-각丁ー再见").exists());
642 fn copy_file_does_not_exist() {
643 let from
= Path
::new("test/nonexistent-bogus-path");
644 let to
= Path
::new("test/other-bogus-path");
646 match fs
::copy(&from
, &to
) {
649 assert
!(!from
.exists());
650 assert
!(!to
.exists());
656 fn copy_src_does_not_exist() {
657 let tmpdir
= tmpdir();
658 let from
= Path
::new("test/nonexistent-bogus-path");
659 let to
= tmpdir
.join("out.txt");
660 check
!(check
!(File
::create(&to
)).write(b
"hello"));
661 assert
!(fs
::copy(&from
, &to
).is_err());
662 assert
!(!from
.exists());
663 let mut v
= Vec
::new();
664 check
!(check
!(File
::open(&to
)).read_to_end(&mut v
));
665 assert_eq
!(v
, b
"hello");
670 let tmpdir
= tmpdir();
671 let input
= tmpdir
.join("in.txt");
672 let out
= tmpdir
.join("out.txt");
674 check
!(check
!(File
::create(&input
)).write(b
"hello"));
675 check
!(fs
::copy(&input
, &out
));
676 let mut v
= Vec
::new();
677 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
678 assert_eq
!(v
, b
"hello");
680 assert_eq
!(check
!(input
.metadata()).permissions(), check
!(out
.metadata()).permissions());
684 fn copy_file_dst_dir() {
685 let tmpdir
= tmpdir();
686 let out
= tmpdir
.join("out");
688 check
!(File
::create(&out
));
689 match fs
::copy(&*out
, tmpdir
.path()) {
696 fn copy_file_dst_exists() {
697 let tmpdir
= tmpdir();
698 let input
= tmpdir
.join("in");
699 let output
= tmpdir
.join("out");
701 check
!(check
!(File
::create(&input
)).write("foo".as_bytes()));
702 check
!(check
!(File
::create(&output
)).write("bar".as_bytes()));
703 check
!(fs
::copy(&input
, &output
));
705 let mut v
= Vec
::new();
706 check
!(check
!(File
::open(&output
)).read_to_end(&mut v
));
707 assert_eq
!(v
, b
"foo".to_vec());
711 fn copy_file_src_dir() {
712 let tmpdir
= tmpdir();
713 let out
= tmpdir
.join("out");
715 match fs
::copy(tmpdir
.path(), &out
) {
719 assert
!(!out
.exists());
723 fn copy_file_preserves_perm_bits() {
724 let tmpdir
= tmpdir();
725 let input
= tmpdir
.join("in.txt");
726 let out
= tmpdir
.join("out.txt");
728 let attr
= check
!(check
!(File
::create(&input
)).metadata());
729 let mut p
= attr
.permissions();
730 p
.set_readonly(true);
731 check
!(fs
::set_permissions(&input
, p
));
732 check
!(fs
::copy(&input
, &out
));
733 assert
!(check
!(out
.metadata()).permissions().readonly());
734 check
!(fs
::set_permissions(&input
, attr
.permissions()));
735 check
!(fs
::set_permissions(&out
, attr
.permissions()));
740 fn copy_file_preserves_streams() {
742 check
!(check
!(File
::create(tmp
.join("in.txt:bunny"))).write("carrot".as_bytes()));
743 assert_eq
!(check
!(fs
::copy(tmp
.join("in.txt"), tmp
.join("out.txt"))), 0);
744 assert_eq
!(check
!(tmp
.join("out.txt").metadata()).len(), 0);
745 let mut v
= Vec
::new();
746 check
!(check
!(File
::open(tmp
.join("out.txt:bunny"))).read_to_end(&mut v
));
747 assert_eq
!(v
, b
"carrot".to_vec());
751 fn copy_file_returns_metadata_len() {
753 let in_path
= tmp
.join("in.txt");
754 let out_path
= tmp
.join("out.txt");
755 check
!(check
!(File
::create(&in_path
)).write(b
"lettuce"));
757 check
!(check
!(File
::create(tmp
.join("in.txt:bunny"))).write(b
"carrot"));
758 let copied_len
= check
!(fs
::copy(&in_path
, &out_path
));
759 assert_eq
!(check
!(out_path
.metadata()).len(), copied_len
);
763 fn copy_file_follows_dst_symlink() {
765 if !got_symlink_permission(&tmp
) {
769 let in_path
= tmp
.join("in.txt");
770 let out_path
= tmp
.join("out.txt");
771 let out_path_symlink
= tmp
.join("out_symlink.txt");
773 check
!(fs
::write(&in_path
, "foo"));
774 check
!(fs
::write(&out_path
, "bar"));
775 check
!(symlink_file(&out_path
, &out_path_symlink
));
777 check
!(fs
::copy(&in_path
, &out_path_symlink
));
779 assert
!(check
!(out_path_symlink
.symlink_metadata()).file_type().is_symlink());
780 assert_eq
!(check
!(fs
::read(&out_path_symlink
)), b
"foo".to_vec());
781 assert_eq
!(check
!(fs
::read(&out_path
)), b
"foo".to_vec());
786 let tmpdir
= tmpdir();
787 if !got_symlink_permission(&tmpdir
) {
791 let input
= tmpdir
.join("in.txt");
792 let out
= tmpdir
.join("out.txt");
794 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
795 check
!(symlink_file(&input
, &out
));
796 assert
!(check
!(out
.symlink_metadata()).file_type().is_symlink());
797 assert_eq
!(check
!(fs
::metadata(&out
)).len(), check
!(fs
::metadata(&input
)).len());
798 let mut v
= Vec
::new();
799 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
800 assert_eq
!(v
, b
"foobar".to_vec());
804 fn symlink_noexist() {
805 // Symlinks can point to things that don't exist
806 let tmpdir
= tmpdir();
807 if !got_symlink_permission(&tmpdir
) {
811 // Use a relative path for testing. Symlinks get normalized by Windows,
812 // so we may not get the same path back for absolute paths
813 check
!(symlink_file(&"foo", &tmpdir
.join("bar")));
814 assert_eq
!(check
!(fs
::read_link(&tmpdir
.join("bar"))).to_str().unwrap(), "foo");
822 check
!(fs
::read_link(r
"C:\Users\All Users")).to_str().unwrap(),
827 check
!(fs
::read_link(r
"C:\Users\Default User")).to_str().unwrap(),
830 // junction with special permissions
832 check
!(fs
::read_link(r
"C:\Documents and Settings\")).to_str().unwrap(),
836 let tmpdir
= tmpdir();
837 let link
= tmpdir
.join("link");
838 if !got_symlink_permission(&tmpdir
) {
841 check
!(symlink_file(&"foo", &link
));
842 assert_eq
!(check
!(fs
::read_link(&link
)).to_str().unwrap(), "foo");
846 fn readlink_not_symlink() {
847 let tmpdir
= tmpdir();
848 match fs
::read_link(tmpdir
.path()) {
849 Ok(..) => panic
!("wanted a failure"),
856 let tmpdir
= tmpdir();
857 let input
= tmpdir
.join("in.txt");
858 let out
= tmpdir
.join("out.txt");
860 check
!(check
!(File
::create(&input
)).write("foobar".as_bytes()));
861 check
!(fs
::hard_link(&input
, &out
));
862 assert_eq
!(check
!(fs
::metadata(&out
)).len(), check
!(fs
::metadata(&input
)).len());
863 assert_eq
!(check
!(fs
::metadata(&out
)).len(), check
!(input
.metadata()).len());
864 let mut v
= Vec
::new();
865 check
!(check
!(File
::open(&out
)).read_to_end(&mut v
));
866 assert_eq
!(v
, b
"foobar".to_vec());
868 // can't link to yourself
869 match fs
::hard_link(&input
, &input
) {
870 Ok(..) => panic
!("wanted a failure"),
873 // can't link to something that doesn't exist
874 match fs
::hard_link(&tmpdir
.join("foo"), &tmpdir
.join("bar")) {
875 Ok(..) => panic
!("wanted a failure"),
882 let tmpdir
= tmpdir();
883 let file
= tmpdir
.join("in.txt");
885 check
!(File
::create(&file
));
886 let attr
= check
!(fs
::metadata(&file
));
887 assert
!(!attr
.permissions().readonly());
888 let mut p
= attr
.permissions();
889 p
.set_readonly(true);
890 check
!(fs
::set_permissions(&file
, p
.clone()));
891 let attr
= check
!(fs
::metadata(&file
));
892 assert
!(attr
.permissions().readonly());
894 match fs
::set_permissions(&tmpdir
.join("foo"), p
.clone()) {
895 Ok(..) => panic
!("wanted an error"),
899 p
.set_readonly(false);
900 check
!(fs
::set_permissions(&file
, p
));
905 let tmpdir
= tmpdir();
906 let path
= tmpdir
.join("in.txt");
908 let file
= check
!(File
::create(&path
));
909 let attr
= check
!(fs
::metadata(&path
));
910 assert
!(!attr
.permissions().readonly());
911 let mut p
= attr
.permissions();
912 p
.set_readonly(true);
913 check
!(file
.set_permissions(p
.clone()));
914 let attr
= check
!(fs
::metadata(&path
));
915 assert
!(attr
.permissions().readonly());
917 p
.set_readonly(false);
918 check
!(file
.set_permissions(p
));
922 fn sync_doesnt_kill_anything() {
923 let tmpdir
= tmpdir();
924 let path
= tmpdir
.join("in.txt");
926 let mut file
= check
!(File
::create(&path
));
927 check
!(file
.sync_all());
928 check
!(file
.sync_data());
929 check
!(file
.write(b
"foo"));
930 check
!(file
.sync_all());
931 check
!(file
.sync_data());
935 fn truncate_works() {
936 let tmpdir
= tmpdir();
937 let path
= tmpdir
.join("in.txt");
939 let mut file
= check
!(File
::create(&path
));
940 check
!(file
.write(b
"foo"));
941 check
!(file
.sync_all());
943 // Do some simple things with truncation
944 assert_eq
!(check
!(file
.metadata()).len(), 3);
945 check
!(file
.set_len(10));
946 assert_eq
!(check
!(file
.metadata()).len(), 10);
947 check
!(file
.write(b
"bar"));
948 check
!(file
.sync_all());
949 assert_eq
!(check
!(file
.metadata()).len(), 10);
951 let mut v
= Vec
::new();
952 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
953 assert_eq
!(v
, b
"foobar\0\0\0\0".to_vec());
955 // Truncate to a smaller length, don't seek, and then write something.
956 // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
957 // past the end of the file).
958 check
!(file
.set_len(2));
959 assert_eq
!(check
!(file
.metadata()).len(), 2);
960 check
!(file
.write(b
"wut"));
961 check
!(file
.sync_all());
962 assert_eq
!(check
!(file
.metadata()).len(), 9);
963 let mut v
= Vec
::new();
964 check
!(check
!(File
::open(&path
)).read_to_end(&mut v
));
965 assert_eq
!(v
, b
"fo\0\0\0\0wut".to_vec());
970 use crate::fs
::OpenOptions
as OO
;
971 fn c
<T
: Clone
>(t
: &T
) -> T
{
975 let tmpdir
= tmpdir();
977 let mut r
= OO
::new();
979 let mut w
= OO
::new();
981 let mut rw
= OO
::new();
982 rw
.read(true).write(true);
983 let mut a
= OO
::new();
985 let mut ra
= OO
::new();
986 ra
.read(true).append(true);
989 let invalid_options
= 87; // ERROR_INVALID_PARAMETER
990 #[cfg(all(unix, not(target_os = "vxworks")))]
991 let invalid_options
= "Invalid argument";
992 #[cfg(target_os = "vxworks")]
993 let invalid_options
= "invalid argument";
995 // Test various combinations of creation modes and access modes.
998 // creation mode | read | write | read-write | append | read-append |
999 // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
1000 // not set (open existing) | X | X | X | X | X |
1001 // create | | X | X | X | X |
1002 // truncate | | X | X | | |
1003 // create and truncate | | X | X | | |
1004 // create_new | | X | X | X | X |
1006 // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
1009 check
!(c(&w
).create_new(true).open(&tmpdir
.join("a")));
1010 check
!(c(&w
).create(true).truncate(true).open(&tmpdir
.join("a")));
1011 check
!(c(&w
).truncate(true).open(&tmpdir
.join("a")));
1012 check
!(c(&w
).create(true).open(&tmpdir
.join("a")));
1013 check
!(c(&w
).open(&tmpdir
.join("a")));
1016 error
!(c(&r
).create_new(true).open(&tmpdir
.join("b")), invalid_options
);
1017 error
!(c(&r
).create(true).truncate(true).open(&tmpdir
.join("b")), invalid_options
);
1018 error
!(c(&r
).truncate(true).open(&tmpdir
.join("b")), invalid_options
);
1019 error
!(c(&r
).create(true).open(&tmpdir
.join("b")), invalid_options
);
1020 check
!(c(&r
).open(&tmpdir
.join("a"))); // try opening the file created with write_only
1023 check
!(c(&rw
).create_new(true).open(&tmpdir
.join("c")));
1024 check
!(c(&rw
).create(true).truncate(true).open(&tmpdir
.join("c")));
1025 check
!(c(&rw
).truncate(true).open(&tmpdir
.join("c")));
1026 check
!(c(&rw
).create(true).open(&tmpdir
.join("c")));
1027 check
!(c(&rw
).open(&tmpdir
.join("c")));
1030 check
!(c(&a
).create_new(true).open(&tmpdir
.join("d")));
1031 error
!(c(&a
).create(true).truncate(true).open(&tmpdir
.join("d")), invalid_options
);
1032 error
!(c(&a
).truncate(true).open(&tmpdir
.join("d")), invalid_options
);
1033 check
!(c(&a
).create(true).open(&tmpdir
.join("d")));
1034 check
!(c(&a
).open(&tmpdir
.join("d")));
1037 check
!(c(&ra
).create_new(true).open(&tmpdir
.join("e")));
1038 error
!(c(&ra
).create(true).truncate(true).open(&tmpdir
.join("e")), invalid_options
);
1039 error
!(c(&ra
).truncate(true).open(&tmpdir
.join("e")), invalid_options
);
1040 check
!(c(&ra
).create(true).open(&tmpdir
.join("e")));
1041 check
!(c(&ra
).open(&tmpdir
.join("e")));
1043 // Test opening a file without setting an access mode
1044 let mut blank
= OO
::new();
1045 error
!(blank
.create(true).open(&tmpdir
.join("f")), invalid_options
);
1048 check
!(check
!(File
::create(&tmpdir
.join("h"))).write("foobar".as_bytes()));
1050 // Test write fails for read-only
1051 check
!(r
.open(&tmpdir
.join("h")));
1053 let mut f
= check
!(r
.open(&tmpdir
.join("h")));
1054 assert
!(f
.write("wut".as_bytes()).is_err());
1057 // Test write overwrites
1059 let mut f
= check
!(c(&w
).open(&tmpdir
.join("h")));
1060 check
!(f
.write("baz".as_bytes()));
1063 let mut f
= check
!(c(&r
).open(&tmpdir
.join("h")));
1064 let mut b
= vec
![0; 6];
1065 check
!(f
.read(&mut b
));
1066 assert_eq
!(b
, "bazbar".as_bytes());
1069 // Test truncate works
1071 let mut f
= check
!(c(&w
).truncate(true).open(&tmpdir
.join("h")));
1072 check
!(f
.write("foo".as_bytes()));
1074 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
1076 // Test append works
1077 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 3);
1079 let mut f
= check
!(c(&a
).open(&tmpdir
.join("h")));
1080 check
!(f
.write("bar".as_bytes()));
1082 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 6);
1084 // Test .append(true) equals .write(true).append(true)
1086 let mut f
= check
!(c(&w
).append(true).open(&tmpdir
.join("h")));
1087 check
!(f
.write("baz".as_bytes()));
1089 assert_eq
!(check
!(fs
::metadata(&tmpdir
.join("h"))).len(), 9);
1093 fn _assert_send_sync() {
1094 fn _assert_send_sync
<T
: Send
+ Sync
>() {}
1095 _assert_send_sync
::<OpenOptions
>();
1100 let mut bytes
= [0; 1024];
1101 StdRng
::from_entropy().fill_bytes(&mut bytes
);
1103 let tmpdir
= tmpdir();
1105 check
!(check
!(File
::create(&tmpdir
.join("test"))).write(&bytes
));
1106 let mut v
= Vec
::new();
1107 check
!(check
!(File
::open(&tmpdir
.join("test"))).read_to_end(&mut v
));
1108 assert
!(v
== &bytes
[..]);
1112 fn write_then_read() {
1113 let mut bytes
= [0; 1024];
1114 StdRng
::from_entropy().fill_bytes(&mut bytes
);
1116 let tmpdir
= tmpdir();
1118 check
!(fs
::write(&tmpdir
.join("test"), &bytes
[..]));
1119 let v
= check
!(fs
::read(&tmpdir
.join("test")));
1120 assert
!(v
== &bytes
[..]);
1122 check
!(fs
::write(&tmpdir
.join("not-utf8"), &[0xFF]));
1124 fs
::read_to_string(&tmpdir
.join("not-utf8")),
1125 "stream did not contain valid UTF-8"
1129 check
!(fs
::write(&tmpdir
.join("utf8"), s
.as_bytes()));
1130 let string
= check
!(fs
::read_to_string(&tmpdir
.join("utf8")));
1131 assert_eq
!(string
, s
);
1135 fn file_try_clone() {
1136 let tmpdir
= tmpdir();
1139 check
!(OpenOptions
::new().read(true).write(true).create(true).open(&tmpdir
.join("test")));
1140 let mut f2
= check
!(f1
.try_clone());
1142 check
!(f1
.write_all(b
"hello world"));
1143 check
!(f1
.seek(SeekFrom
::Start(2)));
1145 let mut buf
= vec
![];
1146 check
!(f2
.read_to_end(&mut buf
));
1147 assert_eq
!(buf
, b
"llo world");
1150 check
!(f1
.write_all(b
"!"));
1154 #[cfg(not(windows))]
1155 fn unlink_readonly() {
1156 let tmpdir
= tmpdir();
1157 let path
= tmpdir
.join("file");
1158 check
!(File
::create(&path
));
1159 let mut perm
= check
!(fs
::metadata(&path
)).permissions();
1160 perm
.set_readonly(true);
1161 check
!(fs
::set_permissions(&path
, perm
));
1162 check
!(fs
::remove_file(&path
));
1166 fn mkdir_trailing_slash() {
1167 let tmpdir
= tmpdir();
1168 let path
= tmpdir
.join("file");
1169 check
!(fs
::create_dir_all(&path
.join("a/")));
1173 fn canonicalize_works_simple() {
1174 let tmpdir
= tmpdir();
1175 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
1176 let file
= tmpdir
.join("test");
1177 File
::create(&file
).unwrap();
1178 assert_eq
!(fs
::canonicalize(&file
).unwrap(), file
);
1182 fn realpath_works() {
1183 let tmpdir
= tmpdir();
1184 if !got_symlink_permission(&tmpdir
) {
1188 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
1189 let file
= tmpdir
.join("test");
1190 let dir
= tmpdir
.join("test2");
1191 let link
= dir
.join("link");
1192 let linkdir
= tmpdir
.join("test3");
1194 File
::create(&file
).unwrap();
1195 fs
::create_dir(&dir
).unwrap();
1196 symlink_file(&file
, &link
).unwrap();
1197 symlink_dir(&dir
, &linkdir
).unwrap();
1199 assert
!(link
.symlink_metadata().unwrap().file_type().is_symlink());
1201 assert_eq
!(fs
::canonicalize(&tmpdir
).unwrap(), tmpdir
);
1202 assert_eq
!(fs
::canonicalize(&file
).unwrap(), file
);
1203 assert_eq
!(fs
::canonicalize(&link
).unwrap(), file
);
1204 assert_eq
!(fs
::canonicalize(&linkdir
).unwrap(), dir
);
1205 assert_eq
!(fs
::canonicalize(&linkdir
.join("link")).unwrap(), file
);
1209 fn realpath_works_tricky() {
1210 let tmpdir
= tmpdir();
1211 if !got_symlink_permission(&tmpdir
) {
1215 let tmpdir
= fs
::canonicalize(tmpdir
.path()).unwrap();
1216 let a
= tmpdir
.join("a");
1217 let b
= a
.join("b");
1218 let c
= b
.join("c");
1219 let d
= a
.join("d");
1220 let e
= d
.join("e");
1221 let f
= a
.join("f");
1223 fs
::create_dir_all(&b
).unwrap();
1224 fs
::create_dir_all(&d
).unwrap();
1225 File
::create(&f
).unwrap();
1226 if cfg
!(not(windows
)) {
1227 symlink_file("../d/e", &c
).unwrap();
1228 symlink_file("../f", &e
).unwrap();
1231 symlink_file(r
"..\d\e", &c
).unwrap();
1232 symlink_file(r
"..\f", &e
).unwrap();
1235 assert_eq
!(fs
::canonicalize(&c
).unwrap(), f
);
1236 assert_eq
!(fs
::canonicalize(&e
).unwrap(), f
);
1240 fn dir_entry_methods() {
1241 let tmpdir
= tmpdir();
1243 fs
::create_dir_all(&tmpdir
.join("a")).unwrap();
1244 File
::create(&tmpdir
.join("b")).unwrap();
1246 for file
in tmpdir
.path().read_dir().unwrap().map(|f
| f
.unwrap()) {
1247 let fname
= file
.file_name();
1248 match fname
.to_str() {
1250 assert
!(file
.file_type().unwrap().is_dir());
1251 assert
!(file
.metadata().unwrap().is_dir());
1254 assert
!(file
.file_type().unwrap().is_file());
1255 assert
!(file
.metadata().unwrap().is_file());
1257 f
=> panic
!("unknown file name: {:?}", f
),
1263 fn dir_entry_debug() {
1264 let tmpdir
= tmpdir();
1265 File
::create(&tmpdir
.join("b")).unwrap();
1266 let mut read_dir
= tmpdir
.path().read_dir().unwrap();
1267 let dir_entry
= read_dir
.next().unwrap().unwrap();
1268 let actual
= format
!("{:?}", dir_entry
);
1269 let expected
= format
!("DirEntry({:?})", dir_entry
.0.path());
1270 assert_eq
!(actual
, expected
);
1274 fn read_dir_not_found() {
1275 let res
= fs
::read_dir("/path/that/does/not/exist");
1276 assert_eq
!(res
.err().unwrap().kind(), ErrorKind
::NotFound
);
1280 fn create_dir_all_with_junctions() {
1281 let tmpdir
= tmpdir();
1282 let target
= tmpdir
.join("target");
1284 let junction
= tmpdir
.join("junction");
1285 let b
= junction
.join("a/b");
1287 let link
= tmpdir
.join("link");
1288 let d
= link
.join("c/d");
1290 fs
::create_dir(&target
).unwrap();
1292 check
!(symlink_junction(&target
, &junction
));
1293 check
!(fs
::create_dir_all(&b
));
1294 // the junction itself is not a directory, but `is_dir()` on a Path
1296 assert
!(junction
.is_dir());
1297 assert
!(b
.exists());
1299 if !got_symlink_permission(&tmpdir
) {
1302 check
!(symlink_dir(&target
, &link
));
1303 check
!(fs
::create_dir_all(&d
));
1304 assert
!(link
.is_dir());
1305 assert
!(d
.exists());
1309 fn metadata_access_times() {
1310 let tmpdir
= tmpdir();
1312 let b
= tmpdir
.join("b");
1313 File
::create(&b
).unwrap();
1315 let a
= check
!(fs
::metadata(&tmpdir
.path()));
1316 let b
= check
!(fs
::metadata(&b
));
1318 assert_eq
!(check
!(a
.accessed()), check
!(a
.accessed()));
1319 assert_eq
!(check
!(a
.modified()), check
!(a
.modified()));
1320 assert_eq
!(check
!(b
.accessed()), check
!(b
.modified()));
1322 if cfg
!(target_os
= "macos") || cfg
!(target_os
= "windows") {
1323 check
!(a
.created());
1324 check
!(b
.created());
1327 if cfg
!(target_os
= "linux") {
1328 // Not always available
1329 match (a
.created(), b
.created()) {
1330 (Ok(t1
), Ok(t2
)) => assert
!(t1
<= t2
),
1332 if e1
.kind() == ErrorKind
::Other
&& e2
.kind() == ErrorKind
::Other
=> {}
1334 panic
!("creation time must be always supported or not supported: {:?} {:?}", a
, b
,)
1340 /// Test creating hard links to symlinks.
1342 fn symlink_hard_link() {
1343 let tmpdir
= tmpdir();
1345 // Create "file", a file.
1346 check
!(fs
::File
::create(tmpdir
.join("file")));
1348 // Create "symlink", a symlink to "file".
1349 check
!(symlink_file("file", tmpdir
.join("symlink")));
1351 // Create "hard_link", a hard link to "symlink".
1352 check
!(fs
::hard_link(tmpdir
.join("symlink"), tmpdir
.join("hard_link")));
1354 // "hard_link" should appear as a symlink.
1355 assert
!(check
!(fs
::symlink_metadata(tmpdir
.join("hard_link"))).file_type().is_symlink());
1357 // We sould be able to open "file" via any of the above names.
1358 let _
= check
!(fs
::File
::open(tmpdir
.join("file")));
1359 assert
!(fs
::File
::open(tmpdir
.join("file.renamed")).is_err());
1360 let _
= check
!(fs
::File
::open(tmpdir
.join("symlink")));
1361 let _
= check
!(fs
::File
::open(tmpdir
.join("hard_link")));
1363 // Rename "file" to "file.renamed".
1364 check
!(fs
::rename(tmpdir
.join("file"), tmpdir
.join("file.renamed")));
1366 // Now, the symlink and the hard link should be dangling.
1367 assert
!(fs
::File
::open(tmpdir
.join("file")).is_err());
1368 let _
= check
!(fs
::File
::open(tmpdir
.join("file.renamed")));
1369 assert
!(fs
::File
::open(tmpdir
.join("symlink")).is_err());
1370 assert
!(fs
::File
::open(tmpdir
.join("hard_link")).is_err());
1372 // The symlink and the hard link should both still point to "file".
1373 assert
!(fs
::read_link(tmpdir
.join("file")).is_err());
1374 assert
!(fs
::read_link(tmpdir
.join("file.renamed")).is_err());
1375 assert_eq
!(check
!(fs
::read_link(tmpdir
.join("symlink"))), Path
::new("file"));
1376 assert_eq
!(check
!(fs
::read_link(tmpdir
.join("hard_link"))), Path
::new("file"));
1378 // Remove "file.renamed".
1379 check
!(fs
::remove_file(tmpdir
.join("file.renamed")));
1381 // Now, we can't open the file by any name.
1382 assert
!(fs
::File
::open(tmpdir
.join("file")).is_err());
1383 assert
!(fs
::File
::open(tmpdir
.join("file.renamed")).is_err());
1384 assert
!(fs
::File
::open(tmpdir
.join("symlink")).is_err());
1385 assert
!(fs
::File
::open(tmpdir
.join("hard_link")).is_err());
1387 // "hard_link" should still appear as a symlink.
1388 assert
!(check
!(fs
::symlink_metadata(tmpdir
.join("hard_link"))).file_type().is_symlink());