xref: /reactos/base/shell/cmd/redir.c (revision c2c66aff)
1 /*
2  *  REDIR.C - redirection handling.
3  *
4  *
5  *  History:
6  *
7  *    12/15/95 (Tim Norman)
8  *        started.
9  *
10  *    12 Jul 98 (Hans B Pufal)
11  *        Rewrote to make more efficient and to conform to new command.c
12  *        and batch.c processing.
13  *
14  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
15  *        Added config.h include
16  *
17  *    22-Jan-1999 (Eric Kohl)
18  *        Unicode safe!
19  *        Added new error redirection "2>" and "2>>".
20  *
21  *    26-Jan-1999 (Eric Kohl)
22  *        Added new error AND output redirection "&>" and "&>>".
23  *
24  *    24-Jun-2005 (Brandon Turner <turnerb7@msu.edu>)
25  *        simple check to fix > and | bug with 'rem'
26  */
27 
28 #include "precomp.h"
29 
30 #ifdef FEATURE_REDIRECTION
31 
32 /*
33  * CMD allows redirection of handles numbered 3-9 even though
34  * these don't correspond to any STD_ constant.
35  */
36 static const PCON_STREAM StdStreams[] = { StdIn, StdOut, StdErr };
37 static HANDLE ExtraHandles[10 - 3]; // 3 == ARRAYSIZE(StdStreams)
38 
GetHandle(UINT Number)39 HANDLE GetHandle(UINT Number)
40 {
41     if (Number < 3)
42         return ConStreamGetOSHandle(StdStreams[Number]);
43         // return GetStdHandle(STD_INPUT_HANDLE - Number);
44     else if (Number < ARRAYSIZE(ExtraHandles) + 3)
45         return ExtraHandles[Number - 3];
46     else
47         return INVALID_HANDLE_VALUE;
48 }
49 
SetHandle(UINT Number,HANDLE Handle)50 VOID SetHandle(UINT Number, HANDLE Handle)
51 {
52     if (Number < 3)
53     {
54         ConStreamSetOSHandle(StdStreams[Number], Handle);
55         /* Synchronize the associated Win32 handle */
56         SetStdHandle(STD_INPUT_HANDLE - Number, Handle);
57     }
58     else if (Number < ARRAYSIZE(ExtraHandles) + 3)
59         ExtraHandles[Number - 3] = Handle;
60 }
61 
62 BOOL
PerformRedirection(REDIRECTION * RedirList)63 PerformRedirection(REDIRECTION *RedirList)
64 {
65     REDIRECTION *Redir;
66     LPTSTR Filename;
67     HANDLE hNew;
68     UINT DupNumber;
69 
70     static SECURITY_ATTRIBUTES SecAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
71 
72     /* Some parameters used for read, write, and append, respectively */
73     static struct REDIR_PARAMS
74     {
75         DWORD dwDesiredAccess;
76         DWORD dwShareMode;
77         DWORD dwCreationDisposition;
78     } RedirParams[] =
79     {
80         {GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING}, // REDIR_READ
81         {GENERIC_WRITE, FILE_SHARE_READ                   , CREATE_ALWAYS}, // REDIR_WRITE
82         {GENERIC_WRITE, FILE_SHARE_READ                   , OPEN_ALWAYS  }  // REDIR_APPEND
83     };
84 
85     for (Redir = RedirList; Redir; Redir = Redir->Next)
86     {
87         Filename = DoDelayedExpansion(Redir->Filename);
88         if (!Filename)
89             goto redir_error;
90         StripQuotes(Filename);
91 
92         if (*Filename == _T('&'))
93         {
94             DupNumber = Filename[1] - _T('0');
95             if (DupNumber >= 10 ||
96                 !DuplicateHandle(GetCurrentProcess(),
97                                  GetHandle(DupNumber),
98                                  GetCurrentProcess(),
99                                  &hNew,
100                                  0,
101                                  TRUE,
102                                  DUPLICATE_SAME_ACCESS))
103             {
104                 hNew = INVALID_HANDLE_VALUE;
105             }
106         }
107         else
108         {
109             hNew = CreateFile(Filename,
110                               RedirParams[Redir->Mode].dwDesiredAccess,
111                               RedirParams[Redir->Mode].dwShareMode,
112                               &SecAttr,
113                               RedirParams[Redir->Mode].dwCreationDisposition,
114                               0,
115                               NULL);
116         }
117 
118         if (hNew == INVALID_HANDLE_VALUE)
119         {
120             /* TODO: Print a more detailed message */
121             ConErrResPrintf(Redir->Mode == REDIR_READ ? STRING_CMD_ERROR1 : STRING_CMD_ERROR3,
122                             Filename);
123             cmd_free(Filename);
124 redir_error:
125             /* Undo all the redirections before this one */
126             UndoRedirection(RedirList, Redir);
127             return FALSE;
128         }
129 
130         if (Redir->Mode == REDIR_APPEND)
131             SetFilePointer(hNew, 0, NULL, FILE_END);
132         Redir->OldHandle = GetHandle(Redir->Number);
133         SetHandle(Redir->Number, hNew);
134 
135         TRACE("%d redirected to: %s\n", Redir->Number, debugstr_aw(Filename));
136         cmd_free(Filename);
137     }
138     return TRUE;
139 }
140 
141 VOID
UndoRedirection(REDIRECTION * Redir,REDIRECTION * End)142 UndoRedirection(REDIRECTION *Redir, REDIRECTION *End)
143 {
144     for (; Redir != End; Redir = Redir->Next)
145     {
146         CloseHandle(GetHandle(Redir->Number));
147         SetHandle(Redir->Number, Redir->OldHandle);
148         Redir->OldHandle = INVALID_HANDLE_VALUE;
149     }
150 }
151 
152 VOID
FreeRedirection(REDIRECTION * Redir)153 FreeRedirection(REDIRECTION *Redir)
154 {
155     REDIRECTION *Next;
156     for (; Redir; Redir = Next)
157     {
158         Next = Redir->Next;
159         ASSERT(Redir->OldHandle == INVALID_HANDLE_VALUE);
160         cmd_free(Redir);
161     }
162 }
163 
164 #endif /* FEATURE_REDIRECTION */
165