@@ -1081,6 +1081,17 @@ no_gvl_fstat(void *data)
10811081 return (VALUE )fstat (arg -> file .fd , arg -> st );
10821082}
10831083
1084+ static int
1085+ fstat_without_gvl (int fd , struct stat * st )
1086+ {
1087+ no_gvl_stat_data data ;
1088+
1089+ data .file .fd = fd ;
1090+ data .st = st ;
1091+
1092+ return (int )(VALUE )rb_thread_io_blocking_region (no_gvl_fstat , & data , fd );
1093+ }
1094+
10841095static void *
10851096no_gvl_stat (void * data )
10861097{
@@ -1089,27 +1100,38 @@ no_gvl_stat(void * data)
10891100}
10901101
10911102static int
1092- rb_stat ( VALUE file , struct stat * st )
1103+ stat_without_gvl ( const char * path , struct stat * st )
10931104{
1094- VALUE tmp ;
1095- VALUE result ;
10961105 no_gvl_stat_data data ;
10971106
1107+ data .file .path = path ;
10981108 data .st = st ;
1109+
1110+ return (int )(VALUE )rb_thread_call_without_gvl (no_gvl_stat , & data ,
1111+ RUBY_UBF_IO , NULL );
1112+ }
1113+
1114+ static int
1115+ rb_stat (VALUE file , struct stat * st )
1116+ {
1117+ VALUE tmp ;
1118+ int result ;
1119+
10991120 tmp = rb_check_convert_type_with_id (file , T_FILE , "IO" , idTo_io );
11001121 if (!NIL_P (tmp )) {
11011122 rb_io_t * fptr ;
11021123
11031124 GetOpenFile (tmp , fptr );
1104- data .file .fd = fptr -> fd ;
1105- result = rb_thread_io_blocking_region (no_gvl_fstat , & data , fptr -> fd );
1106- return (int )result ;
1125+ result = fstat_without_gvl (fptr -> fd , st );
1126+ file = tmp ;
11071127 }
1108- FilePathValue (file );
1109- file = rb_str_encode_ospath (file );
1110- data .file .path = StringValueCStr (file );
1111- result = (VALUE )rb_thread_call_without_gvl (no_gvl_stat , & data , RUBY_UBF_IO , NULL );
1112- return (int )result ;
1128+ else {
1129+ FilePathValue (file );
1130+ file = rb_str_encode_ospath (file );
1131+ result = stat_without_gvl (RSTRING_PTR (file ), st );
1132+ }
1133+ RB_GC_GUARD (file );
1134+ return result ;
11131135}
11141136
11151137/*
@@ -1129,7 +1151,8 @@ rb_file_s_stat(VALUE klass, VALUE fname)
11291151 struct stat st ;
11301152
11311153 FilePathValue (fname );
1132- if (rb_stat (fname , & st ) < 0 ) {
1154+ fname = rb_str_encode_ospath (fname );
1155+ if (stat_without_gvl (RSTRING_PTR (fname ), & st ) < 0 ) {
11331156 rb_sys_fail_path (fname );
11341157 }
11351158 return rb_stat_new (& st );
@@ -3919,7 +3942,7 @@ enum rb_realpath_mode {
39193942};
39203943
39213944static int
3922- realpath_rec (long * prefixlenp , VALUE * resolvedp , const char * unresolved ,
3945+ realpath_rec (long * prefixlenp , VALUE * resolvedp , const char * unresolved , VALUE fallback ,
39233946 VALUE loopcheck , enum rb_realpath_mode mode , int last )
39243947{
39253948 const char * pend = unresolved + strlen (unresolved );
@@ -3977,6 +4000,12 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved,
39774000 ret = lstat_without_gvl (RSTRING_PTR (testpath ), & sbuf );
39784001 if (ret == -1 ) {
39794002 int e = errno ;
4003+ if (e == ENOENT && !NIL_P (fallback )) {
4004+ if (stat_without_gvl (RSTRING_PTR (fallback ), & sbuf ) == 0 ) {
4005+ rb_str_replace (* resolvedp , fallback );
4006+ return 0 ;
4007+ }
4008+ }
39804009 if (mode == RB_REALPATH_CHECK ) return -1 ;
39814010 if (e == ENOENT ) {
39824011 if (mode == RB_REALPATH_STRICT || !last || * unresolved_firstsep )
@@ -4008,7 +4037,7 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved,
40084037 * resolvedp = link ;
40094038 * prefixlenp = link_prefixlen ;
40104039 }
4011- if (realpath_rec (prefixlenp , resolvedp , link_names ,
4040+ if (realpath_rec (prefixlenp , resolvedp , link_names , testpath ,
40124041 loopcheck , mode , !* unresolved_firstsep ))
40134042 return -1 ;
40144043 RB_GC_GUARD (link_orig );
@@ -4097,14 +4126,14 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, enum rb_realpath_mode mode
40974126
40984127 loopcheck = rb_hash_new ();
40994128 if (curdir_names ) {
4100- if (realpath_rec (& prefixlen , & resolved , curdir_names , loopcheck , mode , 0 ))
4129+ if (realpath_rec (& prefixlen , & resolved , curdir_names , Qnil , loopcheck , mode , 0 ))
41014130 return Qnil ;
41024131 }
41034132 if (basedir_names ) {
4104- if (realpath_rec (& prefixlen , & resolved , basedir_names , loopcheck , mode , 0 ))
4133+ if (realpath_rec (& prefixlen , & resolved , basedir_names , Qnil , loopcheck , mode , 0 ))
41054134 return Qnil ;
41064135 }
4107- if (realpath_rec (& prefixlen , & resolved , path_names , loopcheck , mode , 1 ))
4136+ if (realpath_rec (& prefixlen , & resolved , path_names , Qnil , loopcheck , mode , 1 ))
41084137 return Qnil ;
41094138
41104139 if (origenc != rb_enc_get (resolved )) {
0 commit comments