forked from microsoft/terminal
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathObjectHandle.cpp
More file actions
259 lines (226 loc) · 8.42 KB
/
Copy pathObjectHandle.cpp
File metadata and controls
259 lines (226 loc) · 8.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "ObjectHandle.h"
#include "..\host\globals.h"
#include "..\host\inputReadHandleData.h"
#include "..\host\input.h"
#include "..\host\screenInfo.hpp"
#include "..\interactivity\inc\ServiceLocator.hpp"
ConsoleHandleData::ConsoleHandleData(const ULONG ulHandleType,
const ACCESS_MASK amAccess,
const ULONG ulShareAccess,
_In_ PVOID const pvClientPointer) :
_ulHandleType(ulHandleType),
_amAccess(amAccess),
_ulShareAccess(ulShareAccess),
_pvClientPointer(pvClientPointer),
_pClientInput(nullptr)
{
if (_IsInput())
{
_pClientInput = std::make_unique<INPUT_READ_HANDLE_DATA>();
}
}
// Routine Description:
// - Closes this handle destroying memory as appropriate and freeing ref counts.
// Do not use this handle after closing.
ConsoleHandleData::~ConsoleHandleData()
{
if (_IsInput())
{
THROW_IF_FAILED(_CloseInputHandle());
}
else if (_IsOutput())
{
THROW_IF_FAILED(_CloseOutputHandle());
}
else
{
FAIL_FAST_HR(E_UNEXPECTED);
}
}
// Routine Description:
// - Checks if this handle represents an input type object.
// Arguments:
// - <none>
// Return Value:
// - True if this handle is for an input object. False otherwise.
bool ConsoleHandleData::_IsInput() const
{
return WI_IsFlagSet(_ulHandleType, HandleType::Input);
}
// Routine Description:
// - Checks if this handle represents an output type object.
// Arguments:
// - <none>
// Return Value:
// - True if this handle is for an output object. False otherwise.
bool ConsoleHandleData::_IsOutput() const
{
return WI_IsFlagSet(_ulHandleType, HandleType::Output);
}
// Routine Description:
// - Indicates whether this handle is allowed to be used for reading the underlying object data.
// Arguments:
// - <none>
// Return Value:
// - True if read is permitted. False otherwise.
bool ConsoleHandleData::IsReadAllowed() const
{
return WI_IsFlagSet(_amAccess, GENERIC_READ);
}
// Routine Description:
// - Indicates whether this handle allows multiple customers to share reading of the underlying object data.
// Arguments:
// - <none>
// Return Value:
// - True if sharing read access is permitted. False otherwise.
bool ConsoleHandleData::IsReadShared() const
{
return WI_IsFlagSet(_ulShareAccess, FILE_SHARE_READ);
}
// Routine Description:
// - Indicates whether this handle is allowed to be used for writing the underlying object data.
// Arguments:
// - <none>
// Return Value:
// - True if write is permitted. False otherwise.
bool ConsoleHandleData::IsWriteAllowed() const
{
return WI_IsFlagSet(_amAccess, GENERIC_WRITE);
}
// Routine Description:
// - Indicates whether this handle allows multiple customers to share writing of the underlying object data.
// Arguments:
// - <none>
// Return Value:
// - True if sharing write access is permitted. False otherwise.
bool ConsoleHandleData::IsWriteShared() const
{
return WI_IsFlagSet(_ulShareAccess, FILE_SHARE_WRITE);
}
// Routine Description:
// - Retieves the properly typed Input Buffer from the Handle.
// Arguments:
// - amRequested - Access that the client would like for manipulating the buffer
// - ppInputBuffer - On success, filled with the referenced Input Buffer object
// Return Value:
// - HRESULT S_OK or suitable error.
[[nodiscard]] HRESULT ConsoleHandleData::GetInputBuffer(const ACCESS_MASK amRequested,
_Outptr_ InputBuffer** const ppInputBuffer) const
{
*ppInputBuffer = nullptr;
RETURN_HR_IF(E_ACCESSDENIED, WI_IsAnyFlagClear(_amAccess, amRequested));
RETURN_HR_IF(E_HANDLE, WI_IsAnyFlagClear(_ulHandleType, HandleType::Input));
*ppInputBuffer = static_cast<InputBuffer*>(_pvClientPointer);
return S_OK;
}
// Routine Description:
// - Retieves the properly typed Screen Buffer from the Handle.
// Arguments:
// - amRequested - Access that the client would like for manipulating the buffer
// - ppInputBuffer - On success, filled with the referenced Screen Buffer object
// Return Value:
// - HRESULT S_OK or suitable error.
[[nodiscard]] HRESULT ConsoleHandleData::GetScreenBuffer(const ACCESS_MASK amRequested,
_Outptr_ SCREEN_INFORMATION** const ppScreenInfo) const
{
*ppScreenInfo = nullptr;
RETURN_HR_IF(E_ACCESSDENIED, WI_IsAnyFlagClear(_amAccess, amRequested));
RETURN_HR_IF(E_HANDLE, WI_IsAnyFlagClear(_ulHandleType, HandleType::Output));
*ppScreenInfo = static_cast<SCREEN_INFORMATION*>(_pvClientPointer);
return S_OK;
}
// Routine Description:
// - Retrieves the wait queue associated with the given object held by this handle.
// Arguments:
// - ppWaitQueue - On success, filled with a pointer to the desired queue
// Return Value:
// - HRESULT S_OK or E_UNEXPECTED if the handle data structure is in an invalid state.
[[nodiscard]] HRESULT ConsoleHandleData::GetWaitQueue(_Outptr_ ConsoleWaitQueue** const ppWaitQueue) const
{
CONSOLE_INFORMATION& gci = Microsoft::Console::Interactivity::ServiceLocator::LocateGlobals().getConsoleInformation();
if (_IsInput())
{
InputBuffer* const pObj = static_cast<InputBuffer*>(_pvClientPointer);
*ppWaitQueue = &pObj->WaitQueue;
return S_OK;
}
else if (_IsOutput())
{
// TODO MSFT 9405322: shouldn't the output queue be per output object target, not global? https://osgvsowi/9405322
*ppWaitQueue = &gci.OutputQueue;
return S_OK;
}
else
{
return E_UNEXPECTED;
}
}
// Routine Description:
// - For input buffers only, retrieves an extra handle data structure used to save some information
// across multiple reads from the same handle.
// Arguments:
// - <none>
// Return Value:
// - Pointer to the input read handle data structure with the aforementioned extra info.
INPUT_READ_HANDLE_DATA* ConsoleHandleData::GetClientInput() const
{
return _pClientInput.get();
}
// Routine Description:
// - This routine closes an input handle. It decrements the input buffer's
// reference count. If it goes to zero, the buffer is reinitialized.
// Otherwise, the handle is removed from sharing.
// Arguments:
// - <none>
// Return Value:
// - HRESULT S_OK or suitable error code.
// Note:
// - The console lock must be held when calling this routine.
[[nodiscard]] HRESULT ConsoleHandleData::_CloseInputHandle()
{
FAIL_FAST_IF(!(_IsInput()));
InputBuffer* pInputBuffer = static_cast<InputBuffer*>(_pvClientPointer);
INPUT_READ_HANDLE_DATA* pReadHandleData = GetClientInput();
pReadHandleData->CompletePending();
// see if there are any reads waiting for data via this handle. if
// there are, wake them up. there aren't any other outstanding i/o
// operations via this handle because the console lock is held.
if (pReadHandleData->GetReadCount() != 0)
{
pInputBuffer->WaitQueue.NotifyWaiters(true, WaitTerminationReason::HandleClosing);
}
FAIL_FAST_IF(pReadHandleData->GetReadCount() > 0);
// TODO: MSFT: 9115192 - THIS IS BAD. It should use a destructor.
LOG_IF_FAILED(pInputBuffer->FreeIoHandle(this));
if (!pInputBuffer->HasAnyOpenHandles())
{
pInputBuffer->ReinitializeInputBuffer();
}
return S_OK;
}
// Routine Description:
// - This routine closes an output handle. It decrements the screen buffer's
// reference count. If it goes to zero, the buffer is freed. Otherwise,
// the handle is removed from sharing.
// Arguments:
// - <none>
// Return Value:
// - HRESULT S_OK or suitable error code.
// Note:
// - The console lock must be held when calling this routine.
[[nodiscard]] HRESULT ConsoleHandleData::_CloseOutputHandle()
{
FAIL_FAST_IF(!(_IsOutput()));
SCREEN_INFORMATION* pScreenInfo = static_cast<SCREEN_INFORMATION*>(_pvClientPointer);
pScreenInfo = &pScreenInfo->GetMainBuffer();
// TODO: MSFT: 9115192 - THIS IS BAD. It should use a destructor.
LOG_IF_FAILED(pScreenInfo->FreeIoHandle(this));
if (!pScreenInfo->HasAnyOpenHandles())
{
SCREEN_INFORMATION::s_RemoveScreenBuffer(pScreenInfo);
}
return S_OK;
}