7329dbf8f10d4e7c673d00c8c0dc9d9242655c72
[reactos.git] / ntoskrnl / io / iomgr / util.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/util.c
5 * PURPOSE: I/O Utility Functions
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Aleksey Bragin (aleksey@reactos.org)
8 * Daniel Zimmerman (netzimme@aim.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 VOID
18 NTAPI
19 RtlpGetStackLimits(PULONG_PTR StackBase,
20 PULONG_PTR StackLimit);
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 NTSTATUS
25 NTAPI
26 IoComputeDesiredAccessFileObject(IN PFILE_OBJECT FileObject,
27 IN PACCESS_MASK DesiredAccess)
28 {
29 /* Assume failure */
30 *DesiredAccess = 0;
31
32 /* First check we really have a FileObject */
33 if (OBJECT_TO_OBJECT_HEADER(FileObject)->Type != IoFileObjectType)
34 {
35 return STATUS_OBJECT_TYPE_MISMATCH;
36 }
37
38 /* Then compute desired access:
39 * Check if the handle has either FILE_WRITE_DATA or FILE_APPEND_DATA was
40 * granted. However, if this is a named pipe, make sure we don't ask for
41 * FILE_APPEND_DATA as it interferes with the FILE_CREATE_PIPE_INSTANCE
42 * access right!
43 */
44 *DesiredAccess = ((!(FileObject->Flags & FO_NAMED_PIPE) ? FILE_APPEND_DATA : 0) | FILE_WRITE_DATA);
45
46 return STATUS_SUCCESS;
47 }
48
49 /* FUNCTIONS *****************************************************************/
50
51 /*
52 * @implemented
53 */
54 VOID
55 NTAPI
56 IoAcquireCancelSpinLock(OUT PKIRQL Irql)
57 {
58 /* Just acquire the internal lock */
59 *Irql = KeAcquireQueuedSpinLock(LockQueueIoCancelLock);
60 }
61
62 /*
63 * @implemented
64 */
65 PVOID
66 NTAPI
67 IoGetInitialStack(VOID)
68 {
69 /* Return the initial stack from the TCB */
70 return PsGetCurrentThread()->Tcb.InitialStack;
71 }
72
73 /*
74 * @implemented
75 */
76 VOID
77 NTAPI
78 IoGetStackLimits(OUT PULONG_PTR LowLimit,
79 OUT PULONG_PTR HighLimit)
80 {
81 PKPRCB Prcb = KeGetCurrentPrcb();
82 ULONG_PTR DpcStack = (ULONG_PTR)(Prcb->DpcStack);
83 volatile ULONG_PTR StackAddress;
84
85 /* Save our stack address so we always know it's valid */
86 StackAddress = (ULONG_PTR)(&StackAddress);
87
88 /* Get stack values */
89 RtlpGetStackLimits(LowLimit, HighLimit);
90
91 /* Check if we're outside the stack */
92 if ((StackAddress < *LowLimit) || (StackAddress > *HighLimit))
93 {
94 /* Check if we may be in a DPC */
95 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
96 {
97 /* Check if we really are in a DPC */
98 if ((Prcb->DpcRoutineActive) &&
99 (StackAddress <= DpcStack) &&
100 (StackAddress >= DpcStack - KERNEL_STACK_SIZE))
101 {
102 /* Use the DPC stack limits */
103 *HighLimit = DpcStack;
104 *LowLimit = DpcStack - KERNEL_STACK_SIZE;
105 }
106 }
107 }
108 }
109
110 /*
111 * @implemented
112 */
113 BOOLEAN
114 NTAPI
115 IoIsSystemThread(IN PETHREAD Thread)
116 {
117 /* Call the Ps Function */
118 return PsIsSystemThread(Thread);
119 }
120
121 /*
122 * @implemented
123 */
124 BOOLEAN
125 NTAPI
126 IoIsWdmVersionAvailable(IN UCHAR MajorVersion,
127 IN UCHAR MinorVersion)
128 {
129 /* Return support for WDM 1.30 (Windows Server 2003) */
130 if (MajorVersion <= 1 && MinorVersion <= 0x30) return TRUE;
131 return FALSE;
132 }
133
134 /*
135 * @implemented
136 */
137 PEPROCESS
138 NTAPI
139 IoGetCurrentProcess(VOID)
140 {
141 /* Return the current thread's process */
142 return (PEPROCESS)PsGetCurrentThread()->Tcb.ApcState.Process;
143 }
144
145 /*
146 * @implemented
147 */
148 VOID
149 NTAPI
150 IoReleaseCancelSpinLock(IN KIRQL Irql)
151 {
152 /* Release the internal lock */
153 KeReleaseQueuedSpinLock(LockQueueIoCancelLock, Irql);
154 }
155
156 /*
157 * @implemented
158 */
159 PEPROCESS
160 NTAPI
161 IoThreadToProcess(IN PETHREAD Thread)
162 {
163 /* Return the thread's process */
164 return Thread->ThreadsProcess;
165 }
166
167 /*
168 * @implemented
169 */
170 NTSTATUS
171 NTAPI
172 IoCheckDesiredAccess(IN OUT PACCESS_MASK DesiredAccess,
173 IN ACCESS_MASK GrantedAccess)
174 {
175 PAGED_CODE();
176
177 /* Map the generic mask */
178 RtlMapGenericMask(DesiredAccess,
179 &IoFileObjectType->TypeInfo.GenericMapping);
180
181 /* Fail if the access masks don't grant full access */
182 if ((~(*DesiredAccess) & GrantedAccess)) return STATUS_ACCESS_DENIED;
183 return STATUS_SUCCESS;
184 }
185
186 /*
187 * @implemented
188 */
189 NTSTATUS
190 NTAPI
191 IoCheckEaBufferValidity(IN PFILE_FULL_EA_INFORMATION EaBuffer,
192 IN ULONG EaLength,
193 OUT PULONG ErrorOffset)
194 {
195 PFILE_FULL_EA_INFORMATION EaBufferEnd;
196 ULONG NextEaBufferOffset;
197 LONG IntEaLength;
198
199 PAGED_CODE();
200
201 /* Length of the rest */
202 IntEaLength = EaLength;
203 EaBufferEnd = EaBuffer;
204
205 /* The rest length of the buffer */
206 while (IntEaLength >= FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]))
207 {
208 /*
209 * The rest of buffer must greater than
210 * sizeof(FILE_FULL_EA_INFORMATION) + buffer
211 */
212 NextEaBufferOffset =
213 EaBufferEnd->EaNameLength + EaBufferEnd->EaValueLength +
214 FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) + 1;
215
216 if ((ULONG)IntEaLength >= NextEaBufferOffset)
217 {
218 /* is the EaBufferName terminated with zero? */
219 if (EaBufferEnd->EaName[EaBufferEnd->EaNameLength]==0)
220 {
221 /* more EaBuffers ahead */
222 if (EaBufferEnd->NextEntryOffset == 0)
223 {
224 /* test the rest buffersize */
225 IntEaLength = IntEaLength - NextEaBufferOffset;
226 if (IntEaLength >= 0)
227 {
228 return STATUS_SUCCESS;
229 }
230 }
231 else
232 {
233 /*
234 * From MSDN:
235 * http://msdn2.microsoft.com/en-us/library/ms795740.aspx
236 * For all entries except the last one, the value of
237 * NextEntryOffset must be greater than zero and
238 * must fall on a ULONG boundary.
239 */
240 NextEaBufferOffset = ((NextEaBufferOffset + 3) & ~3);
241 if ((EaBufferEnd->NextEntryOffset == NextEaBufferOffset) &&
242 ((LONG)EaBufferEnd->NextEntryOffset > 0))
243 {
244 /*
245 * The rest of buffer must be greater
246 * than the following offset.
247 */
248 IntEaLength =
249 IntEaLength - EaBufferEnd->NextEntryOffset;
250
251 if (IntEaLength >= 0)
252 {
253 EaBufferEnd = (PFILE_FULL_EA_INFORMATION)
254 ((ULONG_PTR)EaBufferEnd +
255 EaBufferEnd->NextEntryOffset);
256 continue;
257 }
258 }
259 }
260 }
261 }
262 break;
263 }
264
265 if (ErrorOffset != NULL)
266 {
267 /* Calculate the error offset */
268 *ErrorOffset = (ULONG)((ULONG_PTR)EaBufferEnd - (ULONG_PTR)EaBuffer);
269 }
270
271 return STATUS_EA_LIST_INCONSISTENT;
272 }
273
274 /*
275 * @unimplemented
276 */
277 NTSTATUS
278 NTAPI
279 IoCheckFunctionAccess(IN ACCESS_MASK GrantedAccess,
280 IN UCHAR MajorFunction,
281 IN UCHAR MinorFunction,
282 IN ULONG IoControlCode,
283 IN PVOID ExtraData OPTIONAL,
284 IN PVOID ExtraData2 OPTIONAL)
285 {
286 UNIMPLEMENTED;
287 return STATUS_NOT_IMPLEMENTED;
288 }
289
290 /*
291 * @unimplemented
292 */
293 NTSTATUS
294 NTAPI
295 IoValidateDeviceIoControlAccess(IN PIRP Irp,
296 IN ULONG RequiredAccess)
297 {
298 UNIMPLEMENTED;
299 return STATUS_NOT_IMPLEMENTED;
300 }
301
302 /*
303 * @implemented
304 */
305 VOID
306 NTAPI
307 IoSetDeviceToVerify(IN PETHREAD Thread,
308 IN PDEVICE_OBJECT DeviceObject)
309 {
310 /* Set the pointer in the thread */
311 Thread->DeviceToVerify = DeviceObject;
312 }
313
314 /*
315 * @implemented
316 */
317 VOID
318 NTAPI
319 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
320 IN PDEVICE_OBJECT DeviceObject)
321 {
322 /* Set the pointer in the IRP */
323 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
324 }
325
326 /*
327 * @implemented
328 */
329 PDEVICE_OBJECT
330 NTAPI
331 IoGetDeviceToVerify(IN PETHREAD Thread)
332 {
333 /* Return the pointer that was set with IoSetDeviceToVerify */
334 return Thread->DeviceToVerify;
335 }
336
337 /*
338 * @unimplemented
339 */
340 NTSTATUS
341 NTAPI
342 IoCheckQuerySetVolumeInformation(IN FS_INFORMATION_CLASS FsInformationClass,
343 IN ULONG Length,
344 IN BOOLEAN SetOperation)
345 {
346 UNIMPLEMENTED;
347 return STATUS_NOT_IMPLEMENTED;
348 }