[SHELL32] SHChangeNotify: Add drive, remove drive (#6782)
[reactos.git] / ntoskrnl / lpc / create.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/lpc/create.c
5 * PURPOSE: Local Procedure Call: Port/Queue/Message Creation
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE FUNCTIONS *********************************************************/
16
17 NTSTATUS
18 NTAPI
19 LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
20 {
21 PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
22
23 PAGED_CODE();
24
25 /* Allocate the queue */
26 MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
27 sizeof(*MessageQueue),
28 'troP');
29 if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
30
31 /* Set it up */
32 KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
33 MessageQueue->BackPointer = Port;
34
35 /* And link it with the Paged Pool part */
36 Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
37 InitializeListHead(&Port->MsgQueue.ReceiveHead);
38 return STATUS_SUCCESS;
39 }
40
41 NTSTATUS
42 NTAPI
43 LpcpCreatePort(OUT PHANDLE PortHandle,
44 IN POBJECT_ATTRIBUTES ObjectAttributes,
45 IN ULONG MaxConnectionInfoLength,
46 IN ULONG MaxMessageLength,
47 IN ULONG MaxPoolUsage,
48 IN BOOLEAN Waitable)
49 {
50 NTSTATUS Status;
51 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
52 UNICODE_STRING CapturedObjectName, *ObjectName;
53 PLPCP_PORT_OBJECT Port;
54 HANDLE Handle;
55
56 PAGED_CODE();
57 LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName);
58
59 RtlInitEmptyUnicodeString(&CapturedObjectName, NULL, 0);
60
61 /* Check if the call comes from user mode */
62 if (PreviousMode != KernelMode)
63 {
64 _SEH2_TRY
65 {
66 /* Probe the PortHandle */
67 ProbeForWriteHandle(PortHandle);
68
69 /* Probe the ObjectAttributes and its object name (not the buffer) */
70 ProbeForRead(ObjectAttributes, sizeof(*ObjectAttributes), sizeof(ULONG));
71 ObjectName = ((volatile OBJECT_ATTRIBUTES*)ObjectAttributes)->ObjectName;
72 if (ObjectName)
73 {
74 ProbeForRead(ObjectName, sizeof(*ObjectName), 1);
75 CapturedObjectName = *(volatile UNICODE_STRING*)ObjectName;
76 }
77 }
78 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
79 {
80 /* Return the exception code */
81 _SEH2_YIELD(return _SEH2_GetExceptionCode());
82 }
83 _SEH2_END;
84 }
85 else
86 {
87 if (ObjectAttributes->ObjectName)
88 CapturedObjectName = *(ObjectAttributes->ObjectName);
89 }
90
91 /* Normalize the buffer pointer in case we don't have a name */
92 if (CapturedObjectName.Length == 0)
93 CapturedObjectName.Buffer = NULL;
94
95 /* Create the Object */
96 Status = ObCreateObject(PreviousMode,
97 LpcPortObjectType,
98 ObjectAttributes,
99 PreviousMode,
100 NULL,
101 sizeof(LPCP_PORT_OBJECT),
102 0,
103 0,
104 (PVOID*)&Port);
105 if (!NT_SUCCESS(Status)) return Status;
106
107 /* Set up the Object */
108 RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
109 Port->ConnectionPort = Port;
110 Port->Creator = PsGetCurrentThread()->Cid;
111 InitializeListHead(&Port->LpcDataInfoChainHead);
112 InitializeListHead(&Port->LpcReplyChainHead);
113
114 /* Check if we don't have a name */
115 if (CapturedObjectName.Buffer == NULL)
116 {
117 /* Set up for an unconnected port */
118 Port->Flags = LPCP_UNCONNECTED_PORT;
119 Port->ConnectedPort = Port;
120 Port->ServerProcess = NULL;
121 }
122 else
123 {
124 /* Set up for a named connection port */
125 Port->Flags = LPCP_CONNECTION_PORT;
126 Port->ServerProcess = PsGetCurrentProcess();
127
128 /* Don't let the process die on us */
129 ObReferenceObject(Port->ServerProcess);
130 }
131
132 /* Check if this is a waitable port */
133 if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
134
135 /* Setup the port queue */
136 Status = LpcpInitializePortQueue(Port);
137 if (!NT_SUCCESS(Status))
138 {
139 /* Fail */
140 ObDereferenceObject(Port);
141 return Status;
142 }
143
144 /* Check if this is a waitable port */
145 if (Port->Flags & LPCP_WAITABLE_PORT)
146 {
147 /* Setup the wait event */
148 KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
149 }
150
151 /* Set the maximum message size allowed */
152 Port->MaxMessageLength = LpcpMaxMessageSize -
153 FIELD_OFFSET(LPCP_MESSAGE, Request);
154
155 /* Now subtract the actual message structures and get the data size */
156 Port->MaxConnectionInfoLength = Port->MaxMessageLength -
157 sizeof(PORT_MESSAGE) -
158 sizeof(LPCP_CONNECTION_MESSAGE);
159
160 /* Validate the sizes */
161 if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
162 {
163 /* Not enough space for your request */
164 ObDereferenceObject(Port);
165 return STATUS_INVALID_PARAMETER_3;
166 }
167 else if (Port->MaxMessageLength < MaxMessageLength)
168 {
169 /* Not enough space for your request */
170 ObDereferenceObject(Port);
171 return STATUS_INVALID_PARAMETER_4;
172 }
173
174 /* Now set the custom setting */
175 Port->MaxMessageLength = MaxMessageLength;
176
177 /* Insert it now */
178 Status = ObInsertObject(Port,
179 NULL,
180 PORT_ALL_ACCESS,
181 0,
182 NULL,
183 &Handle);
184 if (NT_SUCCESS(Status))
185 {
186 _SEH2_TRY
187 {
188 /* Write back the handle, pointer was already probed */
189 *PortHandle = Handle;
190 }
191 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
192 {
193 /* An exception happened, close the opened handle */
194 ObCloseHandle(Handle, PreviousMode);
195 Status = _SEH2_GetExceptionCode();
196 }
197 _SEH2_END;
198 }
199
200 /* Return success or the error */
201 LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %p\n", Port, Handle);
202 return Status;
203 }
204
205 /* PUBLIC FUNCTIONS **********************************************************/
206
207 /*
208 * @implemented
209 */
210 NTSTATUS
211 NTAPI
212 NtCreatePort(OUT PHANDLE PortHandle,
213 IN POBJECT_ATTRIBUTES ObjectAttributes,
214 IN ULONG MaxConnectInfoLength,
215 IN ULONG MaxDataLength,
216 IN ULONG MaxPoolUsage)
217 {
218 PAGED_CODE();
219
220 /* Call the internal API */
221 return LpcpCreatePort(PortHandle,
222 ObjectAttributes,
223 MaxConnectInfoLength,
224 MaxDataLength,
225 MaxPoolUsage,
226 FALSE);
227 }
228
229 /*
230 * @implemented
231 */
232 NTSTATUS
233 NTAPI
234 NtCreateWaitablePort(OUT PHANDLE PortHandle,
235 IN POBJECT_ATTRIBUTES ObjectAttributes,
236 IN ULONG MaxConnectInfoLength,
237 IN ULONG MaxDataLength,
238 IN ULONG MaxPoolUsage)
239 {
240 PAGED_CODE();
241
242 /* Call the internal API */
243 return LpcpCreatePort(PortHandle,
244 ObjectAttributes,
245 MaxConnectInfoLength,
246 MaxDataLength,
247 MaxPoolUsage,
248 TRUE);
249 }
250
251 /* EOF */