[PATCH] cmd: Fixed invalid behavior of "C: && echo test"

Alexander Coffin alexcoffin1999 at gmail.com
Fri Sep 15 02:02:26 CDT 2017


Fixes: https://bugs.winehq.org/show_bug.cgi?id=40694

Fixes the bug, what else is there to say? I also added some tests for
it to test_builtins.cmd, but they don't work on Wine since they
require the "subst" command. However they run on Windows and will be
useful when the "subst" command is added.

Tested on Linux Mint, and a Windows 10 VM

Signed-off-by: Alexander Coffin <alexcoffin1999 at gmail.com>
---
 programs/cmd/tests/test_builtins.cmd     | 60 +++++++++++++++++++++++++++++++
 programs/cmd/tests/test_builtins.cmd.exp |  9 +++++
 programs/cmd/wcmdmain.c                  | 62 ++++++++++++++++++--------------
 3 files changed, 105 insertions(+), 26 deletions(-)

diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index 62334b1..58a9a71 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -2978,6 +2978,66 @@ path
 set path=%WINE_backup_path%
 set WINE_backup_path=
 
+echo ------------ Testing DRIVE PATH ------------
+rem Check if H:\ drive doesn't already exist
+set "removedrive=0"
+set "curdrive=%CD:~0,2%"
+if curdrive == "H:" (
+  echo This test is going to fail...
+  goto :drivepathfailed
+)
+if not exist .\TempDriveFolder\ (
+  mkdir .\TempDriveFolder\
+)
+if not exist H:\ (
+  set "removedrive=1"
+  subst H: .\TempDriveFolder
+)
+if not exist H:\tmpwinetestfolder\ (
+  H:
+  mkdir H:\tmpwinetestfolder\
+  %curdrive%
+)
+H:
+cd H:\tmpwinetestfolder\
+cd
+%curdrive%
+H: 2>nul
+cd
+%curdrive%
+H: C:
+cd
+%curdrive%
+@@H:
+cd
+%curdrive%
+   @@@h:   /blahblah%^^!
+cd
+%curdrive%
+h: && echo test >nul
+cd
+%curdrive%
+h: || echo haha > nul
+cd
+
+%curdrive%
+rem Resets the errorlevel to 0
+ver >nul 2>nul
+h:fail 2>nul
+if not %ERRORLEVEL% == 0 (
+  echo Error
+) else (
+  echo Expected error, didn't get one Error: %ERRORLEVEL%
+)
+
+%curdrive%
+rmdir H:\tmpwinetestfolder\
+rmdir /S /Q .\TempDriveFolder\
+if %removedrive% == 1 (
+  subst H: /D
+)
+:drivepathfailed
+
 echo ------------ Testing combined CALLs/GOTOs ------------
 echo @echo off>foo.cmd
 echo goto :eof>>foot.cmd
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index 796550e..be6eff1 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -1571,6 +1571,15 @@ Correctly ignored trailing information
 PATH=original
 PATH=try2
 PATH=try3
+------------ Testing DRIVE PATH ------------
+ at todo_wine@H:\tmpwinetestfolder
+ at todo_wine@H:\tmpwinetestfolder
+ at todo_wine@H:\tmpwinetestfolder
+ at todo_wine@H:\tmpwinetestfolder
+ at todo_wine@H:\tmpwinetestfolder
+ at todo_wine@H:\tmpwinetestfolder
+ at todo_wine@H:\tmpwinetestfolder
+Error
 ------------ Testing combined CALLs/GOTOs ------------
 world
 cheball
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 102e485..55e2afa 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -1326,32 +1326,6 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
     handleExpansion(new_redir, (context != NULL), delayedsubst);
     cmd = new_cmd;
 
-/*
- *	Changing default drive has to be handled as a special case.
- */
-
-    if ((strlenW(cmd) == 2) && (cmd[1] == ':') && IsCharAlphaW(cmd[0])) {
-      WCHAR envvar[5];
-      WCHAR dir[MAX_PATH];
-
-      /* According to MSDN CreateProcess docs, special env vars record
-         the current directory on each drive, in the form =C:
-         so see if one specified, and if so go back to it             */
-      strcpyW(envvar, equalW);
-      strcatW(envvar, cmd);
-      if (GetEnvironmentVariableW(envvar, dir, MAX_PATH) == 0) {
-        static const WCHAR fmt[] = {'%','s','\\','\0'};
-        wsprintfW(cmd, fmt, cmd);
-        WINE_TRACE("No special directory settings, using dir of %s\n", wine_dbgstr_w(cmd));
-      }
-      WINE_TRACE("Got directory %s as %s\n", wine_dbgstr_w(envvar), wine_dbgstr_w(cmd));
-      status = SetCurrentDirectoryW(cmd);
-      if (!status) WCMD_print_error ();
-      heap_free(cmd );
-      heap_free(new_redir);
-      return;
-    }
-
     sa.nLength = sizeof(sa);
     sa.lpSecurityDescriptor = NULL;
     sa.bInheritHandle = TRUE;
@@ -1451,6 +1425,42 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
     if (whichcmd[0] == '@') whichcmd++;
 
 /*
+ * Changing default drive has to be handled as a special case.
+ *
+ * It appears it only matters if the first command is a letter
+ * followed by a colon. It could be "d: c:", "d: blahblabh", or
+ * even "   @@@D:   /blahblah%^^!"
+ */
+
+    if ((strlenW(cmd) >= 2) && (cmd[1] == ':') && IsCharAlphaW(cmd[0]) && !(strlenW(cmd) >= 3 && cmd[2] != ' ')) {
+      WCHAR envvar[5];
+      WCHAR dir[MAX_PATH];
+
+      /* According to MSDN CreateProcess docs, special env vars record
+         the current directory on each drive, in the form =C:
+         so see if one specified, and if so go back to it             */
+      cmd[0] = toupperW(cmd[0]);
+      /*
+       * The following line is comment merely to help legibility
+      */
+      /*cmd[1] = cmd[1];*/
+      cmd[2] = '\0';
+      strcpyW(envvar, equalW);
+      strcatW(envvar, cmd);
+      if (GetEnvironmentVariableW(envvar, dir, MAX_PATH) == 0) {
+        static const WCHAR fmt[] = {'%','s','\\','\0'};
+        wsprintfW(cmd, fmt, cmd);
+        WINE_TRACE("No special directory settings, using dir of %s\n", wine_dbgstr_w(cmd));
+      }
+      WINE_TRACE("Got directory %s as %s\n", wine_dbgstr_w(envvar), wine_dbgstr_w(cmd));
+      status = SetCurrentDirectoryW(cmd);
+      if (!status) WCMD_print_error ();
+      heap_free(cmd);
+      heap_free(new_redir);
+      return;
+    }
+
+/*
  *	Check if the command entered is internal. If it is, pass the rest of the
  *	line down to the command. If not try to run a program.
  */
-- 
2.7.4




More information about the wine-patches mailing list