diff mbox series

[1/4] linux-user: Split out do_getdents, do_getdents64

Message ID 20211107124845.1174791-2-richard.henderson@linaro.org (mailing list archive)
State New, archived
Headers show
Series linux-user: Fix getdents alignment issues (#704) | expand

Commit Message

Richard Henderson Nov. 7, 2021, 12:48 p.m. UTC
Retain all 3 implementations of getdents for now.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/syscall.c | 325 +++++++++++++++++++++++--------------------
 1 file changed, 172 insertions(+), 153 deletions(-)

Comments

Philippe Mathieu-Daudé Nov. 8, 2021, 7:42 a.m. UTC | #1
On 11/7/21 13:48, Richard Henderson wrote:
> Retain all 3 implementations of getdents for now.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/syscall.c | 325 +++++++++++++++++++++++--------------------
>  1 file changed, 172 insertions(+), 153 deletions(-)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Warner Losh Nov. 9, 2021, 4:45 p.m. UTC | #2
> On Nov 7, 2021, at 5:48 AM, Richard Henderson <richard.henderson@linaro.org> wrote:
> 
> Retain all 3 implementations of getdents for now.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/syscall.c | 325 +++++++++++++++++++++++--------------------
> 1 file changed, 172 insertions(+), 153 deletions(-)

Reviewed by: Warner Losh <imp@bsdimp.com>


> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 544f5b662f..a2f605dec4 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -8137,6 +8137,176 @@ static int host_to_target_cpu_mask(const unsigned long *host_mask,
>     return 0;
> }
> 
> +#ifdef TARGET_NR_getdents
> +static int do_getdents(abi_long arg1, abi_long arg2, abi_long arg3)
> +{
> +    int ret;
> +
> +#ifdef EMULATE_GETDENTS_WITH_GETDENTS
> +# if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
> +    struct target_dirent *target_dirp;
> +    struct linux_dirent *dirp;
> +    abi_long count = arg3;
> +
> +    dirp = g_try_malloc(count);
> +    if (!dirp) {
> +        return -TARGET_ENOMEM;
> +    }
> +
> +    ret = get_errno(sys_getdents(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        struct linux_dirent *de;
> +        struct target_dirent *tde;
> +        int len = ret;
> +        int reclen, treclen;
> +        int count1, tnamelen;
> +
> +        count1 = 0;
> +        de = dirp;
> +        target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +        if (!target_dirp) {
> +            return -TARGET_EFAULT;
> +        }
> +        tde = target_dirp;
> +        while (len > 0) {
> +            reclen = de->d_reclen;
> +            tnamelen = reclen - offsetof(struct linux_dirent, d_name);
> +            assert(tnamelen >= 0);
> +            treclen = tnamelen + offsetof(struct target_dirent, d_name);
> +            assert(count1 + treclen <= count);
> +            tde->d_reclen = tswap16(treclen);
> +            tde->d_ino = tswapal(de->d_ino);
> +            tde->d_off = tswapal(de->d_off);
> +            memcpy(tde->d_name, de->d_name, tnamelen);
> +            de = (struct linux_dirent *)((char *)de + reclen);
> +            len -= reclen;
> +            tde = (struct target_dirent *)((char *)tde + treclen);
> +            count1 += treclen;
> +        }
> +        ret = count1;
> +        unlock_user(target_dirp, arg2, ret);
> +    }
> +    g_free(dirp);
> +# else
> +    struct linux_dirent *dirp;
> +    abi_long count = arg3;
> +
> +    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +    if (!dirp) {
> +        return -TARGET_EFAULT;
> +    }
> +    ret = get_errno(sys_getdents(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        struct linux_dirent *de;
> +        int len = ret;
> +        int reclen;
> +        de = dirp;
> +        while (len > 0) {
> +            reclen = de->d_reclen;
> +            if (reclen > len) {
> +                break;
> +            }
> +            de->d_reclen = tswap16(reclen);
> +            tswapls(&de->d_ino);
> +            tswapls(&de->d_off);
> +            de = (struct linux_dirent *)((char *)de + reclen);
> +            len -= reclen;
> +        }
> +    }
> +    unlock_user(dirp, arg2, ret);
> +# endif
> +#else
> +    /* Implement getdents in terms of getdents64 */
> +    struct linux_dirent64 *dirp;
> +    abi_long count = arg3;
> +
> +    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +    if (!dirp) {
> +        return -TARGET_EFAULT;
> +    }
> +    ret = get_errno(sys_getdents64(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        /*
> +         * Convert the dirent64 structs to target dirent.  We do this
> +         * in-place, since we can guarantee that a target_dirent is no
> +         * larger than a dirent64; however this means we have to be
> +         * careful to read everything before writing in the new format.
> +         */
> +        struct linux_dirent64 *de;
> +        struct target_dirent *tde;
> +        int len = ret;
> +        int tlen = 0;
> +
> +        de = dirp;
> +        tde = (struct target_dirent *)dirp;
> +        while (len > 0) {
> +            int namelen, treclen;
> +            int reclen = de->d_reclen;
> +            uint64_t ino = de->d_ino;
> +            int64_t off = de->d_off;
> +            uint8_t type = de->d_type;
> +
> +            namelen = strlen(de->d_name);
> +            treclen = offsetof(struct target_dirent, d_name) + namelen + 2;
> +            treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
> +
> +            memmove(tde->d_name, de->d_name, namelen + 1);
> +            tde->d_ino = tswapal(ino);
> +            tde->d_off = tswapal(off);
> +            tde->d_reclen = tswap16(treclen);
> +            /*
> +             * The target_dirent type is in what was formerly a padding
> +             * byte at the end of the structure:
> +             */
> +            *(((char *)tde) + treclen - 1) = type;
> +
> +            de = (struct linux_dirent64 *)((char *)de + reclen);
> +            tde = (struct target_dirent *)((char *)tde + treclen);
> +            len -= reclen;
> +            tlen += treclen;
> +        }
> +        ret = tlen;
> +    }
> +    unlock_user(dirp, arg2, ret);
> +#endif
> +    return ret;
> +}
> +#endif /* TARGET_NR_getdents */
> +
> +#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
> +static int do_getdents64(abi_long arg1, abi_long arg2, abi_long arg3)
> +{
> +    struct linux_dirent64 *dirp;
> +    abi_long count = arg3;
> +    int ret;
> +
> +    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> +    if (!dirp) {
> +        return -TARGET_EFAULT;
> +    }
> +    ret = get_errno(sys_getdents64(arg1, dirp, count));
> +    if (!is_error(ret)) {
> +        struct linux_dirent64 *de;
> +        int len = ret;
> +        int reclen;
> +        de = dirp;
> +        while (len > 0) {
> +            reclen = de->d_reclen;
> +            if (reclen > len) {
> +                break;
> +            }
> +            de->d_reclen = tswap16(reclen);
> +            tswap64s((uint64_t *)&de->d_ino);
> +            tswap64s((uint64_t *)&de->d_off);
> +            de = (struct linux_dirent64 *)((char *)de + reclen);
> +            len -= reclen;
> +        }
> +    }
> +    unlock_user(dirp, arg2, ret);
> +    return ret;
> +}
> +#endif /* TARGET_NR_getdents64 */
> +
> #if defined(TARGET_NR_pivot_root) && defined(__NR_pivot_root)
> _syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
> #endif
> @@ -10227,162 +10397,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
> #endif
> #ifdef TARGET_NR_getdents
>     case TARGET_NR_getdents:
> -#ifdef EMULATE_GETDENTS_WITH_GETDENTS
> -#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
> -        {
> -            struct target_dirent *target_dirp;
> -            struct linux_dirent *dirp;
> -            abi_long count = arg3;
> -
> -            dirp = g_try_malloc(count);
> -            if (!dirp) {
> -                return -TARGET_ENOMEM;
> -            }
> -
> -            ret = get_errno(sys_getdents(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                struct linux_dirent *de;
> -		struct target_dirent *tde;
> -                int len = ret;
> -                int reclen, treclen;
> -		int count1, tnamelen;
> -
> -		count1 = 0;
> -                de = dirp;
> -                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
> -                    return -TARGET_EFAULT;
> -		tde = target_dirp;
> -                while (len > 0) {
> -                    reclen = de->d_reclen;
> -                    tnamelen = reclen - offsetof(struct linux_dirent, d_name);
> -                    assert(tnamelen >= 0);
> -                    treclen = tnamelen + offsetof(struct target_dirent, d_name);
> -                    assert(count1 + treclen <= count);
> -                    tde->d_reclen = tswap16(treclen);
> -                    tde->d_ino = tswapal(de->d_ino);
> -                    tde->d_off = tswapal(de->d_off);
> -                    memcpy(tde->d_name, de->d_name, tnamelen);
> -                    de = (struct linux_dirent *)((char *)de + reclen);
> -                    len -= reclen;
> -                    tde = (struct target_dirent *)((char *)tde + treclen);
> -		    count1 += treclen;
> -                }
> -		ret = count1;
> -                unlock_user(target_dirp, arg2, ret);
> -            }
> -            g_free(dirp);
> -        }
> -#else
> -        {
> -            struct linux_dirent *dirp;
> -            abi_long count = arg3;
> -
> -            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
> -                return -TARGET_EFAULT;
> -            ret = get_errno(sys_getdents(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                struct linux_dirent *de;
> -                int len = ret;
> -                int reclen;
> -                de = dirp;
> -                while (len > 0) {
> -                    reclen = de->d_reclen;
> -                    if (reclen > len)
> -                        break;
> -                    de->d_reclen = tswap16(reclen);
> -                    tswapls(&de->d_ino);
> -                    tswapls(&de->d_off);
> -                    de = (struct linux_dirent *)((char *)de + reclen);
> -                    len -= reclen;
> -                }
> -            }
> -            unlock_user(dirp, arg2, ret);
> -        }
> -#endif
> -#else
> -        /* Implement getdents in terms of getdents64 */
> -        {
> -            struct linux_dirent64 *dirp;
> -            abi_long count = arg3;
> -
> -            dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
> -            if (!dirp) {
> -                return -TARGET_EFAULT;
> -            }
> -            ret = get_errno(sys_getdents64(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                /* Convert the dirent64 structs to target dirent.  We do this
> -                 * in-place, since we can guarantee that a target_dirent is no
> -                 * larger than a dirent64; however this means we have to be
> -                 * careful to read everything before writing in the new format.
> -                 */
> -                struct linux_dirent64 *de;
> -                struct target_dirent *tde;
> -                int len = ret;
> -                int tlen = 0;
> -
> -                de = dirp;
> -                tde = (struct target_dirent *)dirp;
> -                while (len > 0) {
> -                    int namelen, treclen;
> -                    int reclen = de->d_reclen;
> -                    uint64_t ino = de->d_ino;
> -                    int64_t off = de->d_off;
> -                    uint8_t type = de->d_type;
> -
> -                    namelen = strlen(de->d_name);
> -                    treclen = offsetof(struct target_dirent, d_name)
> -                        + namelen + 2;
> -                    treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
> -
> -                    memmove(tde->d_name, de->d_name, namelen + 1);
> -                    tde->d_ino = tswapal(ino);
> -                    tde->d_off = tswapal(off);
> -                    tde->d_reclen = tswap16(treclen);
> -                    /* The target_dirent type is in what was formerly a padding
> -                     * byte at the end of the structure:
> -                     */
> -                    *(((char *)tde) + treclen - 1) = type;
> -
> -                    de = (struct linux_dirent64 *)((char *)de + reclen);
> -                    tde = (struct target_dirent *)((char *)tde + treclen);
> -                    len -= reclen;
> -                    tlen += treclen;
> -                }
> -                ret = tlen;
> -            }
> -            unlock_user(dirp, arg2, ret);
> -        }
> -#endif
> -        return ret;
> +        return do_getdents(arg1, arg2, arg3);
> #endif /* TARGET_NR_getdents */
> #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
>     case TARGET_NR_getdents64:
> -        {
> -            struct linux_dirent64 *dirp;
> -            abi_long count = arg3;
> -            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
> -                return -TARGET_EFAULT;
> -            ret = get_errno(sys_getdents64(arg1, dirp, count));
> -            if (!is_error(ret)) {
> -                struct linux_dirent64 *de;
> -                int len = ret;
> -                int reclen;
> -                de = dirp;
> -                while (len > 0) {
> -                    reclen = de->d_reclen;
> -                    if (reclen > len)
> -                        break;
> -                    de->d_reclen = tswap16(reclen);
> -                    tswap64s((uint64_t *)&de->d_ino);
> -                    tswap64s((uint64_t *)&de->d_off);
> -                    de = (struct linux_dirent64 *)((char *)de + reclen);
> -                    len -= reclen;
> -                }
> -            }
> -            unlock_user(dirp, arg2, ret);
> -        }
> -        return ret;
> +        return do_getdents64(arg1, arg2, arg3);
> #endif /* TARGET_NR_getdents64 */
> #if defined(TARGET_NR__newselect)
>     case TARGET_NR__newselect:
> --
> 2.25.1
> 
>
diff mbox series

Patch

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 544f5b662f..a2f605dec4 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8137,6 +8137,176 @@  static int host_to_target_cpu_mask(const unsigned long *host_mask,
     return 0;
 }
 
+#ifdef TARGET_NR_getdents
+static int do_getdents(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    int ret;
+
+#ifdef EMULATE_GETDENTS_WITH_GETDENTS
+# if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
+    struct target_dirent *target_dirp;
+    struct linux_dirent *dirp;
+    abi_long count = arg3;
+
+    dirp = g_try_malloc(count);
+    if (!dirp) {
+        return -TARGET_ENOMEM;
+    }
+
+    ret = get_errno(sys_getdents(arg1, dirp, count));
+    if (!is_error(ret)) {
+        struct linux_dirent *de;
+        struct target_dirent *tde;
+        int len = ret;
+        int reclen, treclen;
+        int count1, tnamelen;
+
+        count1 = 0;
+        de = dirp;
+        target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
+        if (!target_dirp) {
+            return -TARGET_EFAULT;
+        }
+        tde = target_dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            tnamelen = reclen - offsetof(struct linux_dirent, d_name);
+            assert(tnamelen >= 0);
+            treclen = tnamelen + offsetof(struct target_dirent, d_name);
+            assert(count1 + treclen <= count);
+            tde->d_reclen = tswap16(treclen);
+            tde->d_ino = tswapal(de->d_ino);
+            tde->d_off = tswapal(de->d_off);
+            memcpy(tde->d_name, de->d_name, tnamelen);
+            de = (struct linux_dirent *)((char *)de + reclen);
+            len -= reclen;
+            tde = (struct target_dirent *)((char *)tde + treclen);
+            count1 += treclen;
+        }
+        ret = count1;
+        unlock_user(target_dirp, arg2, ret);
+    }
+    g_free(dirp);
+# else
+    struct linux_dirent *dirp;
+    abi_long count = arg3;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
+    if (!dirp) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(sys_getdents(arg1, dirp, count));
+    if (!is_error(ret)) {
+        struct linux_dirent *de;
+        int len = ret;
+        int reclen;
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                break;
+            }
+            de->d_reclen = tswap16(reclen);
+            tswapls(&de->d_ino);
+            tswapls(&de->d_off);
+            de = (struct linux_dirent *)((char *)de + reclen);
+            len -= reclen;
+        }
+    }
+    unlock_user(dirp, arg2, ret);
+# endif
+#else
+    /* Implement getdents in terms of getdents64 */
+    struct linux_dirent64 *dirp;
+    abi_long count = arg3;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
+    if (!dirp) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(sys_getdents64(arg1, dirp, count));
+    if (!is_error(ret)) {
+        /*
+         * Convert the dirent64 structs to target dirent.  We do this
+         * in-place, since we can guarantee that a target_dirent is no
+         * larger than a dirent64; however this means we have to be
+         * careful to read everything before writing in the new format.
+         */
+        struct linux_dirent64 *de;
+        struct target_dirent *tde;
+        int len = ret;
+        int tlen = 0;
+
+        de = dirp;
+        tde = (struct target_dirent *)dirp;
+        while (len > 0) {
+            int namelen, treclen;
+            int reclen = de->d_reclen;
+            uint64_t ino = de->d_ino;
+            int64_t off = de->d_off;
+            uint8_t type = de->d_type;
+
+            namelen = strlen(de->d_name);
+            treclen = offsetof(struct target_dirent, d_name) + namelen + 2;
+            treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
+
+            memmove(tde->d_name, de->d_name, namelen + 1);
+            tde->d_ino = tswapal(ino);
+            tde->d_off = tswapal(off);
+            tde->d_reclen = tswap16(treclen);
+            /*
+             * The target_dirent type is in what was formerly a padding
+             * byte at the end of the structure:
+             */
+            *(((char *)tde) + treclen - 1) = type;
+
+            de = (struct linux_dirent64 *)((char *)de + reclen);
+            tde = (struct target_dirent *)((char *)tde + treclen);
+            len -= reclen;
+            tlen += treclen;
+        }
+        ret = tlen;
+    }
+    unlock_user(dirp, arg2, ret);
+#endif
+    return ret;
+}
+#endif /* TARGET_NR_getdents */
+
+#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
+static int do_getdents64(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    struct linux_dirent64 *dirp;
+    abi_long count = arg3;
+    int ret;
+
+    dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
+    if (!dirp) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(sys_getdents64(arg1, dirp, count));
+    if (!is_error(ret)) {
+        struct linux_dirent64 *de;
+        int len = ret;
+        int reclen;
+        de = dirp;
+        while (len > 0) {
+            reclen = de->d_reclen;
+            if (reclen > len) {
+                break;
+            }
+            de->d_reclen = tswap16(reclen);
+            tswap64s((uint64_t *)&de->d_ino);
+            tswap64s((uint64_t *)&de->d_off);
+            de = (struct linux_dirent64 *)((char *)de + reclen);
+            len -= reclen;
+        }
+    }
+    unlock_user(dirp, arg2, ret);
+    return ret;
+}
+#endif /* TARGET_NR_getdents64 */
+
 #if defined(TARGET_NR_pivot_root) && defined(__NR_pivot_root)
 _syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
 #endif
@@ -10227,162 +10397,11 @@  static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #endif
 #ifdef TARGET_NR_getdents
     case TARGET_NR_getdents:
-#ifdef EMULATE_GETDENTS_WITH_GETDENTS
-#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
-        {
-            struct target_dirent *target_dirp;
-            struct linux_dirent *dirp;
-            abi_long count = arg3;
-
-            dirp = g_try_malloc(count);
-            if (!dirp) {
-                return -TARGET_ENOMEM;
-            }
-
-            ret = get_errno(sys_getdents(arg1, dirp, count));
-            if (!is_error(ret)) {
-                struct linux_dirent *de;
-		struct target_dirent *tde;
-                int len = ret;
-                int reclen, treclen;
-		int count1, tnamelen;
-
-		count1 = 0;
-                de = dirp;
-                if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
-                    return -TARGET_EFAULT;
-		tde = target_dirp;
-                while (len > 0) {
-                    reclen = de->d_reclen;
-                    tnamelen = reclen - offsetof(struct linux_dirent, d_name);
-                    assert(tnamelen >= 0);
-                    treclen = tnamelen + offsetof(struct target_dirent, d_name);
-                    assert(count1 + treclen <= count);
-                    tde->d_reclen = tswap16(treclen);
-                    tde->d_ino = tswapal(de->d_ino);
-                    tde->d_off = tswapal(de->d_off);
-                    memcpy(tde->d_name, de->d_name, tnamelen);
-                    de = (struct linux_dirent *)((char *)de + reclen);
-                    len -= reclen;
-                    tde = (struct target_dirent *)((char *)tde + treclen);
-		    count1 += treclen;
-                }
-		ret = count1;
-                unlock_user(target_dirp, arg2, ret);
-            }
-            g_free(dirp);
-        }
-#else
-        {
-            struct linux_dirent *dirp;
-            abi_long count = arg3;
-
-            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
-                return -TARGET_EFAULT;
-            ret = get_errno(sys_getdents(arg1, dirp, count));
-            if (!is_error(ret)) {
-                struct linux_dirent *de;
-                int len = ret;
-                int reclen;
-                de = dirp;
-                while (len > 0) {
-                    reclen = de->d_reclen;
-                    if (reclen > len)
-                        break;
-                    de->d_reclen = tswap16(reclen);
-                    tswapls(&de->d_ino);
-                    tswapls(&de->d_off);
-                    de = (struct linux_dirent *)((char *)de + reclen);
-                    len -= reclen;
-                }
-            }
-            unlock_user(dirp, arg2, ret);
-        }
-#endif
-#else
-        /* Implement getdents in terms of getdents64 */
-        {
-            struct linux_dirent64 *dirp;
-            abi_long count = arg3;
-
-            dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
-            if (!dirp) {
-                return -TARGET_EFAULT;
-            }
-            ret = get_errno(sys_getdents64(arg1, dirp, count));
-            if (!is_error(ret)) {
-                /* Convert the dirent64 structs to target dirent.  We do this
-                 * in-place, since we can guarantee that a target_dirent is no
-                 * larger than a dirent64; however this means we have to be
-                 * careful to read everything before writing in the new format.
-                 */
-                struct linux_dirent64 *de;
-                struct target_dirent *tde;
-                int len = ret;
-                int tlen = 0;
-
-                de = dirp;
-                tde = (struct target_dirent *)dirp;
-                while (len > 0) {
-                    int namelen, treclen;
-                    int reclen = de->d_reclen;
-                    uint64_t ino = de->d_ino;
-                    int64_t off = de->d_off;
-                    uint8_t type = de->d_type;
-
-                    namelen = strlen(de->d_name);
-                    treclen = offsetof(struct target_dirent, d_name)
-                        + namelen + 2;
-                    treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
-
-                    memmove(tde->d_name, de->d_name, namelen + 1);
-                    tde->d_ino = tswapal(ino);
-                    tde->d_off = tswapal(off);
-                    tde->d_reclen = tswap16(treclen);
-                    /* The target_dirent type is in what was formerly a padding
-                     * byte at the end of the structure:
-                     */
-                    *(((char *)tde) + treclen - 1) = type;
-
-                    de = (struct linux_dirent64 *)((char *)de + reclen);
-                    tde = (struct target_dirent *)((char *)tde + treclen);
-                    len -= reclen;
-                    tlen += treclen;
-                }
-                ret = tlen;
-            }
-            unlock_user(dirp, arg2, ret);
-        }
-#endif
-        return ret;
+        return do_getdents(arg1, arg2, arg3);
 #endif /* TARGET_NR_getdents */
 #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
     case TARGET_NR_getdents64:
-        {
-            struct linux_dirent64 *dirp;
-            abi_long count = arg3;
-            if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
-                return -TARGET_EFAULT;
-            ret = get_errno(sys_getdents64(arg1, dirp, count));
-            if (!is_error(ret)) {
-                struct linux_dirent64 *de;
-                int len = ret;
-                int reclen;
-                de = dirp;
-                while (len > 0) {
-                    reclen = de->d_reclen;
-                    if (reclen > len)
-                        break;
-                    de->d_reclen = tswap16(reclen);
-                    tswap64s((uint64_t *)&de->d_ino);
-                    tswap64s((uint64_t *)&de->d_off);
-                    de = (struct linux_dirent64 *)((char *)de + reclen);
-                    len -= reclen;
-                }
-            }
-            unlock_user(dirp, arg2, ret);
-        }
-        return ret;
+        return do_getdents64(arg1, arg2, arg3);
 #endif /* TARGET_NR_getdents64 */
 #if defined(TARGET_NR__newselect)
     case TARGET_NR__newselect: