@@ -10893,7 +10893,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
10893
10893
} else {
10894
10894
ret = bytes_used ;
10895
10895
}
10896
- unlock_user (target_dirp , arg2 , ret );
10896
+ unlock_user (target_dirp , arg2 , count );
10897
10897
// Don't close the `DIR *` pointer, as that will close the fd
10898
10898
// which was used in `fdopendir`
10899
10899
// closedir(dirp);
@@ -10910,83 +10910,63 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
10910
10910
#ifdef TARGET_NR_ngetdents64
10911
10911
case TARGET_NR_ngetdents64 :
10912
10912
#endif
10913
- #if defined( TARGET_NR_getdents64 ) && defined( __NR_getdents64 )
10913
+ #ifdef TARGET_NR_getdents64
10914
10914
case TARGET_NR_getdents64 :
10915
- #if defined TARGET_ABI_IRIX || defined TARGET_ABI_SOLARIS
10916
- {
10915
+ {
10917
10916
struct target_dirent64 * target_dirp ;
10918
- struct linux_dirent64 * dirp ;
10917
+ DIR * dirp ;
10918
+ abi_long dir_fd = arg1 ;
10919
10919
abi_long count = arg3 ;
10920
10920
10921
- dirp = malloc ( count );
10922
- if (!dirp ) {
10923
- ret = - TARGET_ENOMEM ;
10921
+ dirp = fdopendir ( dir_fd );
10922
+ if (!dirp ) {
10923
+ ret = - host_to_target_errno ( errno ) ;
10924
10924
goto fail ;
10925
10925
}
10926
10926
10927
- ret = get_errno (sys_getdents64 (arg1 , dirp , count ));
10928
- if (!is_error (ret )) {
10929
- struct linux_dirent64 * de ;
10930
- struct target_dirent64 * tde ;
10931
- int len = ret ;
10932
- int reclen , treclen ;
10933
- int count1 , tnamelen ;
10934
-
10935
- count1 = 0 ;
10936
- de = dirp ;
10937
- if (!(target_dirp = lock_user (VERIFY_WRITE , arg2 , count , 0 )))
10938
- goto efault ;
10939
- tde = target_dirp ;
10940
- while (len > 0 ) {
10941
- reclen = de -> d_reclen ;
10942
- tnamelen = reclen - offsetof(struct linux_dirent64 , d_name );
10943
- tnamelen = strnlen (de -> d_name , tnamelen ) + 1 ;
10944
- assert (tnamelen > 0 );
10945
- treclen = tnamelen + offsetof(struct target_dirent64 , d_name );
10946
- treclen = QEMU_ALIGN_UP (treclen , sizeof (abi_llong ));
10947
- /* XXX: avoid buffer overflow, for the price of lost entries */
10948
- if (count1 + treclen > count )
10949
- break ;
10950
- __put_user (treclen , & tde -> d_reclen );
10951
- __put_user (de -> d_ino , & tde -> d_ino );
10952
- __put_user (de -> d_off , & tde -> d_off );
10953
- memcpy (tde -> d_name , de -> d_name , tnamelen );
10954
- de = (struct linux_dirent64 * )((char * )de + reclen );
10955
- len -= reclen ;
10956
- tde = (struct target_dirent64 * )((char * )tde + treclen );
10957
- count1 += treclen ;
10958
- }
10959
- ret = count1 ;
10960
- unlock_user (target_dirp , arg2 , ret );
10961
- }
10962
- free (dirp );
10963
- }
10964
- #else
10965
- {
10966
- struct linux_dirent64 * dirp ;
10967
- abi_long count = arg3 ;
10968
- if (!(dirp = lock_user (VERIFY_WRITE , arg2 , count , 0 )))
10927
+ // collect readdir calls into getdents dirp * buffer
10928
+ target_dirp = lock_user (VERIFY_WRITE , arg2 , count , 0 );
10929
+ if (!target_dirp ) {
10969
10930
goto efault ;
10970
- ret = get_errno (sys_getdents64 (arg1 , dirp , count ));
10971
- if (!is_error (ret )) {
10972
- struct linux_dirent64 * de ;
10973
- int len = ret ;
10974
- int reclen ;
10975
- de = dirp ;
10976
- while (len > 0 ) {
10977
- reclen = de -> d_reclen ;
10978
- if (reclen > len )
10979
- break ;
10980
- __put_user (reclen , & de -> d_reclen );
10981
- tswap64s ((uint64_t * )& de -> d_ino );
10982
- tswap64s ((uint64_t * )& de -> d_off );
10983
- de = (struct linux_dirent64 * )((char * )de + reclen );
10984
- len -= reclen ;
10931
+ }
10932
+
10933
+ struct dirent * de ;
10934
+ struct target_dirent64 * tde = target_dirp ;
10935
+ uint bytes_used = 0 ;
10936
+ uint target_reclen ;
10937
+ uint name_len ;
10938
+
10939
+ errno = 0 ;
10940
+ while ((de = readdir (dirp ))) {
10941
+ // check if new entry will overflow the target buffer
10942
+ name_len = de -> d_namlen + 1 ;
10943
+ target_reclen = TARGET_DIRENT64_LEN + name_len ;
10944
+ // is this the correct way to align this structure..?
10945
+ target_reclen = QEMU_ALIGN_UP (target_reclen , __alignof(struct target_dirent64 ));
10946
+ if (bytes_used + target_reclen > count ) {
10947
+ break ;
10985
10948
}
10949
+ // translate from host to target dirent
10950
+ __put_user (de -> d_ino , & tde -> d_ino );
10951
+ __put_user (de -> d_seekoff , & tde -> d_off );
10952
+ __put_user (target_reclen , & tde -> d_reclen );
10953
+ memcpy (tde -> d_name , de -> d_name , name_len );
10954
+ // advance pointer in target space
10955
+ // host pointer is moved by calling readdir
10956
+ tde = (struct target_dirent64 * )((char * )tde + target_reclen );
10957
+ bytes_used += target_reclen ;
10986
10958
}
10987
- unlock_user (dirp , arg2 , ret );
10959
+
10960
+ if (errno != 0 ) {
10961
+ ret = - host_to_target_errno (errno );
10962
+ } else {
10963
+ ret = bytes_used ;
10964
+ }
10965
+ unlock_user (target_dirp , arg2 , count );
10966
+ // Don't close the `DIR *` pointer, as that will close the fd
10967
+ // which was used in `fdopendir`
10968
+ // closedir(dirp);
10988
10969
}
10989
- #endif
10990
10970
#ifdef TARGET_NR_ngetdents64
10991
10971
if (ret >= 0 && num == TARGET_NR_ngetdents64 ) {
10992
10972
abi_long * p = lock_user (VERIFY_WRITE , arg4 , sizeof (abi_long ), 0 );
0 commit comments