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),
42 assert!(err.raw_os_error() == Some($s), "`{}` did not have a code of `{}`", err, $s)
50 ($e:expr, $s:expr) => {
51 error_contains!($e, $s)
55 macro_rules! error_contains {
56 ($e:expr, $s:expr) => {
58 Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
60 assert!(err.to_string().contains($s), "`{}` did not contain `{}`", err, $s)
66 // Several test fail on windows if the user does not have permission to
67 // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
68 // disabling these test on Windows, use this function to test whether we
69 // have permission, and return otherwise. This way, we still don't run these
70 // tests most of the time, but at least we do if the user has the right
72 pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
76 let link = tmpdir.join("some_hopefully_unique_link_name");
78 match symlink_file(r"nonexisting_target", link) {
79 // ERROR_PRIVILEGE_NOT_HELD = 1314
80 Err(ref err) if err.raw_os_error() == Some(1314) => false,
81 Ok(_) | Err(_) => true,
85 #[cfg(target_os = "macos")]
86 fn able_to_not_follow_symlinks_while_hard_linking() -> bool {
87 weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int);
88 linkat.get().is_some()
91 #[cfg(not(target_os = "macos"))]
92 fn able_to_not_follow_symlinks_while_hard_linking() -> bool {
97 fn file_test_io_smoke_test() {
98 let message = "it's alright. have a good time";
99 let tmpdir = tmpdir();
100 let filename = &tmpdir.join("file_rt_io_file_test.txt");
102 let mut write_stream = check!(File::create(filename));
103 check!(write_stream.write(message.as_bytes()));
106 let mut read_stream = check!(File::open(filename));
107 let mut read_buf = [0; 1028];
108 let read_str = match check!(read_stream.read(&mut read_buf)) {
109 0 => panic!("shouldn't happen"),
110 n => str::from_utf8(&read_buf[..n]).unwrap().to_string(),
112 assert_eq!(read_str, message);
114 check!(fs::remove_file(filename));
118 fn invalid_path_raises() {
119 let tmpdir = tmpdir();
120 let filename = &tmpdir.join("file_that_does_not_exist.txt");
121 let result = File::open(filename);
123 #[cfg(all(unix, not(target_os = "vxworks")))]
124 error!(result, "No such file or directory");
125 #[cfg(target_os = "vxworks")]
126 error!(result, "no such file or directory");
128 error!(result, 2); // ERROR_FILE_NOT_FOUND
132 fn file_test_iounlinking_invalid_path_should_raise_condition() {
133 let tmpdir = tmpdir();
134 let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
136 let result = fs::remove_file(filename);
138 #[cfg(all(unix, not(target_os = "vxworks")))]
139 error!(result, "No such file or directory");
140 #[cfg(target_os = "vxworks")]
141 error!(result, "no such file or directory");
143 error!(result, 2); // ERROR_FILE_NOT_FOUND
147 fn file_test_io_non_positional_read() {
148 let message: &str = "ten-four";
149 let mut read_mem = [0; 8];
150 let tmpdir = tmpdir();
151 let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
153 let mut rw_stream = check!(File::create(filename));
154 check!(rw_stream.write(message.as_bytes()));
157 let mut read_stream = check!(File::open(filename));
159 let read_buf = &mut read_mem[0..4];
160 check!(read_stream.read(read_buf));
163 let read_buf = &mut read_mem[4..8];
164 check!(read_stream.read(read_buf));
167 check!(fs::remove_file(filename));
168 let read_str = str::from_utf8(&read_mem).unwrap();
169 assert_eq!(read_str, message);
173 fn file_test_io_seek_and_tell_smoke_test() {
174 let message = "ten-four";
175 let mut read_mem = [0; 4];
176 let set_cursor = 4 as u64;
177 let tell_pos_pre_read;
178 let tell_pos_post_read;
179 let tmpdir = tmpdir();
180 let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
182 let mut rw_stream = check!(File::create(filename));
183 check!(rw_stream.write(message.as_bytes()));
186 let mut read_stream = check!(File::open(filename));
187 check!(read_stream.seek(SeekFrom::Start(set_cursor)));
188 tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
189 check!(read_stream.read(&mut read_mem));
190 tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
192 check!(fs::remove_file(filename));
193 let read_str = str::from_utf8(&read_mem).unwrap();
194 assert_eq!(read_str, &message[4..8]);
195 assert_eq!(tell_pos_pre_read, set_cursor);
196 assert_eq!(tell_pos_post_read, message.len() as u64);
200 fn file_test_io_seek_and_write() {
201 let initial_msg = "food-is-yummy";
202 let overwrite_msg = "-the-bar!!";
203 let final_msg = "foo-the-bar!!";
205 let mut read_mem = [0; 13];
206 let tmpdir = tmpdir();
207 let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
209 let mut rw_stream = check!(File::create(filename));
210 check!(rw_stream.write(initial_msg.as_bytes()));
211 check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
212 check!(rw_stream.write(overwrite_msg.as_bytes()));
215 let mut read_stream = check!(File::open(filename));
216 check!(read_stream.read(&mut read_mem));
218 check!(fs::remove_file(filename));
219 let read_str = str::from_utf8(&read_mem).unwrap();
220 assert!(read_str == final_msg);
224 fn file_test_io_seek_shakedown() {
226 let initial_msg = "qwer-asdf-zxcv";
227 let chunk_one: &str = "qwer";
228 let chunk_two: &str = "asdf";
229 let chunk_three: &str = "zxcv";
230 let mut read_mem = [0; 4];
231 let tmpdir = tmpdir();
232 let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
234 let mut rw_stream = check!(File::create(filename));
235 check!(rw_stream.write(initial_msg.as_bytes()));
238 let mut read_stream = check!(File::open(filename));
240 check!(read_stream.seek(SeekFrom::End(-4)));
241 check!(read_stream.read(&mut read_mem));
242 assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
244 check!(read_stream.seek(SeekFrom::Current(-9)));
245 check!(read_stream.read(&mut read_mem));
246 assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
248 check!(read_stream.seek(SeekFrom::Start(0)));
249 check!(read_stream.read(&mut read_mem));
250 assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
252 check!(fs::remove_file(filename));
256 fn file_test_io_eof() {
257 let tmpdir = tmpdir();
258 let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
259 let mut buf = [0; 256];
261 let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
262 let mut rw = check!(oo.open(&filename));
263 assert_eq!(check!(rw.read(&mut buf)), 0);
264 assert_eq!(check!(rw.read(&mut buf)), 0);
266 check!(fs::remove_file(&filename));
271 fn file_test_io_read_write_at() {
272 use crate::os::unix::fs::FileExt;
274 let tmpdir = tmpdir();
275 let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
276 let mut buf = [0; 256];
278 let write2 = "qwer-";
279 let write3 = "-zxcv";
280 let content = "qwer-asdf-zxcv";
282 let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
283 let mut rw = check!(oo.open(&filename));
284 assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
285 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
286 assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
287 assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
288 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
289 assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
290 assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
291 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
292 assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
293 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
294 assert_eq!(check!(rw.read(&mut buf)), write1.len());
295 assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
296 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
297 assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
298 assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
299 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
300 assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
301 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
304 let mut read = check!(File::open(&filename));
305 assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
306 assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
307 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
308 assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
309 assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
310 assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
311 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
312 assert_eq!(check!(read.read(&mut buf)), write3.len());
313 assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
314 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
315 assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
316 assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
317 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
318 assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
319 assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
320 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
322 check!(fs::remove_file(&filename));
327 fn set_get_unix_permissions() {
328 use crate::os::unix::fs::PermissionsExt;
330 let tmpdir = tmpdir();
331 let filename = &tmpdir.join("set_get_unix_permissions");
332 check!(fs::create_dir(filename));
335 check!(fs::set_permissions(filename, fs::Permissions::from_mode(0)));
336 let metadata0 = check!(fs::metadata(filename));
337 assert_eq!(mask & metadata0.permissions().mode(), 0);
339 check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
340 let metadata1 = check!(fs::metadata(filename));
341 #[cfg(all(unix, not(target_os = "vxworks")))]
342 assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
343 #[cfg(target_os = "vxworks")]
344 assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
349 fn file_test_io_seek_read_write() {
350 use crate::os::windows::fs::FileExt;
352 let tmpdir = tmpdir();
353 let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
354 let mut buf = [0; 256];
356 let write2 = "qwer-";
357 let write3 = "-zxcv";
358 let content = "qwer-asdf-zxcv";
360 let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
361 let mut rw = check!(oo.open(&filename));
362 assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
363 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
364 assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
365 assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
366 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
367 assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
368 assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
369 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
370 assert_eq!(check!(rw.read(&mut buf)), write1.len());
371 assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
372 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
373 assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
374 assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
375 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
376 assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
377 assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
380 let mut read = check!(File::open(&filename));
381 assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
382 assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
383 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
384 assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
385 assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
386 assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
387 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
388 assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
389 assert_eq!(check!(read.read(&mut buf)), write3.len());
390 assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
391 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
392 assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
393 assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
394 assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
395 assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
396 assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
398 check!(fs::remove_file(&filename));
402 fn file_test_stat_is_correct_on_is_file() {
403 let tmpdir = tmpdir();
404 let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
406 let mut opts = OpenOptions::new();
407 let mut fs = check!(opts.read(true).write(true).create(true).open(filename));
409 fs.write(msg.as_bytes()).unwrap();
411 let fstat_res = check!(fs.metadata());
412 assert!(fstat_res.is_file());
414 let stat_res_fn = check!(fs::metadata(filename));
415 assert!(stat_res_fn.is_file());
416 let stat_res_meth = check!(filename.metadata());
417 assert!(stat_res_meth.is_file());
418 check!(fs::remove_file(filename));
422 fn file_test_stat_is_correct_on_is_dir() {
423 let tmpdir = tmpdir();
424 let filename = &tmpdir.join("file_stat_correct_on_is_dir");
425 check!(fs::create_dir(filename));
426 let stat_res_fn = check!(fs::metadata(filename));
427 assert!(stat_res_fn.is_dir());
428 let stat_res_meth = check!(filename.metadata());
429 assert!(stat_res_meth.is_dir());
430 check!(fs::remove_dir(filename));
434 fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
435 let tmpdir = tmpdir();
436 let dir = &tmpdir.join("fileinfo_false_on_dir");
437 check!(fs::create_dir(dir));
438 assert!(!dir.is_file());
439 check!(fs::remove_dir(dir));
443 fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
444 let tmpdir = tmpdir();
445 let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
446 check!(check!(File::create(file)).write(b"foo"));
447 assert!(file.exists());
448 check!(fs::remove_file(file));
449 assert!(!file.exists());
453 fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
454 let tmpdir = tmpdir();
455 let dir = &tmpdir.join("before_and_after_dir");
456 assert!(!dir.exists());
457 check!(fs::create_dir(dir));
458 assert!(dir.exists());
459 assert!(dir.is_dir());
460 check!(fs::remove_dir(dir));
461 assert!(!dir.exists());
465 fn file_test_directoryinfo_readdir() {
466 let tmpdir = tmpdir();
467 let dir = &tmpdir.join("di_readdir");
468 check!(fs::create_dir(dir));
471 let f = dir.join(&format!("{}.txt", n));
472 let mut w = check!(File::create(&f));
473 let msg_str = format!("{}{}", prefix, n.to_string());
474 let msg = msg_str.as_bytes();
475 check!(w.write(msg));
477 let files = check!(fs::read_dir(dir));
478 let mut mem = [0; 4];
480 let f = f.unwrap().path();
482 let n = f.file_stem().unwrap();
483 check!(check!(File::open(&f)).read(&mut mem));
484 let read_str = str::from_utf8(&mem).unwrap();
485 let expected = format!("{}{}", prefix, n.to_str().unwrap());
486 assert_eq!(expected, read_str);
488 check!(fs::remove_file(&f));
490 check!(fs::remove_dir(dir));
494 fn file_create_new_already_exists_error() {
495 let tmpdir = tmpdir();
496 let file = &tmpdir.join("file_create_new_error_exists");
497 check!(fs::File::create(file));
498 let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err();
499 assert_eq!(e.kind(), ErrorKind::AlreadyExists);
503 fn mkdir_path_already_exists_error() {
504 let tmpdir = tmpdir();
505 let dir = &tmpdir.join("mkdir_error_twice");
506 check!(fs::create_dir(dir));
507 let e = fs::create_dir(dir).unwrap_err();
508 assert_eq!(e.kind(), ErrorKind::AlreadyExists);
512 fn recursive_mkdir() {
513 let tmpdir = tmpdir();
514 let dir = tmpdir.join("d1/d2");
515 check!(fs::create_dir_all(&dir));
516 assert!(dir.is_dir())
520 fn recursive_mkdir_failure() {
521 let tmpdir = tmpdir();
522 let dir = tmpdir.join("d1");
523 let file = dir.join("f1");
525 check!(fs::create_dir_all(&dir));
526 check!(File::create(&file));
528 let result = fs::create_dir_all(&file);
530 assert!(result.is_err());
534 fn concurrent_recursive_mkdir() {
537 let mut dir = dir.join("a");
541 let mut join = vec![];
543 let dir = dir.clone();
544 join.push(thread::spawn(move || {
545 check!(fs::create_dir_all(&dir));
549 // No `Display` on result of `join()`
550 join.drain(..).map(|join| join.join().unwrap()).count();
555 fn recursive_mkdir_slash() {
556 check!(fs::create_dir_all(Path::new("/")));
560 fn recursive_mkdir_dot() {
561 check!(fs::create_dir_all(Path::new(".")));
565 fn recursive_mkdir_empty() {
566 check!(fs::create_dir_all(Path::new("")));
570 fn recursive_rmdir() {
571 let tmpdir = tmpdir();
572 let d1 = tmpdir.join("d1");
573 let dt = d1.join("t");
574 let dtt = dt.join("t");
575 let d2 = tmpdir.join("d2");
576 let canary = d2.join("do_not_delete");
577 check!(fs::create_dir_all(&dtt));
578 check!(fs::create_dir_all(&d2));
579 check!(check!(File::create(&canary)).write(b"foo"));
580 check!(symlink_junction(&d2, &dt.join("d2")));
581 let _ = symlink_file(&canary, &d1.join("canary"));
582 check!(fs::remove_dir_all(&d1));
584 assert!(!d1.is_dir());
585 assert!(canary.exists());
589 fn recursive_rmdir_of_symlink() {
590 // test we do not recursively delete a symlink but only dirs.
591 let tmpdir = tmpdir();
592 let link = tmpdir.join("d1");
593 let dir = tmpdir.join("d2");
594 let canary = dir.join("do_not_delete");
595 check!(fs::create_dir_all(&dir));
596 check!(check!(File::create(&canary)).write(b"foo"));
597 check!(symlink_junction(&dir, &link));
598 check!(fs::remove_dir_all(&link));
600 assert!(!link.is_dir());
601 assert!(canary.exists());
605 // only Windows makes a distinction between file and directory symlinks.
607 fn recursive_rmdir_of_file_symlink() {
608 let tmpdir = tmpdir();
609 if !got_symlink_permission(&tmpdir) {
613 let f1 = tmpdir.join("f1");
614 let f2 = tmpdir.join("f2");
615 check!(check!(File::create(&f1)).write(b"foo"));
616 check!(symlink_file(&f1, &f2));
617 match fs::remove_dir_all(&f2) {
618 Ok(..) => panic!("wanted a failure"),
624 fn unicode_path_is_dir() {
625 assert!(Path::new(".").is_dir());
626 assert!(!Path::new("test/stdtest/fs.rs").is_dir());
628 let tmpdir = tmpdir();
630 let mut dirpath = tmpdir.path().to_path_buf();
631 dirpath.push("test-가一ー你好");
632 check!(fs::create_dir(&dirpath));
633 assert!(dirpath.is_dir());
635 let mut filepath = dirpath;
636 filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
637 check!(File::create(&filepath)); // ignore return; touch only
638 assert!(!filepath.is_dir());
639 assert!(filepath.exists());
643 fn unicode_path_exists() {
644 assert!(Path::new(".").exists());
645 assert!(!Path::new("test/nonexistent-bogus-path").exists());
647 let tmpdir = tmpdir();
648 let unicode = tmpdir.path();
649 let unicode = unicode.join("test-각丁ー再见");
650 check!(fs::create_dir(&unicode));
651 assert!(unicode.exists());
652 assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
656 fn copy_file_does_not_exist() {
657 let from = Path::new("test/nonexistent-bogus-path");
658 let to = Path::new("test/other-bogus-path");
660 match fs::copy(&from, &to) {
663 assert!(!from.exists());
664 assert!(!to.exists());
670 fn copy_src_does_not_exist() {
671 let tmpdir = tmpdir();
672 let from = Path::new("test/nonexistent-bogus-path");
673 let to = tmpdir.join("out.txt");
674 check!(check!(File::create(&to)).write(b"hello"));
675 assert!(fs::copy(&from, &to).is_err());
676 assert!(!from.exists());
677 let mut v = Vec::new();
678 check!(check!(File::open(&to)).read_to_end(&mut v));
679 assert_eq!(v, b"hello");
684 let tmpdir = tmpdir();
685 let input = tmpdir.join("in.txt");
686 let out = tmpdir.join("out.txt");
688 check!(check!(File::create(&input)).write(b"hello"));
689 check!(fs::copy(&input, &out));
690 let mut v = Vec::new();
691 check!(check!(File::open(&out)).read_to_end(&mut v));
692 assert_eq!(v, b"hello");
694 assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions());
698 fn copy_file_dst_dir() {
699 let tmpdir = tmpdir();
700 let out = tmpdir.join("out");
702 check!(File::create(&out));
703 match fs::copy(&*out, tmpdir.path()) {
710 fn copy_file_dst_exists() {
711 let tmpdir = tmpdir();
712 let input = tmpdir.join("in");
713 let output = tmpdir.join("out");
715 check!(check!(File::create(&input)).write("foo".as_bytes()));
716 check!(check!(File::create(&output)).write("bar".as_bytes()));
717 check!(fs::copy(&input, &output));
719 let mut v = Vec::new();
720 check!(check!(File::open(&output)).read_to_end(&mut v));
721 assert_eq!(v, b"foo".to_vec());
725 fn copy_file_src_dir() {
726 let tmpdir = tmpdir();
727 let out = tmpdir.join("out");
729 match fs::copy(tmpdir.path(), &out) {
733 assert!(!out.exists());
737 fn copy_file_preserves_perm_bits() {
738 let tmpdir = tmpdir();
739 let input = tmpdir.join("in.txt");
740 let out = tmpdir.join("out.txt");
742 let attr = check!(check!(File::create(&input)).metadata());
743 let mut p = attr.permissions();
744 p.set_readonly(true);
745 check!(fs::set_permissions(&input, p));
746 check!(fs::copy(&input, &out));
747 assert!(check!(out.metadata()).permissions().readonly());
748 check!(fs::set_permissions(&input, attr.permissions()));
749 check!(fs::set_permissions(&out, attr.permissions()));
754 fn copy_file_preserves_streams() {
756 check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
757 assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0);
758 assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
759 let mut v = Vec::new();
760 check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
761 assert_eq!(v, b"carrot".to_vec());
765 fn copy_file_returns_metadata_len() {
767 let in_path = tmp.join("in.txt");
768 let out_path = tmp.join("out.txt");
769 check!(check!(File::create(&in_path)).write(b"lettuce"));
771 check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot"));
772 let copied_len = check!(fs::copy(&in_path, &out_path));
773 assert_eq!(check!(out_path.metadata()).len(), copied_len);
777 fn copy_file_follows_dst_symlink() {
779 if !got_symlink_permission(&tmp) {
783 let in_path = tmp.join("in.txt");
784 let out_path = tmp.join("out.txt");
785 let out_path_symlink = tmp.join("out_symlink.txt");
787 check!(fs::write(&in_path, "foo"));
788 check!(fs::write(&out_path, "bar"));
789 check!(symlink_file(&out_path, &out_path_symlink));
791 check!(fs::copy(&in_path, &out_path_symlink));
793 assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink());
794 assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec());
795 assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec());
800 let tmpdir = tmpdir();
801 if !got_symlink_permission(&tmpdir) {
805 let input = tmpdir.join("in.txt");
806 let out = tmpdir.join("out.txt");
808 check!(check!(File::create(&input)).write("foobar".as_bytes()));
809 check!(symlink_file(&input, &out));
810 assert!(check!(out.symlink_metadata()).file_type().is_symlink());
811 assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
812 let mut v = Vec::new();
813 check!(check!(File::open(&out)).read_to_end(&mut v));
814 assert_eq!(v, b"foobar".to_vec());
818 fn symlink_noexist() {
819 // Symlinks can point to things that don't exist
820 let tmpdir = tmpdir();
821 if !got_symlink_permission(&tmpdir) {
825 // Use a relative path for testing. Symlinks get normalized by Windows,
826 // so we might not get the same path back for absolute paths
827 check!(symlink_file(&"foo", &tmpdir.join("bar")));
828 assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo");
835 assert_eq!(check!(fs::read_link(r"C:\Users\All Users")), Path::new(r"C:\ProgramData"));
837 assert_eq!(check!(fs::read_link(r"C:\Users\Default User")), Path::new(r"C:\Users\Default"));
838 // junction with special permissions
839 assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")), Path::new(r"C:\Users"));
841 let tmpdir = tmpdir();
842 let link = tmpdir.join("link");
843 if !got_symlink_permission(&tmpdir) {
846 check!(symlink_file(&"foo", &link));
847 assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
851 fn readlink_not_symlink() {
852 let tmpdir = tmpdir();
853 match fs::read_link(tmpdir.path()) {
854 Ok(..) => panic!("wanted a failure"),
861 let tmpdir = tmpdir();
862 let input = tmpdir.join("in.txt");
863 let out = tmpdir.join("out.txt");
865 check!(check!(File::create(&input)).write("foobar".as_bytes()));
866 check!(fs::hard_link(&input, &out));
867 assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
868 assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len());
869 let mut v = Vec::new();
870 check!(check!(File::open(&out)).read_to_end(&mut v));
871 assert_eq!(v, b"foobar".to_vec());
873 // can't link to yourself
874 match fs::hard_link(&input, &input) {
875 Ok(..) => panic!("wanted a failure"),
878 // can't link to something that doesn't exist
879 match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
880 Ok(..) => panic!("wanted a failure"),
887 let tmpdir = tmpdir();
888 let file = tmpdir.join("in.txt");
890 check!(File::create(&file));
891 let attr = check!(fs::metadata(&file));
892 assert!(!attr.permissions().readonly());
893 let mut p = attr.permissions();
894 p.set_readonly(true);
895 check!(fs::set_permissions(&file, p.clone()));
896 let attr = check!(fs::metadata(&file));
897 assert!(attr.permissions().readonly());
899 match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
900 Ok(..) => panic!("wanted an error"),
904 p.set_readonly(false);
905 check!(fs::set_permissions(&file, p));
910 let tmpdir = tmpdir();
911 let path = tmpdir.join("in.txt");
913 let file = check!(File::create(&path));
914 let attr = check!(fs::metadata(&path));
915 assert!(!attr.permissions().readonly());
916 let mut p = attr.permissions();
917 p.set_readonly(true);
918 check!(file.set_permissions(p.clone()));
919 let attr = check!(fs::metadata(&path));
920 assert!(attr.permissions().readonly());
922 p.set_readonly(false);
923 check!(file.set_permissions(p));
927 fn sync_doesnt_kill_anything() {
928 let tmpdir = tmpdir();
929 let path = tmpdir.join("in.txt");
931 let mut file = check!(File::create(&path));
932 check!(file.sync_all());
933 check!(file.sync_data());
934 check!(file.write(b"foo"));
935 check!(file.sync_all());
936 check!(file.sync_data());
940 fn truncate_works() {
941 let tmpdir = tmpdir();
942 let path = tmpdir.join("in.txt");
944 let mut file = check!(File::create(&path));
945 check!(file.write(b"foo"));
946 check!(file.sync_all());
948 // Do some simple things with truncation
949 assert_eq!(check!(file.metadata()).len(), 3);
950 check!(file.set_len(10));
951 assert_eq!(check!(file.metadata()).len(), 10);
952 check!(file.write(b"bar"));
953 check!(file.sync_all());
954 assert_eq!(check!(file.metadata()).len(), 10);
956 let mut v = Vec::new();
957 check!(check!(File::open(&path)).read_to_end(&mut v));
958 assert_eq!(v, b"foobar\0\0\0\0".to_vec());
960 // Truncate to a smaller length, don't seek, and then write something.
961 // Ensure that the intermediate zeroes are all filled in (we have `seek`ed
962 // past the end of the file).
963 check!(file.set_len(2));
964 assert_eq!(check!(file.metadata()).len(), 2);
965 check!(file.write(b"wut"));
966 check!(file.sync_all());
967 assert_eq!(check!(file.metadata()).len(), 9);
968 let mut v = Vec::new();
969 check!(check!(File::open(&path)).read_to_end(&mut v));
970 assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
975 use crate::fs::OpenOptions as OO;
976 fn c<T: Clone>(t: &T) -> T {
980 let tmpdir = tmpdir();
982 let mut r = OO::new();
984 let mut w = OO::new();
986 let mut rw = OO::new();
987 rw.read(true).write(true);
988 let mut a = OO::new();
990 let mut ra = OO::new();
991 ra.read(true).append(true);
994 let invalid_options = 87; // ERROR_INVALID_PARAMETER
995 #[cfg(all(unix, not(target_os = "vxworks")))]
996 let invalid_options = "Invalid argument";
997 #[cfg(target_os = "vxworks")]
998 let invalid_options = "invalid argument";
1000 // Test various combinations of creation modes and access modes.
1003 // creation mode | read | write | read-write | append | read-append |
1004 // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
1005 // not set (open existing) | X | X | X | X | X |
1006 // create | | X | X | X | X |
1007 // truncate | | X | X | | |
1008 // create and truncate | | X | X | | |
1009 // create_new | | X | X | X | X |
1011 // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
1014 check!(c(&w).create_new(true).open(&tmpdir.join("a")));
1015 check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
1016 check!(c(&w).truncate(true).open(&tmpdir.join("a")));
1017 check!(c(&w).create(true).open(&tmpdir.join("a")));
1018 check!(c(&w).open(&tmpdir.join("a")));
1021 error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
1022 error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
1023 error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
1024 error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
1025 check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
1028 check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
1029 check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
1030 check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
1031 check!(c(&rw).create(true).open(&tmpdir.join("c")));
1032 check!(c(&rw).open(&tmpdir.join("c")));
1035 check!(c(&a).create_new(true).open(&tmpdir.join("d")));
1036 error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
1037 error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
1038 check!(c(&a).create(true).open(&tmpdir.join("d")));
1039 check!(c(&a).open(&tmpdir.join("d")));
1042 check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
1043 error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
1044 error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
1045 check!(c(&ra).create(true).open(&tmpdir.join("e")));
1046 check!(c(&ra).open(&tmpdir.join("e")));
1048 // Test opening a file without setting an access mode
1049 let mut blank = OO::new();
1050 error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
1053 check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
1055 // Test write fails for read-only
1056 check!(r.open(&tmpdir.join("h")));
1058 let mut f = check!(r.open(&tmpdir.join("h")));
1059 assert!(f.write("wut".as_bytes()).is_err());
1062 // Test write overwrites
1064 let mut f = check!(c(&w).open(&tmpdir.join("h")));
1065 check!(f.write("baz".as_bytes()));
1068 let mut f = check!(c(&r).open(&tmpdir.join("h")));
1069 let mut b = vec![0; 6];
1070 check!(f.read(&mut b));
1071 assert_eq!(b, "bazbar".as_bytes());
1074 // Test truncate works
1076 let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
1077 check!(f.write("foo".as_bytes()));
1079 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
1081 // Test append works
1082 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
1084 let mut f = check!(c(&a).open(&tmpdir.join("h")));
1085 check!(f.write("bar".as_bytes()));
1087 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
1089 // Test .append(true) equals .write(true).append(true)
1091 let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
1092 check!(f.write("baz".as_bytes()));
1094 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
1098 fn _assert_send_sync() {
1099 fn _assert_send_sync<T: Send + Sync>() {}
1100 _assert_send_sync::<OpenOptions>();
1105 let mut bytes = [0; 1024];
1106 StdRng::from_entropy().fill_bytes(&mut bytes);
1108 let tmpdir = tmpdir();
1110 check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
1111 let mut v = Vec::new();
1112 check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
1113 assert!(v == &bytes[..]);
1117 fn write_then_read() {
1118 let mut bytes = [0; 1024];
1119 StdRng::from_entropy().fill_bytes(&mut bytes);
1121 let tmpdir = tmpdir();
1123 check!(fs::write(&tmpdir.join("test"), &bytes[..]));
1124 let v = check!(fs::read(&tmpdir.join("test")));
1125 assert!(v == &bytes[..]);
1127 check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
1129 fs::read_to_string(&tmpdir.join("not-utf8")),
1130 "stream did not contain valid UTF-8"
1134 check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
1135 let string = check!(fs::read_to_string(&tmpdir.join("utf8")));
1136 assert_eq!(string, s);
1140 fn file_try_clone() {
1141 let tmpdir = tmpdir();
1144 check!(OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test")));
1145 let mut f2 = check!(f1.try_clone());
1147 check!(f1.write_all(b"hello world"));
1148 check!(f1.seek(SeekFrom::Start(2)));
1150 let mut buf = vec![];
1151 check!(f2.read_to_end(&mut buf));
1152 assert_eq!(buf, b"llo world");
1155 check!(f1.write_all(b"!"));
1159 #[cfg(not(windows))]
1160 fn unlink_readonly() {
1161 let tmpdir = tmpdir();
1162 let path = tmpdir.join("file");
1163 check!(File::create(&path));
1164 let mut perm = check!(fs::metadata(&path)).permissions();
1165 perm.set_readonly(true);
1166 check!(fs::set_permissions(&path, perm));
1167 check!(fs::remove_file(&path));
1171 fn mkdir_trailing_slash() {
1172 let tmpdir = tmpdir();
1173 let path = tmpdir.join("file");
1174 check!(fs::create_dir_all(&path.join("a/")));
1178 fn canonicalize_works_simple() {
1179 let tmpdir = tmpdir();
1180 let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
1181 let file = tmpdir.join("test");
1182 File::create(&file).unwrap();
1183 assert_eq!(fs::canonicalize(&file).unwrap(), file);
1187 fn realpath_works() {
1188 let tmpdir = tmpdir();
1189 if !got_symlink_permission(&tmpdir) {
1193 let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
1194 let file = tmpdir.join("test");
1195 let dir = tmpdir.join("test2");
1196 let link = dir.join("link");
1197 let linkdir = tmpdir.join("test3");
1199 File::create(&file).unwrap();
1200 fs::create_dir(&dir).unwrap();
1201 symlink_file(&file, &link).unwrap();
1202 symlink_dir(&dir, &linkdir).unwrap();
1204 assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
1206 assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir);
1207 assert_eq!(fs::canonicalize(&file).unwrap(), file);
1208 assert_eq!(fs::canonicalize(&link).unwrap(), file);
1209 assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir);
1210 assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file);
1214 fn realpath_works_tricky() {
1215 let tmpdir = tmpdir();
1216 if !got_symlink_permission(&tmpdir) {
1220 let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
1221 let a = tmpdir.join("a");
1222 let b = a.join("b");
1223 let c = b.join("c");
1224 let d = a.join("d");
1225 let e = d.join("e");
1226 let f = a.join("f");
1228 fs::create_dir_all(&b).unwrap();
1229 fs::create_dir_all(&d).unwrap();
1230 File::create(&f).unwrap();
1231 if cfg!(not(windows)) {
1232 symlink_file("../d/e", &c).unwrap();
1233 symlink_file("../f", &e).unwrap();
1236 symlink_file(r"..\d\e", &c).unwrap();
1237 symlink_file(r"..\f", &e).unwrap();
1240 assert_eq!(fs::canonicalize(&c).unwrap(), f);
1241 assert_eq!(fs::canonicalize(&e).unwrap(), f);
1245 fn dir_entry_methods() {
1246 let tmpdir = tmpdir();
1248 fs::create_dir_all(&tmpdir.join("a")).unwrap();
1249 File::create(&tmpdir.join("b")).unwrap();
1251 for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
1252 let fname = file.file_name();
1253 match fname.to_str() {
1255 assert!(file.file_type().unwrap().is_dir());
1256 assert!(file.metadata().unwrap().is_dir());
1259 assert!(file.file_type().unwrap().is_file());
1260 assert!(file.metadata().unwrap().is_file());
1262 f => panic!("unknown file name: {:?}", f),
1268 fn dir_entry_debug() {
1269 let tmpdir = tmpdir();
1270 File::create(&tmpdir.join("b")).unwrap();
1271 let mut read_dir = tmpdir.path().read_dir().unwrap();
1272 let dir_entry = read_dir.next().unwrap().unwrap();
1273 let actual = format!("{:?}", dir_entry);
1274 let expected = format!("DirEntry({:?})", dir_entry.0.path());
1275 assert_eq!(actual, expected);
1279 fn read_dir_not_found() {
1280 let res = fs::read_dir("/path/that/does/not/exist");
1281 assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
1285 fn create_dir_all_with_junctions() {
1286 let tmpdir = tmpdir();
1287 let target = tmpdir.join("target");
1289 let junction = tmpdir.join("junction");
1290 let b = junction.join("a/b");
1292 let link = tmpdir.join("link");
1293 let d = link.join("c/d");
1295 fs::create_dir(&target).unwrap();
1297 check!(symlink_junction(&target, &junction));
1298 check!(fs::create_dir_all(&b));
1299 // the junction itself is not a directory, but `is_dir()` on a Path
1301 assert!(junction.is_dir());
1302 assert!(b.exists());
1304 if !got_symlink_permission(&tmpdir) {
1307 check!(symlink_dir(&target, &link));
1308 check!(fs::create_dir_all(&d));
1309 assert!(link.is_dir());
1310 assert!(d.exists());
1314 fn metadata_access_times() {
1315 let tmpdir = tmpdir();
1317 let b = tmpdir.join("b");
1318 File::create(&b).unwrap();
1320 let a = check!(fs::metadata(&tmpdir.path()));
1321 let b = check!(fs::metadata(&b));
1323 assert_eq!(check!(a.accessed()), check!(a.accessed()));
1324 assert_eq!(check!(a.modified()), check!(a.modified()));
1325 assert_eq!(check!(b.accessed()), check!(b.modified()));
1327 if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
1328 check!(a.created());
1329 check!(b.created());
1332 if cfg!(target_os = "linux") {
1333 // Not always available
1334 match (a.created(), b.created()) {
1335 (Ok(t1), Ok(t2)) => assert!(t1 <= t2),
1337 if e1.kind() == ErrorKind::Uncategorized
1338 && e2.kind() == ErrorKind::Uncategorized
1339 || e1.kind() == ErrorKind::Unsupported
1340 && e2.kind() == ErrorKind::Unsupported => {}
1342 panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
1348 /// Test creating hard links to symlinks.
1350 fn symlink_hard_link() {
1351 let tmpdir = tmpdir();
1352 if !got_symlink_permission(&tmpdir) {
1355 if !able_to_not_follow_symlinks_while_hard_linking() {
1359 // Create "file", a file.
1360 check!(fs::File::create(tmpdir.join("file")));
1362 // Create "symlink", a symlink to "file".
1363 check!(symlink_file("file", tmpdir.join("symlink")));
1365 // Create "hard_link", a hard link to "symlink".
1366 check!(fs::hard_link(tmpdir.join("symlink"), tmpdir.join("hard_link")));
1368 // "hard_link" should appear as a symlink.
1369 assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
1371 // We should be able to open "file" via any of the above names.
1372 let _ = check!(fs::File::open(tmpdir.join("file")));
1373 assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
1374 let _ = check!(fs::File::open(tmpdir.join("symlink")));
1375 let _ = check!(fs::File::open(tmpdir.join("hard_link")));
1377 // Rename "file" to "file.renamed".
1378 check!(fs::rename(tmpdir.join("file"), tmpdir.join("file.renamed")));
1380 // Now, the symlink and the hard link should be dangling.
1381 assert!(fs::File::open(tmpdir.join("file")).is_err());
1382 let _ = check!(fs::File::open(tmpdir.join("file.renamed")));
1383 assert!(fs::File::open(tmpdir.join("symlink")).is_err());
1384 assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
1386 // The symlink and the hard link should both still point to "file".
1387 assert!(fs::read_link(tmpdir.join("file")).is_err());
1388 assert!(fs::read_link(tmpdir.join("file.renamed")).is_err());
1389 assert_eq!(check!(fs::read_link(tmpdir.join("symlink"))), Path::new("file"));
1390 assert_eq!(check!(fs::read_link(tmpdir.join("hard_link"))), Path::new("file"));
1392 // Remove "file.renamed".
1393 check!(fs::remove_file(tmpdir.join("file.renamed")));
1395 // Now, we can't open the file by any name.
1396 assert!(fs::File::open(tmpdir.join("file")).is_err());
1397 assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
1398 assert!(fs::File::open(tmpdir.join("symlink")).is_err());
1399 assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
1401 // "hard_link" should still appear as a symlink.
1402 assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
1405 /// Ensure `fs::create_dir` works on Windows with longer paths.
1408 fn create_dir_long_paths() {
1409 use crate::{ffi::OsStr, iter, os::windows::ffi::OsStrExt};
1410 const PATH_LEN: usize = 247;
1412 let tmpdir = tmpdir();
1413 let mut path = tmpdir.path().to_path_buf();
1415 let mut path = path.into_os_string();
1417 let utf16_len = path.encode_wide().count();
1418 if utf16_len >= PATH_LEN {
1419 // Skip the test in the unlikely event the local user has a long temp directory path.
1420 // This should not affect CI.
1423 // Increase the length of the path.
1424 path.extend(iter::repeat(OsStr::new("a")).take(PATH_LEN - utf16_len));
1426 // This should succeed.
1427 fs::create_dir(&path).unwrap();
1429 // This will fail if the path isn't converted to verbatim.
1431 fs::create_dir(&path).unwrap();
1433 // #90940: Ensure an empty path returns the "Not Found" error.
1434 let path = Path::new("");
1435 assert_eq!(path.canonicalize().unwrap_err().kind(), crate::io::ErrorKind::NotFound);