[NTOSKRNL] Implement IoGetFileObjectFilterContext()
[reactos.git] / ntoskrnl / io / iomgr / file.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/file.c
5 * PURPOSE: Functions that deal with managing the FILE_OBJECT itself.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Gunnar Dalsnes
8 * Eric Kohl
9 * Filip Navara (navaraf@reactos.org)
10 * Pierre Schweitzer
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <ntoskrnl.h>
16 #define NDEBUG
17 #include <debug.h>
18
19 extern ERESOURCE IopSecurityResource;
20
21 /* PRIVATE FUNCTIONS *********************************************************/
22
23 VOID
24 NTAPI
25 IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState,
26 IN OUT PULONG CreateOptions,
27 IN KPROCESSOR_MODE PreviousMode,
28 IN ULONG Disposition)
29 {
30 ACCESS_MASK DesiredAccess, ReadAccess, WriteAccess;
31 PRIVILEGE_SET Privileges;
32 BOOLEAN AccessGranted, HaveBackupPriv = FALSE, CheckRestore = FALSE;
33 PAGED_CODE();
34
35 /* Don't do anything if privileges were checked already */
36 if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) return;
37
38 /* Check if the file was actually opened for backup purposes */
39 if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT)
40 {
41 /* Set the check flag since were doing it now */
42 AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED;
43
44 /* Set the access masks required */
45 ReadAccess = READ_CONTROL |
46 ACCESS_SYSTEM_SECURITY |
47 FILE_GENERIC_READ |
48 FILE_TRAVERSE;
49 WriteAccess = WRITE_DAC |
50 WRITE_OWNER |
51 ACCESS_SYSTEM_SECURITY |
52 FILE_GENERIC_WRITE |
53 FILE_ADD_FILE |
54 FILE_ADD_SUBDIRECTORY |
55 DELETE;
56 DesiredAccess = AccessState->RemainingDesiredAccess;
57
58 /* Check if desired access was the maximum */
59 if (DesiredAccess & MAXIMUM_ALLOWED)
60 {
61 /* Then add all the access masks required */
62 DesiredAccess |= (ReadAccess | WriteAccess);
63 }
64
65 /* Check if the file already exists */
66 if (Disposition & FILE_OPEN)
67 {
68 /* Check if desired access has the read mask */
69 if (ReadAccess & DesiredAccess)
70 {
71 /* Setup the privilege check lookup */
72 Privileges.PrivilegeCount = 1;
73 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
74 Privileges.Privilege[0].Luid = SeBackupPrivilege;
75 Privileges.Privilege[0].Attributes = 0;
76 AccessGranted = SePrivilegeCheck(&Privileges,
77 &AccessState->
78 SubjectSecurityContext,
79 PreviousMode);
80 if (AccessGranted)
81 {
82 /* Remember that backup was allowed */
83 HaveBackupPriv = TRUE;
84
85 /* Append the privileges and update the access state */
86 SeAppendPrivileges(AccessState, &Privileges);
87 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & ReadAccess);
88 AccessState->RemainingDesiredAccess &= ~ReadAccess;
89 DesiredAccess &= ~ReadAccess;
90
91 /* Set backup privilege for the token */
92 AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE;
93 }
94 }
95 }
96 else
97 {
98 /* Caller is creating the file, check restore privileges later */
99 CheckRestore = TRUE;
100 }
101
102 /* Check if caller wants write access or if it's creating a file */
103 if ((WriteAccess & DesiredAccess) || (CheckRestore))
104 {
105 /* Setup the privilege lookup and do it */
106 Privileges.PrivilegeCount = 1;
107 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
108 Privileges.Privilege[0].Luid = SeRestorePrivilege;
109 Privileges.Privilege[0].Attributes = 0;
110 AccessGranted = SePrivilegeCheck(&Privileges,
111 &AccessState->SubjectSecurityContext,
112 PreviousMode);
113 if (AccessGranted)
114 {
115 /* Remember that privilege was given */
116 HaveBackupPriv = TRUE;
117
118 /* Append the privileges and update the access state */
119 SeAppendPrivileges(AccessState, &Privileges);
120 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & WriteAccess);
121 AccessState->RemainingDesiredAccess &= ~WriteAccess;
122
123 /* Set restore privilege for the token */
124 AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE;
125 }
126 }
127
128 /* If we don't have the privilege, remove the option */
129 if (!HaveBackupPriv) *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT;
130 }
131 }
132
133 NTSTATUS
134 NTAPI
135 IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,
136 IN PDEVICE_OBJECT DeviceObject)
137 {
138 /* Make sure the object is valid */
139 if ((IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
140 (DOE_UNLOAD_PENDING |
141 DOE_DELETE_PENDING |
142 DOE_REMOVE_PENDING |
143 DOE_REMOVE_PROCESSED)) ||
144 (DeviceObject->Flags & DO_DEVICE_INITIALIZING))
145 {
146 /* It's unloading or initializing, so fail */
147 DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
148 " sucks. Please fix it's AddDevice Routine\n",
149 &DeviceObject->DriverObject->DriverName);
150 return STATUS_NO_SUCH_DEVICE;
151 }
152 else if ((DeviceObject->Flags & DO_EXCLUSIVE) &&
153 (DeviceObject->ReferenceCount) &&
154 !(OpenPacket->RelatedFileObject) &&
155 !(OpenPacket->Options & IO_ATTACH_DEVICE))
156 {
157 return STATUS_ACCESS_DENIED;
158 }
159
160 else
161 {
162 /* Increase reference count */
163 InterlockedIncrement(&DeviceObject->ReferenceCount);
164 return STATUS_SUCCESS;
165 }
166 }
167
168 VOID
169 NTAPI
170 IopDoNameTransmogrify(IN PIRP Irp,
171 IN PFILE_OBJECT FileObject,
172 IN PREPARSE_DATA_BUFFER DataBuffer)
173 {
174 PWSTR Buffer;
175 USHORT Length;
176 USHORT RequiredLength;
177 PWSTR NewBuffer;
178
179 PAGED_CODE();
180
181 ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
182 ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
183 ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
184 ASSERT(DataBuffer != NULL);
185 ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
186 ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
187 ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
188
189 /* First of all, validate data */
190 if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
191 (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
192 DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
193 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
194 {
195 Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
196 }
197
198 /* Everything went right */
199 if (NT_SUCCESS(Irp->IoStatus.Status))
200 {
201 /* Compute buffer & length */
202 Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
203 DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
204 Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
205
206 /* Check we don't overflow */
207 if (((ULONG)MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
208 {
209 Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
210 }
211 else
212 {
213 /* Compute how much mem we'll need */
214 RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
215
216 /* Check if FileObject can already hold what we need */
217 if (FileObject->FileName.MaximumLength >= RequiredLength)
218 {
219 NewBuffer = FileObject->FileName.Buffer;
220 }
221 else
222 {
223 /* Allocate otherwise */
224 NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_IO_NAME);
225 if (NewBuffer == NULL)
226 {
227 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
228 }
229 }
230 }
231 }
232
233 /* Everything went right */
234 if (NT_SUCCESS(Irp->IoStatus.Status))
235 {
236 /* Copy reserved */
237 if (DataBuffer->Reserved)
238 {
239 RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
240 (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer + FileObject->FileName.Length - DataBuffer->Reserved),
241 DataBuffer->Reserved);
242 }
243
244 /* Then, buffer */
245 if (Length)
246 {
247 RtlCopyMemory(NewBuffer, Buffer, Length);
248 }
249
250 /* And finally replace buffer if new one was allocated */
251 FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
252 if (NewBuffer != FileObject->FileName.Buffer)
253 {
254 if (FileObject->FileName.Buffer)
255 {
256 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
257 }
258
259 FileObject->FileName.Buffer = NewBuffer;
260 FileObject->FileName.MaximumLength = RequiredLength;
261 FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
262 }
263 }
264
265 /* We don't need them anymore - it was allocated by the driver */
266 ExFreePool(DataBuffer);
267 }
268
269 NTSTATUS
270 NTAPI
271 IopParseDevice(IN PVOID ParseObject,
272 IN PVOID ObjectType,
273 IN OUT PACCESS_STATE AccessState,
274 IN KPROCESSOR_MODE AccessMode,
275 IN ULONG Attributes,
276 IN OUT PUNICODE_STRING CompleteName,
277 IN OUT PUNICODE_STRING RemainingName,
278 IN OUT PVOID Context,
279 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
280 OUT PVOID *Object)
281 {
282 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
283 PDEVICE_OBJECT OriginalDeviceObject = (PDEVICE_OBJECT)ParseObject;
284 PDEVICE_OBJECT DeviceObject, OwnerDevice;
285 NTSTATUS Status;
286 PFILE_OBJECT FileObject;
287 PVPB Vpb = NULL;
288 PIRP Irp;
289 PIO_STACK_LOCATION StackLoc;
290 IO_SECURITY_CONTEXT SecurityContext;
291 IO_STATUS_BLOCK IoStatusBlock;
292 BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
293 OBJECT_ATTRIBUTES ObjectAttributes;
294 KIRQL OldIrql;
295 PDUMMY_FILE_OBJECT LocalFileObject;
296 PFILE_BASIC_INFORMATION FileBasicInfo;
297 ULONG ReturnLength;
298 KPROCESSOR_MODE CheckMode;
299 BOOLEAN VolumeOpen = FALSE;
300 ACCESS_MASK DesiredAccess, GrantedAccess;
301 BOOLEAN AccessGranted, LockHeld = FALSE;
302 PPRIVILEGE_SET Privileges = NULL;
303 UNICODE_STRING FileString;
304 USHORT Attempt;
305 IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
306 ParseObject, RemainingName);
307
308 for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt)
309 {
310 /* Assume failure */
311 *Object = NULL;
312
313 /* Validate the open packet */
314 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
315
316 /* Valide reparse point in case we traversed a mountpoint */
317 if (OpenPacket->TraversedMountPoint)
318 {
319 /* This is a reparse point we understand */
320 ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
321
322 /* Make sure we're dealing with correct DO */
323 if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
324 OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
325 OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
326 OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
327 {
328 OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
329 return STATUS_IO_REPARSE_DATA_INVALID;
330 }
331 }
332
333 /* Check if we have a related file object */
334 if (OpenPacket->RelatedFileObject)
335 {
336 /* Use the related file object's device object */
337 OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
338 }
339
340 /* Validate device status */
341 Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
342 if (!NT_SUCCESS(Status))
343 {
344 /* We failed, return status */
345 OpenPacket->FinalStatus = Status;
346 return Status;
347 }
348
349 /* Map the generic mask and set the new mapping in the access state */
350 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
351 &IoFileObjectType->TypeInfo.GenericMapping);
352 RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
353 &IoFileObjectType->TypeInfo.GenericMapping);
354 SeSetAccessStateGenericMapping(AccessState,
355 &IoFileObjectType->TypeInfo.GenericMapping);
356 DesiredAccess = AccessState->RemainingDesiredAccess;
357
358 /* Check what kind of access checks to do */
359 if ((AccessMode != KernelMode) ||
360 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
361 {
362 /* Call is from user-mode or kernel is forcing checks */
363 CheckMode = UserMode;
364 }
365 else
366 {
367 /* Call is from the kernel */
368 CheckMode = KernelMode;
369 }
370
371 /* Check privilege for backup or restore operation */
372 IopCheckBackupRestorePrivilege(AccessState,
373 &OpenPacket->CreateOptions,
374 CheckMode,
375 OpenPacket->Disposition);
376
377 /* Check if we are re-parsing */
378 if (((OpenPacket->Override) && !(RemainingName->Length)) ||
379 (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
380 {
381 /* Get granted access from the last call */
382 DesiredAccess |= AccessState->PreviouslyGrantedAccess;
383 }
384
385 /* Check if this is a volume open */
386 if ((OpenPacket->RelatedFileObject) &&
387 (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
388 !(RemainingName->Length))
389 {
390 /* It is */
391 VolumeOpen = TRUE;
392 }
393
394 /* Now check if we need access checks */
395 if (((AccessMode != KernelMode) ||
396 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
397 (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
398 !(OpenPacket->Override))
399 {
400 KeEnterCriticalRegion();
401 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
402
403 /* Check if a device object is being parsed */
404 if (!RemainingName->Length)
405 {
406 /* Lock the subject context */
407 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
408 LockHeld = TRUE;
409
410 /* Do access check */
411 AccessGranted = SeAccessCheck(OriginalDeviceObject->
412 SecurityDescriptor,
413 &AccessState->SubjectSecurityContext,
414 LockHeld,
415 DesiredAccess,
416 0,
417 &Privileges,
418 &IoFileObjectType->
419 TypeInfo.GenericMapping,
420 UserMode,
421 &GrantedAccess,
422 &Status);
423 if (Privileges)
424 {
425 /* Append and free the privileges */
426 SeAppendPrivileges(AccessState, Privileges);
427 SeFreePrivileges(Privileges);
428 }
429
430 /* Check if we got access */
431 if (AccessGranted)
432 {
433 /* Update access state */
434 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
435 AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
436 MAXIMUM_ALLOWED);
437 OpenPacket->Override= TRUE;
438 }
439
440 FileString.Length = 8;
441 FileString.MaximumLength = 8;
442 FileString.Buffer = L"File";
443
444 /* Do Audit/Alarm for open operation */
445 SeOpenObjectAuditAlarm(&FileString,
446 OriginalDeviceObject,
447 CompleteName,
448 OriginalDeviceObject->SecurityDescriptor,
449 AccessState,
450 FALSE,
451 AccessGranted,
452 UserMode,
453 &AccessState->GenerateOnClose);
454 }
455 else
456 {
457 /* Check if we need to do traverse validation */
458 if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
459 ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
460 (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
461 {
462 /* Check if this is a restricted token */
463 if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
464 {
465 /* Do the FAST traverse check */
466 AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
467 AccessState,
468 FILE_TRAVERSE,
469 UserMode);
470 }
471 else
472 {
473 /* Fail */
474 AccessGranted = FALSE;
475 }
476
477 /* Check if we failed to get access */
478 if (!AccessGranted)
479 {
480 /* Lock the subject context */
481 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
482 LockHeld = TRUE;
483
484 /* Do access check */
485 AccessGranted = SeAccessCheck(OriginalDeviceObject->
486 SecurityDescriptor,
487 &AccessState->SubjectSecurityContext,
488 LockHeld,
489 FILE_TRAVERSE,
490 0,
491 &Privileges,
492 &IoFileObjectType->
493 TypeInfo.GenericMapping,
494 UserMode,
495 &GrantedAccess,
496 &Status);
497 if (Privileges)
498 {
499 /* Append and free the privileges */
500 SeAppendPrivileges(AccessState, Privileges);
501 SeFreePrivileges(Privileges);
502 }
503 }
504
505 /* FIXME: Do Audit/Alarm for traverse check */
506 }
507 else
508 {
509 /* Access automatically granted */
510 AccessGranted = TRUE;
511 }
512 }
513
514 ExReleaseResourceLite(&IopSecurityResource);
515 KeLeaveCriticalRegion();
516
517 /* Check if we hold the lock */
518 if (LockHeld)
519 {
520 /* Release it */
521 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
522 }
523
524 /* Check if access failed */
525 if (!AccessGranted)
526 {
527 /* Dereference the device and fail */
528 DPRINT1("Traverse access failed!\n");
529 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
530 return STATUS_ACCESS_DENIED;
531 }
532 }
533
534 /* Check if we can simply use a dummy file */
535 UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
536
537 #if 1
538 /* FIXME: Small hack still exists, have to check why...
539 * This is triggered multiple times by usetup and then once per boot.
540 */
541 if (ExpInTextModeSetup &&
542 !(DirectOpen) &&
543 !(RemainingName->Length) &&
544 !(OpenPacket->RelatedFileObject) &&
545 ((wcsstr(CompleteName->Buffer, L"Harddisk")) ||
546 (wcsstr(CompleteName->Buffer, L"Floppy"))) &&
547 !(UseDummyFile))
548 {
549 DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
550 DesiredAccess & ~(SYNCHRONIZE |
551 FILE_READ_ATTRIBUTES |
552 READ_CONTROL |
553 ACCESS_SYSTEM_SECURITY |
554 WRITE_OWNER |
555 WRITE_DAC));
556 DirectOpen = TRUE;
557 }
558 #endif
559
560 /* Check if this is a direct open */
561 if (!(RemainingName->Length) &&
562 !(OpenPacket->RelatedFileObject) &&
563 ((DesiredAccess & ~(SYNCHRONIZE |
564 FILE_READ_ATTRIBUTES |
565 READ_CONTROL |
566 ACCESS_SYSTEM_SECURITY |
567 WRITE_OWNER |
568 WRITE_DAC)) == 0) &&
569 !(UseDummyFile))
570 {
571 /* Remember this for later */
572 DirectOpen = TRUE;
573 }
574
575 /* Check if we have a related FO that wasn't a direct open */
576 if ((OpenPacket->RelatedFileObject) &&
577 !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
578 {
579 /* The device object is the one we were given */
580 DeviceObject = ParseObject;
581
582 /* Check if the related FO had a VPB */
583 if (OpenPacket->RelatedFileObject->Vpb)
584 {
585 /* Yes, remember it */
586 Vpb = OpenPacket->RelatedFileObject->Vpb;
587
588 /* Reference it */
589 InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
590
591 /* Check if we were given a specific top level device to use */
592 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
593 {
594 DeviceObject = Vpb->DeviceObject;
595 }
596 }
597 }
598 else
599 {
600 /* Check if it has a VPB */
601 if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
602 {
603 /* Check if the VPB is mounted, and mount it */
604 Vpb = IopCheckVpbMounted(OpenPacket,
605 OriginalDeviceObject,
606 RemainingName,
607 &Status);
608 if (!Vpb) return Status;
609
610 /* Get the VPB's device object */
611 DeviceObject = Vpb->DeviceObject;
612 }
613 else
614 {
615 /* The device object is the one we were given */
616 DeviceObject = OriginalDeviceObject;
617 }
618
619 /* If we weren't given a specific top level device, look for an attached device */
620 if (!(OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT) &&
621 DeviceObject->AttachedDevice)
622 {
623 /* Get the attached device */
624 DeviceObject = IoGetAttachedDevice(DeviceObject);
625 }
626 }
627
628 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
629 {
630 // FIXME: Verify our device object is good to use
631 ASSERT(DirectOpen == FALSE);
632 }
633
634 /* If we traversed a mount point, reset the information */
635 if (OpenPacket->TraversedMountPoint)
636 {
637 OpenPacket->TraversedMountPoint = FALSE;
638 }
639
640 /* Check if this is a secure FSD */
641 if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
642 ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
643 (!VolumeOpen))
644 {
645 Privileges = NULL;
646 GrantedAccess = 0;
647
648 KeEnterCriticalRegion();
649 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
650
651 /* Lock the subject context */
652 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
653
654 /* Do access check */
655 AccessGranted = SeAccessCheck(OriginalDeviceObject->SecurityDescriptor,
656 &AccessState->SubjectSecurityContext,
657 TRUE,
658 DesiredAccess,
659 0,
660 &Privileges,
661 &IoFileObjectType->TypeInfo.GenericMapping,
662 UserMode,
663 &GrantedAccess,
664 &Status);
665 if (Privileges != NULL)
666 {
667 /* Append and free the privileges */
668 SeAppendPrivileges(AccessState, Privileges);
669 SeFreePrivileges(Privileges);
670 }
671
672 /* Check if we got access */
673 if (GrantedAccess)
674 {
675 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
676 AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
677 }
678
679 FileString.Length = 8;
680 FileString.MaximumLength = 8;
681 FileString.Buffer = L"File";
682
683 /* Do Audit/Alarm for open operation
684 * NOTA: we audit target device object
685 */
686 SeOpenObjectAuditAlarm(&FileString,
687 DeviceObject,
688 CompleteName,
689 OriginalDeviceObject->SecurityDescriptor,
690 AccessState,
691 FALSE,
692 AccessGranted,
693 UserMode,
694 &AccessState->GenerateOnClose);
695
696 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
697
698 ExReleaseResourceLite(&IopSecurityResource);
699 KeLeaveCriticalRegion();
700
701 /* Check if access failed */
702 if (!AccessGranted)
703 {
704 /* Dereference the device and fail */
705 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
706 if (Vpb) IopDereferenceVpbAndFree(Vpb);
707 return STATUS_ACCESS_DENIED;
708 }
709 }
710
711 /* Allocate the IRP */
712 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
713 if (!Irp)
714 {
715 /* Dereference the device and VPB, then fail */
716 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
717 if (Vpb) IopDereferenceVpbAndFree(Vpb);
718 return STATUS_INSUFFICIENT_RESOURCES;
719 }
720
721 /* Now set the IRP data */
722 Irp->RequestorMode = AccessMode;
723 Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
724 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
725 Irp->UserIosb = &IoStatusBlock;
726 Irp->MdlAddress = NULL;
727 Irp->PendingReturned = FALSE;
728 Irp->UserEvent = NULL;
729 Irp->Cancel = FALSE;
730 Irp->CancelRoutine = NULL;
731 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
732
733 /* Setup the security context */
734 SecurityContext.SecurityQos = SecurityQos;
735 SecurityContext.AccessState = AccessState;
736 SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
737 SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
738
739 /* Get the I/O Stack location */
740 StackLoc = IoGetNextIrpStackLocation(Irp);
741 StackLoc->Control = 0;
742
743 /* Check what kind of file this is */
744 switch (OpenPacket->CreateFileType)
745 {
746 /* Normal file */
747 case CreateFileTypeNone:
748
749 /* Set the major function and EA Length */
750 StackLoc->MajorFunction = IRP_MJ_CREATE;
751 StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
752
753 /* Set the flags */
754 StackLoc->Flags = (UCHAR)OpenPacket->Options;
755 StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
756 break;
757
758 /* Named pipe */
759 case CreateFileTypeNamedPipe:
760
761 /* Set the named pipe MJ and set the parameters */
762 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
763 StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
764 break;
765
766 /* Mailslot */
767 case CreateFileTypeMailslot:
768
769 /* Set the mailslot MJ and set the parameters */
770 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
771 StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
772 break;
773 }
774
775 /* Set the common data */
776 Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
777 Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
778 StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
779 (OpenPacket->CreateOptions &
780 0xFFFFFF);
781 StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
782 StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
783 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
784
785 /* Check if we really need to create an object */
786 if (!UseDummyFile)
787 {
788 ULONG ObjectSize = sizeof(FILE_OBJECT);
789
790 /* Tag on space for a file object extension */
791 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
792 ObjectSize += sizeof(FILE_OBJECT_EXTENSION);
793
794 /* Create the actual file object */
795 InitializeObjectAttributes(&ObjectAttributes,
796 NULL,
797 Attributes,
798 NULL,
799 NULL);
800 Status = ObCreateObject(KernelMode,
801 IoFileObjectType,
802 &ObjectAttributes,
803 AccessMode,
804 NULL,
805 ObjectSize,
806 0,
807 0,
808 (PVOID*)&FileObject);
809 if (!NT_SUCCESS(Status))
810 {
811 /* Create failed, free the IRP */
812 IoFreeIrp(Irp);
813
814 /* Dereference the device and VPB */
815 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
816 if (Vpb) IopDereferenceVpbAndFree(Vpb);
817
818 /* We failed, return status */
819 OpenPacket->FinalStatus = Status;
820 return Status;
821 }
822
823 /* Clear the file object */
824 RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
825
826 /* Check if this is Synch I/O */
827 if (OpenPacket->CreateOptions &
828 (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
829 {
830 /* Set the synch flag */
831 FileObject->Flags |= FO_SYNCHRONOUS_IO;
832
833 /* Check if it's also alertable */
834 if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
835 {
836 /* It is, set the alertable flag */
837 FileObject->Flags |= FO_ALERTABLE_IO;
838 }
839 }
840
841 /* Check if this is synch I/O */
842 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
843 {
844 /* Initialize the event */
845 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
846 }
847
848 /* Check if the caller requested no intermediate buffering */
849 if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
850 {
851 /* Set the correct flag for the FSD to read */
852 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
853 }
854
855 /* Check if the caller requested write through support */
856 if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
857 {
858 /* Set the correct flag for the FSD to read */
859 FileObject->Flags |= FO_WRITE_THROUGH;
860 }
861
862 /* Check if the caller says the file will be only read sequentially */
863 if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
864 {
865 /* Set the correct flag for the FSD to read */
866 FileObject->Flags |= FO_SEQUENTIAL_ONLY;
867 }
868
869 /* Check if the caller believes the file will be only read randomly */
870 if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
871 {
872 /* Set the correct flag for the FSD to read */
873 FileObject->Flags |= FO_RANDOM_ACCESS;
874 }
875
876 /* Check if we were asked to setup a file object extension */
877 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
878 {
879 PFILE_OBJECT_EXTENSION FileObjectExtension;
880
881 /* Make sure the file object knows it has an extension */
882 FileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
883
884 FileObjectExtension = (PFILE_OBJECT_EXTENSION)(FileObject + 1);
885 FileObject->FileObjectExtension = FileObjectExtension;
886
887 /* Add the top level device which we'll send the request to */
888 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
889 {
890 FileObjectExtension->TopDeviceObjectHint = DeviceObject;
891 }
892 }
893 }
894 else
895 {
896 /* Use the dummy object instead */
897 LocalFileObject = OpenPacket->LocalFileObject;
898 RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
899
900 /* Set it up */
901 FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
902 LocalFileObject->ObjectHeader.Type = IoFileObjectType;
903 LocalFileObject->ObjectHeader.PointerCount = 1;
904 }
905
906 /* Setup the file header */
907 FileObject->Type = IO_TYPE_FILE;
908 FileObject->Size = sizeof(FILE_OBJECT);
909 FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
910 FileObject->DeviceObject = OriginalDeviceObject;
911
912 /* Check if this is a direct device open */
913 if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
914
915 /* Check if the caller wants case sensitivity */
916 if (!(Attributes & OBJ_CASE_INSENSITIVE))
917 {
918 /* Tell the driver about it */
919 FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
920 }
921
922 /* Now set the file object */
923 Irp->Tail.Overlay.OriginalFileObject = FileObject;
924 StackLoc->FileObject = FileObject;
925
926 /* Check if the file object has a name */
927 if (RemainingName->Length)
928 {
929 /* Setup the unicode string */
930 FileObject->FileName.MaximumLength = RemainingName->Length +
931 sizeof(WCHAR);
932 FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
933 FileObject->
934 FileName.
935 MaximumLength,
936 TAG_IO_NAME);
937 if (!FileObject->FileName.Buffer)
938 {
939 /* Failed to allocate the name, free the IRP */
940 IoFreeIrp(Irp);
941
942 /* Dereference the device object and VPB */
943 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
944 if (Vpb) IopDereferenceVpbAndFree(Vpb);
945
946 /* Clear the FO and dereference it */
947 FileObject->DeviceObject = NULL;
948 if (!UseDummyFile) ObDereferenceObject(FileObject);
949
950 /* Fail */
951 return STATUS_INSUFFICIENT_RESOURCES;
952 }
953 }
954
955 /* Copy the name */
956 RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
957
958 /* Initialize the File Object event and set the FO */
959 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
960 OpenPacket->FileObject = FileObject;
961
962 /* Queue the IRP and call the driver */
963 IopQueueIrpToThread(Irp);
964 Status = IoCallDriver(DeviceObject, Irp);
965 if (Status == STATUS_PENDING)
966 {
967 /* Wait for the driver to complete the create */
968 KeWaitForSingleObject(&FileObject->Event,
969 Executive,
970 KernelMode,
971 FALSE,
972 NULL);
973
974 /* Get the new status */
975 Status = IoStatusBlock.Status;
976 }
977 else
978 {
979 /* We'll have to complete it ourselves */
980 ASSERT(!Irp->PendingReturned);
981 ASSERT(!Irp->MdlAddress);
982
983 /* Handle name change if required */
984 if (Status == STATUS_REPARSE)
985 {
986 /* Check this is a mount point */
987 if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
988 {
989 PREPARSE_DATA_BUFFER ReparseData;
990
991 /* Reparse point attributes were passed by the driver in the auxiliary buffer */
992 ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
993 ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
994
995 ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
996 ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
997 ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
998
999 IopDoNameTransmogrify(Irp, FileObject, ReparseData);
1000 }
1001 }
1002
1003 /* Completion happens at APC_LEVEL */
1004 KeRaiseIrql(APC_LEVEL, &OldIrql);
1005
1006 /* Get the new I/O Status block ourselves */
1007 IoStatusBlock = Irp->IoStatus;
1008 Status = IoStatusBlock.Status;
1009
1010 /* Manually signal the even, we can't have any waiters */
1011 FileObject->Event.Header.SignalState = 1;
1012
1013 /* Now that we've signaled the events, de-associate the IRP */
1014 IopUnQueueIrpFromThread(Irp);
1015
1016 /* Check if the IRP had an input buffer */
1017 if ((Irp->Flags & IRP_BUFFERED_IO) &&
1018 (Irp->Flags & IRP_DEALLOCATE_BUFFER))
1019 {
1020 /* Free it. A driver might've tacked one on */
1021 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
1022 }
1023
1024 /* Free the IRP and bring the IRQL back down */
1025 IoFreeIrp(Irp);
1026 KeLowerIrql(OldIrql);
1027 }
1028
1029 /* Copy the I/O Status */
1030 OpenPacket->Information = IoStatusBlock.Information;
1031
1032 /* The driver failed to create the file */
1033 if (!NT_SUCCESS(Status))
1034 {
1035 /* Check if we have a name */
1036 if (FileObject->FileName.Length)
1037 {
1038 /* Free it */
1039 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1040 FileObject->FileName.Length = 0;
1041 }
1042
1043 /* Clear its device object */
1044 FileObject->DeviceObject = NULL;
1045
1046 /* Save this now because the FO might go away */
1047 OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
1048 TRUE : FALSE;
1049
1050 /* Clear the file object in the open packet */
1051 OpenPacket->FileObject = NULL;
1052
1053 /* Dereference the file object */
1054 if (!UseDummyFile) ObDereferenceObject(FileObject);
1055
1056 /* Dereference the device object */
1057 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1058
1059 /* Unless the driver cancelled the open, dereference the VPB */
1060 if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
1061
1062 /* Set the status and return */
1063 OpenPacket->FinalStatus = Status;
1064 return Status;
1065 }
1066 else if (Status == STATUS_REPARSE)
1067 {
1068 if (OpenPacket->Information == IO_REPARSE ||
1069 OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1070 {
1071 /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
1072 if (CompleteName->MaximumLength < FileObject->FileName.Length)
1073 {
1074 PWSTR NewCompleteName;
1075
1076 /* Allocate a new buffer for the string */
1077 NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
1078 if (NewCompleteName == NULL)
1079 {
1080 OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
1081 return STATUS_INSUFFICIENT_RESOURCES;
1082 }
1083
1084 /* Release the old one */
1085 if (CompleteName->Buffer != NULL)
1086 {
1087 ExFreePoolWithTag(CompleteName->Buffer, 0);
1088 }
1089
1090 /* And setup the new one */
1091 CompleteName->Buffer = NewCompleteName;
1092 CompleteName->MaximumLength = FileObject->FileName.Length;
1093 }
1094
1095 /* Copy our new complete name */
1096 RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
1097
1098 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1099 {
1100 OpenPacket->RelatedFileObject = NULL;
1101 }
1102 }
1103
1104 /* Check if we have a name */
1105 if (FileObject->FileName.Length)
1106 {
1107 /* Free it */
1108 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1109 FileObject->FileName.Length = 0;
1110 }
1111
1112 /* Clear its device object */
1113 FileObject->DeviceObject = NULL;
1114
1115 /* Clear the file object in the open packet */
1116 OpenPacket->FileObject = NULL;
1117
1118 /* Dereference the file object */
1119 if (!UseDummyFile) ObDereferenceObject(FileObject);
1120
1121 /* Dereference the device object */
1122 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1123
1124 /* Unless the driver cancelled the open, dereference the VPB */
1125 if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
1126
1127 if (OpenPacket->Information != IO_REMOUNT)
1128 {
1129 OpenPacket->RelatedFileObject = NULL;
1130
1131 /* Inform we traversed a mount point for later attempt */
1132 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1133 {
1134 OpenPacket->TraversedMountPoint = 1;
1135 }
1136
1137 /* In case we override checks, but got this on volume open, fail hard */
1138 if (OpenPacket->Override)
1139 {
1140 KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
1141 (ULONG_PTR)OriginalDeviceObject,
1142 (ULONG_PTR)DeviceObject,
1143 (ULONG_PTR)CompleteName,
1144 OpenPacket->Information);
1145 }
1146
1147 /* Return to IO/OB so that information can be upgraded */
1148 return STATUS_REPARSE;
1149 }
1150
1151 /* Loop again and reattempt an opening */
1152 continue;
1153 }
1154
1155 break;
1156 }
1157
1158 if (Attempt == IOP_MAX_REPARSE_TRAVERSAL)
1159 return STATUS_UNSUCCESSFUL;
1160
1161 /* Get the owner of the File Object */
1162 OwnerDevice = IoGetRelatedDeviceObject(FileObject);
1163
1164 /*
1165 * It's possible that the device to whom we sent the IRP to
1166 * isn't actually the device that ended opening the file object
1167 * internally.
1168 */
1169 if (OwnerDevice != DeviceObject)
1170 {
1171 /* We have to de-reference the VPB we had associated */
1172 if (Vpb) IopDereferenceVpbAndFree(Vpb);
1173
1174 /* And re-associate with the actual one */
1175 Vpb = FileObject->Vpb;
1176 if (Vpb) InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
1177 }
1178
1179 /* Make sure we are not using a dummy */
1180 if (!UseDummyFile)
1181 {
1182 /* Check if this was a volume open */
1183 if ((!(FileObject->RelatedFileObject) ||
1184 (FileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN)) &&
1185 !(FileObject->FileName.Length))
1186 {
1187 /* All signs point to it, but make sure it was actually an FSD */
1188 if ((OwnerDevice->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1189 (OwnerDevice->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
1190 (OwnerDevice->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) ||
1191 (OwnerDevice->DeviceType == FILE_DEVICE_FILE_SYSTEM))
1192 {
1193 /* The owner device is an FSD, so this is a volume open for real */
1194 FileObject->Flags |= FO_VOLUME_OPEN;
1195 }
1196 }
1197
1198 /* Reference the object and set the parse check */
1199 ObReferenceObject(FileObject);
1200 *Object = FileObject;
1201 OpenPacket->FinalStatus = IoStatusBlock.Status;
1202 OpenPacket->ParseCheck = TRUE;
1203 return OpenPacket->FinalStatus;
1204 }
1205 else
1206 {
1207 /* Check if this was a query */
1208 if (OpenPacket->QueryOnly)
1209 {
1210 /* Check if the caller wants basic info only */
1211 if (!OpenPacket->FullAttributes)
1212 {
1213 /* Allocate the buffer */
1214 FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool,
1215 sizeof(*FileBasicInfo),
1216 TAG_IO);
1217 if (FileBasicInfo)
1218 {
1219 /* Do the query */
1220 Status = IoQueryFileInformation(FileObject,
1221 FileBasicInformation,
1222 sizeof(*FileBasicInfo),
1223 FileBasicInfo,
1224 &ReturnLength);
1225 if (NT_SUCCESS(Status))
1226 {
1227 /* Copy the data */
1228 RtlCopyMemory(OpenPacket->BasicInformation,
1229 FileBasicInfo,
1230 ReturnLength);
1231 }
1232
1233 /* Free our buffer */
1234 ExFreePoolWithTag(FileBasicInfo, TAG_IO);
1235 }
1236 else
1237 {
1238 /* Fail */
1239 Status = STATUS_INSUFFICIENT_RESOURCES;
1240 }
1241 }
1242 else
1243 {
1244 /* This is a full query */
1245 Status = IoQueryFileInformation(
1246 FileObject,
1247 FileNetworkOpenInformation,
1248 sizeof(FILE_NETWORK_OPEN_INFORMATION),
1249 OpenPacket->NetworkInformation,
1250 &ReturnLength);
1251 if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED);
1252 }
1253 }
1254
1255 /* Delete the file object */
1256 IopDeleteFile(FileObject);
1257
1258 /* Clear out the file */
1259 OpenPacket->FileObject = NULL;
1260
1261 /* Set and return status */
1262 OpenPacket->FinalStatus = Status;
1263 OpenPacket->ParseCheck = TRUE;
1264 return Status;
1265 }
1266 }
1267
1268 NTSTATUS
1269 NTAPI
1270 IopParseFile(IN PVOID ParseObject,
1271 IN PVOID ObjectType,
1272 IN OUT PACCESS_STATE AccessState,
1273 IN KPROCESSOR_MODE AccessMode,
1274 IN ULONG Attributes,
1275 IN OUT PUNICODE_STRING CompleteName,
1276 IN OUT PUNICODE_STRING RemainingName,
1277 IN OUT PVOID Context OPTIONAL,
1278 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
1279 OUT PVOID *Object)
1280 {
1281 PVOID DeviceObject;
1282 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
1283
1284 /* Validate the open packet */
1285 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
1286
1287 /* Get the device object */
1288 DeviceObject = IoGetRelatedDeviceObject(ParseObject);
1289 OpenPacket->RelatedFileObject = ParseObject;
1290
1291 /* Call the main routine */
1292 return IopParseDevice(DeviceObject,
1293 ObjectType,
1294 AccessState,
1295 AccessMode,
1296 Attributes,
1297 CompleteName,
1298 RemainingName,
1299 OpenPacket,
1300 SecurityQos,
1301 Object);
1302 }
1303
1304 VOID
1305 NTAPI
1306 IopDeleteFile(IN PVOID ObjectBody)
1307 {
1308 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1309 PIRP Irp;
1310 PIO_STACK_LOCATION StackPtr;
1311 NTSTATUS Status;
1312 KEVENT Event;
1313 PDEVICE_OBJECT DeviceObject;
1314 BOOLEAN DereferenceDone = FALSE;
1315 PVPB Vpb;
1316 KIRQL OldIrql;
1317 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1318
1319 /* Check if the file has a device object */
1320 if (FileObject->DeviceObject)
1321 {
1322 /* Check if this is a direct open or not */
1323 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1324 {
1325 /* Get the attached device */
1326 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1327 }
1328 else
1329 {
1330 /* Use the file object's device object */
1331 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1332 }
1333
1334 /* Sanity check */
1335 ASSERT(!(FileObject->Flags & FO_SYNCHRONOUS_IO) ||
1336 (InterlockedExchange((PLONG)&FileObject->Busy, TRUE) == FALSE));
1337
1338 /* Check if the handle wasn't created yet */
1339 if (!(FileObject->Flags & FO_HANDLE_CREATED))
1340 {
1341 /* Send the cleanup IRP */
1342 IopCloseFile(NULL, ObjectBody, 0, 1, 1);
1343 }
1344
1345 /* Clear and set up Events */
1346 KeClearEvent(&FileObject->Event);
1347 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1348
1349 /* Allocate an IRP */
1350 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
1351
1352 /* Set it up */
1353 Irp->UserEvent = &Event;
1354 Irp->UserIosb = &Irp->IoStatus;
1355 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1356 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1357 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1358
1359 /* Set up Stack Pointer Data */
1360 StackPtr = IoGetNextIrpStackLocation(Irp);
1361 StackPtr->MajorFunction = IRP_MJ_CLOSE;
1362 StackPtr->FileObject = FileObject;
1363
1364 /* Queue the IRP */
1365 IopQueueIrpToThread(Irp);
1366
1367 /* Get the VPB and check if this isn't a direct open */
1368 Vpb = FileObject->Vpb;
1369 if ((Vpb) && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1370 {
1371 /* Dereference the VPB before the close */
1372 InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
1373 }
1374
1375 /* Check if the FS will never disappear by itself */
1376 if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
1377 {
1378 /* Dereference it */
1379 InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
1380 DereferenceDone = TRUE;
1381 }
1382
1383 /* Call the FS Driver */
1384 Status = IoCallDriver(DeviceObject, Irp);
1385 if (Status == STATUS_PENDING)
1386 {
1387 /* Wait for completion */
1388 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1389 }
1390
1391 /* De-queue the IRP */
1392 KeRaiseIrql(APC_LEVEL, &OldIrql);
1393 IopUnQueueIrpFromThread(Irp);
1394 KeLowerIrql(OldIrql);
1395
1396 /* Free the IRP */
1397 IoFreeIrp(Irp);
1398
1399 /* Clear the file name */
1400 if (FileObject->FileName.Buffer)
1401 {
1402 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1403 FileObject->FileName.Buffer = NULL;
1404 }
1405
1406 /* Check if the FO had a completion port */
1407 if (FileObject->CompletionContext)
1408 {
1409 /* Free it */
1410 ObDereferenceObject(FileObject->CompletionContext->Port);
1411 ExFreePool(FileObject->CompletionContext);
1412 }
1413
1414 /* Check if the FO had extension */
1415 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1416 {
1417 /* Release filter context structure if any */
1418 FsRtlPTeardownPerFileObjectContexts(FileObject);
1419 }
1420
1421 /* Check if dereference has been done yet */
1422 if (!DereferenceDone)
1423 {
1424 /* Dereference device object */
1425 IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
1426 }
1427 }
1428 }
1429
1430 PDEVICE_OBJECT
1431 NTAPI
1432 IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)
1433 {
1434 PDEVICE_OBJECT PDO = DeviceObject;
1435
1436 /* Go down the stack to attempt to get the PDO */
1437 for (; ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo != NULL;
1438 PDO = ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo);
1439
1440 return PDO;
1441 }
1442
1443 PDEVICE_OBJECT
1444 NTAPI
1445 IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)
1446 {
1447 KIRQL OldIrql;
1448 PDEVICE_OBJECT PDO;
1449
1450 ASSERT(DeviceObject != NULL);
1451
1452 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1453 /* Get the base DO */
1454 PDO = IopGetDeviceAttachmentBase(DeviceObject);
1455 /* Check whether that's really a PDO and if so, keep it */
1456 if ((PDO->Flags & DO_BUS_ENUMERATED_DEVICE) != DO_BUS_ENUMERATED_DEVICE)
1457 {
1458 PDO = NULL;
1459 }
1460 else
1461 {
1462 ObReferenceObject(PDO);
1463 }
1464 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1465
1466 return PDO;
1467 }
1468
1469 NTSTATUS
1470 NTAPI
1471 IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,
1472 IN PSECURITY_INFORMATION SecurityInformation,
1473 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1474 IN POOL_TYPE PoolType,
1475 IN PGENERIC_MAPPING GenericMapping)
1476 {
1477 NTSTATUS Status;
1478 PSECURITY_DESCRIPTOR OldSecurityDescriptor, CachedSecurityDescriptor, NewSecurityDescriptor;
1479
1480 PAGED_CODE();
1481
1482 /* Keep attempting till we find our old SD or fail */
1483 while (TRUE)
1484 {
1485 KeEnterCriticalRegion();
1486 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
1487
1488 /* Get our old SD and reference it */
1489 OldSecurityDescriptor = DeviceObject->SecurityDescriptor;
1490 if (OldSecurityDescriptor != NULL)
1491 {
1492 ObReferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1493 }
1494
1495 ExReleaseResourceLite(&IopSecurityResource);
1496 KeLeaveCriticalRegion();
1497
1498 /* Set the SD information */
1499 NewSecurityDescriptor = OldSecurityDescriptor;
1500 Status = SeSetSecurityDescriptorInfo(NULL, SecurityInformation,
1501 SecurityDescriptor, &NewSecurityDescriptor,
1502 PoolType, GenericMapping);
1503
1504 if (!NT_SUCCESS(Status))
1505 {
1506 if (OldSecurityDescriptor != NULL)
1507 {
1508 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1509 }
1510
1511 break;
1512 }
1513
1514 /* Add the new DS to the internal cache */
1515 Status = ObLogSecurityDescriptor(NewSecurityDescriptor,
1516 &CachedSecurityDescriptor, 1);
1517 ExFreePool(NewSecurityDescriptor);
1518 if (!NT_SUCCESS(Status))
1519 {
1520 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1521 break;
1522 }
1523
1524 KeEnterCriticalRegion();
1525 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1526 /* Check if someone changed it in our back */
1527 if (DeviceObject->SecurityDescriptor == OldSecurityDescriptor)
1528 {
1529 /* We're clear, do the swap */
1530 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1531 ExReleaseResourceLite(&IopSecurityResource);
1532 KeLeaveCriticalRegion();
1533
1534 /* And dereference old SD (twice - us + not in use) */
1535 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 2);
1536
1537 break;
1538 }
1539 ExReleaseResourceLite(&IopSecurityResource);
1540 KeLeaveCriticalRegion();
1541
1542 /* If so, try again */
1543 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1544 ObDereferenceSecurityDescriptor(CachedSecurityDescriptor, 1);
1545 }
1546
1547 return Status;
1548 }
1549
1550 NTSTATUS
1551 NTAPI
1552 IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,
1553 IN PDEVICE_OBJECT PhysicalDeviceObject,
1554 IN PSECURITY_INFORMATION SecurityInformation,
1555 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1556 IN POOL_TYPE PoolType,
1557 IN PGENERIC_MAPPING GenericMapping)
1558 {
1559 PDEVICE_OBJECT CurrentDO = PhysicalDeviceObject, NextDevice;
1560 NTSTATUS Status = STATUS_SUCCESS, TmpStatus;
1561
1562 PAGED_CODE();
1563
1564 ASSERT(PhysicalDeviceObject != NULL);
1565
1566 /* We always reference the DO we're working on */
1567 ObReferenceObject(CurrentDO);
1568
1569 /* Go up from PDO to latest DO */
1570 do
1571 {
1572 /* Attempt to set the new SD on it */
1573 TmpStatus = IopSetDeviceSecurityDescriptor(CurrentDO, SecurityInformation,
1574 SecurityDescriptor, PoolType,
1575 GenericMapping);
1576 /* Was our last one? Remember that status then */
1577 if (CurrentDO == UpperDeviceObject)
1578 {
1579 Status = TmpStatus;
1580 }
1581
1582 /* Try to move to the next DO (and thus, reference it) */
1583 NextDevice = CurrentDO->AttachedDevice;
1584 if (NextDevice)
1585 {
1586 ObReferenceObject(NextDevice);
1587 }
1588
1589 /* Dereference current DO and move to the next one */
1590 ObDereferenceObject(CurrentDO);
1591 CurrentDO = NextDevice;
1592 }
1593 while (CurrentDO != NULL);
1594
1595 return Status;
1596 }
1597
1598 NTSTATUS
1599 NTAPI
1600 IopGetSetSecurityObject(IN PVOID ObjectBody,
1601 IN SECURITY_OPERATION_CODE OperationCode,
1602 IN PSECURITY_INFORMATION SecurityInformation,
1603 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1604 IN OUT PULONG BufferLength,
1605 IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
1606 IN POOL_TYPE PoolType,
1607 IN OUT PGENERIC_MAPPING GenericMapping)
1608 {
1609 IO_STATUS_BLOCK IoStatusBlock;
1610 PIO_STACK_LOCATION StackPtr;
1611 PFILE_OBJECT FileObject;
1612 PDEVICE_OBJECT DeviceObject;
1613 PIRP Irp;
1614 BOOLEAN LocalEvent = FALSE;
1615 KEVENT Event;
1616 NTSTATUS Status = STATUS_SUCCESS;
1617 PAGED_CODE();
1618 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1619
1620 /* Check if this is a device or file */
1621 if (((PFILE_OBJECT)ObjectBody)->Type == IO_TYPE_DEVICE)
1622 {
1623 /* It's a device */
1624 DeviceObject = (PDEVICE_OBJECT)ObjectBody;
1625 FileObject = NULL;
1626 }
1627 else
1628 {
1629 /* It's a file */
1630 FileObject = (PFILE_OBJECT)ObjectBody;
1631
1632 /* Check if this is a direct open */
1633 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1634 {
1635 /* Get the Device Object */
1636 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1637 }
1638 else
1639 {
1640 /* Otherwise, use the direct device*/
1641 DeviceObject = FileObject->DeviceObject;
1642 }
1643 }
1644
1645 /* Check if the request was for a device object */
1646 if (!(FileObject) ||
1647 (!(FileObject->FileName.Length) && !(FileObject->RelatedFileObject)) ||
1648 (FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1649 {
1650 /* Check what kind of request this was */
1651 if (OperationCode == QuerySecurityDescriptor)
1652 {
1653 return SeQuerySecurityDescriptorInfo(SecurityInformation,
1654 SecurityDescriptor,
1655 BufferLength,
1656 &DeviceObject->SecurityDescriptor);
1657 }
1658 else if (OperationCode == DeleteSecurityDescriptor)
1659 {
1660 /* Simply return success */
1661 return STATUS_SUCCESS;
1662 }
1663 else if (OperationCode == AssignSecurityDescriptor)
1664 {
1665 Status = STATUS_SUCCESS;
1666
1667 /* Make absolutely sure this is a device object */
1668 if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
1669 {
1670 PSECURITY_DESCRIPTOR CachedSecurityDescriptor;
1671
1672 /* Add the security descriptor in cache */
1673 Status = ObLogSecurityDescriptor(SecurityDescriptor, &CachedSecurityDescriptor, 1);
1674 if (NT_SUCCESS(Status))
1675 {
1676 KeEnterCriticalRegion();
1677 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1678
1679 /* Assign the Security Descriptor */
1680 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1681
1682 ExReleaseResourceLite(&IopSecurityResource);
1683 KeLeaveCriticalRegion();
1684 }
1685 }
1686
1687 /* Return status */
1688 return Status;
1689 }
1690 else if (OperationCode == SetSecurityDescriptor)
1691 {
1692 /* Get the Physical Device Object if any */
1693 PDEVICE_OBJECT PDO = IopGetDevicePDO(DeviceObject);
1694
1695 if (PDO != NULL)
1696 {
1697 /* Apply the new SD to any DO in the path from PDO to current DO */
1698 Status = IopSetDeviceSecurityDescriptors(DeviceObject, PDO,
1699 SecurityInformation,
1700 SecurityDescriptor,
1701 PoolType, GenericMapping);
1702 ObDereferenceObject(PDO);
1703 }
1704 else
1705 {
1706 /* Otherwise, just set for ourselves */
1707 Status = IopSetDeviceSecurityDescriptor(DeviceObject,
1708 SecurityInformation,
1709 SecurityDescriptor,
1710 PoolType, GenericMapping);
1711 }
1712
1713 return STATUS_SUCCESS;
1714 }
1715
1716 /* Shouldn't happen */
1717 return STATUS_SUCCESS;
1718 }
1719 else if (OperationCode == DeleteSecurityDescriptor)
1720 {
1721 /* Same as for devices, do nothing */
1722 return STATUS_SUCCESS;
1723 }
1724
1725 /* At this point, we know we're a file. Reference it */
1726 ObReferenceObject(FileObject);
1727
1728 /* Check if we should use Sync IO or not */
1729 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1730 {
1731 /* Lock the file object */
1732 Status = IopLockFileObject(FileObject, ExGetPreviousMode());
1733 if (Status != STATUS_SUCCESS)
1734 {
1735 ObDereferenceObject(FileObject);
1736 return Status;
1737 }
1738 }
1739 else
1740 {
1741 /* Use local event */
1742 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1743 LocalEvent = TRUE;
1744 }
1745
1746 /* Clear the File Object event */
1747 KeClearEvent(&FileObject->Event);
1748
1749 /* Get the device object */
1750 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1751
1752 /* Allocate the IRP */
1753 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1754 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1755
1756 /* Set the IRP */
1757 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1758 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1759 Irp->RequestorMode = ExGetPreviousMode();
1760 Irp->UserIosb = &IoStatusBlock;
1761 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1762 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1763 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1764
1765 /* Set Stack Parameters */
1766 StackPtr = IoGetNextIrpStackLocation(Irp);
1767 StackPtr->FileObject = FileObject;
1768
1769 /* Check if this is a query or set */
1770 if (OperationCode == QuerySecurityDescriptor)
1771 {
1772 /* Set the major function and parameters */
1773 StackPtr->MajorFunction = IRP_MJ_QUERY_SECURITY;
1774 StackPtr->Parameters.QuerySecurity.SecurityInformation =
1775 *SecurityInformation;
1776 StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
1777 Irp->UserBuffer = SecurityDescriptor;
1778 }
1779 else
1780 {
1781 /* Set the major function and parameters for a set */
1782 StackPtr->MajorFunction = IRP_MJ_SET_SECURITY;
1783 StackPtr->Parameters.SetSecurity.SecurityInformation =
1784 *SecurityInformation;
1785 StackPtr->Parameters.SetSecurity.SecurityDescriptor =
1786 SecurityDescriptor;
1787 }
1788
1789 /* Queue the IRP */
1790 IopQueueIrpToThread(Irp);
1791
1792 /* Update operation counts */
1793 IopUpdateOperationCount(IopOtherTransfer);
1794
1795 /* Call the Driver */
1796 Status = IoCallDriver(DeviceObject, Irp);
1797
1798 /* Check if this was async I/O */
1799 if (LocalEvent)
1800 {
1801 /* Check if the IRP is pending completion */
1802 if (Status == STATUS_PENDING)
1803 {
1804 /* Wait on the local event */
1805 KeWaitForSingleObject(&Event,
1806 Executive,
1807 KernelMode,
1808 FALSE,
1809 NULL);
1810 Status = IoStatusBlock.Status;
1811 }
1812 }
1813 else
1814 {
1815 /* Check if the IRP is pending completion */
1816 if (Status == STATUS_PENDING)
1817 {
1818 /* Wait on the file object */
1819 KeWaitForSingleObject(&FileObject->Event,
1820 Executive,
1821 KernelMode,
1822 FALSE,
1823 NULL);
1824 Status = FileObject->FinalStatus;
1825 }
1826
1827 /* Release the lock */
1828 IopUnlockFileObject(FileObject);
1829 }
1830
1831 /* This Driver doesn't implement Security, so try to give it a default */
1832 if (Status == STATUS_INVALID_DEVICE_REQUEST)
1833 {
1834 /* Was this a query? */
1835 if (OperationCode == QuerySecurityDescriptor)
1836 {
1837 /* Set a World Security Descriptor */
1838 Status = SeSetWorldSecurityDescriptor(*SecurityInformation,
1839 SecurityDescriptor,
1840 BufferLength);
1841 }
1842 else
1843 {
1844 /* It wasn't a query, so just fake success */
1845 Status = STATUS_SUCCESS;
1846 }
1847 }
1848 else if (OperationCode == QuerySecurityDescriptor)
1849 {
1850 /* Callers usually expect the normalized form */
1851 if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_BUFFER_TOO_SMALL;
1852
1853 _SEH2_TRY
1854 {
1855 /* Return length */
1856 *BufferLength = (ULONG)IoStatusBlock.Information;
1857 }
1858 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1859 {
1860 /* Get the exception code */
1861 Status = _SEH2_GetExceptionCode();
1862 }
1863 _SEH2_END;
1864 }
1865
1866 /* Return Status */
1867 return Status;
1868 }
1869
1870 NTSTATUS
1871 NTAPI
1872 IopQueryName(IN PVOID ObjectBody,
1873 IN BOOLEAN HasName,
1874 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1875 IN ULONG Length,
1876 OUT PULONG ReturnLength,
1877 IN KPROCESSOR_MODE PreviousMode)
1878 {
1879 return IopQueryNameInternal(ObjectBody,
1880 HasName,
1881 FALSE,
1882 ObjectNameInfo,
1883 Length,
1884 ReturnLength,
1885 PreviousMode);
1886 }
1887
1888 NTSTATUS
1889 NTAPI
1890 IopQueryNameInternal(IN PVOID ObjectBody,
1891 IN BOOLEAN HasName,
1892 IN BOOLEAN QueryDosName,
1893 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1894 IN ULONG Length,
1895 OUT PULONG ReturnLength,
1896 IN KPROCESSOR_MODE PreviousMode)
1897 {
1898 POBJECT_NAME_INFORMATION LocalInfo;
1899 PFILE_NAME_INFORMATION LocalFileInfo;
1900 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1901 ULONG LocalReturnLength, FileLength;
1902 BOOLEAN LengthMismatch = FALSE;
1903 NTSTATUS Status;
1904 PWCHAR p;
1905 PDEVICE_OBJECT DeviceObject;
1906 BOOLEAN NoObCall;
1907
1908 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1909
1910 /* Validate length */
1911 if (Length < sizeof(OBJECT_NAME_INFORMATION))
1912 {
1913 /* Wrong length, fail */
1914 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1915 return STATUS_INFO_LENGTH_MISMATCH;
1916 }
1917
1918 /* Allocate Buffer */
1919 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
1920 if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
1921
1922 /* Query DOS name if the caller asked to */
1923 NoObCall = FALSE;
1924 if (QueryDosName)
1925 {
1926 DeviceObject = FileObject->DeviceObject;
1927
1928 /* In case of a network file system, don't call mountmgr */
1929 if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
1930 {
1931 /* We'll store separator and terminator */
1932 LocalReturnLength = sizeof(OBJECT_NAME_INFORMATION) + 2 * sizeof(WCHAR);
1933 if (Length < LocalReturnLength)
1934 {
1935 Status = STATUS_BUFFER_OVERFLOW;
1936 }
1937 else
1938 {
1939 LocalInfo->Name.Length = sizeof(WCHAR);
1940 LocalInfo->Name.MaximumLength = sizeof(WCHAR);
1941 LocalInfo->Name.Buffer = (PVOID)((ULONG_PTR)LocalInfo + sizeof(OBJECT_NAME_INFORMATION));
1942 LocalInfo->Name.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
1943 Status = STATUS_SUCCESS;
1944 }
1945 }
1946 /* Otherwise, call mountmgr to get DOS name */
1947 else
1948 {
1949 Status = IoVolumeDeviceToDosName(DeviceObject, &LocalInfo->Name);
1950 LocalReturnLength = LocalInfo->Name.Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
1951 }
1952 }
1953
1954 /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
1955 if (!QueryDosName || !NT_SUCCESS(Status))
1956 {
1957 /* Query the name */
1958 Status = ObQueryNameString(FileObject->DeviceObject,
1959 LocalInfo,
1960 Length,
1961 &LocalReturnLength);
1962 }
1963 else
1964 {
1965 NoObCall = TRUE;
1966 }
1967
1968 if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
1969 {
1970 /* Free the buffer and fail */
1971 ExFreePoolWithTag(LocalInfo, TAG_IO);
1972 return Status;
1973 }
1974
1975 /* Get buffer pointer */
1976 p = (PWCHAR)(ObjectNameInfo + 1);
1977
1978 _SEH2_TRY
1979 {
1980 /* Copy the information */
1981 if (QueryDosName && NoObCall)
1982 {
1983 ASSERT(PreviousMode == KernelMode);
1984
1985 /* Copy structure first */
1986 RtlCopyMemory(ObjectNameInfo,
1987 LocalInfo,
1988 (Length >= LocalReturnLength ? sizeof(OBJECT_NAME_INFORMATION) : Length));
1989 /* Name then */
1990 RtlCopyMemory(p, LocalInfo->Name.Buffer,
1991 (Length >= LocalReturnLength ? LocalInfo->Name.Length : Length - sizeof(OBJECT_NAME_INFORMATION)));
1992
1993 if (FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)
1994 {
1995 ExFreePool(LocalInfo->Name.Buffer);
1996 }
1997 }
1998 else
1999 {
2000 RtlCopyMemory(ObjectNameInfo,
2001 LocalInfo,
2002 (LocalReturnLength > Length) ?
2003 Length : LocalReturnLength);
2004 }
2005
2006 /* Set buffer pointer */
2007 ObjectNameInfo->Name.Buffer = p;
2008
2009 /* Advance in buffer */
2010 p += (LocalInfo->Name.Length / sizeof(WCHAR));
2011
2012 /* Check if this already filled our buffer */
2013 if (LocalReturnLength > Length)
2014 {
2015 /* Set the length mismatch to true, so that we can return
2016 * the proper buffer size to the caller later
2017 */
2018 LengthMismatch = TRUE;
2019
2020 /* Save the initial buffer length value */
2021 *ReturnLength = LocalReturnLength;
2022 }
2023
2024 /* Now get the file name buffer and check the length needed */
2025 LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
2026 FileLength = Length -
2027 LocalReturnLength +
2028 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2029
2030 /* Query the File name */
2031 if (PreviousMode == KernelMode &&
2032 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2033 {
2034 Status = IopGetFileInformation(FileObject,
2035 LengthMismatch ? Length : FileLength,
2036 FileNameInformation,
2037 LocalFileInfo,
2038 &LocalReturnLength);
2039 }
2040 else
2041 {
2042 Status = IoQueryFileInformation(FileObject,
2043 FileNameInformation,
2044 LengthMismatch ? Length : FileLength,
2045 LocalFileInfo,
2046 &LocalReturnLength);
2047 }
2048 if (NT_ERROR(Status))
2049 {
2050 /* Allow status that would mean it's not implemented in the storage stack */
2051 if (Status != STATUS_INVALID_PARAMETER && Status != STATUS_INVALID_DEVICE_REQUEST &&
2052 Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_INFO_CLASS)
2053 {
2054 _SEH2_LEAVE;
2055 }
2056
2057 /* In such case, zero output */
2058 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2059 LocalFileInfo->FileNameLength = 0;
2060 LocalFileInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR;
2061 }
2062 else
2063 {
2064 /* We'll at least return the name length */
2065 if (LocalReturnLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName))
2066 {
2067 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2068 }
2069 }
2070
2071 /* If the provided buffer is too small, return the required size */
2072 if (LengthMismatch)
2073 {
2074 /* Add the required length */
2075 *ReturnLength += LocalFileInfo->FileNameLength;
2076
2077 /* Free the allocated buffer and return failure */
2078 Status = STATUS_BUFFER_OVERFLOW;
2079 _SEH2_LEAVE;
2080 }
2081
2082 /* Now calculate the new lengths left */
2083 FileLength = LocalReturnLength -
2084 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2085 LocalReturnLength = (ULONG)((ULONG_PTR)p -
2086 (ULONG_PTR)ObjectNameInfo +
2087 LocalFileInfo->FileNameLength);
2088
2089 /* Don't copy the name if it's not valid */
2090 if (LocalFileInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR)
2091 {
2092 /* Free the allocated buffer and return failure */
2093 Status = STATUS_OBJECT_PATH_INVALID;
2094 _SEH2_LEAVE;
2095 }
2096
2097 /* Write the Name and null-terminate it */
2098 RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
2099 p += (FileLength / sizeof(WCHAR));
2100 *p = UNICODE_NULL;
2101 LocalReturnLength += sizeof(UNICODE_NULL);
2102
2103 /* Return the length needed */
2104 *ReturnLength = LocalReturnLength;
2105
2106 /* Setup the length and maximum length */
2107 FileLength = (ULONG)((ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo);
2108 ObjectNameInfo->Name.Length = (USHORT)FileLength -
2109 sizeof(OBJECT_NAME_INFORMATION);
2110 ObjectNameInfo->Name.MaximumLength = (USHORT)ObjectNameInfo->Name.Length +
2111 sizeof(UNICODE_NULL);
2112 }
2113 _SEH2_FINALLY
2114 {
2115 /* Free buffer and return */
2116 ExFreePoolWithTag(LocalInfo, TAG_IO);
2117 } _SEH2_END;
2118
2119 return Status;
2120 }
2121
2122 VOID
2123 NTAPI
2124 IopCloseFile(IN PEPROCESS Process OPTIONAL,
2125 IN PVOID ObjectBody,
2126 IN ACCESS_MASK GrantedAccess,
2127 IN ULONG HandleCount,
2128 IN ULONG SystemHandleCount)
2129 {
2130 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
2131 KEVENT Event;
2132 PIRP Irp;
2133 PIO_STACK_LOCATION StackPtr;
2134 NTSTATUS Status;
2135 PDEVICE_OBJECT DeviceObject;
2136 KIRQL OldIrql;
2137 IO_STATUS_BLOCK IoStatusBlock;
2138 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
2139
2140 /* If this isn't the last handle for the current process, quit */
2141 if (HandleCount != 1) return;
2142
2143 /* Check if the file is locked and has more then one handle opened */
2144 if ((FileObject->LockOperation) && (SystemHandleCount != 1))
2145 {
2146 /* Check if this is a direct open or not */
2147 if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN))
2148 {
2149 /* Get the attached device */
2150 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2151 }
2152 else
2153 {
2154 /* Get the FO's device */
2155 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2156 }
2157
2158 /* Check if this is a sync FO and lock it */
2159 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2160 {
2161 (VOID)IopLockFileObject(FileObject, KernelMode);
2162 }
2163
2164 /* Go the FastIO path if possible, otherwise fall back to IRP */
2165 if (DeviceObject->DriverObject->FastIoDispatch == NULL ||
2166 DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll == NULL ||
2167 !DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll(FileObject, PsGetCurrentProcess(), &IoStatusBlock, DeviceObject))
2168 {
2169 /* Clear and set up Events */
2170 KeClearEvent(&FileObject->Event);
2171 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2172
2173 /* Allocate an IRP */
2174 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2175
2176 /* Set it up */
2177 Irp->UserEvent = &Event;
2178 Irp->UserIosb = &Irp->IoStatus;
2179 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2180 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2181 Irp->RequestorMode = KernelMode;
2182 Irp->Flags = IRP_SYNCHRONOUS_API;
2183 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2184 ObReferenceObject(FileObject);
2185
2186 /* Set up Stack Pointer Data */
2187 StackPtr = IoGetNextIrpStackLocation(Irp);
2188 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2189 StackPtr->MinorFunction = IRP_MN_UNLOCK_ALL;
2190 StackPtr->FileObject = FileObject;
2191
2192 /* Queue the IRP */
2193 IopQueueIrpToThread(Irp);
2194
2195 /* Call the FS Driver */
2196 Status = IoCallDriver(DeviceObject, Irp);
2197 if (Status == STATUS_PENDING)
2198 {
2199 /* Wait for completion */
2200 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2201 }
2202
2203 /* IO will unqueue & free for us */
2204 }
2205
2206 /* Release the lock if we were holding it */
2207 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2208 {
2209 IopUnlockFileObject(FileObject);
2210 }
2211 }
2212
2213 /* Make sure this is the last handle */
2214 if (SystemHandleCount != 1) return;
2215
2216 /* Check if this is a direct open or not */
2217 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2218 {
2219 /* Get the attached device */
2220 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2221 }
2222 else
2223 {
2224 /* Get the FO's device */
2225 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2226 }
2227
2228 /* Set the handle created flag */
2229 FileObject->Flags |= FO_HANDLE_CREATED;
2230
2231 /* Check if this is a sync FO and lock it */
2232 if (Process != NULL &&
2233 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2234 {
2235 (VOID)IopLockFileObject(FileObject, KernelMode);
2236 }
2237
2238 /* Clear and set up Events */
2239 KeClearEvent(&FileObject->Event);
2240 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2241
2242 /* Allocate an IRP */
2243 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2244
2245 /* Set it up */
2246 Irp->UserEvent = &Event;
2247 Irp->UserIosb = &Irp->IoStatus;
2248 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2249 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2250 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2251 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
2252
2253 /* Set up Stack Pointer Data */
2254 StackPtr = IoGetNextIrpStackLocation(Irp);
2255 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
2256 StackPtr->FileObject = FileObject;
2257
2258 /* Queue the IRP */
2259 IopQueueIrpToThread(Irp);
2260
2261 /* Update operation counts */
2262 IopUpdateOperationCount(IopOtherTransfer);
2263
2264 /* Call the FS Driver */
2265 Status = IoCallDriver(DeviceObject, Irp);
2266 if (Status == STATUS_PENDING)
2267 {
2268 /* Wait for completion */
2269 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2270 }
2271
2272 /* Unqueue the IRP */
2273 KeRaiseIrql(APC_LEVEL, &OldIrql);
2274 IopUnQueueIrpFromThread(Irp);
2275 KeLowerIrql(OldIrql);
2276
2277 /* Free the IRP */
2278 IoFreeIrp(Irp);
2279
2280 /* Release the lock if we were holding it */
2281 if (Process != NULL &&
2282 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2283 {
2284 IopUnlockFileObject(FileObject);
2285 }
2286 }
2287
2288 NTSTATUS
2289 NTAPI
2290 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2291 IN FILE_INFORMATION_CLASS FileInformationClass,
2292 IN ULONG FileInformationSize,
2293 OUT PVOID FileInformation)
2294 {
2295 NTSTATUS Status;
2296 KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
2297 DUMMY_FILE_OBJECT LocalFileObject;
2298 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
2299 HANDLE Handle;
2300 OPEN_PACKET OpenPacket;
2301 BOOLEAN IsBasic;
2302 PAGED_CODE();
2303 IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
2304
2305 /* Check if the caller was user mode */
2306 if (AccessMode != KernelMode)
2307 {
2308 /* Protect probe in SEH */
2309 _SEH2_TRY
2310 {
2311 /* Probe the buffer */
2312 ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
2313 }
2314 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2315 {
2316 /* Return the exception code */
2317 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2318 }
2319 _SEH2_END;
2320 }
2321
2322 /* Check if this is a basic or full request */
2323 IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
2324
2325 /* Setup the Open Packet */
2326 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2327 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2328 OpenPacket.Size = sizeof(OPEN_PACKET);
2329 OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
2330 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2331 OpenPacket.Disposition = FILE_OPEN;
2332 OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
2333 OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
2334 (AccessMode != KernelMode) ?
2335 &NetworkOpenInfo : FileInformation;
2336 OpenPacket.QueryOnly = TRUE;
2337 OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
2338 OpenPacket.LocalFileObject = &LocalFileObject;
2339
2340 /* Update the operation count */
2341 IopUpdateOperationCount(IopOtherTransfer);
2342
2343 /*
2344 * Attempt opening the file. This will call the I/O Parse Routine for
2345 * the File Object (IopParseDevice) which will use the dummy file obejct
2346 * send the IRP to its device object. Note that we have two statuses
2347 * to worry about: the Object Manager's status (in Status) and the I/O
2348 * status, which is in the Open Packet's Final Status, and determined
2349 * by the Parse Check member.
2350 */
2351 Status = ObOpenObjectByName(ObjectAttributes,
2352 NULL,
2353 AccessMode,
2354 NULL,
2355 FILE_READ_ATTRIBUTES,
2356 &OpenPacket,
2357 &Handle);
2358 if (OpenPacket.ParseCheck == FALSE)
2359 {
2360 /* Parse failed */
2361 DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2362 ObjectAttributes->ObjectName, Status);
2363 return Status;
2364 }
2365 else
2366 {
2367 /* Use the Io status */
2368 Status = OpenPacket.FinalStatus;
2369 }
2370
2371 /* Check if we were succesful and this was user mode and a full query */
2372 if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
2373 {
2374 /* Enter SEH for copy */
2375 _SEH2_TRY
2376 {
2377 /* Copy the buffer back */
2378 RtlCopyMemory(FileInformation,
2379 &NetworkOpenInfo,
2380 FileInformationSize);
2381 }
2382 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2383 {
2384 /* Get exception code */
2385 Status = _SEH2_GetExceptionCode();
2386 }
2387 _SEH2_END;
2388 }
2389
2390 /* Return status */
2391 return Status;
2392 }
2393
2394 NTSTATUS
2395 NTAPI
2396 IopAcquireFileObjectLock(
2397 _In_ PFILE_OBJECT FileObject,
2398 _In_ KPROCESSOR_MODE WaitMode,
2399 _In_ BOOLEAN Alertable,
2400 _Out_ PBOOLEAN LockFailed)
2401 {
2402 NTSTATUS Status;
2403
2404 PAGED_CODE();
2405
2406 InterlockedIncrement((PLONG)&FileObject->Waiters);
2407
2408 Status = STATUS_SUCCESS;
2409 do
2410 {
2411 if (!InterlockedExchange((PLONG)&FileObject->Busy, TRUE))
2412 {
2413 break;
2414 }
2415 Status = KeWaitForSingleObject(&FileObject->Lock,
2416 Executive,
2417 WaitMode,
2418 Alertable,
2419 NULL);
2420 } while (Status == STATUS_SUCCESS);
2421
2422 InterlockedDecrement((PLONG)&FileObject->Waiters);
2423 if (Status == STATUS_SUCCESS)
2424 {
2425 ObReferenceObject(FileObject);
2426 *LockFailed = FALSE;
2427 }
2428 else
2429 {
2430 if (!FileObject->Busy && FileObject->Waiters)
2431 {
2432 KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2433 }
2434 *LockFailed = TRUE;
2435 }
2436
2437 return Status;
2438 }
2439
2440 PVOID
2441 NTAPI
2442 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
2443 {
2444 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2445 {
2446 PFILE_OBJECT_EXTENSION FileObjectExtension;
2447
2448 FileObjectExtension = FileObject->FileObjectExtension;
2449 return FileObjectExtension->FilterContext;
2450 }
2451
2452 return NULL;
2453 }
2454
2455 NTSTATUS
2456 NTAPI
2457 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
2458 IN PVOID FilterContext,
2459 IN BOOLEAN Define)
2460 {
2461 if (!(FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION))
2462 {
2463 return STATUS_INVALID_PARAMETER;
2464 }
2465
2466 UNIMPLEMENTED;
2467
2468 return STATUS_NOT_IMPLEMENTED;
2469 }
2470
2471 NTSTATUS
2472 NTAPI
2473 IopCreateFile(OUT PHANDLE FileHandle,
2474 IN ACCESS_MASK DesiredAccess,
2475 IN POBJECT_ATTRIBUTES ObjectAttributes,
2476 OUT PIO_STATUS_BLOCK IoStatusBlock,
2477 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2478 IN ULONG FileAttributes,
2479 IN ULONG ShareAccess,
2480 IN ULONG Disposition,
2481 IN ULONG CreateOptions,
2482 IN PVOID EaBuffer OPTIONAL,
2483 IN ULONG EaLength,
2484 IN CREATE_FILE_TYPE CreateFileType,
2485 IN PVOID ExtraCreateParameters OPTIONAL,
2486 IN ULONG Options,
2487 IN ULONG Flags,
2488 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2489 {
2490 KPROCESSOR_MODE AccessMode;
2491 HANDLE LocalHandle = 0;
2492 LARGE_INTEGER SafeAllocationSize;
2493 NTSTATUS Status = STATUS_SUCCESS;
2494 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
2495 POPEN_PACKET OpenPacket;
2496 ULONG EaErrorOffset;
2497 PAGED_CODE();
2498
2499 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2500
2501
2502 /* Check if we have no parameter checking to do */
2503 if (Options & IO_NO_PARAMETER_CHECKING)
2504 {
2505 /* Then force kernel-mode access to avoid checks */
2506 AccessMode = KernelMode;
2507 }
2508 else
2509 {
2510 /* Otherwise, use the actual mode */
2511 AccessMode = ExGetPreviousMode();
2512 }
2513
2514 /* Check if we need to do parameter checking */
2515 if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
2516 {
2517 /* Validate parameters */
2518 if (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
2519 {
2520 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2521 return STATUS_INVALID_PARAMETER;
2522 }
2523
2524 if (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
2525 {
2526 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2527 return STATUS_INVALID_PARAMETER;
2528 }
2529
2530 if (Disposition > FILE_MAXIMUM_DISPOSITION)
2531 {
2532 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2533 return STATUS_INVALID_PARAMETER;
2534 }
2535
2536 if (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
2537 {
2538 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2539 return STATUS_INVALID_PARAMETER;
2540 }
2541
2542 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
2543 (!(DesiredAccess & SYNCHRONIZE)))
2544 {
2545 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2546 return STATUS_INVALID_PARAMETER;
2547 }
2548
2549 if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE)))
2550 {
2551 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2552 return STATUS_INVALID_PARAMETER;
2553 }
2554
2555 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
2556 (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT))
2557 {
2558 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2559 return STATUS_INVALID_PARAMETER;
2560 }
2561
2562 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2563 (CreateOptions & ~(FILE_DIRECTORY_FILE |
2564 FILE_SYNCHRONOUS_IO_ALERT |
2565 FILE_SYNCHRONOUS_IO_NONALERT |
2566 FILE_WRITE_THROUGH |
2567 FILE_COMPLETE_IF_OPLOCKED |
2568 FILE_OPEN_FOR_BACKUP_INTENT |
2569 FILE_DELETE_ON_CLOSE |
2570 FILE_OPEN_FOR_FREE_SPACE_QUERY |
2571 FILE_OPEN_BY_FILE_ID |
2572 FILE_NO_COMPRESSION |
2573 FILE_OPEN_REPARSE_POINT)))
2574 {
2575 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2576 return STATUS_INVALID_PARAMETER;
2577 }
2578
2579 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2580 (Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF))
2581 {
2582 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2583 return STATUS_INVALID_PARAMETER;
2584 }
2585
2586 if ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER))
2587 {
2588 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2589 return STATUS_INVALID_PARAMETER;
2590 }
2591
2592 if ((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA))
2593 {
2594 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2595 return STATUS_INVALID_PARAMETER;
2596 }
2597
2598 /* Now check if this is a named pipe */
2599 if (CreateFileType == CreateFileTypeNamedPipe)
2600 {
2601 /* Make sure we have extra parameters */
2602 if (!ExtraCreateParameters)
2603 {
2604 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2605 return STATUS_INVALID_PARAMETER;
2606 }
2607
2608 /* Get the parameters and validate them */
2609 NamedPipeCreateParameters = ExtraCreateParameters;
2610 if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
2611 (NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
2612 (NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
2613 (ShareAccess & FILE_SHARE_DELETE) ||
2614 ((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
2615 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
2616 {
2617 /* Invalid named pipe create */
2618 DPRINT1("Invalid named pipe create\n");
2619 return STATUS_INVALID_PARAMETER;
2620 }
2621 }
2622 else if (CreateFileType == CreateFileTypeMailslot)
2623 {
2624 /* Make sure we have extra parameters */
2625 if (!ExtraCreateParameters)
2626 {
2627 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2628 return STATUS_INVALID_PARAMETER;
2629 }
2630
2631 /* Get the parameters and validate them */
2632 if ((ShareAccess & FILE_SHARE_DELETE) ||
2633 !(ShareAccess & ~FILE_SHARE_WRITE) ||
2634 (Disposition != FILE_CREATE) ||
2635 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
2636 {
2637 /* Invalid mailslot create */
2638 DPRINT1("Invalid mailslot create\n");
2639 return STATUS_INVALID_PARAMETER;
2640 }
2641 }
2642 }
2643
2644 /* Allocate the open packet */
2645 OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
2646 if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
2647 RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
2648
2649 /* Check if the call came from user mode */
2650 if (AccessMode != KernelMode)
2651 {
2652 _SEH2_TRY
2653 {
2654 /* Probe the output parameters */
2655 ProbeForWriteHandle(FileHandle);
2656 ProbeForWriteIoStatusBlock(IoStatusBlock);
2657
2658 /* Probe the allocation size if one was passed in */
2659 if (AllocationSize)
2660 {
2661 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
2662 }
2663 else
2664 {
2665 SafeAllocationSize.QuadPart = 0;
2666 }
2667
2668 /* Make sure it's valid */
2669 if (SafeAllocationSize.QuadPart < 0)
2670 {
2671 RtlRaiseStatus(STATUS_INVALID_PARAMETER);
2672 }
2673
2674 /* Check if EA was passed in */
2675 if ((EaBuffer) && (EaLength))
2676 {
2677 /* Probe it */
2678 ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
2679
2680 /* And marshall it */
2681 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2682 EaLength,
2683 TAG_EA);
2684 OpenPacket->EaLength = EaLength;
2685 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2686
2687 /* Validate the buffer */
2688 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2689 EaLength,
2690 &EaErrorOffset);
2691 if (!NT_SUCCESS(Status))
2692 {
2693 /* Undo everything if it's invalid */
2694 DPRINT1("Invalid EA buffer\n");
2695 IoStatusBlock->Status = Status;
2696 IoStatusBlock->Information = EaErrorOffset;
2697 RtlRaiseStatus(Status);
2698 }
2699 }
2700 }
2701 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2702 {
2703 /* Return the exception code */
2704 if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
2705 ExFreePool(OpenPacket);
2706 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2707 }
2708 _SEH2_END;
2709 }
2710 else
2711 {
2712 /* Check if this is a device attach */
2713 if (CreateOptions & IO_ATTACH_DEVICE_API)
2714 {
2715 /* Set the flag properly */
2716 Options |= IO_ATTACH_DEVICE;
2717 CreateOptions &= ~IO_ATTACH_DEVICE_API;
2718 }
2719
2720 /* Check if we have allocation size */
2721 if (AllocationSize)
2722 {
2723 /* Capture it */
2724 SafeAllocationSize = *AllocationSize;
2725 }
2726 else
2727 {
2728 /* Otherwise, no size */
2729 SafeAllocationSize.QuadPart = 0;
2730 }
2731
2732 /* Check if we have an EA packet */
2733 if ((EaBuffer) && (EaLength))
2734 {
2735 /* Allocate the kernel copy */
2736 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2737 EaLength,
2738 TAG_EA);
2739 if (!OpenPacket->EaBuffer)
2740 {
2741 ExFreePool(OpenPacket);
2742 DPRINT1("Failed to allocate open packet EA buffer\n");
2743 return STATUS_INSUFFICIENT_RESOURCES;
2744 }
2745
2746 /* Copy the data */
2747 OpenPacket->EaLength = EaLength;
2748 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2749
2750 /* Validate the buffer */
2751 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2752 EaLength,
2753 &EaErrorOffset);
2754 if (!NT_SUCCESS(Status))
2755 {
2756 /* Undo everything if it's invalid */
2757 DPRINT1("Invalid EA buffer\n");
2758 ExFreePool(OpenPacket->EaBuffer);
2759 IoStatusBlock->Status = Status;
2760 IoStatusBlock->Information = EaErrorOffset;
2761 ExFreePool(OpenPacket);
2762 return Status;
2763 }
2764 }
2765 }
2766
2767 /* Setup the Open Packet */
2768 OpenPacket->Type = IO_TYPE_OPEN_PACKET;
2769 OpenPacket->Size = sizeof(*OpenPacket);
2770 OpenPacket->AllocationSize = SafeAllocationSize;
2771 OpenPacket->CreateOptions = CreateOptions;
2772 OpenPacket->FileAttributes = (USHORT)FileAttributes;
2773 OpenPacket->ShareAccess = (USHORT)ShareAccess;
2774 OpenPacket->Options = Options;
2775 OpenPacket->Disposition = Disposition;
2776 OpenPacket->CreateFileType = CreateFileType;
2777 OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
2778 OpenPacket->InternalFlags = Flags;
2779 OpenPacket->TopDeviceObjectHint = DeviceObject;
2780
2781 /* Update the operation count */
2782 IopUpdateOperationCount(IopOtherTransfer);
2783
2784 /*
2785 * Attempt opening the file. This will call the I/O Parse Routine for
2786 * the File Object (IopParseDevice) which will create the object and
2787 * send the IRP to its device object. Note that we have two statuses
2788 * to worry about: the Object Manager's status (in Status) and the I/O
2789 * status, which is in the Open Packet's Final Status, and determined
2790 * by the Parse Check member.
2791 */
2792 Status = ObOpenObjectByName(ObjectAttributes,
2793 NULL,
2794 AccessMode,
2795 NULL,
2796 DesiredAccess,
2797 OpenPacket,
2798 &LocalHandle);
2799
2800 /* Free the EA Buffer */
2801 if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
2802
2803 /* Now check for Ob or Io failure */
2804 if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
2805 {
2806 /* Check if Ob thinks well went well */
2807 if (NT_SUCCESS(Status))
2808 {
2809 /*
2810 * Tell it otherwise. Because we didn't use an ObjectType,
2811 * it incorrectly returned us a handle to God knows what.
2812 */
2813 ZwClose(LocalHandle);
2814 Status = STATUS_OBJECT_TYPE_MISMATCH;
2815 }
2816
2817 /* Now check the Io status */
2818 if (!NT_SUCCESS(OpenPacket->FinalStatus))
2819 {
2820 /* Use this status instead of Ob's */
2821 Status = OpenPacket->FinalStatus;
2822
2823 /* Check if it was only a warning */
2824 if (NT_WARNING(Status))
2825 {
2826 /* Protect write with SEH */
2827 _SEH2_TRY
2828 {
2829 /* In this case, we copy the I/O Status back */
2830 IoStatusBlock->Information = OpenPacket->Information;
2831 IoStatusBlock->Status = OpenPacket->FinalStatus;
2832 }
2833 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2834 {
2835 /* Get exception code */
2836 Status = _SEH2_GetExceptionCode();
2837 }
2838 _SEH2_END;
2839 }
2840 }
2841 else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
2842 {
2843 /*
2844 * This can happen in the very bizarre case where the parse routine
2845 * actually executed more then once (due to a reparse) and ended
2846 * up failing after already having created the File Object.
2847 */
2848 if (OpenPacket->FileObject->FileName.Length)
2849 {
2850 /* It had a name, free it */
2851 ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
2852 }
2853
2854 /* Clear the device object to invalidate the FO, and dereference */
2855 OpenPacket->FileObject->DeviceObject = NULL;
2856 ObDereferenceObject(OpenPacket->FileObject);
2857 }
2858 }
2859 else
2860 {
2861 /* We reached success and have a valid file handle */
2862 OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
2863 ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
2864
2865 /* Enter SEH for write back */
2866 _SEH2_TRY
2867 {
2868 /* Write back the handle and I/O Status */
2869 *FileHandle = LocalHandle;
2870 IoStatusBlock->Information = OpenPacket->Information;
2871 IoStatusBlock->Status = OpenPacket->FinalStatus;
2872
2873 /* Get the Io status */
2874 Status = OpenPacket->FinalStatus;
2875 }
2876 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2877 {
2878 /* Get the exception status */
2879 Status = _SEH2_GetExceptionCode();
2880 }
2881 _SEH2_END;
2882 }
2883
2884 /* Check if we were 100% successful */
2885 if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
2886 {
2887 /* Dereference the File Object */
2888 ObDereferenceObject(OpenPacket->FileObject);
2889 }
2890
2891 /* Return status */
2892 ExFreePool(OpenPacket);
2893 return Status;
2894 }
2895
2896 /* FUNCTIONS *****************************************************************/
2897
2898 /*
2899 * @unimplemented
2900 */
2901 NTSTATUS
2902 NTAPI
2903 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
2904 IN ULONG Length,
2905 IN BOOLEAN SetOperation)
2906 {
2907 UNIMPLEMENTED;
2908 return STATUS_NOT_IMPLEMENTED;
2909 }
2910
2911 /*
2912 * @unimplemented
2913 */
2914 NTSTATUS
2915 NTAPI
2916 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
2917 IN ULONG QuotaLength,
2918 OUT PULONG ErrorOffset)
2919 {
2920 UNIMPLEMENTED;
2921 return STATUS_NOT_IMPLEMENTED;
2922 }
2923
2924 /*
2925 * @implemented
2926 */
2927 NTSTATUS
2928 NTAPI
2929 IoCreateFile(OUT PHANDLE FileHandle,
2930 IN ACCESS_MASK DesiredAccess,
2931 IN POBJECT_ATTRIBUTES ObjectAttributes,
2932 OUT PIO_STATUS_BLOCK IoStatusBlock,
2933 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2934 IN ULONG FileAttributes,
2935 IN ULONG ShareAccess,
2936 IN ULONG Disposition,
2937 IN ULONG CreateOptions,
2938 IN PVOID EaBuffer OPTIONAL,
2939 IN ULONG EaLength,
2940 IN CREATE_FILE_TYPE CreateFileType,
2941 IN PVOID ExtraCreateParameters OPTIONAL,
2942 IN ULONG Options)
2943 {
2944 PAGED_CODE();
2945
2946 return IopCreateFile(FileHandle,
2947 DesiredAccess,
2948 ObjectAttributes,
2949 IoStatusBlock,
2950 AllocationSize,
2951 FileAttributes,
2952 ShareAccess,
2953 Disposition,
2954 CreateOptions,
2955 EaBuffer,
2956 EaLength,
2957 CreateFileType,
2958 ExtraCreateParameters,
2959 Options,
2960 0,
2961 NULL);
2962 }
2963
2964 /*
2965 * @unimplemented
2966 */
2967 NTSTATUS
2968 NTAPI
2969 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
2970 IN ACCESS_MASK DesiredAccess,
2971 IN POBJECT_ATTRIBUTES ObjectAttributes,
2972 OUT PIO_STATUS_BLOCK IoStatusBlock,
2973 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2974 IN ULONG FileAttributes,
2975 IN ULONG ShareAccess,
2976 IN ULONG Disposition,
2977 IN ULONG CreateOptions,
2978 IN PVOID EaBuffer OPTIONAL,
2979 IN ULONG EaLength,
2980 IN CREATE_FILE_TYPE CreateFileType,
2981 IN PVOID ExtraCreateParameters OPTIONAL,
2982 IN ULONG Options,
2983 IN PVOID DeviceObject)
2984 {
2985 ULONG Flags = 0;
2986
2987 PAGED_CODE();
2988
2989 /* Check if we were passed a device to send the create request to*/
2990 if (DeviceObject)
2991 {
2992 /* We'll tag this request into a file object extension */
2993 Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
2994 }
2995
2996 return IopCreateFile(FileHandle,
2997 DesiredAccess,
2998 ObjectAttributes,
2999 IoStatusBlock,
3000 AllocationSize,
3001 FileAttributes,
3002 ShareAccess,
3003 Disposition,
3004 CreateOptions,
3005 EaBuffer,
3006 EaLength,
3007 CreateFileType,
3008 ExtraCreateParameters,
3009 Options | IO_NO_PARAMETER_CHECKING,
3010 Flags,
3011 DeviceObject);
3012 }
3013
3014 /*
3015 * @implemented
3016 */
3017 PFILE_OBJECT
3018 NTAPI
3019 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
3020 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
3021 OUT PHANDLE FileObjectHandle OPTIONAL)
3022 {
3023 PFILE_OBJECT CreatedFileObject;
3024 NTSTATUS Status;
3025 HANDLE FileHandle;
3026 OBJECT_ATTRIBUTES ObjectAttributes;
3027 PAGED_CODE();
3028 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3029
3030 /* Choose Device Object */
3031 if (FileObject) DeviceObject = FileObject->DeviceObject;
3032
3033 /* Reference the device object and initialize attributes */
3034 InterlockedIncrement(&DeviceObject->ReferenceCount);
3035 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3036
3037 /* Create the File Object */
3038 Status = ObCreateObject(KernelMode,
3039 IoFileObjectType,
3040 &ObjectAttributes,
3041 KernelMode,
3042 NULL,
3043 sizeof(FILE_OBJECT),
3044 sizeof(FILE_OBJECT),
3045 0,
3046 (PVOID*)&CreatedFileObject);
3047 if (!NT_SUCCESS(Status))
3048 {
3049 /* Fail */
3050 IopDereferenceDeviceObject(DeviceObject, FALSE);
3051 ExRaiseStatus(Status);
3052 }
3053
3054 /* Set File Object Data */
3055 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3056 CreatedFileObject->DeviceObject = DeviceObject;
3057 CreatedFileObject->Type = IO_TYPE_FILE;
3058 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3059 CreatedFileObject->Flags = FO_STREAM_FILE;
3060
3061 /* Initialize the wait event */
3062 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3063
3064 /* Insert it to create a handle for it */
3065 Status = ObInsertObject(CreatedFileObject,
3066 NULL,
3067 FILE_READ_DATA,
3068 1,
3069 (PVOID*)&CreatedFileObject,
3070 &FileHandle);
3071 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
3072
3073 /* Set the handle created flag */
3074 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3075 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3076
3077 /* Check if we have a VPB */
3078 if (DeviceObject->Vpb)
3079 {
3080 /* Reference it */
3081 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3082 }
3083
3084 /* Check if the caller wants the handle */
3085 if (FileObjectHandle)
3086 {
3087 /* Return it */
3088 *FileObjectHandle = FileHandle;
3089 ObDereferenceObject(CreatedFileObject);
3090 }
3091 else
3092 {
3093 /* Otherwise, close it */
3094 ObCloseHandle(FileHandle, KernelMode);
3095 }
3096
3097 /* Return the file object */
3098 return CreatedFileObject;
3099 }
3100
3101 /*
3102 * @implemented
3103 */
3104 PFILE_OBJECT
3105 NTAPI
3106 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
3107 IN PDEVICE_OBJECT DeviceObject)
3108 {
3109 /* Call the newer function */
3110 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
3111 }
3112
3113 /*
3114 * @implemented
3115 */
3116 PFILE_OBJECT
3117 NTAPI
3118 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
3119 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
3120 {
3121 PFILE_OBJECT CreatedFileObject;
3122 NTSTATUS Status;
3123 OBJECT_ATTRIBUTES ObjectAttributes;
3124 PAGED_CODE();
3125 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3126
3127 /* Choose Device Object */
3128 if (FileObject) DeviceObject = FileObject->DeviceObject;
3129
3130 /* Reference the device object and initialize attributes */
3131 InterlockedIncrement(&DeviceObject->ReferenceCount);
3132 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3133
3134 /* Create the File Object */
3135 Status = ObCreateObject(KernelMode,
3136 IoFileObjectType,
3137 &ObjectAttributes,
3138 KernelMode,
3139 NULL,
3140 sizeof(FILE_OBJECT),
3141 sizeof(FILE_OBJECT),
3142 0,
3143 (PVOID*)&CreatedFileObject);
3144 if (!NT_SUCCESS(Status))
3145 {
3146 /* Fail */
3147 IopDereferenceDeviceObject(DeviceObject, FALSE);
3148 ExRaiseStatus(Status);
3149 }
3150
3151 /* Set File Object Data */
3152 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3153 CreatedFileObject->DeviceObject = DeviceObject;
3154 CreatedFileObject->Type = IO_TYPE_FILE;
3155 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3156 CreatedFileObject->Flags = FO_STREAM_FILE;
3157
3158 /* Initialize the wait event */
3159 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3160
3161 /* Destroy create information */
3162 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
3163 ObjectCreateInfo);
3164 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
3165
3166 /* Set the handle created flag */
3167 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3168 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3169
3170 /* Check if we have a VPB */
3171 if (DeviceObject->Vpb)
3172 {
3173 /* Reference it */
3174 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3175 }
3176
3177 /* Return the file object */
3178 return CreatedFileObject;
3179 }
3180
3181 /*
3182 * @implemented
3183 */
3184 PGENERIC_MAPPING
3185 NTAPI
3186 IoGetFileObjectGenericMapping(VOID)
3187 {
3188 /* Return the mapping */
3189 return &IopFileMapping;
3190 }
3191
3192 /*
3193 * @implemented
3194 */
3195 BOOLEAN
3196 NTAPI
3197 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
3198 {
3199 /* Return the flag status */
3200 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3201 }
3202
3203 /*
3204 * @implemented
3205 */
3206 BOOLEAN
3207 NTAPI
3208 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
3209 IN ACCESS_MASK DesiredAccess,
3210 IN ULONG OpenOptions,
3211 OUT PIO_STATUS_BLOCK IoStatus,
3212 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
3213 {
3214 NTSTATUS Status;
3215 DUMMY_FILE_OBJECT LocalFileObject;
3216 HANDLE Handle;
3217 OPEN_PACKET OpenPacket;
3218 PAGED_CODE();
3219 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
3220
3221 /* Setup the Open Packet */
3222 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
3223 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
3224 OpenPacket.Size = sizeof(OPEN_PACKET);
3225 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
3226 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
3227 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
3228 OpenPacket.Disposition = FILE_OPEN;
3229 OpenPacket.NetworkInformation = Buffer;
3230 OpenPacket.QueryOnly = TRUE;
3231 OpenPacket.FullAttributes = TRUE;
3232 OpenPacket.LocalFileObject = &LocalFileObject;
3233
3234 /*
3235 * Attempt opening the file. This will call the I/O Parse Routine for
3236 * the File Object (IopParseDevice) which will use the dummy file obejct
3237 * send the IRP to its device object. Note that we have two statuses
3238 * to worry about: the Object Manager's status (in Status) and the I/O
3239 * status, which is in the Open Packet's Final Status, and determined
3240 * by the Parse Check member.
3241 */
3242 Status = ObOpenObjectByName(ObjectAttributes,
3243 NULL,
3244 KernelMode,
3245 NULL,
3246 DesiredAccess,
3247 &OpenPacket,
3248 &Handle);
3249 if (OpenPacket.ParseCheck == FALSE)
3250 {
3251 /* Parse failed */
3252 IoStatus->Status = Status;
3253 }
3254 else
3255 {
3256 /* Use the Io status */
3257 IoStatus->Status = OpenPacket.FinalStatus;
3258 IoStatus->Information = OpenPacket.Information;
3259 }
3260
3261 /* Return success */
3262 return TRUE;
3263 }
3264
3265 /*
3266 * @implemented
3267 */
3268 VOID
3269 NTAPI
3270 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
3271 OUT PSHARE_ACCESS ShareAccess)
3272 {
3273 PAGED_CODE();
3274
3275 /* Check if the file has an extension */
3276 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3277 {
3278 /* Check if caller specified to ignore access checks */
3279 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3280 {
3281 /* Don't update share access */
3282 return;
3283 }
3284 }
3285
3286 /* Otherwise, check if there's any access present */
3287 if ((FileObject->ReadAccess) ||
3288 (FileObject->WriteAccess) ||
3289 (FileObject->DeleteAccess))
3290 {
3291 /* Increase the open count */
3292 ShareAccess->OpenCount++;
3293
3294 /* Add new share access */
3295 ShareAccess->Readers += FileObject->ReadAccess;
3296 ShareAccess->Writers += FileObject->WriteAccess;
3297 ShareAccess->Deleters += FileObject->DeleteAccess;
3298 ShareAccess->SharedRead += FileObject->SharedRead;
3299 ShareAccess->SharedWrite += FileObject->SharedWrite;
3300 ShareAccess->SharedDelete += FileObject->SharedDelete;
3301 }
3302 }
3303
3304 /*
3305 * @implemented
3306 */
3307 NTSTATUS
3308 NTAPI
3309 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
3310 IN ULONG DesiredShareAccess,
3311 IN PFILE_OBJECT FileObject,
3312 IN PSHARE_ACCESS ShareAccess,
3313 IN BOOLEAN Update)
3314 {
3315 BOOLEAN ReadAccess;
3316 BOOLEAN WriteAccess;
3317 BOOLEAN DeleteAccess;
3318 BOOLEAN SharedRead;
3319 BOOLEAN SharedWrite;
3320 BOOLEAN SharedDelete;
3321 PAGED_CODE();
3322
3323 /* Get access masks */
3324 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3325 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3326 DeleteAccess = (DesiredAccess & DELETE) != 0;
3327
3328 /* Set them in the file object */
3329 FileObject->ReadAccess = ReadAccess;
3330 FileObject->WriteAccess = WriteAccess;
3331 FileObject->DeleteAccess = DeleteAccess;
3332
3333 /* Check if the file has an extension */
3334 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3335 {
3336 /* Check if caller specified to ignore access checks */
3337 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3338 {
3339 /* Don't check share access */
3340 return STATUS_SUCCESS;
3341 }
3342 }
3343
3344 /* Check if we have any access */
3345 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
3346 {
3347 /* Get shared access masks */
3348 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3349 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3350 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3351
3352 /* Set them */
3353 FileObject->SharedRead = SharedRead;
3354 FileObject->SharedWrite = SharedWrite;
3355 FileObject->SharedDelete = SharedDelete;
3356
3357 /* Check if the shared access is violated */
3358 if ((ReadAccess &&
3359 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
3360 (WriteAccess &&
3361 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
3362 (DeleteAccess &&
3363 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
3364 ((ShareAccess->Readers != 0) && !SharedRead) ||
3365 ((ShareAccess->Writers != 0) && !SharedWrite) ||
3366 ((ShareAccess->Deleters != 0) && !SharedDelete))
3367 {
3368 /* Sharing violation, fail */
3369 return STATUS_SHARING_VIOLATION;
3370 }
3371
3372 /* It's not, check if caller wants us to update it */
3373 if (Update)
3374 {
3375 /* Increase open count */
3376 ShareAccess->OpenCount++;
3377
3378 /* Update shared access */
3379 ShareAccess->Readers += ReadAccess;
3380 ShareAccess->Writers += WriteAccess;
3381 ShareAccess->Deleters += DeleteAccess;
3382 ShareAccess->SharedRead += SharedRead;
3383 ShareAccess->SharedWrite += SharedWrite;
3384 ShareAccess->SharedDelete += SharedDelete;
3385 }
3386 }
3387
3388 /* Validation successful */
3389 return STATUS_SUCCESS;
3390 }
3391
3392 /*
3393 * @implemented
3394 */
3395 VOID
3396 NTAPI
3397 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
3398 IN PSHARE_ACCESS ShareAccess)
3399 {
3400 PAGED_CODE();
3401
3402 /* Check if the file has an extension */
3403 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3404 {
3405 /* Check if caller specified to ignore access checks */
3406 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3407 {
3408 /* Don't update share access */
3409 return;
3410 }
3411 }
3412
3413 /* Otherwise, check if there's any access present */
3414 if ((FileObject->ReadAccess) ||
3415 (FileObject->WriteAccess) ||
3416 (FileObject->DeleteAccess))
3417 {
3418 /* Decrement the open count */
3419 ShareAccess->OpenCount--;
3420
3421 /* Remove share access */
3422 ShareAccess->Readers -= FileObject->ReadAccess;
3423 ShareAccess->Writers -= FileObject->WriteAccess;
3424 ShareAccess->Deleters -= FileObject->DeleteAccess;
3425 ShareAccess->SharedRead -= FileObject->SharedRead;
3426 ShareAccess->SharedWrite -= FileObject->SharedWrite;
3427 ShareAccess->SharedDelete -= FileObject->SharedDelete;
3428 }
3429 }
3430
3431 /*
3432 * @implemented
3433 */
3434 VOID
3435 NTAPI
3436 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
3437 IN ULONG DesiredShareAccess,
3438 IN PFILE_OBJECT FileObject,
3439 OUT PSHARE_ACCESS ShareAccess)
3440 {
3441 BOOLEAN ReadAccess;
3442 BOOLEAN WriteAccess;
3443 BOOLEAN DeleteAccess;
3444 BOOLEAN SharedRead;
3445 BOOLEAN SharedWrite;
3446 BOOLEAN SharedDelete;
3447 BOOLEAN Update = TRUE;
3448 PAGED_CODE();
3449
3450 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3451 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3452 DeleteAccess = (DesiredAccess & DELETE) != 0;
3453
3454 /* Check if the file has an extension */
3455 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3456 {
3457 /* Check if caller specified to ignore access checks */
3458 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3459 {
3460 /* Don't update share access */
3461 Update = FALSE;
3462 }
3463 }
3464
3465 /* Update basic access */
3466 FileObject->ReadAccess = ReadAccess;
3467 FileObject->WriteAccess = WriteAccess;
3468 FileObject->DeleteAccess = DeleteAccess;
3469
3470 /* Check if we have no access as all */
3471 if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
3472 {
3473 /* Check if we need to update the structure */
3474 if (!Update) return;
3475
3476 /* Otherwise, clear data */
3477 ShareAccess->OpenCount = 0;
3478 ShareAccess->Readers = 0;
3479 ShareAccess->Writers = 0;
3480 ShareAccess->Deleters = 0;
3481 ShareAccess->SharedRead = 0;
3482 ShareAccess->SharedWrite = 0;
3483 ShareAccess->SharedDelete = 0;
3484 }
3485 else
3486 {
3487 /* Calculate shared access */
3488 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3489 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3490 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3491
3492 /* Set it in the FO */
3493 FileObject->SharedRead = SharedRead;
3494 FileObject->SharedWrite = SharedWrite;
3495 FileObject->SharedDelete = SharedDelete;
3496
3497 /* Check if we need to update the structure */
3498 if (!Update) return;
3499
3500 /* Otherwise, set data */
3501 ShareAccess->OpenCount = 1;
3502 ShareAccess->Readers = ReadAccess;
3503 ShareAccess->Writers = WriteAccess;
3504 ShareAccess->Deleters = DeleteAccess;
3505 ShareAccess->SharedRead = SharedRead;
3506 ShareAccess->SharedWrite = SharedWrite;
3507 ShareAccess->SharedDelete = SharedDelete;
3508 }
3509 }
3510
3511 /*
3512 * @implemented
3513 */
3514 VOID
3515 NTAPI
3516 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
3517 IN PFILE_OBJECT FileObject)
3518 {
3519 PIRP Irp;
3520 KEVENT Event;
3521 KIRQL OldIrql;
3522 NTSTATUS Status;
3523 PIO_STACK_LOCATION Stack;
3524
3525 /* Check if handles were already created for the
3526 * open file. If so, that's over.
3527 */
3528 if (FileObject->Flags & FO_HANDLE_CREATED)
3529 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN,
3530 (ULONG_PTR)FileObject,
3531 (ULONG_PTR)DeviceObject, 0, 0);
3532
3533 /* Reset the events */
3534 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
3535 KeClearEvent(&FileObject->Event);
3536
3537 /* Allocate the IRP we'll use */
3538 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
3539 /* Properly set it */
3540 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3541 Irp->UserEvent = &Event;
3542 Irp->UserIosb = &Irp->IoStatus;
3543 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3544 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3545 Irp->RequestorMode = KernelMode;
3546 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
3547
3548 Stack = IoGetNextIrpStackLocation(Irp);
3549 Stack->MajorFunction = IRP_MJ_CLEANUP;
3550 Stack->FileObject = FileObject;
3551
3552 /* Put on top of IRPs list of the thread */
3553 IopQueueIrpToThread(Irp);
3554
3555 /* Call the driver */
3556 Status = IoCallDriver(DeviceObject, Irp);
3557 if (Status == STATUS_PENDING)
3558 {
3559 KeWaitForSingleObject(&Event, UserRequest,
3560 KernelMode, FALSE, NULL);
3561 }
3562
3563 /* Remove from IRPs list */
3564 KeRaiseIrql(APC_LEVEL, &OldIrql);
3565 IopUnQueueIrpFromThread(Irp);
3566 KeLowerIrql(OldIrql);
3567
3568 /* Free the IRP */
3569 IoFreeIrp(Irp);
3570
3571 /* Clear the event */
3572 KeClearEvent(&FileObject->Event);
3573 /* And finally, mark the open operation as canceled */
3574 FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
3575 }
3576
3577 /*
3578 * @implemented
3579 */
3580 NTSTATUS
3581 NTAPI
3582 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
3583 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
3584 {
3585 NTSTATUS Status;
3586 ULONG Length, ReturnLength;
3587 POBJECT_NAME_INFORMATION LocalInfo;
3588
3589 /* Start with a buffer length of 200 */
3590 ReturnLength = 200;
3591 /*
3592 * We'll loop until query works.
3593 * We will use returned length for next loop
3594 * iteration, trying to have a big enough buffer.
3595 */
3596 for (Length = 200; ; Length = ReturnLength)
3597 {
3598 /* Allocate our work buffer */
3599 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, 'nDoI');
3600 if (LocalInfo == NULL)
3601 {
3602 return STATUS_INSUFFICIENT_RESOURCES;
3603 }
3604
3605 /* Query the DOS name */
3606 Status = IopQueryNameInternal(FileObject,
3607 TRUE,
3608 TRUE,
3609 LocalInfo,
3610 Length,
3611 &ReturnLength,
3612 KernelMode);
3613 /* If it succeed, nothing more to do */
3614 if (Status == STATUS_SUCCESS)
3615 {
3616 break;
3617 }
3618
3619 /* Otherwise, prepare for re-allocation */
3620 ExFreePoolWithTag(LocalInfo, 'nDoI');
3621
3622 /*
3623 * If we failed because of something else
3624 * than memory, simply stop and fail here
3625 */
3626 if (Status != STATUS_BUFFER_OVERFLOW)
3627 {
3628 return Status;
3629 }
3630 }
3631
3632 /* Success case here: return our buffer */
3633 *ObjectNameInformation = LocalInfo;
3634 return STATUS_SUCCESS;
3635 }
3636
3637 /*
3638 * @implemented
3639 */
3640 NTSTATUS
3641 NTAPI
3642 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
3643 IN BOOLEAN Remote)
3644 {
3645 NTSTATUS Status = STATUS_SUCCESS;
3646 BOOLEAN FlagSet;
3647
3648 /* Get the flag status */
3649 FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3650
3651 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
3652 if (Remote && !FlagSet)
3653 {
3654 /* Set the flag */
3655 FileObject->Flags |= FO_REMOTE_ORIGIN;
3656 }
3657 else if (!Remote && FlagSet)
3658 {
3659 /* Remove the flag */
3660 FileObject->Flags &= ~FO_REMOTE_ORIGIN;
3661 }
3662 else
3663 {
3664 /* Fail */
3665 Status = STATUS_INVALID_PARAMETER_MIX;
3666 }
3667
3668 /* Return status */
3669 return Status;
3670 }
3671
3672 /*
3673 * @implemented
3674 */
3675 NTSTATUS
3676 NTAPI
3677 NtCreateFile(PHANDLE FileHandle,
3678 ACCESS_MASK DesiredAccess,
3679 POBJECT_ATTRIBUTES ObjectAttributes,
3680 PIO_STATUS_BLOCK IoStatusBlock,
3681 PLARGE_INTEGER AllocateSize,
3682 ULONG FileAttributes,
3683 ULONG ShareAccess,
3684 ULONG CreateDisposition,
3685 ULONG CreateOptions,
3686 PVOID EaBuffer,
3687 ULONG EaLength)
3688 {
3689 /* Call the I/O Function */
3690 return IoCreateFile(FileHandle,
3691 DesiredAccess,
3692 ObjectAttributes,
3693 IoStatusBlock,
3694 AllocateSize,
3695 FileAttributes,
3696 ShareAccess,
3697 CreateDisposition,
3698 CreateOptions,
3699 EaBuffer,
3700 EaLength,
3701 CreateFileTypeNone,
3702 NULL,
3703 0);
3704 }
3705
3706 NTSTATUS
3707 NTAPI
3708 NtCreateMailslotFile(OUT PHANDLE FileHandle,
3709 IN ACCESS_MASK DesiredAccess,
3710 IN POBJECT_ATTRIBUTES ObjectAttributes,
3711 OUT PIO_STATUS_BLOCK IoStatusBlock,
3712 IN ULONG CreateOptions,
3713 IN ULONG MailslotQuota,
3714 IN ULONG MaxMessageSize,
3715 IN PLARGE_INTEGER TimeOut)
3716 {
3717 MAILSLOT_CREATE_PARAMETERS Buffer;
3718 PAGED_CODE();
3719
3720 /* Check for Timeout */
3721 if (TimeOut)
3722 {
3723 /* check if the call came from user mode */
3724 if (KeGetPreviousMode() != KernelMode)
3725 {
3726 /* Enter SEH for Probe */
3727 _SEH2_TRY
3728 {
3729 /* Probe the timeout */
3730 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
3731 }
3732 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3733 {
3734 /* Return the exception code */
3735 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3736 }
3737 _SEH2_END;
3738 }
3739 else
3740 {
3741 /* Otherwise, capture directly */
3742 Buffer.ReadTimeout = *TimeOut;
3743 }
3744
3745 /* Set the correct setting */
3746 Buffer.TimeoutSpecified = TRUE;
3747 }
3748 else
3749 {
3750 /* Tell the FSD we don't have a timeout */
3751 Buffer.TimeoutSpecified = FALSE;
3752 }
3753
3754 /* Set Settings */
3755 Buffer.MailslotQuota = MailslotQuota;
3756 Buffer.MaximumMessageSize = MaxMessageSize;
3757
3758 /* Call I/O */
3759 return IoCreateFile(FileHandle,
3760 DesiredAccess,
3761 ObjectAttributes,
3762 IoStatusBlock,
3763 NULL,
3764 0,
3765 FILE_SHARE_READ | FILE_SHARE_WRITE,
3766 FILE_CREATE,
3767 CreateOptions,
3768 NULL,
3769 0,
3770 CreateFileTypeMailslot,
3771 (PVOID)&Buffer,
3772 0);
3773 }
3774
3775 NTSTATUS
3776 NTAPI
3777 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
3778 IN ACCESS_MASK DesiredAccess,
3779 IN POBJECT_ATTRIBUTES ObjectAttributes,
3780 OUT PIO_STATUS_BLOCK IoStatusBlock,
3781 IN ULONG ShareAccess,
3782 IN ULONG CreateDisposition,
3783 IN ULONG CreateOptions,
3784 IN ULONG NamedPipeType,
3785 IN ULONG ReadMode,
3786 IN ULONG CompletionMode,
3787 IN ULONG MaximumInstances,
3788 IN ULONG InboundQuota,
3789 IN ULONG OutboundQuota,
3790 IN PLARGE_INTEGER DefaultTimeout)
3791 {
3792 NAMED_PIPE_CREATE_PARAMETERS Buffer;
3793 PAGED_CODE();
3794
3795 /* Check for Timeout */
3796 if (DefaultTimeout)
3797 {
3798 /* check if the call came from user mode */
3799 if (KeGetPreviousMode() != KernelMode)
3800 {
3801 /* Enter SEH for Probe */
3802 _SEH2_TRY
3803 {
3804 /* Probe the timeout */
3805 Buffer.DefaultTimeout =
3806 ProbeForReadLargeInteger(DefaultTimeout);
3807 }
3808 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3809 {
3810 /* Return the exception code */
3811 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3812 }
3813 _SEH2_END;
3814 }
3815 else
3816 {
3817 /* Otherwise, capture directly */
3818 Buffer.DefaultTimeout = *DefaultTimeout;
3819 }
3820
3821 /* Set the correct setting */
3822 Buffer.TimeoutSpecified = TRUE;
3823 }
3824 else
3825 {
3826 /* Tell the FSD we don't have a timeout */
3827 Buffer.TimeoutSpecified = FALSE;
3828 }
3829
3830 /* Set Settings */
3831 Buffer.NamedPipeType = NamedPipeType;
3832 Buffer.ReadMode = ReadMode;
3833 Buffer.CompletionMode = CompletionMode;
3834 Buffer.MaximumInstances = MaximumInstances;
3835 Buffer.InboundQuota = InboundQuota;
3836 Buffer.OutboundQuota = OutboundQuota;
3837
3838 /* Call I/O */
3839 return IoCreateFile(FileHandle,
3840 DesiredAccess,
3841 ObjectAttributes,
3842 IoStatusBlock,
3843 NULL,
3844 0,
3845 ShareAccess,
3846 CreateDisposition,
3847 CreateOptions,
3848 NULL,
3849 0,
3850 CreateFileTypeNamedPipe,
3851 (PVOID)&Buffer,
3852 0);
3853 }
3854
3855 NTSTATUS
3856 NTAPI
3857 NtFlushWriteBuffer(VOID)
3858 {
3859 PAGED_CODE();
3860
3861 /* Call the kernel */
3862 KeFlushWriteBuffer();
3863 return STATUS_SUCCESS;
3864 }
3865
3866 /*
3867 * @implemented
3868 */
3869 NTSTATUS
3870 NTAPI
3871 NtOpenFile(OUT PHANDLE FileHandle,
3872 IN ACCESS_MASK DesiredAccess,
3873 IN POBJECT_ATTRIBUTES ObjectAttributes,
3874 OUT PIO_STATUS_BLOCK IoStatusBlock,
3875 IN ULONG ShareAccess,
3876 IN ULONG OpenOptions)
3877 {
3878 /* Call the I/O Function */
3879 return IoCreateFile(FileHandle,
3880 DesiredAccess,
3881 ObjectAttributes,
3882 IoStatusBlock,
3883 NULL,
3884 0,
3885 ShareAccess,
3886 FILE_OPEN,
3887 OpenOptions,
3888 NULL,
3889 0,
3890 CreateFileTypeNone,
3891 NULL,
3892 0);
3893 }
3894
3895 NTSTATUS
3896 NTAPI
3897 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3898 OUT PFILE_BASIC_INFORMATION FileInformation)
3899 {
3900 /* Call the internal helper API */
3901 return IopQueryAttributesFile(ObjectAttributes,
3902 FileBasicInformation,
3903 sizeof(FILE_BASIC_INFORMATION),
3904 FileInformation);
3905 }
3906
3907 NTSTATUS
3908 NTAPI
3909 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3910 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
3911 {
3912 /* Call the internal helper API */
3913 return IopQueryAttributesFile(ObjectAttributes,
3914 FileNetworkOpenInformation,
3915 sizeof(FILE_NETWORK_OPEN_INFORMATION),
3916 FileInformation);
3917 }
3918
3919 /**
3920 * @name NtCancelIoFile
3921 *
3922 * Cancel all pending I/O operations in the current thread for specified
3923 * file object.
3924 *
3925 * @param FileHandle
3926 * Handle to file object to cancel requests for. No specific
3927 * access rights are needed.
3928 * @param IoStatusBlock
3929 * Pointer to status block which is filled with final completition
3930 * status on successful return.
3931 *
3932 * @return Status.
3933 *
3934 * @implemented
3935 */
3936 NTSTATUS
3937 NTAPI
3938 NtCancelIoFile(IN HANDLE FileHandle,
3939 OUT PIO_STATUS_BLOCK IoStatusBlock)
3940 {
3941 PFILE_OBJECT FileObject;
3942 PETHREAD Thread;
3943 PIRP Irp;
3944 KIRQL OldIrql;
3945 BOOLEAN OurIrpsInList = FALSE;
3946 LARGE_INTEGER Interval;
3947 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3948 NTSTATUS Status;
3949 PLIST_ENTRY ListHead, NextEntry;
3950 PAGED_CODE();
3951 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3952
3953 /* Check the previous mode */
3954 if (PreviousMode != KernelMode)
3955 {
3956 /* Enter SEH for probing */
3957 _SEH2_TRY
3958 {
3959 /* Probe the I/O Status Block */
3960 ProbeForWriteIoStatusBlock(IoStatusBlock);
3961 }
3962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3963 {
3964 /* Return the exception code */
3965 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3966 }
3967 _SEH2_END;
3968 }
3969
3970 /* Reference the file object */
3971 Status = ObReferenceObjectByHandle(FileHandle,
3972 0,
3973 IoFileObjectType,
3974 PreviousMode,
3975 (PVOID*)&FileObject,
3976 NULL);
3977 if (!NT_SUCCESS(Status)) return Status;
3978
3979 /* IRP cancellations are synchronized at APC_LEVEL. */
3980 KeRaiseIrql(APC_LEVEL, &OldIrql);
3981
3982 /* Get the current thread */
3983 Thread = PsGetCurrentThread();
3984
3985 /* Update the operation counts */
3986 IopUpdateOperationCount(IopOtherTransfer);
3987
3988 /* Loop the list */
3989 ListHead = &Thread->IrpList;
3990 NextEntry = ListHead->Flink;
3991 while (ListHead != NextEntry)
3992 {
3993 /* Get the IRP and check if the File Object matches */
3994 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
3995 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
3996 {
3997 /* Cancel this IRP and keep looping */
3998 IoCancelIrp(Irp);
3999 OurIrpsInList = TRUE;
4000 }
4001
4002 /* Go to the next entry */
4003 NextEntry = NextEntry->Flink;
4004 }
4005
4006 /* Lower the IRQL */
4007 KeLowerIrql(OldIrql);
4008
4009 /* Check if we had found an IRP */
4010 if (OurIrpsInList)
4011 {
4012 /* Setup a 10ms wait */
4013 Interval.QuadPart = -100000;
4014
4015 /* Start looping */
4016 while (OurIrpsInList)
4017 {
4018 /* Do the wait */
4019 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
4020 OurIrpsInList = FALSE;
4021
4022 /* Raise IRQL */
4023 KeRaiseIrql(APC_LEVEL, &OldIrql);
4024
4025 /* Now loop the list again */
4026 NextEntry = ListHead->Flink;
4027 while (NextEntry != ListHead)
4028 {
4029 /* Get the IRP and check if the File Object matches */
4030 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
4031 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
4032 {
4033 /* Keep looping */
4034 OurIrpsInList = TRUE;
4035 break;
4036 }
4037
4038 /* Go to the next entry */
4039 NextEntry = NextEntry->Flink;
4040 }
4041
4042 /* Lower the IRQL */
4043 KeLowerIrql(OldIrql);
4044 }
4045 }
4046
4047 /* Enter SEH for writing back the I/O Status */
4048 _SEH2_TRY
4049 {
4050 /* Write success */
4051 IoStatusBlock->Status = STATUS_SUCCESS;
4052 IoStatusBlock->Information = 0;
4053 }
4054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4055 {
4056 /* Ignore exception */
4057 }
4058 _SEH2_END;
4059
4060 /* Dereference the file object and return success */
4061 ObDereferenceObject(FileObject);
4062 return STATUS_SUCCESS;
4063 }
4064
4065 /*
4066 * @implemented
4067 */
4068 NTSTATUS
4069 NTAPI
4070 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
4071 {
4072 NTSTATUS Status;
4073 DUMMY_FILE_OBJECT LocalFileObject;
4074 HANDLE Handle;
4075 KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
4076 OPEN_PACKET OpenPacket;
4077 PAGED_CODE();
4078 IOTRACE(IO_API_DEBUG, "FileMame: %wZ\n", ObjectAttributes->ObjectName);
4079
4080 /* Setup the Open Packet */
4081 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
4082 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
4083 OpenPacket.Size = sizeof(OPEN_PACKET);
4084 OpenPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
4085 OpenPacket.ShareAccess = FILE_SHARE_READ |
4086 FILE_SHARE_WRITE |
4087 FILE_SHARE_DELETE;
4088 OpenPacket.Disposition = FILE_OPEN;
4089 OpenPacket.DeleteOnly = TRUE;
4090 OpenPacket.LocalFileObject = &LocalFileObject;
4091
4092 /* Update the operation counts */
4093 IopUpdateOperationCount(IopOtherTransfer);
4094
4095 /*
4096 * Attempt opening the file. This will call the I/O Parse Routine for
4097 * the File Object (IopParseDevice) which will use the dummy file obejct
4098 * send the IRP to its device object. Note that we have two statuses
4099 * to worry about: the Object Manager's status (in Status) and the I/O
4100 * status, which is in the Open Packet's Final Status, and determined
4101 * by the Parse Check member.
4102 */
4103 Status = ObOpenObjectByName(ObjectAttributes,
4104 NULL,
4105 AccessMode,
4106 NULL,
4107 DELETE,
4108 &OpenPacket,
4109 &Handle);
4110 if (OpenPacket.ParseCheck == FALSE) return Status;
4111
4112 /* Retrn the Io status */
4113 return OpenPacket.FinalStatus;
4114 }
4115
4116 /* EOF */