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