mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +00:00
- Implement X>&Y redirections. Hold redirections in a linked list structure, because order matters (>x 2>&1 is not the same as 2>&1 >x). Allow redirection of any handle number from 0 to 9.
- Allow quotes around the redirection file name. - Batch: Fix buffer overflow bug (incorrect size for bc->BatchFilePath) svn path=/trunk/; revision=35508
This commit is contained in:
parent
4af7567008
commit
07912f2b23
9 changed files with 221 additions and 363 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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))
|
||||
if (!PerformRedirection(RedirList))
|
||||
{
|
||||
nRedirFlags |= OUTPUT_APPEND;
|
||||
_tcscpy(out, bc->Out);
|
||||
}
|
||||
if(bc && !_tcslen (err) && _tcslen (bc->Err))
|
||||
{
|
||||
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 */
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
else if (*sp == _T('2'))
|
||||
/* copy file name */
|
||||
while (*sp && (bInQuote || (!IsRedirection (*sp) && !_istspace (*sp))))
|
||||
{
|
||||
/* error redirection */
|
||||
sp++;
|
||||
|
||||
if (*sp == _T('>'))
|
||||
{
|
||||
*lpnFlags |= ERROR_REDIRECTION;
|
||||
sp++;
|
||||
|
||||
/* append request ? */
|
||||
if (*sp == _T('>'))
|
||||
{
|
||||
*lpnFlags |= ERROR_APPEND;
|
||||
sp++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no redirection!! copy the '2' character! */
|
||||
sp--;
|
||||
*dp++ = *sp++;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (_istspace (*sp))
|
||||
sp++;
|
||||
|
||||
/* copy file name */
|
||||
while (*sp && !IsRedirection (*sp) && !_istspace (*sp))
|
||||
*efn++ = *sp++;
|
||||
*efn = _T('\0');
|
||||
bInQuote ^= (*sp == _T('"'));
|
||||
*fn++ = *sp++;
|
||||
}
|
||||
else if (*sp == _T('&'))
|
||||
*fn++ = _T('\0');
|
||||
|
||||
/* Delete any existing redirection for the same handle number */
|
||||
ListPtr = RedirList;
|
||||
while ((Redir = *ListPtr))
|
||||
{
|
||||
/* output AND error redirection */
|
||||
sp++;
|
||||
|
||||
if (*sp == _T('>'))
|
||||
if (Redir->Number == HandleNumber)
|
||||
{
|
||||
*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++;
|
||||
*ListPtr = Redir->Next;
|
||||
cmd_free(Redir);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (_istspace (*sp))
|
||||
sp++;
|
||||
|
||||
/* copy file name */
|
||||
while (*sp && !IsRedirection (*sp) && !_istspace (*sp))
|
||||
*ofn++ = *efn++ = *sp++;
|
||||
*ofn = *efn = _T('\0');
|
||||
ListPtr = &Redir->Next;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in a new issue