From: Stacey Son Date: Sun, 13 Aug 2023 08:41:41 +0000 (+0200) Subject: bsd-user: Implement getdents related syscalls X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=213444529de083d1cbd1ef2391a1323207182f93;p=qemu.git bsd-user: Implement getdents related syscalls Implement the following syscalls: getdents(2) getdirecentries(2) Signed-off-by: Stacey Son Signed-off-by: Karim Taha Reviewed-by: Richard Henderson Signed-off-by: Warner Losh --- diff --git a/bsd-user/freebsd/os-stat.h b/bsd-user/freebsd/os-stat.h index 9492c93c55..7dc41cd0bf 100644 --- a/bsd-user/freebsd/os-stat.h +++ b/bsd-user/freebsd/os-stat.h @@ -279,4 +279,76 @@ static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr, return ret; } +/* getdents(2) */ +static inline abi_long do_freebsd11_getdents(abi_long arg1, + abi_ulong arg2, abi_long nbytes) +{ + abi_long ret; + struct freebsd11_dirent *dirp; + + dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); + if (dirp == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(freebsd11_getdents(arg1, (char *)dirp, nbytes)); + if (!is_error(ret)) { + struct freebsd11_dirent *de; + int len = ret; + int reclen; + + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) { + return -TARGET_EFAULT; + } + de->d_reclen = tswap16(reclen); + de->d_fileno = tswap32(de->d_fileno); + len -= reclen; + } + } + return ret; +} + +/* getdirecentries(2) */ +static inline abi_long do_freebsd_getdirentries(abi_long arg1, + abi_ulong arg2, abi_long nbytes, abi_ulong arg4) +{ + abi_long ret; + struct dirent *dirp; + long basep; + + dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0); + if (dirp == NULL) { + return -TARGET_EFAULT; + } + ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep)); + if (!is_error(ret)) { + struct dirent *de; + int len = ret; + int reclen; + + de = dirp; + while (len > 0) { + reclen = de->d_reclen; + if (reclen > len) { + return -TARGET_EFAULT; + } + de->d_fileno = tswap64(de->d_fileno); + de->d_off = tswap64(de->d_off); + de->d_reclen = tswap16(de->d_reclen); + de->d_namlen = tswap16(de->d_namlen); + len -= reclen; + de = (struct dirent *)((void *)de + reclen); + } + } + unlock_user(dirp, arg2, ret); + if (arg4) { + if (put_user(basep, arg4, abi_ulong)) { + return -TARGET_EFAULT; + } + } + return ret; +} + #endif /* BSD_USER_FREEBSD_OS_STAT_H */