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