xref: /reactos/ntoskrnl/io/iomgr/util.c (revision 4a7f3bdb)
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 }
349