xref: /reactos/base/shell/cmd/redir.c (revision 2b82fe44)
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 	static SECURITY_ATTRIBUTES SecAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
61 
62 	/* Some parameters used for read, write, and append, respectively */
63 	static const DWORD dwAccess[] = {
64 		GENERIC_READ,
65 		GENERIC_WRITE,
66 		GENERIC_WRITE
67 	};
68 	static const DWORD dwShareMode[] = {
69 		FILE_SHARE_READ | FILE_SHARE_WRITE,
70 		FILE_SHARE_READ,
71 		FILE_SHARE_READ
72 	};
73 	static const DWORD dwCreationDisposition[] = {
74 		OPEN_EXISTING,
75 		CREATE_ALWAYS,
76 		OPEN_ALWAYS
77 	};
78 
79 	for (Redir = RedirList; Redir; Redir = Redir->Next)
80 	{
81 		Filename = DoDelayedExpansion(Redir->Filename);
82 		if (!Filename)
83 			goto redir_error;
84 		StripQuotes(Filename);
85 
86 		if (*Filename == _T('&'))
87 		{
88 			DupNumber = Filename[1] - _T('0');
89 			if (DupNumber >= 10 ||
90 			    !DuplicateHandle(GetCurrentProcess(),
91 			                     GetHandle(DupNumber),
92 			                     GetCurrentProcess(),
93 			                     &hNew,
94 			                     0,
95 			                     TRUE,
96 			                     DUPLICATE_SAME_ACCESS))
97 			{
98 				hNew = INVALID_HANDLE_VALUE;
99 			}
100 		}
101 		else
102 		{
103 			hNew = CreateFile(Filename,
104 			                  dwAccess[Redir->Type],
105 			                  dwShareMode[Redir->Type],
106 			                  &SecAttr,
107 			                  dwCreationDisposition[Redir->Type],
108 			                  0,
109 			                  NULL);
110 		}
111 
112 		if (hNew == INVALID_HANDLE_VALUE)
113 		{
114 			ConErrResPrintf(Redir->Type == REDIR_READ ? STRING_CMD_ERROR1 : STRING_CMD_ERROR3,
115 			                Filename);
116 			cmd_free(Filename);
117 redir_error:
118 			/* Undo all the redirections before this one */
119 			UndoRedirection(RedirList, Redir);
120 			return FALSE;
121 		}
122 
123 		if (Redir->Type == REDIR_APPEND)
124 			SetFilePointer(hNew, 0, NULL, FILE_END);
125 		Redir->OldHandle = GetHandle(Redir->Number);
126 		SetHandle(Redir->Number, hNew);
127 
128 		TRACE("%d redirected to: %s\n", Redir->Number, debugstr_aw(Filename));
129 		cmd_free(Filename);
130 	}
131 	return TRUE;
132 }
133 
134 VOID
135 UndoRedirection(REDIRECTION *Redir, REDIRECTION *End)
136 {
137 	for (; Redir != End; Redir = Redir->Next)
138 	{
139 		CloseHandle(GetHandle(Redir->Number));
140 		SetHandle(Redir->Number, Redir->OldHandle);
141 		Redir->OldHandle = INVALID_HANDLE_VALUE;
142 	}
143 }
144 
145 VOID
146 FreeRedirection(REDIRECTION *Redir)
147 {
148 	REDIRECTION *Next;
149 	for (; Redir; Redir = Next)
150 	{
151 		Next = Redir->Next;
152 		ASSERT(Redir->OldHandle == INVALID_HANDLE_VALUE);
153 		cmd_free(Redir);
154 	}
155 }
156 
157 #endif /* FEATURE_REDIRECTION */
158