]> git.proxmox.com Git - rustc.git/blob - library/std/src/fs/tests.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / library / std / src / fs / tests.rs
1 use crate::io::prelude::*;
2
3 use crate::fs::{self, File, OpenOptions};
4 use crate::io::{ErrorKind, SeekFrom};
5 use crate::path::Path;
6 use crate::str;
7 use crate::sys_common::io::test::{tmpdir, TempDir};
8 use crate::thread;
9
10 use rand::{rngs::StdRng, RngCore, SeedableRng};
11
12 #[cfg(unix)]
13 use crate::os::unix::fs::symlink as symlink_dir;
14 #[cfg(unix)]
15 use crate::os::unix::fs::symlink as symlink_file;
16 #[cfg(unix)]
17 use crate::os::unix::fs::symlink as symlink_junction;
18 #[cfg(windows)]
19 use crate::os::windows::fs::{symlink_dir, symlink_file};
20 #[cfg(windows)]
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};
26
27 macro_rules! check {
28 ($e:expr) => {
29 match $e {
30 Ok(t) => t,
31 Err(e) => panic!("{} failed with: {}", stringify!($e), e),
32 }
33 };
34 }
35
36 #[cfg(windows)]
37 macro_rules! error {
38 ($e:expr, $s:expr) => {
39 match $e {
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)
44 ),
45 }
46 };
47 }
48
49 #[cfg(unix)]
50 macro_rules! error {
51 ($e:expr, $s:expr) => {
52 error_contains!($e, $s)
53 };
54 }
55
56 macro_rules! error_contains {
57 ($e:expr, $s:expr) => {
58 match $e {
59 Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
60 Err(ref err) => {
61 assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s))
62 }
63 }
64 };
65 }
66
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
72 // permissions.
73 pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
74 if cfg!(unix) {
75 return true;
76 }
77 let link = tmpdir.join("some_hopefully_unique_link_name");
78
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,
83 }
84 }
85
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()
90 }
91
92 #[cfg(not(target_os = "macos"))]
93 fn able_to_not_follow_symlinks_while_hard_linking() -> bool {
94 return true;
95 }
96
97 #[test]
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");
102 {
103 let mut write_stream = check!(File::create(filename));
104 check!(write_stream.write(message.as_bytes()));
105 }
106 {
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(),
112 };
113 assert_eq!(read_str, message);
114 }
115 check!(fs::remove_file(filename));
116 }
117
118 #[test]
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);
123
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");
128 #[cfg(windows)]
129 error!(result, 2); // ERROR_FILE_NOT_FOUND
130 }
131
132 #[test]
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");
136
137 let result = fs::remove_file(filename);
138
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");
143 #[cfg(windows)]
144 error!(result, 2); // ERROR_FILE_NOT_FOUND
145 }
146
147 #[test]
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");
153 {
154 let mut rw_stream = check!(File::create(filename));
155 check!(rw_stream.write(message.as_bytes()));
156 }
157 {
158 let mut read_stream = check!(File::open(filename));
159 {
160 let read_buf = &mut read_mem[0..4];
161 check!(read_stream.read(read_buf));
162 }
163 {
164 let read_buf = &mut read_mem[4..8];
165 check!(read_stream.read(read_buf));
166 }
167 }
168 check!(fs::remove_file(filename));
169 let read_str = str::from_utf8(&read_mem).unwrap();
170 assert_eq!(read_str, message);
171 }
172
173 #[test]
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");
182 {
183 let mut rw_stream = check!(File::create(filename));
184 check!(rw_stream.write(message.as_bytes()));
185 }
186 {
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)));
192 }
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);
198 }
199
200 #[test]
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!!";
205 let seek_idx = 3;
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");
209 {
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()));
214 }
215 {
216 let mut read_stream = check!(File::open(filename));
217 check!(read_stream.read(&mut read_mem));
218 }
219 check!(fs::remove_file(filename));
220 let read_str = str::from_utf8(&read_mem).unwrap();
221 assert!(read_str == final_msg);
222 }
223
224 #[test]
225 fn file_test_io_seek_shakedown() {
226 // 01234567890123
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");
234 {
235 let mut rw_stream = check!(File::create(filename));
236 check!(rw_stream.write(initial_msg.as_bytes()));
237 }
238 {
239 let mut read_stream = check!(File::open(filename));
240
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);
244
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);
248
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);
252 }
253 check!(fs::remove_file(filename));
254 }
255
256 #[test]
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];
261 {
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);
266 }
267 check!(fs::remove_file(&filename));
268 }
269
270 #[test]
271 #[cfg(unix)]
272 fn file_test_io_read_write_at() {
273 use crate::os::unix::fs::FileExt;
274
275 let tmpdir = tmpdir();
276 let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
277 let mut buf = [0; 256];
278 let write1 = "asdf";
279 let write2 = "qwer-";
280 let write3 = "-zxcv";
281 let content = "qwer-asdf-zxcv";
282 {
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);
303 }
304 {
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);
322 }
323 check!(fs::remove_file(&filename));
324 }
325
326 #[test]
327 #[cfg(unix)]
328 fn set_get_unix_permissions() {
329 use crate::os::unix::fs::PermissionsExt;
330
331 let tmpdir = tmpdir();
332 let filename = &tmpdir.join("set_get_unix_permissions");
333 check!(fs::create_dir(filename));
334 let mask = 0o7777;
335
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);
339
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);
346 }
347
348 #[test]
349 #[cfg(windows)]
350 fn file_test_io_seek_read_write() {
351 use crate::os::windows::fs::FileExt;
352
353 let tmpdir = tmpdir();
354 let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
355 let mut buf = [0; 256];
356 let write1 = "asdf";
357 let write2 = "qwer-";
358 let write3 = "-zxcv";
359 let content = "qwer-asdf-zxcv";
360 {
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);
379 }
380 {
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);
398 }
399 check!(fs::remove_file(&filename));
400 }
401
402 #[test]
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");
406 {
407 let mut opts = OpenOptions::new();
408 let mut fs = check!(opts.read(true).write(true).create(true).open(filename));
409 let msg = "hw";
410 fs.write(msg.as_bytes()).unwrap();
411
412 let fstat_res = check!(fs.metadata());
413 assert!(fstat_res.is_file());
414 }
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));
420 }
421
422 #[test]
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));
432 }
433
434 #[test]
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));
441 }
442
443 #[test]
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());
451 }
452
453 #[test]
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());
463 }
464
465 #[test]
466 fn file_test_directoryinfo_readdir() {
467 let tmpdir = tmpdir();
468 let dir = &tmpdir.join("di_readdir");
469 check!(fs::create_dir(dir));
470 let prefix = "foo";
471 for n in 0..3 {
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));
477 }
478 let files = check!(fs::read_dir(dir));
479 let mut mem = [0; 4];
480 for f in files {
481 let f = f.unwrap().path();
482 {
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);
488 }
489 check!(fs::remove_file(&f));
490 }
491 check!(fs::remove_dir(dir));
492 }
493
494 #[test]
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);
501 }
502
503 #[test]
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);
510 }
511
512 #[test]
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())
518 }
519
520 #[test]
521 fn recursive_mkdir_failure() {
522 let tmpdir = tmpdir();
523 let dir = tmpdir.join("d1");
524 let file = dir.join("f1");
525
526 check!(fs::create_dir_all(&dir));
527 check!(File::create(&file));
528
529 let result = fs::create_dir_all(&file);
530
531 assert!(result.is_err());
532 }
533
534 #[test]
535 fn concurrent_recursive_mkdir() {
536 for _ in 0..100 {
537 let dir = tmpdir();
538 let mut dir = dir.join("a");
539 for _ in 0..40 {
540 dir = dir.join("a");
541 }
542 let mut join = vec![];
543 for _ in 0..8 {
544 let dir = dir.clone();
545 join.push(thread::spawn(move || {
546 check!(fs::create_dir_all(&dir));
547 }))
548 }
549
550 // No `Display` on result of `join()`
551 join.drain(..).map(|join| join.join().unwrap()).count();
552 }
553 }
554
555 #[test]
556 fn recursive_mkdir_slash() {
557 check!(fs::create_dir_all(Path::new("/")));
558 }
559
560 #[test]
561 fn recursive_mkdir_dot() {
562 check!(fs::create_dir_all(Path::new(".")));
563 }
564
565 #[test]
566 fn recursive_mkdir_empty() {
567 check!(fs::create_dir_all(Path::new("")));
568 }
569
570 #[test]
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));
584
585 assert!(!d1.is_dir());
586 assert!(canary.exists());
587 }
588
589 #[test]
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));
600
601 assert!(!link.is_dir());
602 assert!(canary.exists());
603 }
604
605 #[test]
606 // only Windows makes a distinction between file and directory symlinks.
607 #[cfg(windows)]
608 fn recursive_rmdir_of_file_symlink() {
609 let tmpdir = tmpdir();
610 if !got_symlink_permission(&tmpdir) {
611 return;
612 };
613
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"),
620 Err(..) => {}
621 }
622 }
623
624 #[test]
625 fn unicode_path_is_dir() {
626 assert!(Path::new(".").is_dir());
627 assert!(!Path::new("test/stdtest/fs.rs").is_dir());
628
629 let tmpdir = tmpdir();
630
631 let mut dirpath = tmpdir.path().to_path_buf();
632 dirpath.push("test-가一ー你好");
633 check!(fs::create_dir(&dirpath));
634 assert!(dirpath.is_dir());
635
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());
641 }
642
643 #[test]
644 fn unicode_path_exists() {
645 assert!(Path::new(".").exists());
646 assert!(!Path::new("test/nonexistent-bogus-path").exists());
647
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());
654 }
655
656 #[test]
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");
660
661 match fs::copy(&from, &to) {
662 Ok(..) => panic!(),
663 Err(..) => {
664 assert!(!from.exists());
665 assert!(!to.exists());
666 }
667 }
668 }
669
670 #[test]
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");
681 }
682
683 #[test]
684 fn copy_file_ok() {
685 let tmpdir = tmpdir();
686 let input = tmpdir.join("in.txt");
687 let out = tmpdir.join("out.txt");
688
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");
694
695 assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions());
696 }
697
698 #[test]
699 fn copy_file_dst_dir() {
700 let tmpdir = tmpdir();
701 let out = tmpdir.join("out");
702
703 check!(File::create(&out));
704 match fs::copy(&*out, tmpdir.path()) {
705 Ok(..) => panic!(),
706 Err(..) => {}
707 }
708 }
709
710 #[test]
711 fn copy_file_dst_exists() {
712 let tmpdir = tmpdir();
713 let input = tmpdir.join("in");
714 let output = tmpdir.join("out");
715
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));
719
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());
723 }
724
725 #[test]
726 fn copy_file_src_dir() {
727 let tmpdir = tmpdir();
728 let out = tmpdir.join("out");
729
730 match fs::copy(tmpdir.path(), &out) {
731 Ok(..) => panic!(),
732 Err(..) => {}
733 }
734 assert!(!out.exists());
735 }
736
737 #[test]
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");
742
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()));
751 }
752
753 #[test]
754 #[cfg(windows)]
755 fn copy_file_preserves_streams() {
756 let tmp = tmpdir();
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());
763 }
764
765 #[test]
766 fn copy_file_returns_metadata_len() {
767 let tmp = tmpdir();
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"));
771 #[cfg(windows)]
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);
775 }
776
777 #[test]
778 fn copy_file_follows_dst_symlink() {
779 let tmp = tmpdir();
780 if !got_symlink_permission(&tmp) {
781 return;
782 };
783
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");
787
788 check!(fs::write(&in_path, "foo"));
789 check!(fs::write(&out_path, "bar"));
790 check!(symlink_file(&out_path, &out_path_symlink));
791
792 check!(fs::copy(&in_path, &out_path_symlink));
793
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());
797 }
798
799 #[test]
800 fn symlinks_work() {
801 let tmpdir = tmpdir();
802 if !got_symlink_permission(&tmpdir) {
803 return;
804 };
805
806 let input = tmpdir.join("in.txt");
807 let out = tmpdir.join("out.txt");
808
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());
816 }
817
818 #[test]
819 fn symlink_noexist() {
820 // Symlinks can point to things that don't exist
821 let tmpdir = tmpdir();
822 if !got_symlink_permission(&tmpdir) {
823 return;
824 };
825
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");
830 }
831
832 #[test]
833 fn read_link() {
834 if cfg!(windows) {
835 // directory symlink
836 assert_eq!(
837 check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(),
838 r"C:\ProgramData"
839 );
840 // junction
841 assert_eq!(
842 check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(),
843 r"C:\Users\Default"
844 );
845 // junction with special permissions
846 assert_eq!(
847 check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(),
848 r"C:\Users"
849 );
850 }
851 let tmpdir = tmpdir();
852 let link = tmpdir.join("link");
853 if !got_symlink_permission(&tmpdir) {
854 return;
855 };
856 check!(symlink_file(&"foo", &link));
857 assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
858 }
859
860 #[test]
861 fn readlink_not_symlink() {
862 let tmpdir = tmpdir();
863 match fs::read_link(tmpdir.path()) {
864 Ok(..) => panic!("wanted a failure"),
865 Err(..) => {}
866 }
867 }
868
869 #[test]
870 fn links_work() {
871 let tmpdir = tmpdir();
872 let input = tmpdir.join("in.txt");
873 let out = tmpdir.join("out.txt");
874
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());
882
883 // can't link to yourself
884 match fs::hard_link(&input, &input) {
885 Ok(..) => panic!("wanted a failure"),
886 Err(..) => {}
887 }
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"),
891 Err(..) => {}
892 }
893 }
894
895 #[test]
896 fn chmod_works() {
897 let tmpdir = tmpdir();
898 let file = tmpdir.join("in.txt");
899
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());
908
909 match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
910 Ok(..) => panic!("wanted an error"),
911 Err(..) => {}
912 }
913
914 p.set_readonly(false);
915 check!(fs::set_permissions(&file, p));
916 }
917
918 #[test]
919 fn fchmod_works() {
920 let tmpdir = tmpdir();
921 let path = tmpdir.join("in.txt");
922
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());
931
932 p.set_readonly(false);
933 check!(file.set_permissions(p));
934 }
935
936 #[test]
937 fn sync_doesnt_kill_anything() {
938 let tmpdir = tmpdir();
939 let path = tmpdir.join("in.txt");
940
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());
947 }
948
949 #[test]
950 fn truncate_works() {
951 let tmpdir = tmpdir();
952 let path = tmpdir.join("in.txt");
953
954 let mut file = check!(File::create(&path));
955 check!(file.write(b"foo"));
956 check!(file.sync_all());
957
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);
965
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());
969
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());
981 }
982
983 #[test]
984 fn open_flavors() {
985 use crate::fs::OpenOptions as OO;
986 fn c<T: Clone>(t: &T) -> T {
987 t.clone()
988 }
989
990 let tmpdir = tmpdir();
991
992 let mut r = OO::new();
993 r.read(true);
994 let mut w = OO::new();
995 w.write(true);
996 let mut rw = OO::new();
997 rw.read(true).write(true);
998 let mut a = OO::new();
999 a.append(true);
1000 let mut ra = OO::new();
1001 ra.read(true).append(true);
1002
1003 #[cfg(windows)]
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";
1009
1010 // Test various combinations of creation modes and access modes.
1011 //
1012 // Allowed:
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 |
1020 //
1021 // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
1022
1023 // write-only
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")));
1029
1030 // read-only
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
1036
1037 // read-write
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")));
1043
1044 // append
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")));
1050
1051 // read-append
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")));
1057
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);
1061
1062 // Test write works
1063 check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
1064
1065 // Test write fails for read-only
1066 check!(r.open(&tmpdir.join("h")));
1067 {
1068 let mut f = check!(r.open(&tmpdir.join("h")));
1069 assert!(f.write("wut".as_bytes()).is_err());
1070 }
1071
1072 // Test write overwrites
1073 {
1074 let mut f = check!(c(&w).open(&tmpdir.join("h")));
1075 check!(f.write("baz".as_bytes()));
1076 }
1077 {
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());
1082 }
1083
1084 // Test truncate works
1085 {
1086 let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
1087 check!(f.write("foo".as_bytes()));
1088 }
1089 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
1090
1091 // Test append works
1092 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
1093 {
1094 let mut f = check!(c(&a).open(&tmpdir.join("h")));
1095 check!(f.write("bar".as_bytes()));
1096 }
1097 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
1098
1099 // Test .append(true) equals .write(true).append(true)
1100 {
1101 let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
1102 check!(f.write("baz".as_bytes()));
1103 }
1104 assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
1105 }
1106
1107 #[test]
1108 fn _assert_send_sync() {
1109 fn _assert_send_sync<T: Send + Sync>() {}
1110 _assert_send_sync::<OpenOptions>();
1111 }
1112
1113 #[test]
1114 fn binary_file() {
1115 let mut bytes = [0; 1024];
1116 StdRng::from_entropy().fill_bytes(&mut bytes);
1117
1118 let tmpdir = tmpdir();
1119
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[..]);
1124 }
1125
1126 #[test]
1127 fn write_then_read() {
1128 let mut bytes = [0; 1024];
1129 StdRng::from_entropy().fill_bytes(&mut bytes);
1130
1131 let tmpdir = tmpdir();
1132
1133 check!(fs::write(&tmpdir.join("test"), &bytes[..]));
1134 let v = check!(fs::read(&tmpdir.join("test")));
1135 assert!(v == &bytes[..]);
1136
1137 check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
1138 error_contains!(
1139 fs::read_to_string(&tmpdir.join("not-utf8")),
1140 "stream did not contain valid UTF-8"
1141 );
1142
1143 let s = "𐁁𐀓𐀠𐀴𐀍";
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);
1147 }
1148
1149 #[test]
1150 fn file_try_clone() {
1151 let tmpdir = tmpdir();
1152
1153 let mut f1 =
1154 check!(OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test")));
1155 let mut f2 = check!(f1.try_clone());
1156
1157 check!(f1.write_all(b"hello world"));
1158 check!(f1.seek(SeekFrom::Start(2)));
1159
1160 let mut buf = vec![];
1161 check!(f2.read_to_end(&mut buf));
1162 assert_eq!(buf, b"llo world");
1163 drop(f2);
1164
1165 check!(f1.write_all(b"!"));
1166 }
1167
1168 #[test]
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));
1178 }
1179
1180 #[test]
1181 fn mkdir_trailing_slash() {
1182 let tmpdir = tmpdir();
1183 let path = tmpdir.join("file");
1184 check!(fs::create_dir_all(&path.join("a/")));
1185 }
1186
1187 #[test]
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);
1194 }
1195
1196 #[test]
1197 fn realpath_works() {
1198 let tmpdir = tmpdir();
1199 if !got_symlink_permission(&tmpdir) {
1200 return;
1201 };
1202
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");
1208
1209 File::create(&file).unwrap();
1210 fs::create_dir(&dir).unwrap();
1211 symlink_file(&file, &link).unwrap();
1212 symlink_dir(&dir, &linkdir).unwrap();
1213
1214 assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
1215
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);
1221 }
1222
1223 #[test]
1224 fn realpath_works_tricky() {
1225 let tmpdir = tmpdir();
1226 if !got_symlink_permission(&tmpdir) {
1227 return;
1228 };
1229
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");
1237
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();
1244 }
1245 if cfg!(windows) {
1246 symlink_file(r"..\d\e", &c).unwrap();
1247 symlink_file(r"..\f", &e).unwrap();
1248 }
1249
1250 assert_eq!(fs::canonicalize(&c).unwrap(), f);
1251 assert_eq!(fs::canonicalize(&e).unwrap(), f);
1252 }
1253
1254 #[test]
1255 fn dir_entry_methods() {
1256 let tmpdir = tmpdir();
1257
1258 fs::create_dir_all(&tmpdir.join("a")).unwrap();
1259 File::create(&tmpdir.join("b")).unwrap();
1260
1261 for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
1262 let fname = file.file_name();
1263 match fname.to_str() {
1264 Some("a") => {
1265 assert!(file.file_type().unwrap().is_dir());
1266 assert!(file.metadata().unwrap().is_dir());
1267 }
1268 Some("b") => {
1269 assert!(file.file_type().unwrap().is_file());
1270 assert!(file.metadata().unwrap().is_file());
1271 }
1272 f => panic!("unknown file name: {:?}", f),
1273 }
1274 }
1275 }
1276
1277 #[test]
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);
1286 }
1287
1288 #[test]
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);
1292 }
1293
1294 #[test]
1295 fn create_dir_all_with_junctions() {
1296 let tmpdir = tmpdir();
1297 let target = tmpdir.join("target");
1298
1299 let junction = tmpdir.join("junction");
1300 let b = junction.join("a/b");
1301
1302 let link = tmpdir.join("link");
1303 let d = link.join("c/d");
1304
1305 fs::create_dir(&target).unwrap();
1306
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
1310 // follows links
1311 assert!(junction.is_dir());
1312 assert!(b.exists());
1313
1314 if !got_symlink_permission(&tmpdir) {
1315 return;
1316 };
1317 check!(symlink_dir(&target, &link));
1318 check!(fs::create_dir_all(&d));
1319 assert!(link.is_dir());
1320 assert!(d.exists());
1321 }
1322
1323 #[test]
1324 fn metadata_access_times() {
1325 let tmpdir = tmpdir();
1326
1327 let b = tmpdir.join("b");
1328 File::create(&b).unwrap();
1329
1330 let a = check!(fs::metadata(&tmpdir.path()));
1331 let b = check!(fs::metadata(&b));
1332
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()));
1336
1337 if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
1338 check!(a.created());
1339 check!(b.created());
1340 }
1341
1342 if cfg!(target_os = "linux") {
1343 // Not always available
1344 match (a.created(), b.created()) {
1345 (Ok(t1), Ok(t2)) => assert!(t1 <= t2),
1346 (Err(e1), Err(e2))
1347 if e1.kind() == ErrorKind::Uncategorized
1348 && e2.kind() == ErrorKind::Uncategorized
1349 || e1.kind() == ErrorKind::Unsupported
1350 && e2.kind() == ErrorKind::Unsupported => {}
1351 (a, b) => {
1352 panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
1353 }
1354 }
1355 }
1356 }
1357
1358 /// Test creating hard links to symlinks.
1359 #[test]
1360 fn symlink_hard_link() {
1361 let tmpdir = tmpdir();
1362 if !got_symlink_permission(&tmpdir) {
1363 return;
1364 };
1365 if !able_to_not_follow_symlinks_while_hard_linking() {
1366 return;
1367 }
1368
1369 // Create "file", a file.
1370 check!(fs::File::create(tmpdir.join("file")));
1371
1372 // Create "symlink", a symlink to "file".
1373 check!(symlink_file("file", tmpdir.join("symlink")));
1374
1375 // Create "hard_link", a hard link to "symlink".
1376 check!(fs::hard_link(tmpdir.join("symlink"), tmpdir.join("hard_link")));
1377
1378 // "hard_link" should appear as a symlink.
1379 assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
1380
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")));
1386
1387 // Rename "file" to "file.renamed".
1388 check!(fs::rename(tmpdir.join("file"), tmpdir.join("file.renamed")));
1389
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());
1395
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"));
1401
1402 // Remove "file.renamed".
1403 check!(fs::remove_file(tmpdir.join("file.renamed")));
1404
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());
1410
1411 // "hard_link" should still appear as a symlink.
1412 assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
1413 }