@@ -592,48 +592,39 @@ static void append_win_escaped_arg(smart_str *str, zend_string *arg, bool is_cmd
592592 smart_str_appendc (str , '"' );
593593}
594594
595- static inline int stricmp_end (const char * suffix , const char * str ) {
596- size_t suffix_len = strlen (suffix );
597- size_t str_len = strlen (str );
595+ static bool is_executed_by_cmd (const char * prog_name , size_t prog_name_length )
596+ {
597+ size_t out_len ;
598+ WCHAR long_name [MAX_PATH ];
599+ WCHAR full_name [MAX_PATH ];
600+ LPWSTR file_part = NULL ;
598601
599- if (suffix_len > str_len ) {
600- return -1 ; /* Suffix is longer than string, cannot match. */
601- }
602+ wchar_t * prog_name_wide = php_win32_cp_conv_any_to_w (prog_name , prog_name_length , & out_len );
602603
603- /* Compare the end of the string with the suffix, ignoring case. */
604- return _stricmp (str + (str_len - suffix_len ), suffix );
605- }
604+ if (GetLongPathNameW (prog_name_wide , long_name , MAX_PATH ) == 0 ) {
605+ /* This can fail for example with ERROR_FILE_NOT_FOUND (short path resolution only works for existing files)
606+ * in which case we'll pass the path verbatim to the FullPath transformation. */
607+ lstrcpynW (long_name , prog_name_wide , MAX_PATH );
608+ }
606609
607- static bool is_executed_by_cmd (const char * prog_name )
608- {
609- /* If program name is cmd.exe, then return true. */
610- if (_stricmp ("cmd.exe" , prog_name ) == 0 || _stricmp ("cmd" , prog_name ) == 0
611- || stricmp_end ("\\cmd.exe" , prog_name ) == 0 || stricmp_end ("\\cmd" , prog_name ) == 0 ) {
612- return true;
613- }
610+ free (prog_name_wide );
611+ prog_name_wide = NULL ;
614612
615- /* Find the last occurrence of the directory separator (backslash or forward slash). */
616- char * last_separator = strrchr (prog_name , '\\' );
617- char * last_separator_fwd = strrchr (prog_name , '/' );
618- if (last_separator_fwd && (!last_separator || last_separator < last_separator_fwd )) {
619- last_separator = last_separator_fwd ;
613+ if (GetFullPathNameW (long_name , MAX_PATH , full_name , & file_part ) == 0 || file_part == NULL ) {
614+ return false;
620615 }
621616
622- /* Find the last dot in the filename after the last directory separator. */
623- char * extension = NULL ;
624- if (last_separator != NULL ) {
625- extension = strrchr (last_separator , '.' );
617+ bool uses_cmd = false;
618+ if (_wcsicmp (file_part , L"cmd.exe" ) == 0 || _wcsicmp (file_part , L"cmd" ) == 0 ) {
619+ uses_cmd = true;
626620 } else {
627- extension = strrchr (prog_name , '.' );
628- }
629-
630- if (extension == NULL || extension == prog_name ) {
631- /* No file extension found, it is not batch file. */
632- return false;
621+ const WCHAR * extension_dot = wcsrchr (file_part , L'.' );
622+ if (extension_dot && (_wcsicmp (extension_dot , L".bat" ) == 0 || _wcsicmp (extension_dot , L".cmd" ) == 0 )) {
623+ uses_cmd = true;
624+ }
633625 }
634626
635- /* Check if the file extension is ".bat" or ".cmd" which is always executed by cmd.exe. */
636- return _stricmp (extension , ".bat" ) == 0 || _stricmp (extension , ".cmd" ) == 0 ;
627+ return uses_cmd ;
637628}
638629
639630static zend_string * create_win_command_from_args (HashTable * args )
@@ -652,7 +643,7 @@ static zend_string *create_win_command_from_args(HashTable *args)
652643 }
653644
654645 if (is_prog_name ) {
655- is_cmd_execution = is_executed_by_cmd (ZSTR_VAL (arg_str ));
646+ is_cmd_execution = is_executed_by_cmd (ZSTR_VAL (arg_str ), ZSTR_LEN ( arg_str ) );
656647 } else {
657648 smart_str_appendc (& str , ' ' );
658649 }
0 commit comments