@@ -400,13 +400,34 @@ PHP_FUNCTION(getcwd)
400
400
/* }}} */
401
401
402
402
/* {{{ Find pathnames matching a pattern */
403
+ #if defined(ZTS ) && defined(PHP_GLOB_ALTDIRFUNC )
404
+ static void * php_glob_opendir_wrapper (const char * path )
405
+ {
406
+ return VCWD_OPENDIR (path );
407
+ }
408
+
409
+ static void php_glob_closedir_wrapper (void * dir )
410
+ {
411
+ (void ) closedir (dir );
412
+ }
413
+
414
+ static int php_glob_lstat_wrapper (const char * buf , zend_stat_t * sb )
415
+ {
416
+ return VCWD_LSTAT (buf , sb );
417
+ }
418
+
419
+ static int php_glob_stat_wrapper (const char * buf , zend_stat_t * sb )
420
+ {
421
+ return VCWD_STAT (buf , sb );
422
+ }
423
+ #endif
424
+
403
425
PHP_FUNCTION (glob )
404
426
{
405
427
size_t cwd_skip = 0 ;
406
- #ifdef ZTS
428
+ #if defined( ZTS ) && !defined( PHP_GLOB_ALTDIRFUNC )
407
429
char cwd [MAXPATHLEN ];
408
430
char work_pattern [MAXPATHLEN ];
409
- char * result ;
410
431
#endif
411
432
char * pattern = NULL ;
412
433
size_t pattern_len ;
@@ -433,9 +454,28 @@ PHP_FUNCTION(glob)
433
454
RETURN_FALSE ;
434
455
}
435
456
457
+ memset (& globbuf , 0 , sizeof (globbuf ));
458
+
459
+ int passed_glob_flags = flags & PHP_GLOB_FLAGMASK ;
460
+
436
461
#ifdef ZTS
437
462
if (!IS_ABSOLUTE_PATH (pattern , pattern_len )) {
438
- result = VCWD_GETCWD (cwd , MAXPATHLEN );
463
+ /* System glob uses the current work directory which is not thread safe.
464
+ * The first fix is to override the functions used to open/read/... paths
465
+ * with the VCWD ones used in PHP.
466
+ * If that functionality is unavailable for whatever reason, fall back
467
+ * to prepending the current working directory to the passed path.
468
+ * However, that comes with limitations regarding meta characters
469
+ * that is not solvable in general (GH-13204). */
470
+ #ifdef PHP_GLOB_ALTDIRFUNC
471
+ globbuf .gl_opendir = php_glob_opendir_wrapper ;
472
+ globbuf .gl_readdir = (struct dirent * (* )(void * )) readdir ;
473
+ globbuf .gl_closedir = php_glob_closedir_wrapper ;
474
+ globbuf .gl_lstat = php_glob_lstat_wrapper ;
475
+ globbuf .gl_stat = php_glob_stat_wrapper ;
476
+ passed_glob_flags |= PHP_GLOB_ALTDIRFUNC ;
477
+ #else
478
+ char * result = VCWD_GETCWD (cwd , MAXPATHLEN );
439
479
if (!result ) {
440
480
cwd [0 ] = '\0' ;
441
481
}
@@ -448,13 +488,13 @@ PHP_FUNCTION(glob)
448
488
449
489
snprintf (work_pattern , MAXPATHLEN , "%s%c%s" , cwd , DEFAULT_SLASH , pattern );
450
490
pattern = work_pattern ;
491
+ #endif
451
492
}
452
493
#endif
453
494
454
495
455
- memset (& globbuf , 0 , sizeof (globbuf ));
456
496
globbuf .gl_offs = 0 ;
457
- if (0 != (ret = php_glob (pattern , flags & PHP_GLOB_FLAGMASK , NULL , & globbuf ))) {
497
+ if (0 != (ret = php_glob (pattern , passed_glob_flags , NULL , & globbuf ))) {
458
498
#ifdef PHP_GLOB_NOMATCH
459
499
if (PHP_GLOB_NOMATCH == ret ) {
460
500
/* Some glob implementation simply return no data if no matches
0 commit comments