[CMD]: Continue refactoring to lay out the way to using the CONUTILS library in 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 struct REDIR_PARAMS
65 {
66 DWORD dwDesiredAccess;
67 DWORD dwShareMode;
68 DWORD dwCreationDisposition;
69 } RedirParams[] =
70 {
71 {GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING}, // REDIR_READ
72 {GENERIC_WRITE, FILE_SHARE_READ , CREATE_ALWAYS}, // REDIR_WRITE
73 {GENERIC_WRITE, FILE_SHARE_READ , OPEN_ALWAYS } // REDIR_APPEND
74 };
75
76 for (Redir = RedirList; Redir; Redir = Redir->Next)
77 {
78 Filename = DoDelayedExpansion(Redir->Filename);
79 if (!Filename)
80 goto redir_error;
81 StripQuotes(Filename);
82
83 if (*Filename == _T('&'))
84 {
85 DupNumber = Filename[1] - _T('0');
86 if (DupNumber >= 10 ||
87 !DuplicateHandle(GetCurrentProcess(),
88 GetHandle(DupNumber),
89 GetCurrentProcess(),
90 &hNew,
91 0,
92 TRUE,
93 DUPLICATE_SAME_ACCESS))
94 {
95 hNew = INVALID_HANDLE_VALUE;
96 }
97 }
98 else
99 {
100 hNew = CreateFile(Filename,
101 RedirParams[Redir->Mode].dwDesiredAccess,
102 RedirParams[Redir->Mode].dwShareMode,
103 &SecAttr,
104 RedirParams[Redir->Mode].dwCreationDisposition,
105 0,
106 NULL);
107 }
108
109 if (hNew == INVALID_HANDLE_VALUE)
110 {
111 /* TODO: Print a more detailed message */
112 ConErrResPrintf(Redir->Mode == REDIR_READ ? STRING_CMD_ERROR1 : STRING_CMD_ERROR3,
113 Filename);
114 cmd_free(Filename);
115 redir_error:
116 /* Undo all the redirections before this one */
117 UndoRedirection(RedirList, Redir);
118 return FALSE;
119 }
120
121 if (Redir->Mode == REDIR_APPEND)
122 SetFilePointer(hNew, 0, NULL, FILE_END);
123 Redir->OldHandle = GetHandle(Redir->Number);
124 SetHandle(Redir->Number, hNew);
125
126 TRACE("%d redirected to: %s\n", Redir->Number, debugstr_aw(Filename));
127 cmd_free(Filename);
128 }
129 return TRUE;
130 }
131
132 VOID
133 UndoRedirection(REDIRECTION *Redir, REDIRECTION *End)
134 {
135 for (; Redir != End; Redir = Redir->Next)
136 {
137 CloseHandle(GetHandle(Redir->Number));
138 SetHandle(Redir->Number, Redir->OldHandle);
139 Redir->OldHandle = INVALID_HANDLE_VALUE;
140 }
141 }
142
143 VOID
144 FreeRedirection(REDIRECTION *Redir)
145 {
146 REDIRECTION *Next;
147 for (; Redir; Redir = Next)
148 {
149 Next = Redir->Next;
150 ASSERT(Redir->OldHandle == INVALID_HANDLE_VALUE);
151 cmd_free(Redir);
152 }
153 }
154
155 #endif /* FEATURE_REDIRECTION */