@@ -635,55 +635,87 @@ static void sim_handle_trap0(CPUHexagonState *env)
635635
636636 case HEX_SYS_OPENDIR :
637637 {
638- DIR * dir ;
639- char buf [BUFSIZ ];
638+ char dir_path [BUFSIZ ];
639+ GDir * dir ;
640+ GError * gerr = NULL ;
640641 int rc = 0 , err = 0 ;
641642
643+ /* Read directory path string, following arch-independent pattern */
642644 int i = 0 ;
643645 do {
644- hexagon_read_memory (env , swi_info + i , 1 , & buf [i ], retaddr );
646+ hexagon_read_memory (env , swi_info + i , 1 , & dir_path [i ], retaddr );
645647 i ++ ;
646- } while (buf [i - 1 ]);
648+ if (i >= BUFSIZ - 1 ) {
649+ semi_cb (cs , -1 , ENAMETOOLONG );
650+ return ;
651+ }
652+ } while (dir_path [i - 1 ]);
647653
648- dir = opendir ( buf );
654+ dir = g_dir_open ( dir_path , 0 , & gerr );
649655 if (dir != NULL ) {
656+ /* Initialize dir_paths hash table if not already done */
657+ if (!env -> dir_paths ) {
658+ env -> dir_paths = g_hash_table_new_full (g_direct_hash , g_direct_equal ,
659+ NULL , g_free );
660+ }
661+ /* Store the directory path for later use in readdir */
662+ g_hash_table_insert (env -> dir_paths , dir , g_strdup (dir_path ));
650663 env -> dir_list = g_list_append (env -> dir_list , dir );
651664 rc = g_list_index (env -> dir_list , dir ) + DIR_INDEX_OFFSET ;
652665 } else {
653- err = errno ;
666+ err = gerr ? gerr -> code : ENOENT ;
667+ if (gerr ) {
668+ g_error_free (gerr );
669+ }
654670 }
655671 semi_cb (cs , rc , rc != 0 ? 0 : err );
656672 break ;
657673 }
658674
659675 case HEX_SYS_READDIR :
660676 {
661- struct dirent * host_dir_entry = NULL ;
677+ const gchar * entry_name = NULL ;
662678 int dir_index = swi_info - DIR_INDEX_OFFSET ;
663- DIR * dir = g_list_nth_data (env -> dir_list , dir_index );
679+ GDir * dir = g_list_nth_data (env -> dir_list , dir_index );
664680 uint32_t rc = 0 , err = 0 ;
665681
666682 if (dir ) {
667- errno = 0 ;
668- host_dir_entry = readdir (dir );
669- if (host_dir_entry == NULL ) {
670- err = errno ;
683+ entry_name = g_dir_read_name (dir );
684+ if (entry_name == NULL ) {
685+ err = 0 ; /* End of directory */
671686 }
672687 } else {
673688 err = EBADF ;
674689 }
675690
676- if (host_dir_entry ) {
691+ if (entry_name ) {
677692 uint32_t guest_dir_entry = arch_get_thread_reg (env , HEX_REG_R02 );
678- hexagon_write_memory (env , guest_dir_entry , 4 , host_dir_entry -> d_ino ,
679- retaddr );
680- for (int i = 0 ; i < sizeof (host_dir_entry -> d_name ); i ++ ) {
681- hexagon_write_memory (env , guest_dir_entry + 4 + i , 1 ,
682- host_dir_entry -> d_name [i ], retaddr );
683- if (!host_dir_entry -> d_name [i ]) {
684- break ;
693+ uint32_t ino = 1 ; /* Default fallback */
694+
695+ const char * dir_path = g_hash_table_lookup (env -> dir_paths , dir );
696+ if (dir_path ) {
697+ char * full_path = g_build_filename (dir_path , entry_name , NULL );
698+ if (full_path ) {
699+ struct stat st ;
700+ if (stat (full_path , & st ) == 0 ) {
701+ if (st .st_ino != (uint32_t )st .st_ino ) {
702+ g_free (full_path );
703+ semi_cb (cs , -1 , EOVERFLOW );
704+ break ;
705+ }
706+ ino = (uint32_t )st .st_ino ;
707+ }
708+ g_free (full_path );
685709 }
686710 }
711+
712+ hexagon_write_memory (env , guest_dir_entry , 4 , ino , retaddr );
713+
714+ int name_len = strlen (entry_name ) + 1 ;
715+ for (int i = 0 ; i < name_len ; i ++ ) {
716+ hexagon_write_memory (env , guest_dir_entry + 4 + i , 1 ,
717+ entry_name [i ], retaddr );
718+ }
687719 rc = guest_dir_entry ;
688720 }
689721 semi_cb (cs , rc , err );
@@ -692,16 +724,19 @@ static void sim_handle_trap0(CPUHexagonState *env)
692724
693725 case HEX_SYS_CLOSEDIR :
694726 {
695- DIR * dir ;
696- int ret = -1 , err ;
727+ GDir * dir ;
728+ int ret = -1 , err = 0 ;
697729 int dir_index = swi_info - DIR_INDEX_OFFSET ;
698730
699731 dir = g_list_nth_data (env -> dir_list , dir_index );
700732 if (dir != NULL ) {
701- ret = closedir ( dir );
702- if (ret != 0 ) {
703- err = errno ;
733+ /* Remove from hash table before closing */
734+ if (env -> dir_paths ) {
735+ g_hash_table_remove ( env -> dir_paths , dir ) ;
704736 }
737+ g_dir_close (dir );
738+ env -> dir_list = g_list_remove (env -> dir_list , dir );
739+ ret = 0 ;
705740 } else {
706741 err = EBADF ;
707742 }
0 commit comments