xref: /reactos/ntoskrnl/io/iomgr/util.c (revision 9592728f)
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     ULONG NextEntryOffset;
196     UCHAR EaNameLength;
197     ULONG ComputedLength;
198     PFILE_FULL_EA_INFORMATION Current;
199 
200     PAGED_CODE();
201 
202     /* We will browse all the entries */
203     for (Current = EaBuffer; ; Current = (PFILE_FULL_EA_INFORMATION)((ULONG_PTR)Current + NextEntryOffset))
204     {
205         /* Check that we have enough bits left for the current entry */
206         if (EaLength < FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName))
207         {
208             goto FailPath;
209         }
210 
211         EaNameLength = Current->EaNameLength;
212         ComputedLength = Current->EaValueLength + EaNameLength + FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + 1;
213         /* Check that we have enough bits left for storing the name and its value */
214         if (EaLength < ComputedLength)
215         {
216             goto FailPath;
217         }
218 
219         /* Make sure the name is null terminated */
220         if (Current->EaName[EaNameLength] != ANSI_NULL)
221         {
222             goto FailPath;
223         }
224 
225         /* Get the next entry offset */
226         NextEntryOffset = Current->NextEntryOffset;
227         /* If it's 0, it's a termination case */
228         if (NextEntryOffset == 0)
229         {
230             /* If we don't overflow! */
231             if ((LONG)(EaLength - ComputedLength) < 0)
232             {
233                 goto FailPath;
234             }
235 
236             break;
237         }
238 
239         /* Compare the next offset we computed with the provided one, they must match */
240         if (ALIGN_UP_BY(ComputedLength, sizeof(ULONG)) != NextEntryOffset)
241         {
242             goto FailPath;
243         }
244 
245         /* Check next entry offset value is positive */
246         if ((LONG)NextEntryOffset < 0)
247         {
248             goto FailPath;
249         }
250 
251         /* Compute the remaining bits */
252         EaLength -= NextEntryOffset;
253         /* We must have bits left */
254         if ((LONG)EaLength < 0)
255         {
256             goto FailPath;
257         }
258 
259         /* Move to the next entry */
260     }
261 
262     /* If we end here, everything went OK */
263     return STATUS_SUCCESS;
264 
265 FailPath:
266     /* If we end here, we failed, set failed offset */
267     *ErrorOffset = (ULONG_PTR)Current - (ULONG_PTR)EaBuffer;
268     return STATUS_EA_LIST_INCONSISTENT;
269 }
270 
271 /*
272  * @unimplemented
273  */
274 NTSTATUS
275 NTAPI
276 IoCheckFunctionAccess(IN ACCESS_MASK GrantedAccess,
277                       IN UCHAR MajorFunction,
278                       IN UCHAR MinorFunction,
279                       IN ULONG IoControlCode,
280                       IN PVOID ExtraData OPTIONAL,
281                       IN PVOID ExtraData2 OPTIONAL)
282 {
283     UNIMPLEMENTED;
284     return STATUS_NOT_IMPLEMENTED;
285 }
286 
287 /*
288  * @unimplemented
289  */
290 NTSTATUS
291 NTAPI
292 IoValidateDeviceIoControlAccess(IN PIRP Irp,
293                                 IN ULONG RequiredAccess)
294 {
295     UNIMPLEMENTED;
296     return STATUS_NOT_IMPLEMENTED;
297 }
298 
299 /*
300  * @implemented
301  */
302 VOID
303 NTAPI
304 IoSetDeviceToVerify(IN PETHREAD Thread,
305                     IN PDEVICE_OBJECT DeviceObject)
306 {
307     /* Set the pointer in the thread */
308     Thread->DeviceToVerify = DeviceObject;
309 }
310 
311 /*
312  * @implemented
313  */
314 VOID
315 NTAPI
316 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
317                              IN PDEVICE_OBJECT DeviceObject)
318 {
319     /* Ignore in case the IRP is not associated with any thread */
320     if (!Irp->Tail.Overlay.Thread)
321     {
322         DPRINT1("IoSetHardErrorOrVerifyDevice(0x%p, 0x%p): IRP has no thread, ignoring.\n",
323                 Irp, DeviceObject);
324         return;
325     }
326 
327     /* Set the pointer in the IRP */
328     Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
329 }
330 
331 /*
332  * @implemented
333  */
334 PDEVICE_OBJECT
335 NTAPI
336 IoGetDeviceToVerify(IN PETHREAD Thread)
337 {
338     /* Return the pointer that was set with IoSetDeviceToVerify */
339     return Thread->DeviceToVerify;
340 }
341 
342 /*
343  * @unimplemented
344  */
345 NTSTATUS
346 NTAPI
347 IoCheckQuerySetVolumeInformation(IN FS_INFORMATION_CLASS FsInformationClass,
348                                  IN ULONG Length,
349                                  IN BOOLEAN SetOperation)
350 {
351     UNIMPLEMENTED;
352     return STATUS_NOT_IMPLEMENTED;
353 }
354