mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 11:48:30 +00:00
1340 lines
42 KiB
Rust
1340 lines
42 KiB
Rust
use crate::io::prelude::*;
|
|
|
|
use crate::fs::{self, File, OpenOptions};
|
|
use crate::io::{ErrorKind, SeekFrom};
|
|
use crate::path::Path;
|
|
use crate::str;
|
|
use crate::sys_common::io::test::{tmpdir, TempDir};
|
|
use crate::thread;
|
|
|
|
use rand::{rngs::StdRng, RngCore, SeedableRng};
|
|
|
|
#[cfg(unix)]
|
|
use crate::os::unix::fs::symlink as symlink_dir;
|
|
#[cfg(unix)]
|
|
use crate::os::unix::fs::symlink as symlink_file;
|
|
#[cfg(unix)]
|
|
use crate::os::unix::fs::symlink as symlink_junction;
|
|
#[cfg(windows)]
|
|
use crate::os::windows::fs::{symlink_dir, symlink_file};
|
|
#[cfg(windows)]
|
|
use crate::sys::fs::symlink_junction;
|
|
|
|
macro_rules! check {
|
|
($e:expr) => {
|
|
match $e {
|
|
Ok(t) => t,
|
|
Err(e) => panic!("{} failed with: {}", stringify!($e), e),
|
|
}
|
|
};
|
|
}
|
|
|
|
#[cfg(windows)]
|
|
macro_rules! error {
|
|
($e:expr, $s:expr) => {
|
|
match $e {
|
|
Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
|
|
Err(ref err) => assert!(
|
|
err.raw_os_error() == Some($s),
|
|
format!("`{}` did not have a code of `{}`", err, $s)
|
|
),
|
|
}
|
|
};
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
macro_rules! error {
|
|
($e:expr, $s:expr) => {
|
|
error_contains!($e, $s)
|
|
};
|
|
}
|
|
|
|
macro_rules! error_contains {
|
|
($e:expr, $s:expr) => {
|
|
match $e {
|
|
Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
|
|
Err(ref err) => {
|
|
assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s))
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Several test fail on windows if the user does not have permission to
|
|
// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of
|
|
// disabling these test on Windows, use this function to test whether we
|
|
// have permission, and return otherwise. This way, we still don't run these
|
|
// tests most of the time, but at least we do if the user has the right
|
|
// permissions.
|
|
pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
|
|
if cfg!(unix) {
|
|
return true;
|
|
}
|
|
let link = tmpdir.join("some_hopefully_unique_link_name");
|
|
|
|
match symlink_file(r"nonexisting_target", link) {
|
|
Ok(_) => true,
|
|
// ERROR_PRIVILEGE_NOT_HELD = 1314
|
|
Err(ref err) if err.raw_os_error() == Some(1314) => false,
|
|
Err(_) => true,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_io_smoke_test() {
|
|
let message = "it's alright. have a good time";
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_rt_io_file_test.txt");
|
|
{
|
|
let mut write_stream = check!(File::create(filename));
|
|
check!(write_stream.write(message.as_bytes()));
|
|
}
|
|
{
|
|
let mut read_stream = check!(File::open(filename));
|
|
let mut read_buf = [0; 1028];
|
|
let read_str = match check!(read_stream.read(&mut read_buf)) {
|
|
0 => panic!("shouldn't happen"),
|
|
n => str::from_utf8(&read_buf[..n]).unwrap().to_string(),
|
|
};
|
|
assert_eq!(read_str, message);
|
|
}
|
|
check!(fs::remove_file(filename));
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_path_raises() {
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_that_does_not_exist.txt");
|
|
let result = File::open(filename);
|
|
|
|
#[cfg(all(unix, not(target_os = "vxworks")))]
|
|
error!(result, "No such file or directory");
|
|
#[cfg(target_os = "vxworks")]
|
|
error!(result, "no such file or directory");
|
|
#[cfg(windows)]
|
|
error!(result, 2); // ERROR_FILE_NOT_FOUND
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_iounlinking_invalid_path_should_raise_condition() {
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt");
|
|
|
|
let result = fs::remove_file(filename);
|
|
|
|
#[cfg(all(unix, not(target_os = "vxworks")))]
|
|
error!(result, "No such file or directory");
|
|
#[cfg(target_os = "vxworks")]
|
|
error!(result, "no such file or directory");
|
|
#[cfg(windows)]
|
|
error!(result, 2); // ERROR_FILE_NOT_FOUND
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_io_non_positional_read() {
|
|
let message: &str = "ten-four";
|
|
let mut read_mem = [0; 8];
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_rt_io_file_test_positional.txt");
|
|
{
|
|
let mut rw_stream = check!(File::create(filename));
|
|
check!(rw_stream.write(message.as_bytes()));
|
|
}
|
|
{
|
|
let mut read_stream = check!(File::open(filename));
|
|
{
|
|
let read_buf = &mut read_mem[0..4];
|
|
check!(read_stream.read(read_buf));
|
|
}
|
|
{
|
|
let read_buf = &mut read_mem[4..8];
|
|
check!(read_stream.read(read_buf));
|
|
}
|
|
}
|
|
check!(fs::remove_file(filename));
|
|
let read_str = str::from_utf8(&read_mem).unwrap();
|
|
assert_eq!(read_str, message);
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_io_seek_and_tell_smoke_test() {
|
|
let message = "ten-four";
|
|
let mut read_mem = [0; 4];
|
|
let set_cursor = 4 as u64;
|
|
let tell_pos_pre_read;
|
|
let tell_pos_post_read;
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt");
|
|
{
|
|
let mut rw_stream = check!(File::create(filename));
|
|
check!(rw_stream.write(message.as_bytes()));
|
|
}
|
|
{
|
|
let mut read_stream = check!(File::open(filename));
|
|
check!(read_stream.seek(SeekFrom::Start(set_cursor)));
|
|
tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0)));
|
|
check!(read_stream.read(&mut read_mem));
|
|
tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0)));
|
|
}
|
|
check!(fs::remove_file(filename));
|
|
let read_str = str::from_utf8(&read_mem).unwrap();
|
|
assert_eq!(read_str, &message[4..8]);
|
|
assert_eq!(tell_pos_pre_read, set_cursor);
|
|
assert_eq!(tell_pos_post_read, message.len() as u64);
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_io_seek_and_write() {
|
|
let initial_msg = "food-is-yummy";
|
|
let overwrite_msg = "-the-bar!!";
|
|
let final_msg = "foo-the-bar!!";
|
|
let seek_idx = 3;
|
|
let mut read_mem = [0; 13];
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt");
|
|
{
|
|
let mut rw_stream = check!(File::create(filename));
|
|
check!(rw_stream.write(initial_msg.as_bytes()));
|
|
check!(rw_stream.seek(SeekFrom::Start(seek_idx)));
|
|
check!(rw_stream.write(overwrite_msg.as_bytes()));
|
|
}
|
|
{
|
|
let mut read_stream = check!(File::open(filename));
|
|
check!(read_stream.read(&mut read_mem));
|
|
}
|
|
check!(fs::remove_file(filename));
|
|
let read_str = str::from_utf8(&read_mem).unwrap();
|
|
assert!(read_str == final_msg);
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_io_seek_shakedown() {
|
|
// 01234567890123
|
|
let initial_msg = "qwer-asdf-zxcv";
|
|
let chunk_one: &str = "qwer";
|
|
let chunk_two: &str = "asdf";
|
|
let chunk_three: &str = "zxcv";
|
|
let mut read_mem = [0; 4];
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt");
|
|
{
|
|
let mut rw_stream = check!(File::create(filename));
|
|
check!(rw_stream.write(initial_msg.as_bytes()));
|
|
}
|
|
{
|
|
let mut read_stream = check!(File::open(filename));
|
|
|
|
check!(read_stream.seek(SeekFrom::End(-4)));
|
|
check!(read_stream.read(&mut read_mem));
|
|
assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three);
|
|
|
|
check!(read_stream.seek(SeekFrom::Current(-9)));
|
|
check!(read_stream.read(&mut read_mem));
|
|
assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two);
|
|
|
|
check!(read_stream.seek(SeekFrom::Start(0)));
|
|
check!(read_stream.read(&mut read_mem));
|
|
assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one);
|
|
}
|
|
check!(fs::remove_file(filename));
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_io_eof() {
|
|
let tmpdir = tmpdir();
|
|
let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
|
|
let mut buf = [0; 256];
|
|
{
|
|
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
|
|
let mut rw = check!(oo.open(&filename));
|
|
assert_eq!(check!(rw.read(&mut buf)), 0);
|
|
assert_eq!(check!(rw.read(&mut buf)), 0);
|
|
}
|
|
check!(fs::remove_file(&filename));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn file_test_io_read_write_at() {
|
|
use crate::os::unix::fs::FileExt;
|
|
|
|
let tmpdir = tmpdir();
|
|
let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
|
|
let mut buf = [0; 256];
|
|
let write1 = "asdf";
|
|
let write2 = "qwer-";
|
|
let write3 = "-zxcv";
|
|
let content = "qwer-asdf-zxcv";
|
|
{
|
|
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
|
|
let mut rw = check!(oo.open(&filename));
|
|
assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
|
|
assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
|
|
assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
|
|
assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
|
|
assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
|
|
assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
|
|
assert_eq!(check!(rw.read(&mut buf)), write1.len());
|
|
assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
|
|
assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
|
|
assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
|
|
assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
|
|
}
|
|
{
|
|
let mut read = check!(File::open(&filename));
|
|
assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
|
|
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
|
|
assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
|
|
assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
|
|
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
|
|
assert_eq!(check!(read.read(&mut buf)), write3.len());
|
|
assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
|
|
assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
|
|
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
|
|
assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
|
|
assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
|
|
}
|
|
check!(fs::remove_file(&filename));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn set_get_unix_permissions() {
|
|
use crate::os::unix::fs::PermissionsExt;
|
|
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("set_get_unix_permissions");
|
|
check!(fs::create_dir(filename));
|
|
let mask = 0o7777;
|
|
|
|
check!(fs::set_permissions(filename, fs::Permissions::from_mode(0)));
|
|
let metadata0 = check!(fs::metadata(filename));
|
|
assert_eq!(mask & metadata0.permissions().mode(), 0);
|
|
|
|
check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
|
|
let metadata1 = check!(fs::metadata(filename));
|
|
#[cfg(all(unix, not(target_os = "vxworks")))]
|
|
assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
|
|
#[cfg(target_os = "vxworks")]
|
|
assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(windows)]
|
|
fn file_test_io_seek_read_write() {
|
|
use crate::os::windows::fs::FileExt;
|
|
|
|
let tmpdir = tmpdir();
|
|
let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
|
|
let mut buf = [0; 256];
|
|
let write1 = "asdf";
|
|
let write2 = "qwer-";
|
|
let write3 = "-zxcv";
|
|
let content = "qwer-asdf-zxcv";
|
|
{
|
|
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
|
|
let mut rw = check!(oo.open(&filename));
|
|
assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
|
|
assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
|
|
assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
|
|
assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
|
|
assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
|
|
assert_eq!(check!(rw.read(&mut buf)), write1.len());
|
|
assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
|
|
assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
|
|
assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
|
|
assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
|
|
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
|
|
}
|
|
{
|
|
let mut read = check!(File::open(&filename));
|
|
assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
|
|
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
|
|
assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
|
|
assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
|
|
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
|
|
assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
|
|
assert_eq!(check!(read.read(&mut buf)), write3.len());
|
|
assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
|
|
assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
|
|
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
|
|
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
|
|
assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
|
|
assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
|
|
}
|
|
check!(fs::remove_file(&filename));
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_stat_is_correct_on_is_file() {
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
|
|
{
|
|
let mut opts = OpenOptions::new();
|
|
let mut fs = check!(opts.read(true).write(true).create(true).open(filename));
|
|
let msg = "hw";
|
|
fs.write(msg.as_bytes()).unwrap();
|
|
|
|
let fstat_res = check!(fs.metadata());
|
|
assert!(fstat_res.is_file());
|
|
}
|
|
let stat_res_fn = check!(fs::metadata(filename));
|
|
assert!(stat_res_fn.is_file());
|
|
let stat_res_meth = check!(filename.metadata());
|
|
assert!(stat_res_meth.is_file());
|
|
check!(fs::remove_file(filename));
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_stat_is_correct_on_is_dir() {
|
|
let tmpdir = tmpdir();
|
|
let filename = &tmpdir.join("file_stat_correct_on_is_dir");
|
|
check!(fs::create_dir(filename));
|
|
let stat_res_fn = check!(fs::metadata(filename));
|
|
assert!(stat_res_fn.is_dir());
|
|
let stat_res_meth = check!(filename.metadata());
|
|
assert!(stat_res_meth.is_dir());
|
|
check!(fs::remove_dir(filename));
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() {
|
|
let tmpdir = tmpdir();
|
|
let dir = &tmpdir.join("fileinfo_false_on_dir");
|
|
check!(fs::create_dir(dir));
|
|
assert!(!dir.is_file());
|
|
check!(fs::remove_dir(dir));
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_fileinfo_check_exists_before_and_after_file_creation() {
|
|
let tmpdir = tmpdir();
|
|
let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt");
|
|
check!(check!(File::create(file)).write(b"foo"));
|
|
assert!(file.exists());
|
|
check!(fs::remove_file(file));
|
|
assert!(!file.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_directoryinfo_check_exists_before_and_after_mkdir() {
|
|
let tmpdir = tmpdir();
|
|
let dir = &tmpdir.join("before_and_after_dir");
|
|
assert!(!dir.exists());
|
|
check!(fs::create_dir(dir));
|
|
assert!(dir.exists());
|
|
assert!(dir.is_dir());
|
|
check!(fs::remove_dir(dir));
|
|
assert!(!dir.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn file_test_directoryinfo_readdir() {
|
|
let tmpdir = tmpdir();
|
|
let dir = &tmpdir.join("di_readdir");
|
|
check!(fs::create_dir(dir));
|
|
let prefix = "foo";
|
|
for n in 0..3 {
|
|
let f = dir.join(&format!("{}.txt", n));
|
|
let mut w = check!(File::create(&f));
|
|
let msg_str = format!("{}{}", prefix, n.to_string());
|
|
let msg = msg_str.as_bytes();
|
|
check!(w.write(msg));
|
|
}
|
|
let files = check!(fs::read_dir(dir));
|
|
let mut mem = [0; 4];
|
|
for f in files {
|
|
let f = f.unwrap().path();
|
|
{
|
|
let n = f.file_stem().unwrap();
|
|
check!(check!(File::open(&f)).read(&mut mem));
|
|
let read_str = str::from_utf8(&mem).unwrap();
|
|
let expected = format!("{}{}", prefix, n.to_str().unwrap());
|
|
assert_eq!(expected, read_str);
|
|
}
|
|
check!(fs::remove_file(&f));
|
|
}
|
|
check!(fs::remove_dir(dir));
|
|
}
|
|
|
|
#[test]
|
|
fn file_create_new_already_exists_error() {
|
|
let tmpdir = tmpdir();
|
|
let file = &tmpdir.join("file_create_new_error_exists");
|
|
check!(fs::File::create(file));
|
|
let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err();
|
|
assert_eq!(e.kind(), ErrorKind::AlreadyExists);
|
|
}
|
|
|
|
#[test]
|
|
fn mkdir_path_already_exists_error() {
|
|
let tmpdir = tmpdir();
|
|
let dir = &tmpdir.join("mkdir_error_twice");
|
|
check!(fs::create_dir(dir));
|
|
let e = fs::create_dir(dir).unwrap_err();
|
|
assert_eq!(e.kind(), ErrorKind::AlreadyExists);
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_mkdir() {
|
|
let tmpdir = tmpdir();
|
|
let dir = tmpdir.join("d1/d2");
|
|
check!(fs::create_dir_all(&dir));
|
|
assert!(dir.is_dir())
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_mkdir_failure() {
|
|
let tmpdir = tmpdir();
|
|
let dir = tmpdir.join("d1");
|
|
let file = dir.join("f1");
|
|
|
|
check!(fs::create_dir_all(&dir));
|
|
check!(File::create(&file));
|
|
|
|
let result = fs::create_dir_all(&file);
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn concurrent_recursive_mkdir() {
|
|
for _ in 0..100 {
|
|
let dir = tmpdir();
|
|
let mut dir = dir.join("a");
|
|
for _ in 0..40 {
|
|
dir = dir.join("a");
|
|
}
|
|
let mut join = vec![];
|
|
for _ in 0..8 {
|
|
let dir = dir.clone();
|
|
join.push(thread::spawn(move || {
|
|
check!(fs::create_dir_all(&dir));
|
|
}))
|
|
}
|
|
|
|
// No `Display` on result of `join()`
|
|
join.drain(..).map(|join| join.join().unwrap()).count();
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_mkdir_slash() {
|
|
check!(fs::create_dir_all(Path::new("/")));
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_mkdir_dot() {
|
|
check!(fs::create_dir_all(Path::new(".")));
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_mkdir_empty() {
|
|
check!(fs::create_dir_all(Path::new("")));
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_rmdir() {
|
|
let tmpdir = tmpdir();
|
|
let d1 = tmpdir.join("d1");
|
|
let dt = d1.join("t");
|
|
let dtt = dt.join("t");
|
|
let d2 = tmpdir.join("d2");
|
|
let canary = d2.join("do_not_delete");
|
|
check!(fs::create_dir_all(&dtt));
|
|
check!(fs::create_dir_all(&d2));
|
|
check!(check!(File::create(&canary)).write(b"foo"));
|
|
check!(symlink_junction(&d2, &dt.join("d2")));
|
|
let _ = symlink_file(&canary, &d1.join("canary"));
|
|
check!(fs::remove_dir_all(&d1));
|
|
|
|
assert!(!d1.is_dir());
|
|
assert!(canary.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn recursive_rmdir_of_symlink() {
|
|
// test we do not recursively delete a symlink but only dirs.
|
|
let tmpdir = tmpdir();
|
|
let link = tmpdir.join("d1");
|
|
let dir = tmpdir.join("d2");
|
|
let canary = dir.join("do_not_delete");
|
|
check!(fs::create_dir_all(&dir));
|
|
check!(check!(File::create(&canary)).write(b"foo"));
|
|
check!(symlink_junction(&dir, &link));
|
|
check!(fs::remove_dir_all(&link));
|
|
|
|
assert!(!link.is_dir());
|
|
assert!(canary.exists());
|
|
}
|
|
|
|
#[test]
|
|
// only Windows makes a distinction between file and directory symlinks.
|
|
#[cfg(windows)]
|
|
fn recursive_rmdir_of_file_symlink() {
|
|
let tmpdir = tmpdir();
|
|
if !got_symlink_permission(&tmpdir) {
|
|
return;
|
|
};
|
|
|
|
let f1 = tmpdir.join("f1");
|
|
let f2 = tmpdir.join("f2");
|
|
check!(check!(File::create(&f1)).write(b"foo"));
|
|
check!(symlink_file(&f1, &f2));
|
|
match fs::remove_dir_all(&f2) {
|
|
Ok(..) => panic!("wanted a failure"),
|
|
Err(..) => {}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn unicode_path_is_dir() {
|
|
assert!(Path::new(".").is_dir());
|
|
assert!(!Path::new("test/stdtest/fs.rs").is_dir());
|
|
|
|
let tmpdir = tmpdir();
|
|
|
|
let mut dirpath = tmpdir.path().to_path_buf();
|
|
dirpath.push("test-가一ー你好");
|
|
check!(fs::create_dir(&dirpath));
|
|
assert!(dirpath.is_dir());
|
|
|
|
let mut filepath = dirpath;
|
|
filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs");
|
|
check!(File::create(&filepath)); // ignore return; touch only
|
|
assert!(!filepath.is_dir());
|
|
assert!(filepath.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn unicode_path_exists() {
|
|
assert!(Path::new(".").exists());
|
|
assert!(!Path::new("test/nonexistent-bogus-path").exists());
|
|
|
|
let tmpdir = tmpdir();
|
|
let unicode = tmpdir.path();
|
|
let unicode = unicode.join("test-각丁ー再见");
|
|
check!(fs::create_dir(&unicode));
|
|
assert!(unicode.exists());
|
|
assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists());
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_does_not_exist() {
|
|
let from = Path::new("test/nonexistent-bogus-path");
|
|
let to = Path::new("test/other-bogus-path");
|
|
|
|
match fs::copy(&from, &to) {
|
|
Ok(..) => panic!(),
|
|
Err(..) => {
|
|
assert!(!from.exists());
|
|
assert!(!to.exists());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn copy_src_does_not_exist() {
|
|
let tmpdir = tmpdir();
|
|
let from = Path::new("test/nonexistent-bogus-path");
|
|
let to = tmpdir.join("out.txt");
|
|
check!(check!(File::create(&to)).write(b"hello"));
|
|
assert!(fs::copy(&from, &to).is_err());
|
|
assert!(!from.exists());
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&to)).read_to_end(&mut v));
|
|
assert_eq!(v, b"hello");
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_ok() {
|
|
let tmpdir = tmpdir();
|
|
let input = tmpdir.join("in.txt");
|
|
let out = tmpdir.join("out.txt");
|
|
|
|
check!(check!(File::create(&input)).write(b"hello"));
|
|
check!(fs::copy(&input, &out));
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&out)).read_to_end(&mut v));
|
|
assert_eq!(v, b"hello");
|
|
|
|
assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions());
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_dst_dir() {
|
|
let tmpdir = tmpdir();
|
|
let out = tmpdir.join("out");
|
|
|
|
check!(File::create(&out));
|
|
match fs::copy(&*out, tmpdir.path()) {
|
|
Ok(..) => panic!(),
|
|
Err(..) => {}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_dst_exists() {
|
|
let tmpdir = tmpdir();
|
|
let input = tmpdir.join("in");
|
|
let output = tmpdir.join("out");
|
|
|
|
check!(check!(File::create(&input)).write("foo".as_bytes()));
|
|
check!(check!(File::create(&output)).write("bar".as_bytes()));
|
|
check!(fs::copy(&input, &output));
|
|
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&output)).read_to_end(&mut v));
|
|
assert_eq!(v, b"foo".to_vec());
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_src_dir() {
|
|
let tmpdir = tmpdir();
|
|
let out = tmpdir.join("out");
|
|
|
|
match fs::copy(tmpdir.path(), &out) {
|
|
Ok(..) => panic!(),
|
|
Err(..) => {}
|
|
}
|
|
assert!(!out.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_preserves_perm_bits() {
|
|
let tmpdir = tmpdir();
|
|
let input = tmpdir.join("in.txt");
|
|
let out = tmpdir.join("out.txt");
|
|
|
|
let attr = check!(check!(File::create(&input)).metadata());
|
|
let mut p = attr.permissions();
|
|
p.set_readonly(true);
|
|
check!(fs::set_permissions(&input, p));
|
|
check!(fs::copy(&input, &out));
|
|
assert!(check!(out.metadata()).permissions().readonly());
|
|
check!(fs::set_permissions(&input, attr.permissions()));
|
|
check!(fs::set_permissions(&out, attr.permissions()));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(windows)]
|
|
fn copy_file_preserves_streams() {
|
|
let tmp = tmpdir();
|
|
check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
|
|
assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0);
|
|
assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
|
|
assert_eq!(v, b"carrot".to_vec());
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_returns_metadata_len() {
|
|
let tmp = tmpdir();
|
|
let in_path = tmp.join("in.txt");
|
|
let out_path = tmp.join("out.txt");
|
|
check!(check!(File::create(&in_path)).write(b"lettuce"));
|
|
#[cfg(windows)]
|
|
check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot"));
|
|
let copied_len = check!(fs::copy(&in_path, &out_path));
|
|
assert_eq!(check!(out_path.metadata()).len(), copied_len);
|
|
}
|
|
|
|
#[test]
|
|
fn copy_file_follows_dst_symlink() {
|
|
let tmp = tmpdir();
|
|
if !got_symlink_permission(&tmp) {
|
|
return;
|
|
};
|
|
|
|
let in_path = tmp.join("in.txt");
|
|
let out_path = tmp.join("out.txt");
|
|
let out_path_symlink = tmp.join("out_symlink.txt");
|
|
|
|
check!(fs::write(&in_path, "foo"));
|
|
check!(fs::write(&out_path, "bar"));
|
|
check!(symlink_file(&out_path, &out_path_symlink));
|
|
|
|
check!(fs::copy(&in_path, &out_path_symlink));
|
|
|
|
assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink());
|
|
assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec());
|
|
assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec());
|
|
}
|
|
|
|
#[test]
|
|
fn symlinks_work() {
|
|
let tmpdir = tmpdir();
|
|
if !got_symlink_permission(&tmpdir) {
|
|
return;
|
|
};
|
|
|
|
let input = tmpdir.join("in.txt");
|
|
let out = tmpdir.join("out.txt");
|
|
|
|
check!(check!(File::create(&input)).write("foobar".as_bytes()));
|
|
check!(symlink_file(&input, &out));
|
|
assert!(check!(out.symlink_metadata()).file_type().is_symlink());
|
|
assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&out)).read_to_end(&mut v));
|
|
assert_eq!(v, b"foobar".to_vec());
|
|
}
|
|
|
|
#[test]
|
|
fn symlink_noexist() {
|
|
// Symlinks can point to things that don't exist
|
|
let tmpdir = tmpdir();
|
|
if !got_symlink_permission(&tmpdir) {
|
|
return;
|
|
};
|
|
|
|
// Use a relative path for testing. Symlinks get normalized by Windows,
|
|
// so we may not get the same path back for absolute paths
|
|
check!(symlink_file(&"foo", &tmpdir.join("bar")));
|
|
assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo");
|
|
}
|
|
|
|
#[test]
|
|
fn read_link() {
|
|
if cfg!(windows) {
|
|
// directory symlink
|
|
assert_eq!(
|
|
check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(),
|
|
r"C:\ProgramData"
|
|
);
|
|
// junction
|
|
assert_eq!(
|
|
check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(),
|
|
r"C:\Users\Default"
|
|
);
|
|
// junction with special permissions
|
|
assert_eq!(
|
|
check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(),
|
|
r"C:\Users"
|
|
);
|
|
}
|
|
let tmpdir = tmpdir();
|
|
let link = tmpdir.join("link");
|
|
if !got_symlink_permission(&tmpdir) {
|
|
return;
|
|
};
|
|
check!(symlink_file(&"foo", &link));
|
|
assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo");
|
|
}
|
|
|
|
#[test]
|
|
fn readlink_not_symlink() {
|
|
let tmpdir = tmpdir();
|
|
match fs::read_link(tmpdir.path()) {
|
|
Ok(..) => panic!("wanted a failure"),
|
|
Err(..) => {}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn links_work() {
|
|
let tmpdir = tmpdir();
|
|
let input = tmpdir.join("in.txt");
|
|
let out = tmpdir.join("out.txt");
|
|
|
|
check!(check!(File::create(&input)).write("foobar".as_bytes()));
|
|
check!(fs::hard_link(&input, &out));
|
|
assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len());
|
|
assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len());
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&out)).read_to_end(&mut v));
|
|
assert_eq!(v, b"foobar".to_vec());
|
|
|
|
// can't link to yourself
|
|
match fs::hard_link(&input, &input) {
|
|
Ok(..) => panic!("wanted a failure"),
|
|
Err(..) => {}
|
|
}
|
|
// can't link to something that doesn't exist
|
|
match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) {
|
|
Ok(..) => panic!("wanted a failure"),
|
|
Err(..) => {}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn chmod_works() {
|
|
let tmpdir = tmpdir();
|
|
let file = tmpdir.join("in.txt");
|
|
|
|
check!(File::create(&file));
|
|
let attr = check!(fs::metadata(&file));
|
|
assert!(!attr.permissions().readonly());
|
|
let mut p = attr.permissions();
|
|
p.set_readonly(true);
|
|
check!(fs::set_permissions(&file, p.clone()));
|
|
let attr = check!(fs::metadata(&file));
|
|
assert!(attr.permissions().readonly());
|
|
|
|
match fs::set_permissions(&tmpdir.join("foo"), p.clone()) {
|
|
Ok(..) => panic!("wanted an error"),
|
|
Err(..) => {}
|
|
}
|
|
|
|
p.set_readonly(false);
|
|
check!(fs::set_permissions(&file, p));
|
|
}
|
|
|
|
#[test]
|
|
fn fchmod_works() {
|
|
let tmpdir = tmpdir();
|
|
let path = tmpdir.join("in.txt");
|
|
|
|
let file = check!(File::create(&path));
|
|
let attr = check!(fs::metadata(&path));
|
|
assert!(!attr.permissions().readonly());
|
|
let mut p = attr.permissions();
|
|
p.set_readonly(true);
|
|
check!(file.set_permissions(p.clone()));
|
|
let attr = check!(fs::metadata(&path));
|
|
assert!(attr.permissions().readonly());
|
|
|
|
p.set_readonly(false);
|
|
check!(file.set_permissions(p));
|
|
}
|
|
|
|
#[test]
|
|
fn sync_doesnt_kill_anything() {
|
|
let tmpdir = tmpdir();
|
|
let path = tmpdir.join("in.txt");
|
|
|
|
let mut file = check!(File::create(&path));
|
|
check!(file.sync_all());
|
|
check!(file.sync_data());
|
|
check!(file.write(b"foo"));
|
|
check!(file.sync_all());
|
|
check!(file.sync_data());
|
|
}
|
|
|
|
#[test]
|
|
fn truncate_works() {
|
|
let tmpdir = tmpdir();
|
|
let path = tmpdir.join("in.txt");
|
|
|
|
let mut file = check!(File::create(&path));
|
|
check!(file.write(b"foo"));
|
|
check!(file.sync_all());
|
|
|
|
// Do some simple things with truncation
|
|
assert_eq!(check!(file.metadata()).len(), 3);
|
|
check!(file.set_len(10));
|
|
assert_eq!(check!(file.metadata()).len(), 10);
|
|
check!(file.write(b"bar"));
|
|
check!(file.sync_all());
|
|
assert_eq!(check!(file.metadata()).len(), 10);
|
|
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&path)).read_to_end(&mut v));
|
|
assert_eq!(v, b"foobar\0\0\0\0".to_vec());
|
|
|
|
// Truncate to a smaller length, don't seek, and then write something.
|
|
// Ensure that the intermediate zeroes are all filled in (we have `seek`ed
|
|
// past the end of the file).
|
|
check!(file.set_len(2));
|
|
assert_eq!(check!(file.metadata()).len(), 2);
|
|
check!(file.write(b"wut"));
|
|
check!(file.sync_all());
|
|
assert_eq!(check!(file.metadata()).len(), 9);
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&path)).read_to_end(&mut v));
|
|
assert_eq!(v, b"fo\0\0\0\0wut".to_vec());
|
|
}
|
|
|
|
#[test]
|
|
fn open_flavors() {
|
|
use crate::fs::OpenOptions as OO;
|
|
fn c<T: Clone>(t: &T) -> T {
|
|
t.clone()
|
|
}
|
|
|
|
let tmpdir = tmpdir();
|
|
|
|
let mut r = OO::new();
|
|
r.read(true);
|
|
let mut w = OO::new();
|
|
w.write(true);
|
|
let mut rw = OO::new();
|
|
rw.read(true).write(true);
|
|
let mut a = OO::new();
|
|
a.append(true);
|
|
let mut ra = OO::new();
|
|
ra.read(true).append(true);
|
|
|
|
#[cfg(windows)]
|
|
let invalid_options = 87; // ERROR_INVALID_PARAMETER
|
|
#[cfg(all(unix, not(target_os = "vxworks")))]
|
|
let invalid_options = "Invalid argument";
|
|
#[cfg(target_os = "vxworks")]
|
|
let invalid_options = "invalid argument";
|
|
|
|
// Test various combinations of creation modes and access modes.
|
|
//
|
|
// Allowed:
|
|
// creation mode | read | write | read-write | append | read-append |
|
|
// :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:|
|
|
// not set (open existing) | X | X | X | X | X |
|
|
// create | | X | X | X | X |
|
|
// truncate | | X | X | | |
|
|
// create and truncate | | X | X | | |
|
|
// create_new | | X | X | X | X |
|
|
//
|
|
// tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it.
|
|
|
|
// write-only
|
|
check!(c(&w).create_new(true).open(&tmpdir.join("a")));
|
|
check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a")));
|
|
check!(c(&w).truncate(true).open(&tmpdir.join("a")));
|
|
check!(c(&w).create(true).open(&tmpdir.join("a")));
|
|
check!(c(&w).open(&tmpdir.join("a")));
|
|
|
|
// read-only
|
|
error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options);
|
|
error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options);
|
|
error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options);
|
|
error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options);
|
|
check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only
|
|
|
|
// read-write
|
|
check!(c(&rw).create_new(true).open(&tmpdir.join("c")));
|
|
check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c")));
|
|
check!(c(&rw).truncate(true).open(&tmpdir.join("c")));
|
|
check!(c(&rw).create(true).open(&tmpdir.join("c")));
|
|
check!(c(&rw).open(&tmpdir.join("c")));
|
|
|
|
// append
|
|
check!(c(&a).create_new(true).open(&tmpdir.join("d")));
|
|
error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options);
|
|
error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options);
|
|
check!(c(&a).create(true).open(&tmpdir.join("d")));
|
|
check!(c(&a).open(&tmpdir.join("d")));
|
|
|
|
// read-append
|
|
check!(c(&ra).create_new(true).open(&tmpdir.join("e")));
|
|
error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options);
|
|
error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options);
|
|
check!(c(&ra).create(true).open(&tmpdir.join("e")));
|
|
check!(c(&ra).open(&tmpdir.join("e")));
|
|
|
|
// Test opening a file without setting an access mode
|
|
let mut blank = OO::new();
|
|
error!(blank.create(true).open(&tmpdir.join("f")), invalid_options);
|
|
|
|
// Test write works
|
|
check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes()));
|
|
|
|
// Test write fails for read-only
|
|
check!(r.open(&tmpdir.join("h")));
|
|
{
|
|
let mut f = check!(r.open(&tmpdir.join("h")));
|
|
assert!(f.write("wut".as_bytes()).is_err());
|
|
}
|
|
|
|
// Test write overwrites
|
|
{
|
|
let mut f = check!(c(&w).open(&tmpdir.join("h")));
|
|
check!(f.write("baz".as_bytes()));
|
|
}
|
|
{
|
|
let mut f = check!(c(&r).open(&tmpdir.join("h")));
|
|
let mut b = vec![0; 6];
|
|
check!(f.read(&mut b));
|
|
assert_eq!(b, "bazbar".as_bytes());
|
|
}
|
|
|
|
// Test truncate works
|
|
{
|
|
let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h")));
|
|
check!(f.write("foo".as_bytes()));
|
|
}
|
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
|
|
|
|
// Test append works
|
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3);
|
|
{
|
|
let mut f = check!(c(&a).open(&tmpdir.join("h")));
|
|
check!(f.write("bar".as_bytes()));
|
|
}
|
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6);
|
|
|
|
// Test .append(true) equals .write(true).append(true)
|
|
{
|
|
let mut f = check!(c(&w).append(true).open(&tmpdir.join("h")));
|
|
check!(f.write("baz".as_bytes()));
|
|
}
|
|
assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9);
|
|
}
|
|
|
|
#[test]
|
|
fn _assert_send_sync() {
|
|
fn _assert_send_sync<T: Send + Sync>() {}
|
|
_assert_send_sync::<OpenOptions>();
|
|
}
|
|
|
|
#[test]
|
|
fn binary_file() {
|
|
let mut bytes = [0; 1024];
|
|
StdRng::from_entropy().fill_bytes(&mut bytes);
|
|
|
|
let tmpdir = tmpdir();
|
|
|
|
check!(check!(File::create(&tmpdir.join("test"))).write(&bytes));
|
|
let mut v = Vec::new();
|
|
check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v));
|
|
assert!(v == &bytes[..]);
|
|
}
|
|
|
|
#[test]
|
|
fn write_then_read() {
|
|
let mut bytes = [0; 1024];
|
|
StdRng::from_entropy().fill_bytes(&mut bytes);
|
|
|
|
let tmpdir = tmpdir();
|
|
|
|
check!(fs::write(&tmpdir.join("test"), &bytes[..]));
|
|
let v = check!(fs::read(&tmpdir.join("test")));
|
|
assert!(v == &bytes[..]);
|
|
|
|
check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF]));
|
|
error_contains!(
|
|
fs::read_to_string(&tmpdir.join("not-utf8")),
|
|
"stream did not contain valid UTF-8"
|
|
);
|
|
|
|
let s = "𐁁𐀓𐀠𐀴𐀍";
|
|
check!(fs::write(&tmpdir.join("utf8"), s.as_bytes()));
|
|
let string = check!(fs::read_to_string(&tmpdir.join("utf8")));
|
|
assert_eq!(string, s);
|
|
}
|
|
|
|
#[test]
|
|
fn file_try_clone() {
|
|
let tmpdir = tmpdir();
|
|
|
|
let mut f1 =
|
|
check!(OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test")));
|
|
let mut f2 = check!(f1.try_clone());
|
|
|
|
check!(f1.write_all(b"hello world"));
|
|
check!(f1.seek(SeekFrom::Start(2)));
|
|
|
|
let mut buf = vec![];
|
|
check!(f2.read_to_end(&mut buf));
|
|
assert_eq!(buf, b"llo world");
|
|
drop(f2);
|
|
|
|
check!(f1.write_all(b"!"));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(not(windows))]
|
|
fn unlink_readonly() {
|
|
let tmpdir = tmpdir();
|
|
let path = tmpdir.join("file");
|
|
check!(File::create(&path));
|
|
let mut perm = check!(fs::metadata(&path)).permissions();
|
|
perm.set_readonly(true);
|
|
check!(fs::set_permissions(&path, perm));
|
|
check!(fs::remove_file(&path));
|
|
}
|
|
|
|
#[test]
|
|
fn mkdir_trailing_slash() {
|
|
let tmpdir = tmpdir();
|
|
let path = tmpdir.join("file");
|
|
check!(fs::create_dir_all(&path.join("a/")));
|
|
}
|
|
|
|
#[test]
|
|
fn canonicalize_works_simple() {
|
|
let tmpdir = tmpdir();
|
|
let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
|
|
let file = tmpdir.join("test");
|
|
File::create(&file).unwrap();
|
|
assert_eq!(fs::canonicalize(&file).unwrap(), file);
|
|
}
|
|
|
|
#[test]
|
|
fn realpath_works() {
|
|
let tmpdir = tmpdir();
|
|
if !got_symlink_permission(&tmpdir) {
|
|
return;
|
|
};
|
|
|
|
let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
|
|
let file = tmpdir.join("test");
|
|
let dir = tmpdir.join("test2");
|
|
let link = dir.join("link");
|
|
let linkdir = tmpdir.join("test3");
|
|
|
|
File::create(&file).unwrap();
|
|
fs::create_dir(&dir).unwrap();
|
|
symlink_file(&file, &link).unwrap();
|
|
symlink_dir(&dir, &linkdir).unwrap();
|
|
|
|
assert!(link.symlink_metadata().unwrap().file_type().is_symlink());
|
|
|
|
assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir);
|
|
assert_eq!(fs::canonicalize(&file).unwrap(), file);
|
|
assert_eq!(fs::canonicalize(&link).unwrap(), file);
|
|
assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir);
|
|
assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file);
|
|
}
|
|
|
|
#[test]
|
|
fn realpath_works_tricky() {
|
|
let tmpdir = tmpdir();
|
|
if !got_symlink_permission(&tmpdir) {
|
|
return;
|
|
};
|
|
|
|
let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
|
|
let a = tmpdir.join("a");
|
|
let b = a.join("b");
|
|
let c = b.join("c");
|
|
let d = a.join("d");
|
|
let e = d.join("e");
|
|
let f = a.join("f");
|
|
|
|
fs::create_dir_all(&b).unwrap();
|
|
fs::create_dir_all(&d).unwrap();
|
|
File::create(&f).unwrap();
|
|
if cfg!(not(windows)) {
|
|
symlink_file("../d/e", &c).unwrap();
|
|
symlink_file("../f", &e).unwrap();
|
|
}
|
|
if cfg!(windows) {
|
|
symlink_file(r"..\d\e", &c).unwrap();
|
|
symlink_file(r"..\f", &e).unwrap();
|
|
}
|
|
|
|
assert_eq!(fs::canonicalize(&c).unwrap(), f);
|
|
assert_eq!(fs::canonicalize(&e).unwrap(), f);
|
|
}
|
|
|
|
#[test]
|
|
fn dir_entry_methods() {
|
|
let tmpdir = tmpdir();
|
|
|
|
fs::create_dir_all(&tmpdir.join("a")).unwrap();
|
|
File::create(&tmpdir.join("b")).unwrap();
|
|
|
|
for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) {
|
|
let fname = file.file_name();
|
|
match fname.to_str() {
|
|
Some("a") => {
|
|
assert!(file.file_type().unwrap().is_dir());
|
|
assert!(file.metadata().unwrap().is_dir());
|
|
}
|
|
Some("b") => {
|
|
assert!(file.file_type().unwrap().is_file());
|
|
assert!(file.metadata().unwrap().is_file());
|
|
}
|
|
f => panic!("unknown file name: {:?}", f),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn dir_entry_debug() {
|
|
let tmpdir = tmpdir();
|
|
File::create(&tmpdir.join("b")).unwrap();
|
|
let mut read_dir = tmpdir.path().read_dir().unwrap();
|
|
let dir_entry = read_dir.next().unwrap().unwrap();
|
|
let actual = format!("{:?}", dir_entry);
|
|
let expected = format!("DirEntry({:?})", dir_entry.0.path());
|
|
assert_eq!(actual, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn read_dir_not_found() {
|
|
let res = fs::read_dir("/path/that/does/not/exist");
|
|
assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
|
|
}
|
|
|
|
#[test]
|
|
fn create_dir_all_with_junctions() {
|
|
let tmpdir = tmpdir();
|
|
let target = tmpdir.join("target");
|
|
|
|
let junction = tmpdir.join("junction");
|
|
let b = junction.join("a/b");
|
|
|
|
let link = tmpdir.join("link");
|
|
let d = link.join("c/d");
|
|
|
|
fs::create_dir(&target).unwrap();
|
|
|
|
check!(symlink_junction(&target, &junction));
|
|
check!(fs::create_dir_all(&b));
|
|
// the junction itself is not a directory, but `is_dir()` on a Path
|
|
// follows links
|
|
assert!(junction.is_dir());
|
|
assert!(b.exists());
|
|
|
|
if !got_symlink_permission(&tmpdir) {
|
|
return;
|
|
};
|
|
check!(symlink_dir(&target, &link));
|
|
check!(fs::create_dir_all(&d));
|
|
assert!(link.is_dir());
|
|
assert!(d.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn metadata_access_times() {
|
|
let tmpdir = tmpdir();
|
|
|
|
let b = tmpdir.join("b");
|
|
File::create(&b).unwrap();
|
|
|
|
let a = check!(fs::metadata(&tmpdir.path()));
|
|
let b = check!(fs::metadata(&b));
|
|
|
|
assert_eq!(check!(a.accessed()), check!(a.accessed()));
|
|
assert_eq!(check!(a.modified()), check!(a.modified()));
|
|
assert_eq!(check!(b.accessed()), check!(b.modified()));
|
|
|
|
if cfg!(target_os = "macos") || cfg!(target_os = "windows") {
|
|
check!(a.created());
|
|
check!(b.created());
|
|
}
|
|
|
|
if cfg!(target_os = "linux") {
|
|
// Not always available
|
|
match (a.created(), b.created()) {
|
|
(Ok(t1), Ok(t2)) => assert!(t1 <= t2),
|
|
(Err(e1), Err(e2))
|
|
if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {}
|
|
(a, b) => {
|
|
panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,)
|
|
}
|
|
}
|
|
}
|
|
}
|