@@ -546,48 +546,39 @@ static void append_win_escaped_arg(smart_str *str, zend_string *arg, bool is_cmd
546546 smart_str_appendc (str , '"' );
547547}
548548
549- static inline int stricmp_end (const char * suffix , const char * str ) {
550- size_t suffix_len = strlen (suffix );
551- size_t str_len = strlen (str );
549+ static bool is_executed_by_cmd (const char * prog_name , size_t prog_name_length )
550+ {
551+ size_t out_len ;
552+ WCHAR long_name [MAX_PATH ];
553+ WCHAR full_name [MAX_PATH ];
554+ LPWSTR file_part = NULL ;
552555
553- if (suffix_len > str_len ) {
554- return -1 ; /* Suffix is longer than string, cannot match. */
555- }
556+ wchar_t * prog_name_wide = php_win32_cp_conv_any_to_w (prog_name , prog_name_length , & out_len );
556557
557- /* Compare the end of the string with the suffix, ignoring case. */
558- return _stricmp (str + (str_len - suffix_len ), suffix );
559- }
558+ if (GetLongPathNameW (prog_name_wide , long_name , MAX_PATH ) == 0 ) {
559+ /* This can fail for example with ERROR_FILE_NOT_FOUND (short path resolution only works for existing files)
560+ * in which case we'll pass the path verbatim to the FullPath transformation. */
561+ lstrcpynW (long_name , prog_name_wide , MAX_PATH );
562+ }
560563
561- static bool is_executed_by_cmd (const char * prog_name )
562- {
563- /* If program name is cmd.exe, then return true. */
564- if (_stricmp ("cmd.exe" , prog_name ) == 0 || _stricmp ("cmd" , prog_name ) == 0
565- || stricmp_end ("\\cmd.exe" , prog_name ) == 0 || stricmp_end ("\\cmd" , prog_name ) == 0 ) {
566- return true;
567- }
564+ free (prog_name_wide );
565+ prog_name_wide = NULL ;
568566
569- /* Find the last occurrence of the directory separator (backslash or forward slash). */
570- char * last_separator = strrchr (prog_name , '\\' );
571- char * last_separator_fwd = strrchr (prog_name , '/' );
572- if (last_separator_fwd && (!last_separator || last_separator < last_separator_fwd )) {
573- last_separator = last_separator_fwd ;
567+ if (GetFullPathNameW (long_name , MAX_PATH , full_name , & file_part ) == 0 || file_part == NULL ) {
568+ return false;
574569 }
575570
576- /* Find the last dot in the filename after the last directory separator. */
577- char * extension = NULL ;
578- if (last_separator != NULL ) {
579- extension = strrchr (last_separator , '.' );
571+ bool uses_cmd = false;
572+ if (_wcsicmp (file_part , L"cmd.exe" ) == 0 || _wcsicmp (file_part , L"cmd" ) == 0 ) {
573+ uses_cmd = true;
580574 } else {
581- extension = strrchr (prog_name , '.' );
582- }
583-
584- if (extension == NULL || extension == prog_name ) {
585- /* No file extension found, it is not batch file. */
586- return false;
575+ const WCHAR * extension_dot = wcsrchr (file_part , L'.' );
576+ if (extension_dot && (_wcsicmp (extension_dot , L".bat" ) == 0 || _wcsicmp (extension_dot , L".cmd" ) == 0 )) {
577+ uses_cmd = true;
578+ }
587579 }
588580
589- /* Check if the file extension is ".bat" or ".cmd" which is always executed by cmd.exe. */
590- return _stricmp (extension , ".bat" ) == 0 || _stricmp (extension , ".cmd" ) == 0 ;
581+ return uses_cmd ;
591582}
592583
593584static zend_string * create_win_command_from_args (HashTable * args )
@@ -606,7 +597,7 @@ static zend_string *create_win_command_from_args(HashTable *args)
606597 }
607598
608599 if (is_prog_name ) {
609- is_cmd_execution = is_executed_by_cmd (ZSTR_VAL (arg_str ));
600+ is_cmd_execution = is_executed_by_cmd (ZSTR_VAL (arg_str ), ZSTR_LEN ( arg_str ) );
610601 } else {
611602 smart_str_appendc (& str , ' ' );
612603 }
0 commit comments