- Implement X>&Y redirections. Hold redirections in a linked list structure, because...
authorJeffrey Morlan <mrnobo1024@yahoo.com>
Thu, 21 Aug 2008 15:33:59 +0000 (15:33 +0000)
committerJeffrey Morlan <mrnobo1024@yahoo.com>
Thu, 21 Aug 2008 15:33:59 +0000 (15:33 +0000)
- Allow quotes around the redirection file name.
- Batch: Fix buffer overflow bug (incorrect size for bc->BatchFilePath)

svn path=/trunk/; revision=35508

reactos/base/shell/cmd/batch.c
reactos/base/shell/cmd/batch.h
reactos/base/shell/cmd/call.c
reactos/base/shell/cmd/cmd.c
reactos/base/shell/cmd/cmd.h
reactos/base/shell/cmd/for.c
reactos/base/shell/cmd/misc.c
reactos/base/shell/cmd/redir.c
reactos/base/shell/cmd/start.c

index bbf1ff5..752eb1f 100644 (file)
@@ -194,6 +194,9 @@ VOID ExitBatch (LPTSTR msg)
                if (bc->ffind)
                        cmd_free(bc->ffind);
 
+               UndoRedirection(bc->RedirList, NULL);
+               FreeRedirection(bc->RedirList);
+
                /* Preserve echo state across batch calls */
                bEcho = bc->bEcho;
 
@@ -248,9 +251,7 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param)
 
                n->prev = bc;
                bc = n;
-               bc->In[0] = _T('\0');
-               bc->Out[0] = _T('\0');
-               bc->Err[0] = _T('\0');
+               bc->RedirList = NULL;
        }
        else if (bc->hBatchFile != INVALID_HANDLE_VALUE)
        {
@@ -263,7 +264,7 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param)
                        cmd_free (bc->raw_params);
        }
 
-       GetFullPathName(fullname, sizeof(bc->BatchFilePath), bc->BatchFilePath, &tmp);
+       GetFullPathName(fullname, sizeof(bc->BatchFilePath) / sizeof(TCHAR), bc->BatchFilePath, &tmp);
        *tmp = '\0';
 
        bc->hBatchFile = hFile;
@@ -300,17 +301,23 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param)
        return TRUE;
 }
 
-VOID AddBatchRedirection(TCHAR * ifn, TCHAR * ofn, TCHAR * efn)
+VOID AddBatchRedirection(REDIRECTION **RedirList)
 {
+       REDIRECTION **ListEnd;
+
        if(!bc)
                return;
-       if(_tcslen(ifn))
-               _tcscpy(bc->In,ifn);
-       if(_tcslen(ofn))
-               _tcscpy(bc->Out,ofn);
-       if(_tcslen(efn))
-               _tcscpy(bc->Err,efn);
 
+       /* Prepend the list to the batch context's list */
+       ListEnd = RedirList;
+       while (*ListEnd)
+               ListEnd = &(*ListEnd)->Next;
+       *ListEnd = bc->RedirList;
+       bc->RedirList = *RedirList;
+
+       /* Null out the pointer so that the list will not be cleared prematurely.
+        * These redirections should persist until the batch file exits. */
+       *RedirList = NULL;
 }
 
 /*
index 85e8edd..badf2b5 100644 (file)
@@ -19,9 +19,7 @@ typedef struct tagBATCHCONTEXT
        INT    shiftlevel;
        BOOL   bEcho;        /* Preserve echo flag across batch calls */
        HANDLE hFind;        /* Preserve find handle when doing a for */
-       TCHAR In[MAX_PATH];
-       TCHAR Out[MAX_PATH];
-       TCHAR Err[MAX_PATH];
+       REDIRECTION *RedirList;
        TCHAR forvar;
        INT   bCmdBlock;
        BOOL  bExecuteBlock[MAX_PATH];
@@ -47,6 +45,6 @@ LPTSTR BatchParams (LPTSTR, LPTSTR);
 VOID   ExitBatch (LPTSTR);
 BOOL   Batch (LPTSTR, LPTSTR, LPTSTR);
 LPTSTR ReadBatchLine (LPBOOL);
-VOID AddBatchRedirection(TCHAR *, TCHAR *, TCHAR *);
+VOID AddBatchRedirection(REDIRECTION **);
 
 #endif /* _BATCH_H_INCLUDED_ */
index f90dfee..084bfda 100644 (file)
@@ -76,19 +76,8 @@ INT cmd_call (LPTSTR cmd, LPTSTR param)
        bc->shiftlevel = 0;
        bc->forvar = 0;        /* HBP004 */
        bc->forproto = NULL;   /* HBP004 */
+       bc->RedirList = NULL;
        ParseCommandLine (param);
-       if (bc->prev)
-       {
-               _tcscpy(bc->In, bc->prev->In);
-               _tcscpy(bc->Out, bc->prev->Out);
-               _tcscpy(bc->Err, bc->prev->Err);
-       }
-       else
-       {
-               bc->In[0] = _T('\0');
-               bc->Out[0] = _T('\0');
-               bc->Err[0] = _T('\0');
-       }
 
 
        /* Wasn't a batch file so remove conext */
index 84c1e95..3b91633 100644 (file)
@@ -690,21 +690,16 @@ VOID ParseCommandLine (LPTSTR cmd)
        TCHAR cmdline[CMDLINE_LENGTH];
        LPTSTR s;
 #ifdef FEATURE_REDIRECTION
-       TCHAR in[CMDLINE_LENGTH] = _T("");
-       TCHAR out[CMDLINE_LENGTH] = _T("");
-       TCHAR err[CMDLINE_LENGTH] = _T("");
+       REDIRECTION *RedirList = NULL;
        TCHAR szTempPath[MAX_PATH] = _T(".\\");
        TCHAR szFileName[2][MAX_PATH] = {_T(""), _T("")};
        HANDLE hFile[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
-       LPTSTR t = NULL;
        INT  num = 0;
-       INT  nRedirFlags = 0;
        INT  Length;
        UINT Attributes;
        BOOL bNewBatch = TRUE;
        HANDLE hOldConIn;
        HANDLE hOldConOut;
-       HANDLE hOldConErr;
 #endif /* FEATURE_REDIRECTION */
 
        _tcscpy (cmdline, cmd);
@@ -732,65 +727,18 @@ VOID ParseCommandLine (LPTSTR cmd)
                _tcscat (szTempPath, _T("\\"));
 
        /* get the redirections from the command line */
-       num = GetRedirection (s, in, out, err, &nRedirFlags);
+       num = GetRedirection (s, &RedirList);
 
-       /* more efficient, but do we really need to do this? */
-       for (t = in; _istspace (*t); t++)
-               ;
-       _tcscpy (in, t);
-
-       for (t = out; _istspace (*t); t++)
-               ;
-       _tcscpy (out, t);
-
-       for (t = err; _istspace (*t); t++)
-               ;
-       _tcscpy (err, t);
-
-       if(bc && !_tcslen (in) && _tcslen (bc->In))
-               _tcscpy(in, bc->In);
-       if(bc && !out[0] && _tcslen(bc->Out))
-       {
-               nRedirFlags |= OUTPUT_APPEND;
-               _tcscpy(out, bc->Out);
-       }
-       if(bc && !_tcslen (err) && _tcslen (bc->Err))
+       if (!PerformRedirection(RedirList))
        {
-               nRedirFlags |= ERROR_APPEND;
-               _tcscpy(err, bc->Err);
+               FreeRedirection(RedirList);
+               return;
        }
 
        /* Set up the initial conditions ... */
-       /* preserve STDIN, STDOUT and STDERR handles */
+       /* preserve STDIN and STDOUT handles */
        hOldConIn  = GetStdHandle (STD_INPUT_HANDLE);
        hOldConOut = GetStdHandle (STD_OUTPUT_HANDLE);
-       hOldConErr = GetStdHandle (STD_ERROR_HANDLE);
-
-       /* redirect STDIN */
-       if (in[0])
-       {
-               HANDLE hFile;
-               SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
-
-       /* we need make sure the LastError msg is zero before calling CreateFile */
-               SetLastError(0);
-
-       /* Set up pipe for the standard input handler */
-               hFile = CreateFile (in, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING,
-                                   FILE_ATTRIBUTE_NORMAL, NULL);
-               if (hFile == INVALID_HANDLE_VALUE)
-               {
-                       ConErrResPrintf(STRING_CMD_ERROR1, in);
-                       return;
-               }
-
-               if (!SetStdHandle (STD_INPUT_HANDLE, hFile))
-               {
-                       ConErrResPrintf(STRING_CMD_ERROR1, in);
-                       return;
-               }
-               TRACE ("Input redirected from: %s\n", debugstr_aw(in));
-       }
 
        /* Now do all but the last pipe command */
        *szFileName[0] = _T('\0');
@@ -855,123 +803,7 @@ VOID ParseCommandLine (LPTSTR cmd)
        }
 
        /* Now set up the end conditions... */
-       /* redirect STDOUT */
-       if (out[0])
-       {
-               /* Final output to here */
-               HANDLE hFile;
-               SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
-
-               /* we need make sure the LastError msg is zero before calling CreateFile */
-               SetLastError(0);
-
-               hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, &sa,
-                                   (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
-                                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
-
-               if (hFile == INVALID_HANDLE_VALUE)
-               {
-                       INT size = _tcslen(out)-1;
-
-                       if (out[size] != _T(':'))
-                       {
-                               ConErrResPrintf(STRING_CMD_ERROR3, out);
-                               return;
-                       }
-
-                       out[size]=_T('\0');
-                       hFile = CreateFile (out, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, &sa,
-                                           (nRedirFlags & OUTPUT_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
-                                           FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL);
-
-                       if (hFile == INVALID_HANDLE_VALUE)
-                       {
-                               ConErrResPrintf(STRING_CMD_ERROR3, out);
-                               return;
-                       }
-
-               }
-
-               if (!SetStdHandle (STD_OUTPUT_HANDLE, hFile))
-               {
-                       ConErrResPrintf(STRING_CMD_ERROR3, out);
-                       return;
-               }
-
-               if (nRedirFlags & OUTPUT_APPEND)
-               {
-                       LONG lHighPos = 0;
-
-                       if (GetFileType (hFile) == FILE_TYPE_DISK)
-                               SetFilePointer (hFile, 0, &lHighPos, FILE_END);
-               }
-               TRACE ("Output redirected to: %s\n", debugstr_aw(out));
-       }
-       else if (hOldConOut != INVALID_HANDLE_VALUE)
-       {
-               /* Restore original stdout */
-               HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
-               SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
-               if (hOldConOut != hOut)
-                       CloseHandle (hOut);
-               hOldConOut = INVALID_HANDLE_VALUE;
-       }
-
-       /* redirect STDERR */
-       if (err[0])
-       {
-               /* Final output to here */
-               HANDLE hFile;
-               SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
-
-               if (!_tcscmp (err, out))
-               {
-                       TRACE ("Stdout and stderr will use the same file!!\n");
-                       DuplicateHandle (GetCurrentProcess (),
-                                        GetStdHandle (STD_OUTPUT_HANDLE),
-                                        GetCurrentProcess (),
-                                        &hFile, 0, TRUE, DUPLICATE_SAME_ACCESS);
-               }
-               else
-               {
-                       hFile = CreateFile (err,
-                                           GENERIC_WRITE,
-                                           FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
-                                           &sa,
-                                           (nRedirFlags & ERROR_APPEND) ? OPEN_ALWAYS : CREATE_ALWAYS,
-                                           FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
-                                           NULL);
-                       if (hFile == INVALID_HANDLE_VALUE)
-                       {
-                               ConErrResPrintf(STRING_CMD_ERROR3, err);
-                               return;
-                       }
-               }
-
-               if (!SetStdHandle (STD_ERROR_HANDLE, hFile))
-               {
-                       ConErrResPrintf(STRING_CMD_ERROR3, err);
-                       return;
-               }
-
-               if (nRedirFlags & ERROR_APPEND)
-               {
-                       LONG lHighPos = 0;
-
-                       if (GetFileType (hFile) == FILE_TYPE_DISK)
-                               SetFilePointer (hFile, 0, &lHighPos, FILE_END);
-               }
-               TRACE ("Error redirected to: %s\n", debugstr_aw(err));
-       }
-       else if (hOldConErr != INVALID_HANDLE_VALUE)
-       {
-               /* Restore original stderr */
-               HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE);
-               SetStdHandle (STD_ERROR_HANDLE, hOldConErr);
-               if (hOldConErr != hErr)
-                       CloseHandle (hErr);
-               hOldConErr = INVALID_HANDLE_VALUE;
-       }
+       SetStdHandle(STD_OUTPUT_HANDLE, hOldConOut);
 
        if(bc)
                bNewBatch = FALSE;
@@ -982,7 +814,7 @@ VOID ParseCommandLine (LPTSTR cmd)
 
 #ifdef FEATURE_REDIRECTION
        if(bNewBatch && bc)
-               AddBatchRedirection(in, out, err);
+               AddBatchRedirection(&RedirList);
        /* close old stdin file */
 #if 0  /* buggy implementation */
        SetStdHandle (STD_INPUT_HANDLE, hOldConIn);
@@ -1039,26 +871,8 @@ VOID ParseCommandLine (LPTSTR cmd)
                }
        }
 
-
-       /* Restore original STDOUT */
-       if (hOldConOut != INVALID_HANDLE_VALUE)
-       {
-               HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
-               SetStdHandle (STD_OUTPUT_HANDLE, hOldConOut);
-               if (hOldConOut != hOut)
-                       CloseHandle (hOut);
-               hOldConOut = INVALID_HANDLE_VALUE;
-       }
-
-       /* Restore original STDERR */
-       if (hOldConErr != INVALID_HANDLE_VALUE)
-       {
-               HANDLE hErr = GetStdHandle (STD_ERROR_HANDLE);
-               SetStdHandle (STD_ERROR_HANDLE, hOldConErr);
-               if (hOldConErr != hErr)
-                       CloseHandle (hErr);
-               hOldConErr = INVALID_HANDLE_VALUE;
-       }
+       UndoRedirection(RedirList, NULL);
+       FreeRedirection(RedirList);
 #endif /* FEATURE_REDIRECTION */
 }
 
index 2d7f685..b047064 100644 (file)
@@ -301,6 +301,7 @@ BOOL add_entry (LPINT ac, LPTSTR **arg, LPCTSTR entry);
 LPTSTR *split (LPTSTR, LPINT, BOOL);
 VOID   freep (LPTSTR *);
 LPTSTR _stpcpy (LPTSTR, LPCTSTR);
+VOID   StripQuotes(LPTSTR);
 BOOL   IsValidPathName (LPCTSTR);
 BOOL   IsExistingFile (LPCTSTR);
 BOOL   IsExistingDirectory (LPCTSTR);
@@ -335,12 +336,19 @@ INT  cmd_prompt (LPTSTR, LPTSTR);
 
 
 /* Prototypes for REDIR.C */
-#define INPUT_REDIRECTION    1
-#define OUTPUT_REDIRECTION   2
-#define OUTPUT_APPEND        4
-#define ERROR_REDIRECTION    8
-#define ERROR_APPEND        16
-INT GetRedirection (LPTSTR, LPTSTR, LPTSTR, LPTSTR, LPINT);
+enum { REDIR_READ, REDIR_WRITE, REDIR_APPEND };
+typedef struct _REDIRECTION
+{
+       struct _REDIRECTION *Next;
+       HANDLE OldHandle;
+       BYTE Number;
+       BYTE Type;
+       TCHAR Filename[];
+} REDIRECTION;
+BOOL PerformRedirection(REDIRECTION *);
+VOID UndoRedirection(REDIRECTION *, REDIRECTION *End);
+INT GetRedirection(LPTSTR, REDIRECTION **);
+VOID FreeRedirection(REDIRECTION *);
 
 
 /* Prototypes for REN.C */
index 6800eab..ff586c9 100644 (file)
@@ -138,9 +138,7 @@ INT cmd_for (LPTSTR cmd, LPTSTR param)
                bc->bEcho = bc->prev->bEcho;
        else
                bc->bEcho = bEcho;
-               bc->In[0] = _T('\0');
-               bc->Out[0] = _T('\0');
-               bc->Err[0] = _T('\0');
+       bc->RedirList = NULL;
 
 
        return 0;
index 0a0ad75..3739cf9 100644 (file)
@@ -411,6 +411,18 @@ LPTSTR _stpcpy (LPTSTR dest, LPCTSTR src)
        return (dest + _tcslen (src));
 }
 
+VOID
+StripQuotes(TCHAR *in)
+{
+       TCHAR *out = in;
+       for (; *in; in++)
+       {
+               if (*in != _T('"'))
+                       *out++ = *in;
+       }
+       *out = _T('\0');
+}
+
 
 
 /*
index 0d476e4..6456c92 100644 (file)
@@ -51,11 +51,12 @@ IsRedirection (TCHAR c)
  *
  */
 
-INT GetRedirection (LPTSTR s, LPTSTR ifn, LPTSTR ofn, LPTSTR efn, LPINT lpnFlags)
+INT GetRedirection (LPTSTR s, REDIRECTION **RedirList)
 {
        INT num = 1;
        LPTSTR dp = s;
        LPTSTR sp = s;
+       TCHAR Filename[MAX_PATH];
 
 #ifdef INCLUDE_CMD_REM
 
@@ -68,10 +69,6 @@ INT GetRedirection (LPTSTR s, LPTSTR ifn, LPTSTR ofn, LPTSTR efn, LPINT lpnFlags
        /*first thing first.  check to see if this is "rem" and hope out*/
        if(!_tcsncmp (line, _T("rem "), 4))
        {
-               lpnFlags = 0;
-               *ifn=('\0');
-               *ofn=('\0');
-               *efn=_T('\0');
                return 1;
        }
 #endif
@@ -94,148 +91,74 @@ INT GetRedirection (LPTSTR s, LPTSTR ifn, LPTSTR ofn, LPTSTR efn, LPINT lpnFlags
                        while (*sp && *sp != qc);
 
                        *dp++ = *sp++;
+                       continue;
                }
-               else if ((*sp == _T('<')) || (*sp == _T('>')) ||
-                                (*sp == _T('1')) || (*sp == _T('2')) || (*sp == _T('&')))
+
+               int NumberGiven = (*sp >= _T('0') && *sp <= _T('9')) ? 1 : 0;
+               if (sp[NumberGiven] == _T('<') || sp[NumberGiven] == _T('>'))
                {
-                       /* MS-DOS ignores multiple redirection symbols and uses the last */
-                       /* redirection, so we'll emulate that and not check */
+                       BYTE HandleNumber;
+                       BYTE Type;
+                       BOOL bInQuote = FALSE;
+                       TCHAR *fn = Filename;
+                       REDIRECTION *Redir, **ListPtr;
+
+                       if (NumberGiven)
+                               HandleNumber = *sp++ - _T('0');
+                       else
+                               HandleNumber = *sp == _T('<') ? 0 : 1;
 
                        if (*sp == _T('<'))
                        {
                                /* input redirection */
-                               *lpnFlags |= INPUT_REDIRECTION;
-                               do sp++;
-                               while( _istspace (*sp) );
-
-                               /* copy file name */
-                               while (*sp && !IsRedirection (*sp) && !_istspace (*sp))
-                                       *ifn++ = *sp++;
-                               *ifn = _T('\0');
+                               Type = REDIR_READ;
+                               sp++;
                        }
-                       else if (*sp == _T('>'))
+                       else
                        {
                                /* output redirection */
-                               *lpnFlags |= OUTPUT_REDIRECTION;
+                               Type = REDIR_WRITE;
                                sp++;
 
                                /* append request ? */
                                if (*sp == _T('>'))
                                {
-                                       *lpnFlags |= OUTPUT_APPEND;
+                                       Type = REDIR_APPEND;
                                        sp++;
                                }
-
-                               while (_istspace (*sp))
-                                       sp++;
-
-                               /* copy file name */
-                               while (*sp && !IsRedirection (*sp) && !_istspace (*sp))
-                                       *ofn++ = *sp++;
-                               *ofn = _T('\0');
                        }
 
-                        else if (*sp == _T('1'))
-                       {
-                               /* output redirection */
+                       while (_istspace(*sp))
                                sp++;
 
-                               if (*sp == _T('>'))
-                               {
-                                       /* output redirection */
-                                       *lpnFlags |= OUTPUT_REDIRECTION;
-                                       sp++;
-
-                                       /* append request ? */
-                                       if (*sp == _T('>'))
-                                       {
-                                               *lpnFlags |= OUTPUT_APPEND;
-                                               sp++;
-                                       }
-                               }
-                               else
-                               {
-                                       /* no redirection!! copy the '1' character! */
-                                       sp--;
-                                       *dp++ = *sp++;
-                                       continue;
-                               }
-
-                               while (_istspace (*sp))
-                                       sp++;
-
-                               /* copy file name */
-                               while (*sp && !IsRedirection (*sp) && !_istspace (*sp))
-                                       *ofn++ = *sp++;
-                               *ofn = _T('\0');
+                       /* copy file name */
+                       while (*sp && (bInQuote || (!IsRedirection (*sp) && !_istspace (*sp))))
+                       {
+                               bInQuote ^= (*sp == _T('"'));
+                               *fn++ = *sp++;
                        }
+                       *fn++ = _T('\0');
 
-                       else if (*sp == _T('2'))
+                       /* Delete any existing redirection for the same handle number */
+                       ListPtr = RedirList;
+                       while ((Redir = *ListPtr))
                        {
-                               /* error redirection */
-                               sp++;
-
-                               if (*sp == _T('>'))
-                               {
-                                       *lpnFlags |= ERROR_REDIRECTION;
-                                       sp++;
-
-                                       /* append request ? */
-                                       if (*sp == _T('>'))
-                                       {
-                                               *lpnFlags |= ERROR_APPEND;
-                                               sp++;
-                                       }
-                               }
-                               else
+                               if (Redir->Number == HandleNumber)
                                {
-                                       /* no redirection!! copy the '2'  character! */
-                                       sp--;
-                                       *dp++ = *sp++;
+                                       *ListPtr = Redir->Next;
+                                       cmd_free(Redir);
                                        continue;
                                }
-
-                               while (_istspace (*sp))
-                                       sp++;
-
-                               /* copy file name */
-                               while (*sp && !IsRedirection (*sp) && !_istspace (*sp))
-                                       *efn++ = *sp++;
-                               *efn = _T('\0');
+                               ListPtr = &Redir->Next;
                        }
-                       else if (*sp == _T('&'))
-                       {
-                               /* output AND error redirection */
-                               sp++;
-
-                               if (*sp == _T('>'))
-                               {
-                                       *lpnFlags |= (ERROR_REDIRECTION | OUTPUT_REDIRECTION);
-                                       sp++;
-
-                                       /* append request ? */
-                                       if (*sp == _T('>'))
-                                       {
-                                               *lpnFlags |= (ERROR_APPEND | OUTPUT_APPEND);
-                                               sp++;
-                                       }
-                               }
-                               else
-                               {
-                                       /* no redirection!! copy the '&' character! */
-                                       sp--;
-                                       *dp++ = *sp++;
-                                       continue;
-                               }
-
-                               while (_istspace (*sp))
-                                       sp++;
 
-                               /* copy file name */
-                               while (*sp && !IsRedirection (*sp) && !_istspace (*sp))
-                                       *ofn++ = *efn++ = *sp++;
-                               *ofn = *efn = _T('\0');
-                       }
+                       Redir = cmd_alloc(FIELD_OFFSET(REDIRECTION, Filename[fn - Filename]));
+                       Redir->Next = NULL;
+                       Redir->OldHandle = INVALID_HANDLE_VALUE;
+                       Redir->Number = HandleNumber;
+                       Redir->Type = Type;
+                       _tcscpy(Redir->Filename, Filename);
+                       *ListPtr = Redir;
                }
                else
                        *dp++ = *sp++;
@@ -276,4 +199,124 @@ INT GetRedirection (LPTSTR s, LPTSTR ifn, LPTSTR ofn, LPTSTR efn, LPINT lpnFlags
        return num;
 }
 
+/* cmd allows redirection of handles numbered 3-9 even though these don't
+ * correspond to any STD_ constant. */
+static HANDLE ExtraHandles[10 - 3];
+
+static HANDLE GetHandle(UINT Number)
+{
+       if (Number < 3)
+               return GetStdHandle(STD_INPUT_HANDLE - Number);
+       else
+               return ExtraHandles[Number - 3];
+}
+
+static VOID SetHandle(UINT Number, HANDLE Handle)
+{
+       if (Number < 3)
+               SetStdHandle(STD_INPUT_HANDLE - Number, Handle);
+       else
+               ExtraHandles[Number - 3] = Handle;
+}
+
+BOOL
+PerformRedirection(REDIRECTION *RedirList)
+{
+       REDIRECTION *Redir;
+       TCHAR Filename[MAX_PATH];
+       HANDLE hNew;
+       UINT DupNumber;
+       static SECURITY_ATTRIBUTES SecAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+
+       /* Some parameters used for read, write, and append, respectively */
+       static const DWORD dwAccess[] = {
+               GENERIC_READ, 
+               GENERIC_WRITE,
+               GENERIC_WRITE
+       };
+       static const DWORD dwShareMode[] = {
+               FILE_SHARE_READ | FILE_SHARE_WRITE,
+               FILE_SHARE_READ,
+               FILE_SHARE_READ
+       };
+       static const DWORD dwCreationDisposition[] = {
+               OPEN_EXISTING,
+               CREATE_ALWAYS,
+               OPEN_ALWAYS
+       };
+
+       for (Redir = RedirList; Redir; Redir = Redir->Next)
+       {
+               *Filename = _T('\0');
+               _tcsncat(Filename, Redir->Filename, MAX_PATH - 1);
+               StripQuotes(Filename);
+
+               if (*Filename == _T('&'))
+               {
+                       DupNumber = Filename[1] - _T('0');
+                       if (DupNumber >= 10 ||
+                           !DuplicateHandle(GetCurrentProcess(),
+                                            GetHandle(DupNumber),
+                                            GetCurrentProcess(),
+                                            &hNew,
+                                            0,
+                                            TRUE,
+                                            DUPLICATE_SAME_ACCESS))
+                       {
+                               hNew = INVALID_HANDLE_VALUE;
+                       }
+               }
+               else
+               {
+                       hNew = CreateFile(Filename,
+                                         dwAccess[Redir->Type],
+                                         dwShareMode[Redir->Type],
+                                         &SecAttr,
+                                         dwCreationDisposition[Redir->Type],
+                                         0,
+                                         NULL);
+               }
+
+               if (hNew == INVALID_HANDLE_VALUE)
+               {
+                       ConErrResPrintf(Redir->Type == REDIR_READ ? STRING_CMD_ERROR1 : STRING_CMD_ERROR3,
+                                       Filename);
+                       /* Undo all the redirections before this one */
+                       UndoRedirection(RedirList, Redir);
+                       return FALSE;
+               }
+
+               if (Redir->Type == REDIR_APPEND)
+                       SetFilePointer(hNew, 0, NULL, FILE_END);
+               Redir->OldHandle = GetHandle(Redir->Number);
+               SetHandle(Redir->Number, hNew);
+
+               TRACE("%d redirected to: %s\n", Redir->Number, debugstr_aw(Filename));
+       }
+       return TRUE;
+}
+
+VOID
+UndoRedirection(REDIRECTION *Redir, REDIRECTION *End)
+{
+       for (; Redir != End; Redir = Redir->Next)
+       {
+               CloseHandle(GetHandle(Redir->Number));
+               SetHandle(Redir->Number, Redir->OldHandle);
+               Redir->OldHandle = INVALID_HANDLE_VALUE;
+       }
+}
+
+VOID
+FreeRedirection(REDIRECTION *Redir)
+{
+       REDIRECTION *Next;
+       for (; Redir; Redir = Next)
+       {
+               Next = Redir->Next;
+               ASSERT(Redir->OldHandle == INVALID_HANDLE_VALUE);
+               cmd_free(Redir);
+       }
+}
+
 #endif /* FEATURE_REDIRECTION */
index 5532c54..1c9d587 100644 (file)
@@ -34,17 +34,6 @@ static TCHAR *GetParameter(TCHAR **pPointer)
        return start - 1;
 }
 
-static void StripQuotes(TCHAR *in)
-{
-       TCHAR *out = in;
-       for (; *in; in++)
-       {
-               if (*in != _T('"'))
-                       *out++ = *in;
-       }
-       *out = _T('\0');
-}
-
 INT cmd_start (LPTSTR First, LPTSTR Rest)
 {
        TCHAR szFullName[CMDLINE_LENGTH];