57
57
#include <sys/shm.h>
58
58
#include <sys/sem.h>
59
59
#include <sys/ioctl.h>
60
+ #include <stdbool.h>
60
61
/* #include <sys/statfs.h> not supported on macOS/darwin, convert from statvfs if possble */
61
62
#include <sys/statvfs.h>
62
63
#include <time.h>
@@ -289,6 +290,64 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
289
290
#endif
290
291
*/
291
292
293
+
294
+ /**
295
+ * catalina_ino_convert:
296
+ * @param fd: fd of dir that produced struct dirent `de`
297
+ * @param fd_path: pointer to the (possibly un-initialized) path string of fd
298
+ * @param fd_path_init: has `fdPath` been initialized
299
+ * @param de: `struct dirent` produced from `basePath`
300
+ * @returns ino of `de` as seen from `stat(de->d_name)`
301
+ *
302
+ * Catalina (macOS 10.15) stores certain system critical files and paths
303
+ * on a separate, read-only partition (https://support.apple.com/en-us/HT210650).
304
+ * This can cause issues with `ino_t` values returned from dirent when viewed from
305
+ * the root directory. Ino values seem to change. E.g., the ino of `stat("/Users/")`
306
+ * differs from 'dp = opendir("\"); readdir(dp)`.
307
+ * This function attempts to convert back from the readonly ino to the stat ino
308
+ */
309
+ static ino_t catalina_ino_convert (
310
+ int fd ,
311
+ char * fd_path ,
312
+ bool * fd_path_init ,
313
+ const struct dirent * de
314
+ ){
315
+ char de_path [PATH_MAX ];
316
+ struct stat st ;
317
+ int ret = 0 ;
318
+ bool is_catalina_ino = ((uint64_t )de -> d_ino >> 32 ) == 0x0fffffff ;
319
+
320
+ if (is_catalina_ino ) {
321
+ // High bits set seem to imply Catalina readonly ino
322
+ if (!(* fd_path_init )) {
323
+ ret = fcntl (fd , F_GETPATH , fd_path );
324
+ if (ret != -1 ) { * fd_path_init = TRUE; }
325
+ }
326
+
327
+ if (* fd_path_init ) {
328
+ memset (de_path , '\0' , PATH_MAX );
329
+ pstrcpy (de_path , PATH_MAX , fd_path );
330
+ pstrcat (de_path , PATH_MAX , "/" );
331
+ pstrcat (de_path , PATH_MAX , de -> d_name );
332
+ ret = stat (de_path , & st );
333
+ if (ret != -1 ) {
334
+ return st .st_ino ;
335
+ } else {
336
+ // stat failed; don't convert
337
+ errno = 0 ;
338
+ return de -> d_ino ;
339
+ }
340
+ } else {
341
+ // issue with fcntl; don't convert
342
+ errno = 0 ;
343
+ return de -> d_ino ;
344
+ }
345
+ }
346
+
347
+ // do not attempt to convert ino
348
+ return de -> d_ino ;
349
+ }
350
+
292
351
#ifdef TARGET_NR_rt_sigqueueinfo
293
352
_syscall3 (int , sys_rt_sigqueueinfo , pid_t , pid , int , sig , siginfo_t * , uinfo )
294
353
_syscall4 (int , sys_rt_tgsigqueueinfo , pid_t , pid , pid_t , tid , int , sig ,
@@ -7325,9 +7384,9 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
7325
7384
#endif
7326
7385
int cnvt_st_mode = host_to_target_bitmask (host_st -> st_mode , st_mode_tlb );
7327
7386
7328
-
7329
7387
if (!lock_user_struct (VERIFY_WRITE , target_st , target_addr , 0 ))
7330
7388
return - TARGET_EFAULT ;
7389
+
7331
7390
memset (target_st , 0 , sizeof (* target_st ));
7332
7391
__put_user (host_st -> st_dev , & target_st -> st_dev );
7333
7392
__put_user (host_st -> st_ino , & target_st -> st_ino );
@@ -10863,11 +10922,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
10863
10922
goto efault ;
10864
10923
}
10865
10924
10925
+ // Catalina (10.15) readonly system volume workaround
10926
+ char fd_path [PATH_MAX ] = { '\0' };
10927
+ bool fd_path_init = FALSE;
10928
+
10866
10929
struct dirent * de ;
10867
10930
struct target_dirent * tde = target_dirp ;
10868
10931
uint bytes_used = 0 ;
10869
10932
uint target_reclen ;
10870
10933
uint name_len ;
10934
+ ino_t converted_ino ;
10871
10935
10872
10936
errno = 0 ;
10873
10937
while ((de = readdir (dirp ))) {
@@ -10880,7 +10944,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
10880
10944
break ;
10881
10945
}
10882
10946
// translate from host to target dirent
10883
- __put_user (de -> d_ino , & tde -> d_ino );
10947
+ // EDIT HERERE
10948
+ converted_ino = catalina_ino_convert (dir_fd , fd_path , & fd_path_init , de );
10949
+ __put_user (converted_ino , & tde -> d_ino );
10884
10950
__put_user (de -> d_seekoff , & tde -> d_off );
10885
10951
__put_user (target_reclen , & tde -> d_reclen );
10886
10952
memcpy (tde -> d_name , de -> d_name , name_len );
0 commit comments