[CMD] Protect certain actions with a critical section, patch by Katayama Hirofumi
[reactos.git] / reactos / base / shell / cmd / cmd.c
index 0ec4d67..54ff9b2 100644 (file)
@@ -156,7 +156,7 @@ BOOL bCanExit = TRUE;     /* indicates if this shell is exitable */
 BOOL bCtrlBreak = FALSE;  /* Ctrl-Break or Ctrl-C hit */
 BOOL bIgnoreEcho = FALSE; /* Set this to TRUE to prevent a newline, when executing a command */
 INT  nErrorLevel = 0;     /* Errorlevel of last launched external program */
-BOOL bChildProcessRunning = FALSE;
+CRITICAL_SECTION ChildProcessRunningLock;
 BOOL bUnicodeOutput = FALSE;
 BOOL bDisableBatchEcho = FALSE;
 BOOL bDelayedExpansion = FALSE;
@@ -182,7 +182,7 @@ WORD wDefColor;           /* default color */
 INT
 ConvertULargeInteger(ULONGLONG num, LPTSTR des, INT len, BOOL bPutSeperator)
 {
-       TCHAR temp[32];
+       TCHAR temp[39];   /* maximum length with nNumberGroups == 1 */
        UINT  n, iTarget;
 
        if (len <= 1)
@@ -198,15 +198,15 @@ ConvertULargeInteger(ULONGLONG num, LPTSTR des, INT len, BOOL bPutSeperator)
                if (iTarget == n && bPutSeperator)
                {
                        iTarget += nNumberGroups + 1;
-                       temp[31 - n++] = cThousandSeparator;
+                       temp[38 - n++] = cThousandSeparator;
                }
-               temp[31 - n++] = (TCHAR)(num % 10) + _T('0');
+               temp[38 - n++] = (TCHAR)(num % 10) + _T('0');
                num /= 10;
        } while (num > 0);
        if (n > len-1)
                n = len-1;
 
-       memcpy(des, temp + 32 - n, n * sizeof(TCHAR));
+       memcpy(des, temp + 39 - n, n * sizeof(TCHAR));
        des[n] = _T('\0');
 
        return n;
@@ -244,7 +244,7 @@ static BOOL IsConsoleProcess(HANDLE Process)
                return TRUE;
        }
 
-       return IMAGE_SUBSYSTEM_WINDOWS_CUI == ProcessPeb.ImageSubSystem;
+       return IMAGE_SUBSYSTEM_WINDOWS_CUI == ProcessPeb.ImageSubsystem;
 }
 
 
@@ -436,14 +436,12 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
                {
                        if (IsConsoleProcess(prci.hProcess))
                        {
-                               /* FIXME: Protect this with critical section */
-                               bChildProcessRunning = TRUE;
+                               EnterCriticalSection(&ChildProcessRunningLock);
                                dwChildProcessId = prci.dwProcessId;
 
                                WaitForSingleObject (prci.hProcess, INFINITE);
 
-                               /* FIXME: Protect this with critical section */
-                               bChildProcessRunning = FALSE;
+                               LeaveCriticalSection(&ChildProcessRunningLock);
 
                                GetExitCodeProcess (prci.hProcess, &dwExitCode);
                                nErrorLevel = (INT)dwExitCode;
@@ -484,15 +482,24 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
 INT
 DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd)
 {
-       TCHAR com[_tcslen(first) + _tcslen(rest) + 2];  /* full command line */
+       TCHAR *com;
        TCHAR *cp;
        LPTSTR param;   /* pointer to command's parameters */
        INT cl;
        LPCOMMAND cmdptr;
        BOOL nointernal = FALSE;
+       INT ret;
 
        TRACE ("DoCommand: (\'%s\' \'%s\')\n", debugstr_aw(first), debugstr_aw(rest));
 
+       /* full command line */
+       com = cmd_alloc((_tcslen(first) + _tcslen(rest) + 2) * sizeof(TCHAR));
+       if (com == NULL)
+       {
+               error_out_of_memory();
+               return 1;
+       }
+
        /* If present in the first word, these characters end the name of an
         * internal command and become the beginning of its parameters. */
        cp = first + _tcscspn(first, _T("\t +,/;=[]"));
@@ -526,11 +533,15 @@ DoCommand(LPTSTR first, LPTSTR rest, PARSED_COMMAND *Cmd)
                        if (_tcsicmp(cmdptr->name, _T("echo")) != 0)
                                while (_istspace(*param))
                                        param++;
-                       return cmdptr->func(param);
+                       ret = cmdptr->func(param);
+                       cmd_free(com);
+                       return ret;
                }
        }
 
-       return Execute(com, first, rest, Cmd);
+       ret = Execute(com, first, rest, Cmd);
+       cmd_free(com);
+       return ret;
 }
 
 
@@ -652,9 +663,9 @@ ExecutePipeline(PARSED_COMMAND *Cmd)
        SetStdHandle(STD_INPUT_HANDLE, hOldConIn);
 
        /* Wait for all processes to complete */
-       bChildProcessRunning = TRUE;
+       EnterCriticalSection(&ChildProcessRunningLock);
        WaitForMultipleObjects(nProcesses, hProcess, TRUE, INFINITE);
-       bChildProcessRunning = FALSE;
+       LeaveCriticalSection(&ChildProcessRunningLock);
 
        /* Use the exit code of the last process in the pipeline */
        GetExitCodeProcess(hProcess[nProcesses - 1], &dwExitCode);
@@ -739,42 +750,22 @@ ExecuteCommand(PARSED_COMMAND *Cmd)
        return Ret;
 }
 
-BOOL
-GrowIfNecessary_dbg ( UINT needed, LPTSTR* ret, UINT* retlen, const char *file, int line )
-{
-       if ( *ret && needed < *retlen )
-               return TRUE;
-       *retlen = needed;
-       if ( *ret )
-               cmd_free ( *ret );
-#ifdef _DEBUG_MEM
-       *ret = (LPTSTR)cmd_alloc_dbg ( *retlen * sizeof(TCHAR), file, line );
-#else
-       *ret = (LPTSTR)cmd_alloc ( *retlen * sizeof(TCHAR) );
-#endif
-       if ( !*ret )
-               SetLastError ( ERROR_OUTOFMEMORY );
-       return *ret != NULL;
-}
-#define GrowIfNecessary(x, y, z) GrowIfNecessary_dbg(x, y, z, __FILE__, __LINE__)
-
 LPTSTR
 GetEnvVar(LPCTSTR varName)
 {
        static LPTSTR ret = NULL;
-       static UINT retlen = 0;
        UINT size;
 
-       size = GetEnvironmentVariable ( varName, ret, retlen );
-       if ( size > retlen )
+       cmd_free(ret);
+       ret = NULL;
+       size = GetEnvironmentVariable(varName, NULL, 0);
+       if (size > 0)
        {
-               if ( !GrowIfNecessary ( size, &ret, &retlen ) )
-                       return NULL;
-               size = GetEnvironmentVariable ( varName, ret, retlen );
+               ret = cmd_alloc(size * sizeof(TCHAR));
+               if (ret != NULL)
+                       GetEnvironmentVariable(varName, ret, size + 1);
        }
-       if ( size )
-               return ret;
-       return NULL;
+       return ret;
 }
 
 LPCTSTR
@@ -1446,13 +1437,16 @@ BOOL WINAPI BreakHandler (DWORD dwCtrlType)
                }
        }
 
-       if (bChildProcessRunning == TRUE)
+       if (!TryEnterCriticalSection(&ChildProcessRunningLock))
        {
                SelfGenerated = TRUE;
                GenerateConsoleCtrlEvent (dwCtrlType, 0);
                return TRUE;
        }
-
+       else
+       {
+               LeaveCriticalSection(&ChildProcessRunningLock);
+       }
 
     rec.EventType = KEY_EVENT;
     rec.Event.KeyEvent.bKeyDown = TRUE;
@@ -1636,9 +1630,6 @@ Initialize()
                NtReadVirtualMemoryPtr = (NtReadVirtualMemoryProc)GetProcAddress(NtDllModule, "NtReadVirtualMemory");
        }
 
-       cmdLine = GetCommandLine();
-       TRACE ("[command args: %s]\n", debugstr_aw(cmdLine));
-
        InitLocale ();
 
        /* get default input and output console handles */
@@ -1652,9 +1643,32 @@ Initialize()
        if (GetEnvironmentVariable(_T("PROMPT"),lpBuffer, sizeof(lpBuffer) / sizeof(lpBuffer[0])) == 0)
            SetEnvironmentVariable (_T("PROMPT"), _T("$P$G"));
 
+#ifdef FEATURE_DIR_STACK
+       /* initialize directory stack */
+       InitDirectoryStack ();
+#endif
+
+#ifdef FEATURE_HISTORY
+       /*initialize history*/
+       InitHistory();
+#endif
+
+       /* Set COMSPEC environment variable */
+       if (0 != GetModuleFileName (NULL, ModuleName, _MAX_PATH + 1))
+       {
+               ModuleName[_MAX_PATH] = _T('\0');
+               SetEnvironmentVariable (_T("COMSPEC"), ModuleName);
+       }
+
+       /* add ctrl break handler */
+       AddBreakHandler ();
+
 
        SetConsoleMode (hIn, ENABLE_PROCESSED_INPUT);
 
+       cmdLine = GetCommandLine();
+       TRACE ("[command args: %s]\n", debugstr_aw(cmdLine));
+
        for (ptr = cmdLine; *ptr; ptr++)
        {
                if (*ptr == _T('/'))
@@ -1663,7 +1677,9 @@ Initialize()
                        if (option == _T('?'))
                        {
                                ConOutResPaging(TRUE,STRING_CMD_HELP8);
-                               cmd_exit(0);
+                               nErrorLevel = 1;
+                               bExit = TRUE;
+                               return;
                        }
                        else if (option == _T('P'))
                        {
@@ -1731,27 +1747,6 @@ Initialize()
                ConOutPuts(_T("(C) Copyright 1998-") _T(COPYRIGHT_YEAR) _T(" ReactOS Team."));
        }
 
-#ifdef FEATURE_DIR_STACK
-       /* initialize directory stack */
-       InitDirectoryStack ();
-#endif
-
-
-#ifdef FEATURE_HISTORY
-       /*initialize history*/
-       InitHistory();
-#endif
-
-       /* Set COMSPEC environment variable */
-       if (0 != GetModuleFileName (NULL, ModuleName, _MAX_PATH + 1))
-       {
-               ModuleName[_MAX_PATH] = _T('\0');
-               SetEnvironmentVariable (_T("COMSPEC"), ModuleName);
-       }
-
-       /* add ctrl break handler */
-       AddBreakHandler ();
-
        if (AutoRun)
        {
                ExecuteAutoRunFile(HKEY_LOCAL_MACHINE);
@@ -1796,11 +1791,14 @@ static VOID Cleanup()
        CleanHistory();
 #endif
 
+       /* free GetEnvVar's buffer */
+       GetEnvVar(NULL);
 
        /* remove ctrl break handler */
        RemoveBreakHandler ();
        SetConsoleMode( GetStdHandle( STD_INPUT_HANDLE ),
                        ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT );
+       DeleteCriticalSection(&ChildProcessRunningLock);
 }
 
 /*
@@ -1812,6 +1810,7 @@ int cmd_main (int argc, const TCHAR *argv[])
        TCHAR startPath[MAX_PATH];
        CONSOLE_SCREEN_BUFFER_INFO Info;
 
+       InitializeCriticalSection(&ChildProcessRunningLock);
        lpOriginalEnvironment = DuplicateEnvironment();
 
        GetCurrentDirectory(MAX_PATH,startPath);