1 use nix::fcntl::{fcntl, FcntlArg, FdFlag, open, OFlag, readlink};
2 use nix::unistd::*;
3 use nix::unistd::ForkResult::*;
4 use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
5 use nix::sys::wait::*;
6 use nix::sys::stat::{self, Mode, SFlag};
7 use nix::errno::Errno;
8 use std::{env, iter};
9 use std::ffi::CString;
10 use std::fs::{self, File};
11 use std::io::Write;
12 use std::os::unix::prelude::*;
13 use tempfile::{self, tempfile};
14 use libc::{self, _exit, off_t};
15 
16 #[test]
17 #[cfg(not(any(target_os = "netbsd")))]
test_fork_and_waitpid()18 fn test_fork_and_waitpid() {
19     let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
20 
21     // Safe: Child only calls `_exit`, which is signal-safe
22     match fork().expect("Error: Fork Failed") {
23         Child => unsafe { _exit(0) },
24         Parent { child } => {
25             // assert that child was created and pid > 0
26             let child_raw: ::libc::pid_t = child.into();
27             assert!(child_raw > 0);
28             let wait_status = waitpid(child, None);
29             match wait_status {
30                 // assert that waitpid returned correct status and the pid is the one of the child
31                 Ok(WaitStatus::Exited(pid_t, _)) =>  assert!(pid_t == child),
32 
33                 // panic, must never happen
34                 s @ Ok(_) => panic!("Child exited {:?}, should never happen", s),
35 
36                 // panic, waitpid should never fail
37                 Err(s) => panic!("Error: waitpid returned Err({:?}", s)
38             }
39 
40         },
41     }
42 }
43 
44 #[test]
test_wait()45 fn test_wait() {
46     // Grab FORK_MTX so wait doesn't reap a different test's child process
47     let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
48 
49     // Safe: Child only calls `_exit`, which is signal-safe
50     match fork().expect("Error: Fork Failed") {
51         Child => unsafe { _exit(0) },
52         Parent { child } => {
53             let wait_status = wait();
54 
55             // just assert that (any) one child returns with WaitStatus::Exited
56             assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
57         },
58     }
59 }
60 
61 #[test]
test_mkstemp()62 fn test_mkstemp() {
63     let mut path = env::temp_dir();
64     path.push("nix_tempfile.XXXXXX");
65 
66     let result = mkstemp(&path);
67     match result {
68         Ok((fd, path)) => {
69             close(fd).unwrap();
70             unlink(path.as_path()).unwrap();
71         },
72         Err(e) => panic!("mkstemp failed: {}", e)
73     }
74 }
75 
76 #[test]
test_mkstemp_directory()77 fn test_mkstemp_directory() {
78     // mkstemp should fail if a directory is given
79     assert!(mkstemp(&env::temp_dir()).is_err());
80 }
81 
82 #[test]
test_mkfifo()83 fn test_mkfifo() {
84     let tempdir = tempfile::tempdir().unwrap();
85     let mkfifo_fifo = tempdir.path().join("mkfifo_fifo");
86 
87     mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap();
88 
89     let stats = stat::stat(&mkfifo_fifo).unwrap();
90     let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
91     assert!(typ == SFlag::S_IFIFO);
92 }
93 
94 #[test]
test_mkfifo_directory()95 fn test_mkfifo_directory() {
96     // mkfifo should fail if a directory is given
97     assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err());
98 }
99 
100 #[test]
test_getpid()101 fn test_getpid() {
102     let pid: ::libc::pid_t = getpid().into();
103     let ppid: ::libc::pid_t = getppid().into();
104     assert!(pid > 0);
105     assert!(ppid > 0);
106 }
107 
108 #[test]
test_getsid()109 fn test_getsid() {
110     let none_sid: ::libc::pid_t = getsid(None).unwrap().into();
111     let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into();
112     assert!(none_sid > 0);
113     assert!(none_sid == pid_sid);
114 }
115 
116 #[cfg(any(target_os = "linux", target_os = "android"))]
117 mod linux_android {
118     use nix::unistd::gettid;
119 
120     #[test]
test_gettid()121     fn test_gettid() {
122         let tid: ::libc::pid_t = gettid().into();
123         assert!(tid > 0);
124     }
125 }
126 
127 #[test]
128 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
129 #[cfg(not(any(target_os = "ios", target_os = "macos")))]
test_setgroups()130 fn test_setgroups() {
131     // Skip this test when not run as root as `setgroups()` requires root.
132     skip_if_not_root!("test_setgroups");
133 
134     let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
135 
136     // Save the existing groups
137     let old_groups = getgroups().unwrap();
138 
139     // Set some new made up groups
140     let groups = [Gid::from_raw(123), Gid::from_raw(456)];
141     setgroups(&groups).unwrap();
142 
143     let new_groups = getgroups().unwrap();
144     assert_eq!(new_groups, groups);
145 
146     // Revert back to the old groups
147     setgroups(&old_groups).unwrap();
148 }
149 
150 #[test]
151 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
152 #[cfg(not(any(target_os = "ios", target_os = "macos")))]
test_initgroups()153 fn test_initgroups() {
154     // Skip this test when not run as root as `initgroups()` and `setgroups()`
155     // require root.
156     skip_if_not_root!("test_initgroups");
157 
158     let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
159 
160     // Save the existing groups
161     let old_groups = getgroups().unwrap();
162 
163     // It doesn't matter if the root user is not called "root" or if a user
164     // called "root" doesn't exist. We are just checking that the extra,
165     // made-up group, `123`, is set.
166     // FIXME: Test the other half of initgroups' functionality: whether the
167     // groups that the user belongs to are also set.
168     let user = CString::new("root").unwrap();
169     let group = Gid::from_raw(123);
170     let group_list = getgrouplist(&user, group).unwrap();
171     assert!(group_list.contains(&group));
172 
173     initgroups(&user, group).unwrap();
174 
175     let new_groups = getgroups().unwrap();
176     assert_eq!(new_groups, group_list);
177 
178     // Revert back to the old groups
179     setgroups(&old_groups).unwrap();
180 }
181 
182 macro_rules! execve_test_factory(
183     ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
184     #[test]
185     fn $test_name() {
186         let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
187         // The `exec`d process will write to `writer`, and we'll read that
188         // data from `reader`.
189         let (reader, writer) = pipe().unwrap();
190 
191         // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function.
192         // NOTE: Technically, this makes the macro unsafe to use because you could pass anything.
193         //       The tests make sure not to do that, though.
194         match fork().unwrap() {
195             Child => {
196                 // Close stdout.
197                 close(1).unwrap();
198                 // Make `writer` be the stdout of the new process.
199                 dup(writer).unwrap();
200                 // exec!
201                 $syscall(
202                     $exe,
203                     $(&CString::new($pathname).unwrap(), )*
204                     &[CString::new(b"".as_ref()).unwrap(),
205                       CString::new(b"-c".as_ref()).unwrap(),
206                       CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
207                                    .as_ref()).unwrap()],
208                     &[CString::new(b"foo=bar".as_ref()).unwrap(),
209                       CString::new(b"baz=quux".as_ref()).unwrap()]
210                     $(, $flags)*).unwrap();
211             },
212             Parent { child } => {
213                 // Wait for the child to exit.
214                 waitpid(child, None).unwrap();
215                 // Read 1024 bytes.
216                 let mut buf = [0u8; 1024];
217                 read(reader, &mut buf).unwrap();
218                 // It should contain the things we printed using `/bin/sh`.
219                 let string = String::from_utf8_lossy(&buf);
220                 assert!(string.contains("nix!!!"));
221                 assert!(string.contains("foo=bar"));
222                 assert!(string.contains("baz=quux"));
223             }
224         }
225     }
226     )
227 );
228 
229 cfg_if!{
230     if #[cfg(target_os = "android")] {
231         execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap());
232         execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
233     } else if #[cfg(any(target_os = "freebsd",
234                         target_os = "linux"))] {
235         execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
236         execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
237     } else if #[cfg(any(target_os = "dragonfly",
238                         target_os = "ios",
239                         target_os = "macos",
240                         target_os = "netbsd",
241                         target_os = "openbsd"))] {
242         execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
243         // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD.
244         //
245         // Note for NetBSD and OpenBSD: although rust-lang/libc includes it
246         // (under unix/bsd/netbsdlike/) fexecve is not currently implemented on
247         // NetBSD nor on OpenBSD.
248     }
249 }
250 
251 #[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
252 execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
253 
254 cfg_if!{
255     if #[cfg(target_os = "android")] {
256         use nix::fcntl::AtFlags;
257         execve_test_factory!(test_execveat_empty, execveat, File::open("/system/bin/sh").unwrap().into_raw_fd(),
258                              "", AtFlags::AT_EMPTY_PATH);
259         execve_test_factory!(test_execveat_relative, execveat, File::open("/system/bin/").unwrap().into_raw_fd(),
260                              "./sh", AtFlags::empty());
261         execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
262                              "/system/bin/sh", AtFlags::empty());
263     } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] {
264         use nix::fcntl::AtFlags;
265         execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
266                              "", AtFlags::AT_EMPTY_PATH);
267         execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(),
268                              "./sh", AtFlags::empty());
269         execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
270                              "/bin/sh", AtFlags::empty());
271     }
272 }
273 
274 #[test]
test_fchdir()275 fn test_fchdir() {
276     // fchdir changes the process's cwd
277     let _dr = ::DirRestore::new();
278 
279     let tmpdir = tempfile::tempdir().unwrap();
280     let tmpdir_path = tmpdir.path().canonicalize().unwrap();
281     let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
282 
283     assert!(fchdir(tmpdir_fd).is_ok());
284     assert_eq!(getcwd().unwrap(), tmpdir_path);
285 
286     assert!(close(tmpdir_fd).is_ok());
287 }
288 
289 #[test]
test_getcwd()290 fn test_getcwd() {
291     // chdir changes the process's cwd
292     let _dr = ::DirRestore::new();
293 
294     let tmpdir = tempfile::tempdir().unwrap();
295     let tmpdir_path = tmpdir.path().canonicalize().unwrap();
296     assert!(chdir(&tmpdir_path).is_ok());
297     assert_eq!(getcwd().unwrap(), tmpdir_path);
298 
299     // make path 500 chars longer so that buffer doubling in getcwd
300     // kicks in.  Note: One path cannot be longer than 255 bytes
301     // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually
302     // 4096 on linux, 1024 on macos)
303     let mut inner_tmp_dir = tmpdir_path.to_path_buf();
304     for _ in 0..5 {
305         let newdir = iter::repeat("a").take(100).collect::<String>();
306         inner_tmp_dir.push(newdir);
307         assert!(mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU).is_ok());
308     }
309     assert!(chdir(inner_tmp_dir.as_path()).is_ok());
310     assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path());
311 }
312 
313 #[test]
test_chown()314 fn test_chown() {
315     // Testing for anything other than our own UID/GID is hard.
316     let uid = Some(getuid());
317     let gid = Some(getgid());
318 
319     let tempdir = tempfile::tempdir().unwrap();
320     let path = tempdir.path().join("file");
321     {
322         File::create(&path).unwrap();
323     }
324 
325     chown(&path, uid, gid).unwrap();
326     chown(&path, uid, None).unwrap();
327     chown(&path, None, gid).unwrap();
328 
329     fs::remove_file(&path).unwrap();
330     chown(&path, uid, gid).unwrap_err();
331 }
332 
333 #[test]
test_fchownat()334 fn test_fchownat() {
335     let _dr = ::DirRestore::new();
336     // Testing for anything other than our own UID/GID is hard.
337     let uid = Some(getuid());
338     let gid = Some(getgid());
339 
340     let tempdir = tempfile::tempdir().unwrap();
341     let path = tempdir.path().join("file");
342     {
343         File::create(&path).unwrap();
344     }
345 
346     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
347 
348     fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
349 
350     chdir(tempdir.path()).unwrap();
351     fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
352 
353     fs::remove_file(&path).unwrap();
354     fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err();
355 }
356 
357 #[test]
test_lseek()358 fn test_lseek() {
359     const CONTENTS: &[u8] = b"abcdef123456";
360     let mut tmp = tempfile().unwrap();
361     tmp.write_all(CONTENTS).unwrap();
362     let tmpfd = tmp.into_raw_fd();
363 
364     let offset: off_t = 5;
365     lseek(tmpfd, offset, Whence::SeekSet).unwrap();
366 
367     let mut buf = [0u8; 7];
368     ::read_exact(tmpfd, &mut buf);
369     assert_eq!(b"f123456", &buf);
370 
371     close(tmpfd).unwrap();
372 }
373 
374 #[cfg(any(target_os = "linux", target_os = "android"))]
375 #[test]
test_lseek64()376 fn test_lseek64() {
377     const CONTENTS: &[u8] = b"abcdef123456";
378     let mut tmp = tempfile().unwrap();
379     tmp.write_all(CONTENTS).unwrap();
380     let tmpfd = tmp.into_raw_fd();
381 
382     lseek64(tmpfd, 5, Whence::SeekSet).unwrap();
383 
384     let mut buf = [0u8; 7];
385     ::read_exact(tmpfd, &mut buf);
386     assert_eq!(b"f123456", &buf);
387 
388     close(tmpfd).unwrap();
389 }
390 
391 cfg_if!{
392     if #[cfg(any(target_os = "android", target_os = "linux"))] {
393         macro_rules! require_acct{
394             () => {
395                 require_capability!(CAP_SYS_PACCT);
396             }
397         }
398     } else if #[cfg(target_os = "freebsd")] {
399         macro_rules! require_acct{
400             () => {
401                 skip_if_not_root!("test_acct");
402                 skip_if_jailed!("test_acct");
403             }
404         }
405     } else {
406         macro_rules! require_acct{
407             () => {
408                 skip_if_not_root!("test_acct");
409             }
410         }
411     }
412 }
413 
414 #[test]
test_acct()415 fn test_acct() {
416     use tempfile::NamedTempFile;
417     use std::process::Command;
418     use std::{thread, time};
419 
420     let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
421     require_acct!();
422 
423     let file = NamedTempFile::new().unwrap();
424     let path = file.path().to_str().unwrap();
425 
426     acct::enable(path).unwrap();
427 
428     loop {
429         Command::new("echo").arg("Hello world");
430         let len = fs::metadata(path).unwrap().len();
431         if len > 0 { break; }
432         thread::sleep(time::Duration::from_millis(10));
433     }
434     acct::disable().unwrap();
435 }
436 
437 #[test]
test_fpathconf_limited()438 fn test_fpathconf_limited() {
439     let f = tempfile().unwrap();
440     // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
441     let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX);
442     assert!(path_max.expect("fpathconf failed").expect("PATH_MAX is unlimited") > 0);
443 }
444 
445 #[test]
test_pathconf_limited()446 fn test_pathconf_limited() {
447     // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
448     let path_max = pathconf("/", PathconfVar::PATH_MAX);
449     assert!(path_max.expect("pathconf failed").expect("PATH_MAX is unlimited") > 0);
450 }
451 
452 #[test]
test_sysconf_limited()453 fn test_sysconf_limited() {
454     // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test
455     let open_max = sysconf(SysconfVar::OPEN_MAX);
456     assert!(open_max.expect("sysconf failed").expect("OPEN_MAX is unlimited") > 0);
457 }
458 
459 #[cfg(target_os = "freebsd")]
460 #[test]
test_sysconf_unsupported()461 fn test_sysconf_unsupported() {
462     // I know of no sysconf variables that are unsupported everywhere, but
463     // _XOPEN_CRYPT is unsupported on FreeBSD 11.0, which is one of the platforms
464     // we test.
465     let open_max = sysconf(SysconfVar::_XOPEN_CRYPT);
466     assert!(open_max.expect("sysconf failed").is_none())
467 }
468 
469 // Test that we can create a pair of pipes.  No need to verify that they pass
470 // data; that's the domain of the OS, not nix.
471 #[test]
test_pipe()472 fn test_pipe() {
473     let (fd0, fd1) = pipe().unwrap();
474     let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode);
475     // S_IFIFO means it's a pipe
476     assert_eq!(m0, SFlag::S_IFIFO);
477     let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode);
478     assert_eq!(m1, SFlag::S_IFIFO);
479 }
480 
481 // pipe2(2) is the same as pipe(2), except it allows setting some flags.  Check
482 // that we can set a flag.
483 #[test]
test_pipe2()484 fn test_pipe2() {
485     let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
486     let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
487     assert!(f0.contains(FdFlag::FD_CLOEXEC));
488     let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap());
489     assert!(f1.contains(FdFlag::FD_CLOEXEC));
490 }
491 
492 #[test]
test_truncate()493 fn test_truncate() {
494     let tempdir = tempfile::tempdir().unwrap();
495     let path = tempdir.path().join("file");
496 
497     {
498         let mut tmp = File::create(&path).unwrap();
499         const CONTENTS: &[u8] = b"12345678";
500         tmp.write_all(CONTENTS).unwrap();
501     }
502 
503     truncate(&path, 4).unwrap();
504 
505     let metadata = fs::metadata(&path).unwrap();
506     assert_eq!(4, metadata.len());
507 }
508 
509 #[test]
test_ftruncate()510 fn test_ftruncate() {
511     let tempdir = tempfile::tempdir().unwrap();
512     let path = tempdir.path().join("file");
513 
514     let tmpfd = {
515         let mut tmp = File::create(&path).unwrap();
516         const CONTENTS: &[u8] = b"12345678";
517         tmp.write_all(CONTENTS).unwrap();
518         tmp.into_raw_fd()
519     };
520 
521     ftruncate(tmpfd, 2).unwrap();
522     close(tmpfd).unwrap();
523 
524     let metadata = fs::metadata(&path).unwrap();
525     assert_eq!(2, metadata.len());
526 }
527 
528 // Used in `test_alarm`.
529 static mut ALARM_CALLED: bool = false;
530 
531 // Used in `test_alarm`.
alarm_signal_handler(raw_signal: libc::c_int)532 pub extern fn alarm_signal_handler(raw_signal: libc::c_int) {
533     assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal);
534     unsafe { ALARM_CALLED = true };
535 }
536 
537 #[test]
test_alarm()538 fn test_alarm() {
539     let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
540 
541     let handler = SigHandler::Handler(alarm_signal_handler);
542     let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty());
543     let old_handler = unsafe {
544         sigaction(Signal::SIGALRM, &signal_action)
545             .expect("unable to set signal handler for alarm")
546     };
547 
548     // Set an alarm.
549     assert_eq!(alarm::set(60), None);
550 
551     // Overwriting an alarm should return the old alarm.
552     assert_eq!(alarm::set(1), Some(60));
553 
554     // We should be woken up after 1 second by the alarm, so we'll sleep for 2
555     // seconds to be sure.
556     sleep(2);
557     assert_eq!(unsafe { ALARM_CALLED }, true, "expected our alarm signal handler to be called");
558 
559     // Reset the signal.
560     unsafe {
561         sigaction(Signal::SIGALRM, &old_handler)
562             .expect("unable to set signal handler for alarm");
563     }
564 }
565 
566 #[test]
test_canceling_alarm()567 fn test_canceling_alarm() {
568     let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
569 
570     assert_eq!(alarm::cancel(), None);
571 
572     assert_eq!(alarm::set(60), None);
573     assert_eq!(alarm::cancel(), Some(60));
574 }
575 
576 #[test]
test_symlinkat()577 fn test_symlinkat() {
578     let mut buf = [0; 1024];
579     let tempdir = tempfile::tempdir().unwrap();
580 
581     let target = tempdir.path().join("a");
582     let linkpath = tempdir.path().join("b");
583     symlinkat(&target, None, &linkpath).unwrap();
584     assert_eq!(
585         readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
586         target.to_str().unwrap()
587     );
588 
589     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
590     let target = "c";
591     let linkpath = "d";
592     symlinkat(target, Some(dirfd), linkpath).unwrap();
593     assert_eq!(
594         readlink(&tempdir.path().join(linkpath), &mut buf)
595             .unwrap()
596             .to_str()
597             .unwrap(),
598         target
599     );
600 }
601 
602 #[test]
test_access_not_existing()603 fn test_access_not_existing() {
604     let tempdir = tempfile::tempdir().unwrap();
605     let dir = tempdir.path().join("does_not_exist.txt");
606     assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(),
607                Errno::ENOENT);
608 }
609 
610 #[test]
test_access_file_exists()611 fn test_access_file_exists() {
612     let tempdir = tempfile::tempdir().unwrap();
613     let path  = tempdir.path().join("does_exist.txt");
614     let _file = File::create(path.clone()).unwrap();
615     assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok());
616 }
617