Skip to content

Commit 4e8a734

Browse files
authored
Merge pull request #4068 from devnexen/solarish_stat2
solarish stat following-up, supports for readdir.
2 parents 658edd4 + 579b680 commit 4e8a734

File tree

5 files changed

+62
-31
lines changed

5 files changed

+62
-31
lines changed

src/tools/miri/src/helpers.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -309,18 +309,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
309309
}
310310

311311
/// Project to the given *named* field (which must be a struct or union type).
312-
fn project_field_named<P: Projectable<'tcx, Provenance>>(
312+
fn try_project_field_named<P: Projectable<'tcx, Provenance>>(
313313
&self,
314314
base: &P,
315315
name: &str,
316-
) -> InterpResult<'tcx, P> {
316+
) -> InterpResult<'tcx, Option<P>> {
317317
let this = self.eval_context_ref();
318318
let adt = base.layout().ty.ty_adt_def().unwrap();
319319
for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() {
320320
if field.name.as_str() == name {
321-
return this.project_field(base, idx);
321+
return interp_ok(Some(this.project_field(base, idx)?));
322322
}
323323
}
324+
interp_ok(None)
325+
}
326+
327+
/// Project to the given *named* field (which must be a struct or union type).
328+
fn project_field_named<P: Projectable<'tcx, Provenance>>(
329+
&self,
330+
base: &P,
331+
name: &str,
332+
) -> InterpResult<'tcx, P> {
333+
if let Some(field) = self.try_project_field_named(base, name)? {
334+
return interp_ok(field);
335+
}
324336
bug!("No field named {} in type {}", name, base.layout().ty);
325337
}
326338

@@ -330,13 +342,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
330342
base: &P,
331343
name: &str,
332344
) -> bool {
333-
let adt = base.layout().ty.ty_adt_def().unwrap();
334-
for field in adt.non_enum_variant().fields.iter() {
335-
if field.name.as_str() == name {
336-
return true;
337-
}
338-
}
339-
false
345+
self.try_project_field_named(base, name).unwrap().is_some()
340346
}
341347

342348
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,

src/tools/miri/src/shims/unix/fs.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,10 +1048,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10481048
}
10491049
}
10501050

1051-
fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
1051+
fn linux_solarish_readdir64(
1052+
&mut self,
1053+
dirent_type: &str,
1054+
dirp_op: &OpTy<'tcx>,
1055+
) -> InterpResult<'tcx, Scalar> {
10521056
let this = self.eval_context_mut();
10531057

1054-
this.assert_target_os("linux", "readdir64");
1058+
if !matches!(&*this.tcx.sess.target.os, "linux" | "solaris" | "illumos") {
1059+
panic!("`linux_solaris_readdir64` should not be called on {}", this.tcx.sess.target.os);
1060+
}
10551061

10561062
let dirp = this.read_target_usize(dirp_op)?;
10571063

@@ -1070,29 +1076,40 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10701076
Some(Ok(dir_entry)) => {
10711077
// Write the directory entry into a newly allocated buffer.
10721078
// The name is written with write_bytes, while the rest of the
1073-
// dirent64 struct is written using write_int_fields.
1079+
// dirent64 (or dirent) struct is written using write_int_fields.
10741080

10751081
// For reference:
1082+
// On Linux:
10761083
// pub struct dirent64 {
10771084
// pub d_ino: ino64_t,
10781085
// pub d_off: off64_t,
10791086
// pub d_reclen: c_ushort,
10801087
// pub d_type: c_uchar,
10811088
// pub d_name: [c_char; 256],
10821089
// }
1090+
//
1091+
// On Solaris:
1092+
// pub struct dirent {
1093+
// pub d_ino: ino64_t,
1094+
// pub d_off: off64_t,
1095+
// pub d_reclen: c_ushort,
1096+
// pub d_name: [c_char; 3],
1097+
// }
10831098

10841099
let mut name = dir_entry.file_name(); // not a Path as there are no separators!
10851100
name.push("\0"); // Add a NUL terminator
10861101
let name_bytes = name.as_encoded_bytes();
10871102
let name_len = u64::try_from(name_bytes.len()).unwrap();
10881103

1089-
let dirent64_layout = this.libc_ty_layout("dirent64");
1090-
let d_name_offset = dirent64_layout.fields.offset(4 /* d_name */).bytes();
1104+
let dirent_layout = this.libc_ty_layout(dirent_type);
1105+
let fields = &dirent_layout.fields;
1106+
let last_field = fields.count().strict_sub(1);
1107+
let d_name_offset = fields.offset(last_field).bytes();
10911108
let size = d_name_offset.strict_add(name_len);
10921109

10931110
let entry = this.allocate_ptr(
10941111
Size::from_bytes(size),
1095-
dirent64_layout.align.abi,
1112+
dirent_layout.align.abi,
10961113
MiriMemoryKind::Runtime.into(),
10971114
)?;
10981115
let entry: Pointer = entry.into();
@@ -1105,17 +1122,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
11051122
let ino = 0u64;
11061123

11071124
let file_type = this.file_type_to_d_type(dir_entry.file_type())?;
1108-
11091125
this.write_int_fields_named(
1110-
&[
1111-
("d_ino", ino.into()),
1112-
("d_off", 0),
1113-
("d_reclen", size.into()),
1114-
("d_type", file_type.into()),
1115-
],
1116-
&this.ptr_to_mplace(entry, dirent64_layout),
1126+
&[("d_ino", ino.into()), ("d_off", 0), ("d_reclen", size.into())],
1127+
&this.ptr_to_mplace(entry, dirent_layout),
11171128
)?;
11181129

1130+
if let Some(d_type) = this
1131+
.try_project_field_named(&this.ptr_to_mplace(entry, dirent_layout), "d_type")?
1132+
{
1133+
this.write_int(file_type, &d_type)?;
1134+
}
1135+
11191136
let name_ptr = entry.wrapping_offset(Size::from_bytes(d_name_offset), this);
11201137
this.write_bytes_ptr(name_ptr, name_bytes.iter().copied())?;
11211138

src/tools/miri/src/shims/unix/linux/foreign_items.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
3737
"readdir64" => {
3838
let [dirp] =
3939
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
40-
let result = this.linux_readdir64(dirp)?;
40+
let result = this.linux_solarish_readdir64("dirent64", dirp)?;
4141
this.write_scalar(result, dest)?;
4242
}
4343
"sync_file_range" => {

src/tools/miri/src/shims/unix/solarish/foreign_items.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
7676
let result = this.macos_fbsd_solaris_fstat(fd, buf)?;
7777
this.write_scalar(result, dest)?;
7878
}
79+
"readdir" => {
80+
let [dirp] =
81+
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
82+
let result = this.linux_solarish_readdir64("dirent", dirp)?;
83+
this.write_scalar(result, dest)?;
84+
}
7985

8086
// Miscellaneous
8187
"___errno" => {

src/tools/miri/tests/pass/shims/fs.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,8 @@ fn main() {
2727
test_file_sync();
2828
test_errors();
2929
test_rename();
30-
// solarish needs to support readdir/readdir64 for these tests.
31-
if cfg!(not(any(target_os = "solaris", target_os = "illumos"))) {
32-
test_directory();
33-
test_canonicalize();
34-
}
30+
test_directory();
31+
test_canonicalize();
3532
test_from_raw_os_error();
3633
#[cfg(unix)]
3734
test_pread_pwrite();
@@ -279,7 +276,12 @@ fn test_directory() {
279276
.collect::<BTreeMap<_, _>>()
280277
);
281278
// Deleting the directory should fail, since it is not empty.
282-
assert_eq!(ErrorKind::DirectoryNotEmpty, remove_dir(&dir_path).unwrap_err().kind());
279+
280+
// Solaris/Illumos `rmdir` call set errno to EEXIST if directory contains
281+
// other entries than `.` and `..`.
282+
// https://docs.oracle.com/cd/E86824_01/html/E54765/rmdir-2.html
283+
let err = remove_dir(&dir_path).unwrap_err().kind();
284+
assert!(matches!(err, ErrorKind::AlreadyExists | ErrorKind::DirectoryNotEmpty));
283285
// Clean up the files in the directory
284286
remove_file(&path_1).unwrap();
285287
remove_file(&path_2).unwrap();

0 commit comments

Comments
 (0)