@@ -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
0 commit comments