Skip to content

Commit de09b60

Browse files
committed
add possible catalina fix for getdents
1 parent 6187219 commit de09b60

File tree

1 file changed

+68
-2
lines changed

1 file changed

+68
-2
lines changed

darwin-user/syscall.c

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include <sys/shm.h>
5858
#include <sys/sem.h>
5959
#include <sys/ioctl.h>
60+
#include <stdbool.h>
6061
/* #include <sys/statfs.h> not supported on macOS/darwin, convert from statvfs if possble */
6162
#include <sys/statvfs.h>
6263
#include <time.h>
@@ -289,6 +290,64 @@ _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
289290
#endif
290291
*/
291292

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+
292351
#ifdef TARGET_NR_rt_sigqueueinfo
293352
_syscall3(int, sys_rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t *, uinfo)
294353
_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,
73257384
#endif
73267385
int cnvt_st_mode = host_to_target_bitmask(host_st->st_mode, st_mode_tlb);
73277386

7328-
73297387
if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
73307388
return -TARGET_EFAULT;
7389+
73317390
memset(target_st, 0, sizeof(*target_st));
73327391
__put_user(host_st->st_dev, &target_st->st_dev);
73337392
__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,
1086310922
goto efault;
1086410923
}
1086510924

10925+
// Catalina (10.15) readonly system volume workaround
10926+
char fd_path[PATH_MAX] = { '\0' };
10927+
bool fd_path_init = FALSE;
10928+
1086610929
struct dirent *de;
1086710930
struct target_dirent *tde = target_dirp;
1086810931
uint bytes_used = 0;
1086910932
uint target_reclen;
1087010933
uint name_len;
10934+
ino_t converted_ino;
1087110935

1087210936
errno = 0;
1087310937
while ((de = readdir(dirp))) {
@@ -10880,7 +10944,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
1088010944
break;
1088110945
}
1088210946
// 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);
1088410950
__put_user(de->d_seekoff, &tde->d_off);
1088510951
__put_user(target_reclen, &tde->d_reclen);
1088610952
memcpy(tde->d_name, de->d_name, name_len);

0 commit comments

Comments
 (0)