[CMD]
[reactos.git] / reactos / base / shell / cmd / redir.c
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 these don't
34 * correspond to any STD_ constant. */
35 static HANDLE ExtraHandles[10 - 3];
36
37 static HANDLE GetHandle(UINT Number)
38 {
39 if (Number < 3)
40 return GetStdHandle(STD_INPUT_HANDLE - Number);
41 else
42 return ExtraHandles[Number - 3];
43 }
44
45 static VOID SetHandle(UINT Number, HANDLE Handle)
46 {
47 if (Number < 3)
48 SetStdHandle(STD_INPUT_HANDLE - Number, Handle);
49 else
50 ExtraHandles[Number - 3] = Handle;
51 }
52
53 BOOL
54 PerformRedirection(REDIRECTION *RedirList)
55 {
56 REDIRECTION *Redir;
57 LPTSTR Filename;
58 HANDLE hNew;
59 UINT DupNumber;
60
61 static SECURITY_ATTRIBUTES SecAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
62
63 /* Some parameters used for read, write, and append, respectively */
64 static
65 struct REDIR_PARAMS
66 {
67 DWORD dwDesiredAccess;
68 DWORD dwShareMode;
69 DWORD dwCreationDisposition;
70 } RedirParams[] =
71 {
72 {GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING}, // REDIR_READ
73 {GENERIC_WRITE, FILE_SHARE_READ , CREATE_ALWAYS}, // REDIR_WRITE
74 {GENERIC_WRITE, FILE_SHARE_READ , OPEN_ALWAYS } // REDIR_APPEND
75 };
76
77 for (Redir = RedirList; Redir; Redir = Redir->Next)
78 {
79 Filename = DoDelayedExpansion(Redir->Filename);
80 if (!Filename)
81 goto redir_error;
82 StripQuotes(Filename);
83
84 if (*Filename == _T('&'))
85 {
86 DupNumber = Filename[1] - _T('0');
87 if (DupNumber >= 10 ||
88 !DuplicateHandle(GetCurrentProcess(),
89 GetHandle(DupNumber),
90 GetCurrentProcess(),
91 &hNew,
92 0,
93 TRUE,
94 DUPLICATE_SAME_ACCESS))
95 {
96 hNew = INVALID_HANDLE_VALUE;
97 }
98 }
99 else
100 {
101 hNew = CreateFile(Filename,
102 RedirParams[Redir->Mode].dwDesiredAccess,
103 RedirParams[Redir->Mode].dwShareMode,
104 &SecAttr,
105 RedirParams[Redir->Mode].dwCreationDisposition,
106 0,
107 NULL);
108 }
109
110 if (hNew == INVALID_HANDLE_VALUE)
111 {
112 /* TODO: Print a more detailed message */
113 ConErrResPrintf(Redir->Mode == REDIR_READ ? STRING_CMD_ERROR1 : STRING_CMD_ERROR3,
114 Filename);
115 cmd_free(Filename);
116 redir_error:
117 /* Undo all the redirections before this one */
118 UndoRedirection(RedirList, Redir);
119 return FALSE;
120 }
121
122 if (Redir->Mode == REDIR_APPEND)
123 SetFilePointer(hNew, 0, NULL, FILE_END);
124 Redir->OldHandle = GetHandle(Redir->Number);
125 SetHandle(Redir->Number, hNew);
126
127 TRACE("%d redirected to: %s\n", Redir->Number, debugstr_aw(Filename));
128 cmd_free(Filename);
129 }
130 return TRUE;
131 }
132
133 VOID
134 UndoRedirection(REDIRECTION *Redir, REDIRECTION *End)
135 {
136 for (; Redir != End; Redir = Redir->Next)
137 {
138 CloseHandle(GetHandle(Redir->Number));
139 SetHandle(Redir->Number, Redir->OldHandle);
140 Redir->OldHandle = INVALID_HANDLE_VALUE;
141 }
142 }
143
144 VOID
145 FreeRedirection(REDIRECTION *Redir)
146 {
147 REDIRECTION *Next;
148 for (; Redir; Redir = Next)
149 {
150 Next = Redir->Next;
151 ASSERT(Redir->OldHandle == INVALID_HANDLE_VALUE);
152 cmd_free(Redir);
153 }
154 }
155
156 #endif /* FEATURE_REDIRECTION */