Skip to content

Commit d3f4d06

Browse files
committed
Auto merge of rust-lang#3591 - RalfJung:win-symlink-trouble, r=RalfJung
do not run symlink tests on Windows hosts Fixes rust-lang/miri#3587
2 parents 3028864 + 1edd3d5 commit d3f4d06

File tree

7 files changed

+151
-150
lines changed

7 files changed

+151
-150
lines changed
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Symlink tests are separate since they don't in general work on a Windows host.
2+
//@ignore-host-windows: creating symlinks requires admin permissions on Windows
3+
//@ignore-target-windows: File handling is not implemented yet
4+
//@compile-flags: -Zmiri-disable-isolation
5+
6+
use std::ffi::CString;
7+
use std::io::{Error, ErrorKind};
8+
use std::os::unix::ffi::OsStrExt;
9+
10+
#[path = "../../utils/mod.rs"]
11+
mod utils;
12+
13+
fn main() {
14+
let bytes = b"Hello, World!\n";
15+
let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes);
16+
let expected_path = path.as_os_str().as_bytes();
17+
18+
let symlink_path = utils::prepare("miri_test_fs_symlink.txt");
19+
std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
20+
21+
// Test that the expected string gets written to a buffer of proper
22+
// length, and that a trailing null byte is not written.
23+
let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
24+
let symlink_c_ptr = symlink_c_str.as_ptr();
25+
26+
// Make the buf one byte larger than it needs to be,
27+
// and check that the last byte is not overwritten.
28+
let mut large_buf = vec![0xFF; expected_path.len() + 1];
29+
let res =
30+
unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) };
31+
// Check that the resolved path was properly written into the buf.
32+
assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path);
33+
assert_eq!(large_buf.last(), Some(&0xFF));
34+
assert_eq!(res, large_buf.len() as isize - 1);
35+
36+
// Test that the resolved path is truncated if the provided buffer
37+
// is too small.
38+
let mut small_buf = [0u8; 2];
39+
let res =
40+
unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) };
41+
assert_eq!(small_buf, &expected_path[..small_buf.len()]);
42+
assert_eq!(res, small_buf.len() as isize);
43+
44+
// Test that we report a proper error for a missing path.
45+
let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap();
46+
let res = unsafe {
47+
libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len())
48+
};
49+
assert_eq!(res, -1);
50+
assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
51+
}

Diff for: src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ignore-target-windows: no libc on Windows
1+
//@ignore-target-windows: File handling is not implemented yet
22
//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
33
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"
44

Diff for: src/tools/miri/tests/pass-dep/libc/libc-fs.rs

+9-75
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
//@ignore-target-windows: no libc on Windows
1+
//@ignore-target-windows: File handling is not implemented yet
22
//@compile-flags: -Zmiri-disable-isolation
33

44
#![feature(io_error_more)]
55
#![feature(io_error_uncategorized)]
66

77
use std::ffi::{CStr, CString, OsString};
8-
use std::fs::{canonicalize, remove_dir_all, remove_file, File};
8+
use std::fs::{canonicalize, remove_file, File};
99
use std::io::{Error, ErrorKind, Write};
1010
use std::os::unix::ffi::OsStrExt;
1111
use std::os::unix::io::AsRawFd;
@@ -21,7 +21,6 @@ fn main() {
2121
test_ftruncate::<libc::off_t>(libc::ftruncate);
2222
#[cfg(target_os = "linux")]
2323
test_ftruncate::<libc::off64_t>(libc::ftruncate64);
24-
test_readlink();
2524
test_file_open_unix_allow_two_args();
2625
test_file_open_unix_needs_three_args();
2726
test_file_open_unix_extra_third_arg();
@@ -38,33 +37,8 @@ fn main() {
3837
test_isatty();
3938
}
4039

41-
/// Prepare: compute filename and make sure the file does not exist.
42-
fn prepare(filename: &str) -> PathBuf {
43-
let path = utils::tmp().join(filename);
44-
// Clean the paths for robustness.
45-
remove_file(&path).ok();
46-
path
47-
}
48-
49-
/// Prepare directory: compute directory name and make sure it does not exist.
50-
#[allow(unused)]
51-
fn prepare_dir(dirname: &str) -> PathBuf {
52-
let path = utils::tmp().join(&dirname);
53-
// Clean the directory for robustness.
54-
remove_dir_all(&path).ok();
55-
path
56-
}
57-
58-
/// Prepare like above, and also write some initial content to the file.
59-
fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
60-
let path = prepare(filename);
61-
let mut file = File::create(&path).unwrap();
62-
file.write(content).unwrap();
63-
path
64-
}
65-
6640
fn test_file_open_unix_allow_two_args() {
67-
let path = prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]);
41+
let path = utils::prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]);
6842

6943
let mut name = path.into_os_string();
7044
name.push("\0");
@@ -73,7 +47,7 @@ fn test_file_open_unix_allow_two_args() {
7347
}
7448

7549
fn test_file_open_unix_needs_three_args() {
76-
let path = prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]);
50+
let path = utils::prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]);
7751

7852
let mut name = path.into_os_string();
7953
name.push("\0");
@@ -82,7 +56,7 @@ fn test_file_open_unix_needs_three_args() {
8256
}
8357

8458
fn test_file_open_unix_extra_third_arg() {
85-
let path = prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]);
59+
let path = utils::prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]);
8660

8761
let mut name = path.into_os_string();
8862
name.push("\0");
@@ -106,49 +80,9 @@ fn test_canonicalize_too_long() {
10680
assert!(canonicalize(too_long).is_err());
10781
}
10882

109-
fn test_readlink() {
110-
let bytes = b"Hello, World!\n";
111-
let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
112-
let expected_path = path.as_os_str().as_bytes();
113-
114-
let symlink_path = prepare("miri_test_fs_symlink.txt");
115-
std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
116-
117-
// Test that the expected string gets written to a buffer of proper
118-
// length, and that a trailing null byte is not written.
119-
let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
120-
let symlink_c_ptr = symlink_c_str.as_ptr();
121-
122-
// Make the buf one byte larger than it needs to be,
123-
// and check that the last byte is not overwritten.
124-
let mut large_buf = vec![0xFF; expected_path.len() + 1];
125-
let res =
126-
unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) };
127-
// Check that the resolved path was properly written into the buf.
128-
assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path);
129-
assert_eq!(large_buf.last(), Some(&0xFF));
130-
assert_eq!(res, large_buf.len() as isize - 1);
131-
132-
// Test that the resolved path is truncated if the provided buffer
133-
// is too small.
134-
let mut small_buf = [0u8; 2];
135-
let res =
136-
unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) };
137-
assert_eq!(small_buf, &expected_path[..small_buf.len()]);
138-
assert_eq!(res, small_buf.len() as isize);
139-
140-
// Test that we report a proper error for a missing path.
141-
let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap();
142-
let res = unsafe {
143-
libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len())
144-
};
145-
assert_eq!(res, -1);
146-
assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
147-
}
148-
14983
fn test_rename() {
150-
let path1 = prepare("miri_test_libc_fs_source.txt");
151-
let path2 = prepare("miri_test_libc_fs_rename_destination.txt");
84+
let path1 = utils::prepare("miri_test_libc_fs_source.txt");
85+
let path2 = utils::prepare("miri_test_libc_fs_rename_destination.txt");
15286

15387
let file = File::create(&path1).unwrap();
15488
drop(file);
@@ -178,7 +112,7 @@ fn test_ftruncate<T: From<i32>>(
178112
// https://docs.rs/libc/latest/i686-unknown-linux-gnu/libc/type.off_t.html
179113

180114
let bytes = b"hello";
181-
let path = prepare("miri_test_libc_fs_ftruncate.txt");
115+
let path = utils::prepare("miri_test_libc_fs_ftruncate.txt");
182116
let mut file = File::create(&path).unwrap();
183117
file.write(bytes).unwrap();
184118
file.sync_all().unwrap();
@@ -209,7 +143,7 @@ fn test_ftruncate<T: From<i32>>(
209143
fn test_o_tmpfile_flag() {
210144
use std::fs::{create_dir, OpenOptions};
211145
use std::os::unix::fs::OpenOptionsExt;
212-
let dir_path = prepare_dir("miri_test_fs_dir");
146+
let dir_path = utils::prepare_dir("miri_test_fs_dir");
213147
create_dir(&dir_path).unwrap();
214148
// test that the `O_TMPFILE` custom flag gracefully errors instead of stopping execution
215149
assert_eq!(

Diff for: src/tools/miri/tests/pass-dep/libc/libc-time.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//@ignore-target-windows: no libc on Windows
1+
//@ignore-target-windows: no libc time APIs on Windows
22
//@compile-flags: -Zmiri-disable-isolation
33
use std::ffi::CStr;
44
use std::{env, mem, ptr};

Diff for: src/tools/miri/tests/pass/shims/fs-symlink.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Symlink tests are separate since they don't in general work on a Windows host.
2+
//@ignore-host-windows: creating symlinks requires admin permissions on Windows
3+
//@ignore-target-windows: File handling is not implemented yet
4+
//@compile-flags: -Zmiri-disable-isolation
5+
6+
use std::fs::{read_link, remove_file, File};
7+
use std::io::{Read, Result};
8+
use std::path::Path;
9+
10+
#[path = "../../utils/mod.rs"]
11+
mod utils;
12+
13+
fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
14+
// Test that the file metadata is correct.
15+
let metadata = path.metadata()?;
16+
// `path` should point to a file.
17+
assert!(metadata.is_file());
18+
// The size of the file must be equal to the number of written bytes.
19+
assert_eq!(bytes.len() as u64, metadata.len());
20+
Ok(())
21+
}
22+
23+
fn main() {
24+
let bytes = b"Hello, World!\n";
25+
let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes);
26+
let symlink_path = utils::prepare("miri_test_fs_symlink.txt");
27+
28+
// Creating a symbolic link should succeed.
29+
#[cfg(unix)]
30+
std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
31+
#[cfg(windows)]
32+
std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();
33+
// Test that the symbolic link has the same contents as the file.
34+
let mut symlink_file = File::open(&symlink_path).unwrap();
35+
let mut contents = Vec::new();
36+
symlink_file.read_to_end(&mut contents).unwrap();
37+
assert_eq!(bytes, contents.as_slice());
38+
39+
// Test that metadata of a symbolic link (i.e., the file it points to) is correct.
40+
check_metadata(bytes, &symlink_path).unwrap();
41+
// Test that the metadata of a symbolic link is correct when not following it.
42+
assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
43+
// Check that we can follow the link.
44+
assert_eq!(read_link(&symlink_path).unwrap(), path);
45+
// Removing symbolic link should succeed.
46+
remove_file(&symlink_path).unwrap();
47+
48+
// Removing file should succeed.
49+
remove_file(&path).unwrap();
50+
}

0 commit comments

Comments
 (0)