2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/file.c
5 * PURPOSE: Functions that deal with managing the FILE_OBJECT itself.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 * Filip Navara (navaraf@reactos.org)
12 /* INCLUDES *****************************************************************/
18 /* PRIVATE FUNCTIONS *********************************************************/
22 IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState
,
23 IN OUT PULONG CreateOptions
,
24 IN KPROCESSOR_MODE PreviousMode
,
27 ACCESS_MASK DesiredAccess
, ReadAccess
, WriteAccess
;
28 PRIVILEGE_SET Privileges
;
29 BOOLEAN AccessGranted
, HaveBackupPriv
= FALSE
, CheckRestore
= FALSE
;
32 /* Don't do anything if privileges were checked already */
33 if (AccessState
->Flags
& SE_BACKUP_PRIVILEGES_CHECKED
) return;
35 /* Check if the file was actually opened for backup purposes */
36 if (*CreateOptions
& FILE_OPEN_FOR_BACKUP_INTENT
)
38 /* Set the check flag since were doing it now */
39 AccessState
->Flags
|= SE_BACKUP_PRIVILEGES_CHECKED
;
41 /* Set the access masks required */
42 ReadAccess
= READ_CONTROL
|
43 ACCESS_SYSTEM_SECURITY
|
46 WriteAccess
= WRITE_DAC
|
48 ACCESS_SYSTEM_SECURITY
|
51 FILE_ADD_SUBDIRECTORY
|
53 DesiredAccess
= AccessState
->RemainingDesiredAccess
;
55 /* Check if desired access was the maximum */
56 if (DesiredAccess
& MAXIMUM_ALLOWED
)
58 /* Then add all the access masks required */
59 DesiredAccess
|= (ReadAccess
| WriteAccess
);
62 /* Check if the file already exists */
63 if (Disposition
& FILE_OPEN
)
65 /* Check if desired access has the read mask */
66 if (ReadAccess
& DesiredAccess
)
68 /* Setup the privilege check lookup */
69 Privileges
.PrivilegeCount
= 1;
70 Privileges
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
71 Privileges
.Privilege
[0].Luid
= SeBackupPrivilege
;
72 Privileges
.Privilege
[0].Attributes
= 0;
73 AccessGranted
= SePrivilegeCheck(&Privileges
,
75 SubjectSecurityContext
,
79 /* Remember that backup was allowed */
80 HaveBackupPriv
= TRUE
;
82 /* Append the privileges and update the access state */
83 SeAppendPrivileges(AccessState
, &Privileges
);
84 AccessState
->PreviouslyGrantedAccess
|= (DesiredAccess
& ReadAccess
);
85 AccessState
->RemainingDesiredAccess
&= ~ReadAccess
;
86 DesiredAccess
&= ~ReadAccess
;
88 /* Set backup privilege for the token */
89 AccessState
->Flags
|= TOKEN_HAS_BACKUP_PRIVILEGE
;
95 /* Caller is creating the file, check restore privileges later */
99 /* Check if caller wants write access or if it's creating a file */
100 if ((WriteAccess
& DesiredAccess
) || (CheckRestore
))
102 /* Setup the privilege lookup and do it */
103 Privileges
.PrivilegeCount
= 1;
104 Privileges
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
105 Privileges
.Privilege
[0].Luid
= SeRestorePrivilege
;
106 Privileges
.Privilege
[0].Attributes
= 0;
107 AccessGranted
= SePrivilegeCheck(&Privileges
,
108 &AccessState
->SubjectSecurityContext
,
112 /* Remember that privilege was given */
113 HaveBackupPriv
= TRUE
;
115 /* Append the privileges and update the access state */
116 SeAppendPrivileges(AccessState
, &Privileges
);
117 AccessState
->PreviouslyGrantedAccess
|= (DesiredAccess
& WriteAccess
);
118 AccessState
->RemainingDesiredAccess
&= ~WriteAccess
;
120 /* Set restore privilege for the token */
121 AccessState
->Flags
|= TOKEN_HAS_RESTORE_PRIVILEGE
;
125 /* If we don't have the privilege, remove the option */
126 if (!HaveBackupPriv
) *CreateOptions
&= ~FILE_OPEN_FOR_BACKUP_INTENT
;
132 IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket
,
133 IN PDEVICE_OBJECT DeviceObject
)
135 /* Make sure the object is valid */
136 if ((IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
137 (DOE_UNLOAD_PENDING
|
140 DOE_REMOVE_PROCESSED
)) ||
141 (DeviceObject
->Flags
& DO_DEVICE_INITIALIZING
))
143 /* It's unloading or initializing, so fail */
144 DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
145 " sucks. Please fix it's AddDevice Routine\n",
146 &DeviceObject
->DriverObject
->DriverName
);
147 return STATUS_NO_SUCH_DEVICE
;
149 else if ((DeviceObject
->Flags
& DO_EXCLUSIVE
) &&
150 (DeviceObject
->ReferenceCount
) &&
151 !(OpenPacket
->RelatedFileObject
) &&
152 !(OpenPacket
->Options
& IO_ATTACH_DEVICE
))
154 return STATUS_ACCESS_DENIED
;
159 /* Increase reference count */
160 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
161 return STATUS_SUCCESS
;
167 IopParseDevice(IN PVOID ParseObject
,
169 IN OUT PACCESS_STATE AccessState
,
170 IN KPROCESSOR_MODE AccessMode
,
172 IN OUT PUNICODE_STRING CompleteName
,
173 IN OUT PUNICODE_STRING RemainingName
,
174 IN OUT PVOID Context
,
175 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
178 POPEN_PACKET OpenPacket
= (POPEN_PACKET
)Context
;
179 PDEVICE_OBJECT OriginalDeviceObject
= (PDEVICE_OBJECT
)ParseObject
;
180 PDEVICE_OBJECT DeviceObject
, OwnerDevice
;
182 PFILE_OBJECT FileObject
;
185 PEXTENDED_IO_STACK_LOCATION StackLoc
;
186 IO_SECURITY_CONTEXT SecurityContext
;
187 IO_STATUS_BLOCK IoStatusBlock
;
188 BOOLEAN DirectOpen
= FALSE
, OpenCancelled
, UseDummyFile
;
189 OBJECT_ATTRIBUTES ObjectAttributes
;
191 PDUMMY_FILE_OBJECT DummyFileObject
;
192 PFILE_BASIC_INFORMATION FileBasicInfo
;
194 KPROCESSOR_MODE CheckMode
;
195 BOOLEAN VolumeOpen
= FALSE
;
196 ACCESS_MASK DesiredAccess
, GrantedAccess
;
197 BOOLEAN AccessGranted
, LockHeld
= FALSE
;
198 PPRIVILEGE_SET Privileges
= NULL
;
199 IOTRACE(IO_FILE_DEBUG
, "ParseObject: %p. RemainingName: %wZ\n",
200 ParseObject
, RemainingName
);
205 /* Validate the open packet */
206 if (!IopValidateOpenPacket(OpenPacket
)) return STATUS_OBJECT_TYPE_MISMATCH
;
208 /* Check if we have a related file object */
209 if (OpenPacket
->RelatedFileObject
)
211 /* Use the related file object's device object */
212 OriginalDeviceObject
= OpenPacket
->RelatedFileObject
->DeviceObject
;
215 /* Validate device status */
216 Status
= IopCheckDeviceAndDriver(OpenPacket
, OriginalDeviceObject
);
217 if (!NT_SUCCESS(Status
))
219 /* We failed, return status */
220 OpenPacket
->FinalStatus
= Status
;
224 /* Map the generic mask and set the new mapping in the access state */
225 RtlMapGenericMask(&AccessState
->RemainingDesiredAccess
,
226 &IoFileObjectType
->TypeInfo
.GenericMapping
);
227 RtlMapGenericMask(&AccessState
->OriginalDesiredAccess
,
228 &IoFileObjectType
->TypeInfo
.GenericMapping
);
229 SeSetAccessStateGenericMapping(AccessState
,
230 &IoFileObjectType
->TypeInfo
.GenericMapping
);
231 DesiredAccess
= AccessState
->RemainingDesiredAccess
;
233 /* Check what kind of access checks to do */
234 if ((AccessMode
!= KernelMode
) ||
235 (OpenPacket
->Options
& IO_FORCE_ACCESS_CHECK
))
237 /* Call is from user-mode or kernel is forcing checks */
238 CheckMode
= UserMode
;
242 /* Call is from the kernel */
243 CheckMode
= KernelMode
;
246 /* Check privilege for backup or restore operation */
247 IopCheckBackupRestorePrivilege(AccessState
,
248 &OpenPacket
->CreateOptions
,
250 OpenPacket
->Disposition
);
252 /* Check if we are re-parsing */
253 if (((OpenPacket
->Override
) && !(RemainingName
->Length
)) ||
254 (AccessState
->Flags
& SE_BACKUP_PRIVILEGES_CHECKED
))
256 /* Get granted access from the last call */
257 DesiredAccess
|= AccessState
->PreviouslyGrantedAccess
;
260 /* Check if this is a volume open */
261 if ((OpenPacket
->RelatedFileObject
) &&
262 (OpenPacket
->RelatedFileObject
->Flags
& FO_VOLUME_OPEN
) &&
263 !(RemainingName
->Length
))
269 /* Now check if we need access checks */
270 if (((AccessMode
!= KernelMode
) ||
271 (OpenPacket
->Options
& IO_FORCE_ACCESS_CHECK
)) &&
272 (!(OpenPacket
->RelatedFileObject
) || (VolumeOpen
)) &&
273 !(OpenPacket
->Override
))
275 /* Check if a device object is being parsed */
276 if (!RemainingName
->Length
)
278 /* Lock the subject context */
279 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
282 /* Do access check */
283 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->
285 &AccessState
->SubjectSecurityContext
,
291 TypeInfo
.GenericMapping
,
297 /* Append and free the privileges */
298 SeAppendPrivileges(AccessState
, Privileges
);
299 SeFreePrivileges(Privileges
);
302 /* Check if we got access */
305 /* Update access state */
306 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
307 AccessState
->RemainingDesiredAccess
&= ~(GrantedAccess
&
309 OpenPacket
->Override
= TRUE
;
312 /* FIXME: Do Audit/Alarm for open operation */
316 /* Check if we need to do traverse validation */
317 if (!(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
) ||
318 ((OriginalDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
319 (OriginalDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
)))
321 /* Check if this is a restricted token */
322 if (!(AccessState
->Flags
& TOKEN_IS_RESTRICTED
))
324 /* FIXME: Do the FAST traverse check */
325 AccessGranted
= FALSE
;
330 AccessGranted
= FALSE
;
333 /* Check if we failed to get access */
336 /* Lock the subject context */
337 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
340 /* Do access check */
341 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->
343 &AccessState
->SubjectSecurityContext
,
349 TypeInfo
.GenericMapping
,
355 /* Append and free the privileges */
356 SeAppendPrivileges(AccessState
, Privileges
);
357 SeFreePrivileges(Privileges
);
361 /* FIXME: Do Audit/Alarm for traverse check */
365 /* Access automatically granted */
366 AccessGranted
= TRUE
;
370 /* Check if we hold the lock */
374 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
377 /* Check if access failed */
380 /* Dereference the device and fail */
381 DPRINT1("Traverse access failed!\n");
382 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
383 return STATUS_ACCESS_DENIED
;
387 /* Check if we can simply use a dummy file */
388 UseDummyFile
= ((OpenPacket
->QueryOnly
) || (OpenPacket
->DeleteOnly
));
390 /* Check if this is a direct open */
391 if (!(RemainingName
->Length
) &&
392 !(OpenPacket
->RelatedFileObject
) &&
393 ((DesiredAccess
& ~(SYNCHRONIZE
|
394 FILE_READ_ATTRIBUTES
|
396 ACCESS_SYSTEM_SECURITY
|
401 /* Remember this for later */
405 /* FIXME: Small hack still exists, have to check why...
406 * This is triggered multiple times by usetup and then once per boot.
409 !(RemainingName
->Length
) &&
410 !(OpenPacket
->RelatedFileObject
) &&
411 ((wcsstr(CompleteName
->Buffer
, L
"Harddisk")) ||
412 (wcsstr(CompleteName
->Buffer
, L
"Floppy"))) &&
415 DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
416 DesiredAccess
& ~(SYNCHRONIZE
|
417 FILE_READ_ATTRIBUTES
|
419 ACCESS_SYSTEM_SECURITY
|
425 /* Check if we have a related FO that wasn't a direct open */
426 if ((OpenPacket
->RelatedFileObject
) &&
427 !(OpenPacket
->RelatedFileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
429 /* The device object is the one we were given */
430 DeviceObject
= ParseObject
;
432 /* Check if the related FO had a VPB */
433 if (OpenPacket
->RelatedFileObject
->Vpb
)
435 /* Yes, remember it */
436 Vpb
= OpenPacket
->RelatedFileObject
->Vpb
;
439 InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
444 /* The device object is the one we were given */
445 DeviceObject
= OriginalDeviceObject
;
447 /* Check if it has a VPB */
448 if ((OriginalDeviceObject
->Vpb
) && !(DirectOpen
))
450 /* Check if the VPB is mounted, and mount it */
451 Vpb
= IopCheckVpbMounted(OpenPacket
,
452 OriginalDeviceObject
,
455 if (!Vpb
) return Status
;
457 /* Get the VPB's device object */
458 DeviceObject
= Vpb
->DeviceObject
;
461 /* Check if there's an attached device */
462 if (DeviceObject
->AttachedDevice
)
464 /* Get the attached device */
465 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
469 /* Check if this is a secure FSD */
470 if ((DeviceObject
->Characteristics
& FILE_DEVICE_SECURE_OPEN
) &&
471 ((OpenPacket
->RelatedFileObject
) || (RemainingName
->Length
)) &&
474 DPRINT("Fix Secure FSD support!!!\n");
477 /* Allocate the IRP */
478 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
481 /* Dereference the device and VPB, then fail */
482 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
483 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
484 return STATUS_INSUFFICIENT_RESOURCES
;
487 /* Now set the IRP data */
488 Irp
->RequestorMode
= AccessMode
;
489 Irp
->Flags
= IRP_CREATE_OPERATION
|
490 IRP_SYNCHRONOUS_API
|
491 IRP_DEFER_IO_COMPLETION
;
492 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
493 Irp
->UserIosb
= &IoStatusBlock
;
494 Irp
->MdlAddress
= NULL
;
495 Irp
->PendingReturned
= FALSE
;
496 Irp
->UserEvent
= NULL
;
498 Irp
->CancelRoutine
= NULL
;
499 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
501 /* Setup the security context */
502 SecurityContext
.SecurityQos
= SecurityQos
;
503 SecurityContext
.AccessState
= AccessState
;
504 SecurityContext
.DesiredAccess
= AccessState
->RemainingDesiredAccess
;
505 SecurityContext
.FullCreateOptions
= OpenPacket
->CreateOptions
;
507 /* Get the I/O Stack location */
508 StackLoc
= (PEXTENDED_IO_STACK_LOCATION
)IoGetNextIrpStackLocation(Irp
);
509 StackLoc
->Control
= 0;
511 /* Check what kind of file this is */
512 switch (OpenPacket
->CreateFileType
)
515 case CreateFileTypeNone
:
517 /* Set the major function and EA Length */
518 StackLoc
->MajorFunction
= IRP_MJ_CREATE
;
519 StackLoc
->Parameters
.Create
.EaLength
= OpenPacket
->EaLength
;
522 StackLoc
->Flags
= (UCHAR
)OpenPacket
->Options
;
523 StackLoc
->Flags
|= !(Attributes
& OBJ_CASE_INSENSITIVE
) ?
524 SL_CASE_SENSITIVE
: 0;
528 case CreateFileTypeNamedPipe
:
530 /* Set the named pipe MJ and set the parameters */
531 StackLoc
->MajorFunction
= IRP_MJ_CREATE_NAMED_PIPE
;
532 StackLoc
->Parameters
.CreatePipe
.Parameters
=
533 OpenPacket
->MailslotOrPipeParameters
;
537 case CreateFileTypeMailslot
:
539 /* Set the mailslot MJ and set the parameters */
540 StackLoc
->MajorFunction
= IRP_MJ_CREATE_MAILSLOT
;
541 StackLoc
->Parameters
.CreateMailslot
.Parameters
=
542 OpenPacket
->MailslotOrPipeParameters
;
546 /* Set the common data */
547 Irp
->Overlay
.AllocationSize
= OpenPacket
->AllocationSize
;
548 Irp
->AssociatedIrp
.SystemBuffer
= OpenPacket
->EaBuffer
;
549 StackLoc
->Parameters
.Create
.Options
= (OpenPacket
->Disposition
<< 24) |
550 (OpenPacket
->CreateOptions
&
552 StackLoc
->Parameters
.Create
.FileAttributes
= OpenPacket
->FileAttributes
;
553 StackLoc
->Parameters
.Create
.ShareAccess
= OpenPacket
->ShareAccess
;
554 StackLoc
->Parameters
.Create
.SecurityContext
= &SecurityContext
;
556 /* Check if we really need to create an object */
559 /* Create the actual file object */
560 InitializeObjectAttributes(&ObjectAttributes
,
565 Status
= ObCreateObject(KernelMode
,
573 (PVOID
*)&FileObject
);
574 if (!NT_SUCCESS(Status
))
576 /* Create failed, free the IRP */
579 /* Dereference the device and VPB */
580 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
581 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
583 /* We failed, return status */
584 OpenPacket
->FinalStatus
= Status
;
588 /* Clear the file object */
589 RtlZeroMemory(FileObject
, sizeof(FILE_OBJECT
));
591 /* Check if this is Synch I/O */
592 if (OpenPacket
->CreateOptions
&
593 (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
))
595 /* Set the synch flag */
596 FileObject
->Flags
|= FO_SYNCHRONOUS_IO
;
598 /* Check if it's also alertable */
599 if (OpenPacket
->CreateOptions
& FILE_SYNCHRONOUS_IO_ALERT
)
601 /* It is, set the alertable flag */
602 FileObject
->Flags
|= FO_ALERTABLE_IO
;
606 /* Check if this is synch I/O */
607 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
609 /* Initialize the event */
610 KeInitializeEvent(&FileObject
->Lock
, SynchronizationEvent
, FALSE
);
613 /* Check if the caller requested no intermediate buffering */
614 if (OpenPacket
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
)
616 /* Set the correct flag for the FSD to read */
617 FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
620 /* Check if the caller requested write through support */
621 if (OpenPacket
->CreateOptions
& FILE_WRITE_THROUGH
)
623 /* Set the correct flag for the FSD to read */
624 FileObject
->Flags
|= FO_WRITE_THROUGH
;
627 /* Check if the caller says the file will be only read sequentially */
628 if (OpenPacket
->CreateOptions
& FILE_SEQUENTIAL_ONLY
)
630 /* Set the correct flag for the FSD to read */
631 FileObject
->Flags
|= FO_SEQUENTIAL_ONLY
;
634 /* Check if the caller believes the file will be only read randomly */
635 if (OpenPacket
->CreateOptions
& FILE_RANDOM_ACCESS
)
637 /* Set the correct flag for the FSD to read */
638 FileObject
->Flags
|= FO_RANDOM_ACCESS
;
643 /* Use the dummy object instead */
644 DummyFileObject
= OpenPacket
->DummyFileObject
;
645 RtlZeroMemory(DummyFileObject
, sizeof(DUMMY_FILE_OBJECT
));
648 FileObject
= (PFILE_OBJECT
)&DummyFileObject
->ObjectHeader
.Body
;
649 DummyFileObject
->ObjectHeader
.Type
= IoFileObjectType
;
650 DummyFileObject
->ObjectHeader
.PointerCount
= 1;
653 /* Setup the file header */
654 FileObject
->Type
= IO_TYPE_FILE
;
655 FileObject
->Size
= sizeof(FILE_OBJECT
);
656 FileObject
->RelatedFileObject
= OpenPacket
->RelatedFileObject
;
657 FileObject
->DeviceObject
= OriginalDeviceObject
;
659 /* Check if this is a direct device open */
660 if (DirectOpen
) FileObject
->Flags
|= FO_DIRECT_DEVICE_OPEN
;
662 /* Check if the caller wants case sensitivity */
663 if (!(Attributes
& OBJ_CASE_INSENSITIVE
))
665 /* Tell the driver about it */
666 FileObject
->Flags
|= FO_OPENED_CASE_SENSITIVE
;
669 /* Now set the file object */
670 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
671 StackLoc
->FileObject
= FileObject
;
673 /* Check if the file object has a name */
674 if (RemainingName
->Length
)
676 /* Setup the unicode string */
677 FileObject
->FileName
.MaximumLength
= RemainingName
->Length
+
679 FileObject
->FileName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
684 if (!FileObject
->FileName
.Buffer
)
686 /* Failed to allocate the name, free the IRP */
689 /* Dereference the device object and VPB */
690 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
691 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
693 /* Clear the FO and dereference it */
694 FileObject
->DeviceObject
= NULL
;
695 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
698 return STATUS_INSUFFICIENT_RESOURCES
;
703 RtlCopyUnicodeString(&FileObject
->FileName
, RemainingName
);
705 /* Initialize the File Object event and set the FO */
706 KeInitializeEvent(&FileObject
->Event
, NotificationEvent
, FALSE
);
707 OpenPacket
->FileObject
= FileObject
;
709 /* Queue the IRP and call the driver */
710 IopQueueIrpToThread(Irp
);
711 Status
= IoCallDriver(DeviceObject
, Irp
);
712 if (Status
== STATUS_PENDING
)
714 /* Wait for the driver to complete the create */
715 KeWaitForSingleObject(&FileObject
->Event
,
721 /* Get the new status */
722 Status
= IoStatusBlock
.Status
;
726 /* We'll have to complete it ourselves */
727 ASSERT(!Irp
->PendingReturned
);
728 ASSERT(!Irp
->MdlAddress
);
730 /* Completion happens at APC_LEVEL */
731 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
733 /* Get the new I/O Status block ourselves */
734 IoStatusBlock
= Irp
->IoStatus
;
735 Status
= IoStatusBlock
.Status
;
737 /* Manually signal the even, we can't have any waiters */
738 FileObject
->Event
.Header
.SignalState
= 1;
740 /* Now that we've signaled the events, de-associate the IRP */
741 IopUnQueueIrpFromThread(Irp
);
743 /* Check if the IRP had an input buffer */
744 if ((Irp
->Flags
& IRP_BUFFERED_IO
) &&
745 (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
))
747 /* Free it. A driver might've tacked one on */
748 ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
751 /* Free the IRP and bring the IRQL back down */
753 KeLowerIrql(OldIrql
);
756 /* Copy the I/O Status */
757 OpenPacket
->Information
= IoStatusBlock
.Information
;
759 /* The driver failed to create the file */
760 if (!NT_SUCCESS(Status
))
762 /* Check if we have a name */
763 if (FileObject
->FileName
.Length
)
766 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
767 FileObject
->FileName
.Length
= 0;
770 /* Clear its device object */
771 FileObject
->DeviceObject
= NULL
;
773 /* Save this now because the FO might go away */
774 OpenCancelled
= FileObject
->Flags
& FO_FILE_OPEN_CANCELLED
?
777 /* Clear the file object in the open packet */
778 OpenPacket
->FileObject
= NULL
;
780 /* Dereference the file object */
781 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
783 /* Dereference the device object */
784 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
786 /* Unless the driver cancelled the open, dereference the VPB */
787 if (!(OpenCancelled
) && (Vpb
)) IopDereferenceVpbAndFree(Vpb
);
789 /* Set the status and return */
790 OpenPacket
->FinalStatus
= Status
;
793 else if (Status
== STATUS_REPARSE
)
795 /* FIXME: We don't handle this at all! */
799 /* Get the owner of the File Object */
800 OwnerDevice
= IoGetRelatedDeviceObject(FileObject
);
803 * It's possible that the device to whom we sent the IRP to
804 * isn't actually the device that ended opening the file object
807 if (OwnerDevice
!= DeviceObject
)
809 /* We have to de-reference the VPB we had associated */
810 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
812 /* And re-associate with the actual one */
813 Vpb
= FileObject
->Vpb
;
814 if (Vpb
) InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
817 /* Make sure we are not using a dummy */
820 /* Check if this was a volume open */
821 if ((!(FileObject
->RelatedFileObject
) ||
822 (FileObject
->RelatedFileObject
->Flags
& FO_VOLUME_OPEN
)) &&
823 !(FileObject
->FileName
.Length
))
825 /* All signs point to it, but make sure it was actually an FSD */
826 if ((OwnerDevice
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
827 (OwnerDevice
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
828 (OwnerDevice
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
) ||
829 (OwnerDevice
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
))
831 /* The owner device is an FSD, so this is a volume open for real */
832 FileObject
->Flags
|= FO_VOLUME_OPEN
;
836 /* Reference the object and set the parse check */
837 ObReferenceObject(FileObject
);
838 *Object
= FileObject
;
839 OpenPacket
->FinalStatus
= IoStatusBlock
.Status
;
840 OpenPacket
->ParseCheck
= TRUE
;
841 return OpenPacket
->FinalStatus
;
845 /* Check if this was a query */
846 if (OpenPacket
->QueryOnly
)
848 /* Check if the caller wants basic info only */
849 if (!OpenPacket
->FullAttributes
)
851 /* Allocate the buffer */
852 FileBasicInfo
= ExAllocatePoolWithTag(NonPagedPool
,
853 sizeof(*FileBasicInfo
),
858 Status
= IoQueryFileInformation(FileObject
,
859 FileBasicInformation
,
860 sizeof(*FileBasicInfo
),
863 if (NT_SUCCESS(Status
))
866 RtlCopyMemory(OpenPacket
->BasicInformation
,
871 /* Free our buffer */
872 ExFreePoolWithTag(FileBasicInfo
, TAG_IO
);
877 Status
= STATUS_INSUFFICIENT_RESOURCES
;
882 /* This is a full query */
883 Status
= IoQueryFileInformation(
885 FileNetworkOpenInformation
,
886 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
887 OpenPacket
->NetworkInformation
,
889 if (!NT_SUCCESS(Status
)) ASSERT(Status
!= STATUS_NOT_IMPLEMENTED
);
893 /* Delete the file object */
894 IopDeleteFile(FileObject
);
896 /* Clear out the file */
897 OpenPacket
->FileObject
= NULL
;
899 /* Set and return status */
900 OpenPacket
->FinalStatus
= Status
;
901 OpenPacket
->ParseCheck
= TRUE
;
908 IopParseFile(IN PVOID ParseObject
,
910 IN OUT PACCESS_STATE AccessState
,
911 IN KPROCESSOR_MODE AccessMode
,
913 IN OUT PUNICODE_STRING CompleteName
,
914 IN OUT PUNICODE_STRING RemainingName
,
915 IN OUT PVOID Context OPTIONAL
,
916 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
920 POPEN_PACKET OpenPacket
= (POPEN_PACKET
)Context
;
922 /* Validate the open packet */
923 if (!IopValidateOpenPacket(OpenPacket
)) return STATUS_OBJECT_TYPE_MISMATCH
;
925 /* Get the device object */
926 DeviceObject
= IoGetRelatedDeviceObject(ParseObject
);
927 OpenPacket
->RelatedFileObject
= ParseObject
;
929 /* Call the main routine */
930 return IopParseDevice(DeviceObject
,
944 IopDeleteFile(IN PVOID ObjectBody
)
946 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
948 PIO_STACK_LOCATION StackPtr
;
951 PDEVICE_OBJECT DeviceObject
;
952 BOOLEAN DereferenceDone
= FALSE
;
955 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
957 /* Check if the file has a device object */
958 if (FileObject
->DeviceObject
)
960 /* Check if this is a direct open or not */
961 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
963 /* Get the attached device */
964 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
968 /* Use the file object's device object */
969 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
973 ASSERT(!(FileObject
->Flags
& FO_SYNCHRONOUS_IO
) ||
974 (InterlockedExchange((PLONG
)&FileObject
->Busy
, TRUE
) == FALSE
));
976 /* Check if the handle wasn't created yet */
977 if (!(FileObject
->Flags
& FO_HANDLE_CREATED
))
979 /* Send the cleanup IRP */
980 IopCloseFile(NULL
, ObjectBody
, 0, 1, 1);
983 /* Clear and set up Events */
984 KeClearEvent(&FileObject
->Event
);
985 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
987 /* Allocate an IRP */
988 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
992 Irp
->UserEvent
= &Event
;
993 Irp
->UserIosb
= &Irp
->IoStatus
;
994 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
995 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
996 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
998 /* Set up Stack Pointer Data */
999 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1000 StackPtr
->MajorFunction
= IRP_MJ_CLOSE
;
1001 StackPtr
->FileObject
= FileObject
;
1004 IopQueueIrpToThread(Irp
);
1006 /* Get the VPB and check if this isn't a direct open */
1007 Vpb
= FileObject
->Vpb
;
1008 if ((Vpb
) && !(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1010 /* Dereference the VPB before the close */
1011 InterlockedDecrement((PLONG
)&Vpb
->ReferenceCount
);
1014 /* Check if the FS will never disappear by itself */
1015 if (FileObject
->DeviceObject
->Flags
& DO_NEVER_LAST_DEVICE
)
1017 /* Dereference it */
1018 InterlockedDecrement(&FileObject
->DeviceObject
->ReferenceCount
);
1019 DereferenceDone
= TRUE
;
1022 /* Call the FS Driver */
1023 Status
= IoCallDriver(DeviceObject
, Irp
);
1024 if (Status
== STATUS_PENDING
)
1026 /* Wait for completion */
1027 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1030 /* De-queue the IRP */
1031 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1032 IopUnQueueIrpFromThread(Irp
);
1033 KeLowerIrql(OldIrql
);
1038 /* Clear the file name */
1039 if (FileObject
->FileName
.Buffer
)
1041 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
1042 FileObject
->FileName
.Buffer
= NULL
;
1045 /* Check if the FO had a completion port */
1046 if (FileObject
->CompletionContext
)
1049 ObDereferenceObject(FileObject
->CompletionContext
->Port
);
1050 ExFreePool(FileObject
->CompletionContext
);
1053 /* Check if the FO had extension */
1054 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1056 /* Release filter context structure if any */
1057 FsRtlPTeardownPerFileObjectContexts(FileObject
);
1060 /* Check if dereference has been done yet */
1061 if (!DereferenceDone
)
1063 /* Dereference device object */
1064 IopDereferenceDeviceObject(FileObject
->DeviceObject
, FALSE
);
1071 IopSecurityFile(IN PVOID ObjectBody
,
1072 IN SECURITY_OPERATION_CODE OperationCode
,
1073 IN PSECURITY_INFORMATION SecurityInformation
,
1074 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1075 IN OUT PULONG BufferLength
,
1076 IN OUT PSECURITY_DESCRIPTOR
*OldSecurityDescriptor
,
1077 IN POOL_TYPE PoolType
,
1078 IN OUT PGENERIC_MAPPING GenericMapping
)
1080 IO_STATUS_BLOCK IoStatusBlock
;
1081 PIO_STACK_LOCATION StackPtr
;
1082 PFILE_OBJECT FileObject
;
1083 PDEVICE_OBJECT DeviceObject
;
1085 BOOLEAN LocalEvent
= FALSE
;
1087 NTSTATUS Status
= STATUS_SUCCESS
;
1089 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1091 /* Check if this is a device or file */
1092 if (((PFILE_OBJECT
)ObjectBody
)->Type
== IO_TYPE_DEVICE
)
1095 DeviceObject
= (PDEVICE_OBJECT
)ObjectBody
;
1101 FileObject
= (PFILE_OBJECT
)ObjectBody
;
1103 /* Check if this is a direct open */
1104 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1106 /* Get the Device Object */
1107 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1111 /* Otherwise, use the direct device*/
1112 DeviceObject
= FileObject
->DeviceObject
;
1116 /* Check if the request was for a device object */
1117 if (!(FileObject
) ||
1118 (!(FileObject
->FileName
.Length
) && !(FileObject
->RelatedFileObject
)) ||
1119 (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1121 /* Check what kind of request this was */
1122 if (OperationCode
== QuerySecurityDescriptor
)
1124 return SeQuerySecurityDescriptorInfo(SecurityInformation
,
1127 &DeviceObject
->SecurityDescriptor
);
1129 else if (OperationCode
== DeleteSecurityDescriptor
)
1131 /* Simply return success */
1132 return STATUS_SUCCESS
;
1134 else if (OperationCode
== AssignSecurityDescriptor
)
1136 /* Make absolutely sure this is a device object */
1137 if (!(FileObject
) || !(FileObject
->Flags
& FO_STREAM_FILE
))
1139 /* Assign the Security Descriptor */
1140 DeviceObject
->SecurityDescriptor
= SecurityDescriptor
;
1143 /* Return success */
1144 return STATUS_SUCCESS
;
1148 DPRINT1("FIXME: Set SD unimplemented for Devices\n");
1149 return STATUS_SUCCESS
;
1152 else if (OperationCode
== DeleteSecurityDescriptor
)
1154 /* Same as for devices, do nothing */
1155 return STATUS_SUCCESS
;
1158 /* At this point, we know we're a file. Reference it */
1159 ObReferenceObject(FileObject
);
1161 /* Check if we should use Sync IO or not */
1162 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
1164 /* Lock the file object */
1165 IopLockFileObject(FileObject
);
1169 /* Use local event */
1170 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1174 /* Clear the File Object event */
1175 KeClearEvent(&FileObject
->Event
);
1177 /* Get the device object */
1178 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1180 /* Allocate the IRP */
1181 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1182 if (!Irp
) return IopCleanupFailedIrp(FileObject
, NULL
, NULL
);
1185 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1186 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1187 Irp
->RequestorMode
= ExGetPreviousMode();
1188 Irp
->UserIosb
= &IoStatusBlock
;
1189 Irp
->UserEvent
= (LocalEvent
) ? &Event
: NULL
;
1190 Irp
->Flags
= (LocalEvent
) ? IRP_SYNCHRONOUS_API
: 0;
1191 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
1193 /* Set Stack Parameters */
1194 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1195 StackPtr
->FileObject
= FileObject
;
1197 /* Check if this is a query or set */
1198 if (OperationCode
== QuerySecurityDescriptor
)
1200 /* Set the major function and parameters */
1201 StackPtr
->MajorFunction
= IRP_MJ_QUERY_SECURITY
;
1202 StackPtr
->Parameters
.QuerySecurity
.SecurityInformation
=
1203 *SecurityInformation
;
1204 StackPtr
->Parameters
.QuerySecurity
.Length
= *BufferLength
;
1205 Irp
->UserBuffer
= SecurityDescriptor
;
1209 /* Set the major function and parameters for a set */
1210 StackPtr
->MajorFunction
= IRP_MJ_SET_SECURITY
;
1211 StackPtr
->Parameters
.SetSecurity
.SecurityInformation
=
1212 *SecurityInformation
;
1213 StackPtr
->Parameters
.SetSecurity
.SecurityDescriptor
=
1218 IopQueueIrpToThread(Irp
);
1220 /* Update operation counts */
1221 IopUpdateOperationCount(IopOtherTransfer
);
1223 /* Call the Driver */
1224 Status
= IoCallDriver(DeviceObject
, Irp
);
1226 /* Check if this was async I/O */
1229 /* Check if the IRP is pending completion */
1230 if (Status
== STATUS_PENDING
)
1232 /* Wait on the local event */
1233 KeWaitForSingleObject(&Event
,
1238 Status
= IoStatusBlock
.Status
;
1243 /* Check if the IRP is pending completion */
1244 if (Status
== STATUS_PENDING
)
1246 /* Wait on the file object */
1247 KeWaitForSingleObject(&FileObject
->Event
,
1252 Status
= FileObject
->FinalStatus
;
1255 /* Release the lock */
1256 IopUnlockFileObject(FileObject
);
1259 /* This Driver doesn't implement Security, so try to give it a default */
1260 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
1262 /* Was this a query? */
1263 if (OperationCode
== QuerySecurityDescriptor
)
1265 /* Set a World Security Descriptor */
1266 Status
= SeSetWorldSecurityDescriptor(*SecurityInformation
,
1272 /* It wasn't a query, so just fake success */
1273 Status
= STATUS_SUCCESS
;
1276 else if (OperationCode
== QuerySecurityDescriptor
)
1278 /* Callers usually expect the normalized form */
1279 if (Status
== STATUS_BUFFER_OVERFLOW
) Status
= STATUS_BUFFER_TOO_SMALL
;
1284 *BufferLength
= (ULONG
)IoStatusBlock
.Information
;
1286 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1288 /* Get the exception code */
1289 Status
= _SEH2_GetExceptionCode();
1300 IopQueryNameFile(IN PVOID ObjectBody
,
1302 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1304 OUT PULONG ReturnLength
,
1305 IN KPROCESSOR_MODE PreviousMode
)
1307 POBJECT_NAME_INFORMATION LocalInfo
;
1308 PFILE_NAME_INFORMATION LocalFileInfo
;
1309 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1310 ULONG LocalReturnLength
, FileLength
;
1311 BOOLEAN LengthMismatch
= FALSE
;
1314 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1316 /* Validate length */
1317 if (Length
< sizeof(OBJECT_NAME_INFORMATION
))
1319 /* Wrong length, fail */
1320 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1321 return STATUS_INFO_LENGTH_MISMATCH
;
1324 /* Allocate Buffer */
1325 LocalInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_IO
);
1326 if (!LocalInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
1328 /* Query the name */
1329 Status
= ObQueryNameString(FileObject
->DeviceObject
,
1332 &LocalReturnLength
);
1333 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_INFO_LENGTH_MISMATCH
))
1335 /* Free the buffer and fail */
1336 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
1340 /* Copy the information */
1341 RtlCopyMemory(ObjectNameInfo
,
1343 (LocalReturnLength
> Length
) ?
1344 Length
: LocalReturnLength
);
1346 /* Set buffer pointer */
1347 p
= (PWCHAR
)(ObjectNameInfo
+ 1);
1348 ObjectNameInfo
->Name
.Buffer
= p
;
1350 /* Advance in buffer */
1351 p
+= (LocalInfo
->Name
.Length
/ sizeof(WCHAR
));
1353 /* Check if this already filled our buffer */
1354 if (LocalReturnLength
> Length
)
1356 /* Set the length mismatch to true, so that we can return
1357 * the proper buffer size to the caller later
1359 LengthMismatch
= TRUE
;
1361 /* Save the initial buffer length value */
1362 *ReturnLength
= LocalReturnLength
;
1365 /* Now get the file name buffer and check the length needed */
1366 LocalFileInfo
= (PFILE_NAME_INFORMATION
)LocalInfo
;
1367 FileLength
= Length
-
1369 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
1371 /* Query the File name */
1372 Status
= IoQueryFileInformation(FileObject
,
1373 FileNameInformation
,
1374 LengthMismatch
? Length
: FileLength
,
1376 &LocalReturnLength
);
1377 if (NT_ERROR(Status
))
1379 /* Fail on errors only, allow warnings */
1380 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
1384 /* If the provided buffer is too small, return the required size */
1387 /* Add the required length */
1388 *ReturnLength
+= LocalFileInfo
->FileNameLength
;
1390 /* Free the allocated buffer and return failure */
1391 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
1392 return STATUS_BUFFER_OVERFLOW
;
1395 /* Now calculate the new lengths left */
1396 FileLength
= LocalReturnLength
-
1397 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
1398 LocalReturnLength
= (ULONG
)((ULONG_PTR
)p
-
1399 (ULONG_PTR
)ObjectNameInfo
+
1400 LocalFileInfo
->FileNameLength
);
1402 /* Write the Name and null-terminate it */
1403 RtlCopyMemory(p
, LocalFileInfo
->FileName
, FileLength
);
1404 p
+= (FileLength
/ sizeof(WCHAR
));
1406 LocalReturnLength
+= sizeof(UNICODE_NULL
);
1408 /* Return the length needed */
1409 *ReturnLength
= LocalReturnLength
;
1411 /* Setup the length and maximum length */
1412 FileLength
= (ULONG
)((ULONG_PTR
)p
- (ULONG_PTR
)ObjectNameInfo
);
1413 ObjectNameInfo
->Name
.Length
= (USHORT
)FileLength
-
1414 sizeof(OBJECT_NAME_INFORMATION
);
1415 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)ObjectNameInfo
->Name
.Length
+
1416 sizeof(UNICODE_NULL
);
1418 /* Free buffer and return */
1419 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
1425 IopCloseFile(IN PEPROCESS Process OPTIONAL
,
1426 IN PVOID ObjectBody
,
1427 IN ACCESS_MASK GrantedAccess
,
1428 IN ULONG HandleCount
,
1429 IN ULONG SystemHandleCount
)
1431 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1434 PIO_STACK_LOCATION StackPtr
;
1436 PDEVICE_OBJECT DeviceObject
;
1438 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1440 /* If this isn't the last handle for the current process, quit */
1441 if (HandleCount
!= 1) return;
1443 /* Check if the file is locked and has more then one handle opened */
1444 if ((FileObject
->LockOperation
) && (SystemHandleCount
!= 1))
1446 DPRINT1("We need to unlock this file!\n");
1450 /* Make sure this is the last handle */
1451 if (SystemHandleCount
!= 1) return;
1453 /* Check if this is a direct open or not */
1454 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1456 /* Get the attached device */
1457 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1461 /* Get the FO's device */
1462 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1465 /* Set the handle created flag */
1466 FileObject
->Flags
|= FO_HANDLE_CREATED
;
1468 /* Check if this is a sync FO and lock it */
1469 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
) IopLockFileObject(FileObject
);
1471 /* Clear and set up Events */
1472 KeClearEvent(&FileObject
->Event
);
1473 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1475 /* Allocate an IRP */
1476 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1480 Irp
->UserEvent
= &Event
;
1481 Irp
->UserIosb
= &Irp
->IoStatus
;
1482 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1483 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1484 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
1485 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
1487 /* Set up Stack Pointer Data */
1488 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1489 StackPtr
->MajorFunction
= IRP_MJ_CLEANUP
;
1490 StackPtr
->FileObject
= FileObject
;
1493 IopQueueIrpToThread(Irp
);
1495 /* Update operation counts */
1496 IopUpdateOperationCount(IopOtherTransfer
);
1498 /* Call the FS Driver */
1499 Status
= IoCallDriver(DeviceObject
, Irp
);
1500 if (Status
== STATUS_PENDING
)
1502 /* Wait for completion */
1503 KeWaitForSingleObject(&Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1506 /* Unqueue the IRP */
1507 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1508 IopUnQueueIrpFromThread(Irp
);
1509 KeLowerIrql(OldIrql
);
1514 /* Release the lock if we were holding it */
1515 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
) IopUnlockFileObject(FileObject
);
1520 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1521 IN FILE_INFORMATION_CLASS FileInformationClass
,
1522 IN ULONG FileInformationSize
,
1523 OUT PVOID FileInformation
)
1526 KPROCESSOR_MODE AccessMode
= ExGetPreviousMode();
1527 DUMMY_FILE_OBJECT DummyFileObject
;
1528 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo
;
1530 OPEN_PACKET OpenPacket
;
1533 IOTRACE(IO_FILE_DEBUG
, "Class: %lx\n", FileInformationClass
);
1535 /* Check if the caller was user mode */
1536 if (AccessMode
!= KernelMode
)
1538 /* Protect probe in SEH */
1541 /* Probe the buffer */
1542 ProbeForWrite(FileInformation
, FileInformationSize
, sizeof(ULONG
));
1544 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1546 /* Return the exception code */
1547 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1552 /* Check if this is a basic or full request */
1553 IsBasic
= (FileInformationSize
== sizeof(FILE_BASIC_INFORMATION
));
1555 /* Setup the Open Packet */
1556 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
1557 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
1558 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
1559 OpenPacket
.CreateOptions
= FILE_OPEN_REPARSE_POINT
;
1560 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
1561 OpenPacket
.Disposition
= FILE_OPEN
;
1562 OpenPacket
.BasicInformation
= IsBasic
? FileInformation
: NULL
;
1563 OpenPacket
.NetworkInformation
= IsBasic
? &NetworkOpenInfo
:
1564 (AccessMode
!= KernelMode
) ?
1565 &NetworkOpenInfo
: FileInformation
;
1566 OpenPacket
.QueryOnly
= TRUE
;
1567 OpenPacket
.FullAttributes
= IsBasic
? FALSE
: TRUE
;
1568 OpenPacket
.DummyFileObject
= &DummyFileObject
;
1570 /* Update the operation count */
1571 IopUpdateOperationCount(IopOtherTransfer
);
1574 * Attempt opening the file. This will call the I/O Parse Routine for
1575 * the File Object (IopParseDevice) which will use the dummy file obejct
1576 * send the IRP to its device object. Note that we have two statuses
1577 * to worry about: the Object Manager's status (in Status) and the I/O
1578 * status, which is in the Open Packet's Final Status, and determined
1579 * by the Parse Check member.
1581 Status
= ObOpenObjectByName(ObjectAttributes
,
1585 FILE_READ_ATTRIBUTES
,
1588 if (OpenPacket
.ParseCheck
!= TRUE
)
1595 /* Use the Io status */
1596 Status
= OpenPacket
.FinalStatus
;
1599 /* Check if we were succesful and this was user mode and a full query */
1600 if ((NT_SUCCESS(Status
)) && (AccessMode
!= KernelMode
) && !(IsBasic
))
1602 /* Enter SEH for copy */
1605 /* Copy the buffer back */
1606 RtlCopyMemory(FileInformation
,
1608 FileInformationSize
);
1610 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1612 /* Get exception code */
1613 Status
= _SEH2_GetExceptionCode();
1624 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject
)
1626 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1629 /* FIXME: return NULL for the moment ~ */
1638 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject
,
1639 IN PVOID FilterContext
,
1642 if (!(FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
))
1644 return STATUS_INVALID_PARAMETER
;
1649 return STATUS_NOT_IMPLEMENTED
;
1652 /* FUNCTIONS *****************************************************************/
1659 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass
,
1661 IN BOOLEAN SetOperation
)
1664 return STATUS_NOT_IMPLEMENTED
;
1672 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer
,
1673 IN ULONG QuotaLength
,
1674 OUT PULONG ErrorOffset
)
1677 return STATUS_NOT_IMPLEMENTED
;
1685 IoCreateFile(OUT PHANDLE FileHandle
,
1686 IN ACCESS_MASK DesiredAccess
,
1687 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1688 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1689 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
1690 IN ULONG FileAttributes
,
1691 IN ULONG ShareAccess
,
1692 IN ULONG Disposition
,
1693 IN ULONG CreateOptions
,
1694 IN PVOID EaBuffer OPTIONAL
,
1696 IN CREATE_FILE_TYPE CreateFileType
,
1697 IN PVOID ExtraCreateParameters OPTIONAL
,
1700 KPROCESSOR_MODE AccessMode
;
1701 HANDLE LocalHandle
= 0;
1702 LARGE_INTEGER SafeAllocationSize
;
1703 volatile PVOID SystemEaBuffer
= NULL
;
1704 NTSTATUS Status
= STATUS_SUCCESS
;
1705 OPEN_PACKET OpenPacket
;
1706 ULONG EaErrorOffset
;
1709 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
1711 /* Check if we have no parameter checking to do */
1712 if (Options
& IO_NO_PARAMETER_CHECKING
)
1714 /* Then force kernel-mode access to avoid checks */
1715 AccessMode
= KernelMode
;
1719 /* Otherwise, use the actual mode */
1720 AccessMode
= ExGetPreviousMode();
1723 /* Check if the call came from user mode */
1724 if (AccessMode
!= KernelMode
)
1728 ProbeForWriteHandle(FileHandle
);
1729 ProbeForWriteIoStatusBlock(IoStatusBlock
);
1732 SafeAllocationSize
= ProbeForReadLargeInteger(AllocationSize
);
1736 SafeAllocationSize
.QuadPart
= 0;
1739 if ((EaBuffer
) && (EaLength
))
1741 ProbeForRead(EaBuffer
, EaLength
, sizeof(ULONG
));
1743 /* marshal EaBuffer */
1744 SystemEaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1749 _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES
);
1752 RtlCopyMemory(SystemEaBuffer
, EaBuffer
, EaLength
);
1754 /* Validate the buffer */
1755 Status
= IoCheckEaBufferValidity(SystemEaBuffer
,
1758 IoStatusBlock
->Status
= Status
;
1759 IoStatusBlock
->Information
= EaErrorOffset
;
1762 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1764 /* Return the exception code */
1765 Status
= _SEH2_GetExceptionCode();
1771 /* Check if this is a device attach */
1772 if (CreateOptions
& IO_ATTACH_DEVICE_API
)
1774 /* Set the flag properly */
1775 Options
|= IO_ATTACH_DEVICE
;
1776 CreateOptions
&= ~IO_ATTACH_DEVICE_API
;
1779 /* Check if we have allocation size */
1783 SafeAllocationSize
= *AllocationSize
;
1787 /* Otherwise, no size */
1788 SafeAllocationSize
.QuadPart
= 0;
1791 /* Check if we have an EA packet */
1792 if ((EaBuffer
) && (EaLength
))
1794 /* Allocate the kernel copy */
1795 SystemEaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1798 if (!SystemEaBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1801 RtlCopyMemory(SystemEaBuffer
, EaBuffer
, EaLength
);
1803 /* Validate the buffer */
1804 Status
= IoCheckEaBufferValidity(SystemEaBuffer
,
1807 IoStatusBlock
->Status
= Status
;
1808 IoStatusBlock
->Information
= EaErrorOffset
;
1812 if (!NT_SUCCESS(Status
))
1814 DPRINT1("FIXME: IoCheckEaBufferValidity() failed with Status: %lx\n",
1817 /* Free SystemEaBuffer if needed and return the error */
1818 if (SystemEaBuffer
) ExFreePoolWithTag(SystemEaBuffer
, TAG_EA
);
1822 /* Setup the Open Packet */
1823 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
1824 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
1825 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
1826 OpenPacket
.OriginalAttributes
= *ObjectAttributes
;
1827 OpenPacket
.AllocationSize
= SafeAllocationSize
;
1828 OpenPacket
.CreateOptions
= CreateOptions
;
1829 OpenPacket
.FileAttributes
= (USHORT
)FileAttributes
;
1830 OpenPacket
.ShareAccess
= (USHORT
)ShareAccess
;
1831 OpenPacket
.EaBuffer
= SystemEaBuffer
;
1832 OpenPacket
.EaLength
= EaLength
;
1833 OpenPacket
.Options
= Options
;
1834 OpenPacket
.Disposition
= Disposition
;
1835 OpenPacket
.CreateFileType
= CreateFileType
;
1836 OpenPacket
.MailslotOrPipeParameters
= ExtraCreateParameters
;
1838 /* Update the operation count */
1839 IopUpdateOperationCount(IopOtherTransfer
);
1842 * Attempt opening the file. This will call the I/O Parse Routine for
1843 * the File Object (IopParseDevice) which will create the object and
1844 * send the IRP to its device object. Note that we have two statuses
1845 * to worry about: the Object Manager's status (in Status) and the I/O
1846 * status, which is in the Open Packet's Final Status, and determined
1847 * by the Parse Check member.
1849 Status
= ObOpenObjectByName(ObjectAttributes
,
1857 /* Free the EA Buffer */
1858 if (OpenPacket
.EaBuffer
) ExFreePool(OpenPacket
.EaBuffer
);
1860 /* Now check for Ob or Io failure */
1861 if (!(NT_SUCCESS(Status
)) || (OpenPacket
.ParseCheck
!= TRUE
))
1863 /* Check if Ob thinks well went well */
1864 if (NT_SUCCESS(Status
))
1867 * Tell it otherwise. Because we didn't use an ObjectType,
1868 * it incorrectly returned us a handle to God knows what.
1870 ZwClose(LocalHandle
);
1871 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1874 /* Now check the Io status */
1875 if (!NT_SUCCESS(OpenPacket
.FinalStatus
))
1877 /* Use this status instead of Ob's */
1878 Status
= OpenPacket
.FinalStatus
;
1880 /* Check if it was only a warning */
1881 if (NT_WARNING(Status
))
1883 /* Protect write with SEH */
1886 /* In this case, we copy the I/O Status back */
1887 IoStatusBlock
->Information
= OpenPacket
.Information
;
1888 IoStatusBlock
->Status
= OpenPacket
.FinalStatus
;
1890 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1892 /* Get exception code */
1893 Status
= _SEH2_GetExceptionCode();
1898 else if ((OpenPacket
.FileObject
) && (OpenPacket
.ParseCheck
!= 1))
1901 * This can happen in the very bizarre case where the parse routine
1902 * actually executed more then once (due to a reparse) and ended
1903 * up failing after already having created the File Object.
1905 if (OpenPacket
.FileObject
->FileName
.Length
)
1907 /* It had a name, free it */
1908 ExFreePoolWithTag(OpenPacket
.FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
1911 /* Clear the device object to invalidate the FO, and dereference */
1912 OpenPacket
.FileObject
->DeviceObject
= NULL
;
1913 ObDereferenceObject(OpenPacket
.FileObject
);
1918 /* We reached success and have a valid file handle */
1919 OpenPacket
.FileObject
->Flags
|= FO_HANDLE_CREATED
;
1921 /* Enter SEH for write back */
1924 /* Write back the handle and I/O Status */
1925 *FileHandle
= LocalHandle
;
1926 IoStatusBlock
->Information
= OpenPacket
.Information
;
1927 IoStatusBlock
->Status
= OpenPacket
.FinalStatus
;
1929 /* Get the Io status */
1930 Status
= OpenPacket
.FinalStatus
;
1932 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1934 /* Get the exception status */
1935 Status
= _SEH2_GetExceptionCode();
1940 /* Check if we were 100% successful */
1941 if ((OpenPacket
.ParseCheck
== TRUE
) && (OpenPacket
.FileObject
))
1943 /* Dereference the File Object */
1944 ObDereferenceObject(OpenPacket
.FileObject
);
1956 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle
,
1957 IN ACCESS_MASK DesiredAccess
,
1958 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1959 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1960 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
1961 IN ULONG FileAttributes
,
1962 IN ULONG ShareAccess
,
1963 IN ULONG Disposition
,
1964 IN ULONG CreateOptions
,
1965 IN PVOID EaBuffer OPTIONAL
,
1967 IN CREATE_FILE_TYPE CreateFileType
,
1968 IN PVOID ExtraCreateParameters OPTIONAL
,
1970 IN PVOID DeviceObject
)
1973 return STATUS_NOT_IMPLEMENTED
;
1981 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL
,
1982 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
1983 OUT PHANDLE FileObjectHandle OPTIONAL
)
1985 PFILE_OBJECT CreatedFileObject
;
1988 OBJECT_ATTRIBUTES ObjectAttributes
;
1990 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
1992 /* Choose Device Object */
1993 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
1995 /* Reference the device object and initialize attributes */
1996 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
1997 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
1999 /* Create the File Object */
2000 Status
= ObCreateObject(KernelMode
,
2005 sizeof(FILE_OBJECT
),
2006 sizeof(FILE_OBJECT
),
2008 (PVOID
*)&CreatedFileObject
);
2009 if (!NT_SUCCESS(Status
))
2012 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
2013 ExRaiseStatus(Status
);
2016 /* Set File Object Data */
2017 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
2018 CreatedFileObject
->DeviceObject
= DeviceObject
;
2019 CreatedFileObject
->Type
= IO_TYPE_FILE
;
2020 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
2021 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
2023 /* Initialize the wait event */
2024 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
2026 /* Insert it to create a handle for it */
2027 Status
= ObInsertObject(CreatedFileObject
,
2031 (PVOID
*)&CreatedFileObject
,
2033 if (!NT_SUCCESS(Status
)) ExRaiseStatus(Status
);
2035 /* Set the handle created flag */
2036 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
2037 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
2039 /* Check if we have a VPB */
2040 if (DeviceObject
->Vpb
)
2043 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
2046 /* Check if the caller wants the handle */
2047 if (FileObjectHandle
)
2050 *FileObjectHandle
= FileHandle
;
2051 ObDereferenceObject(CreatedFileObject
);
2055 /* Otherwise, close it */
2056 ObCloseHandle(FileHandle
, KernelMode
);
2059 /* Return the file object */
2060 return CreatedFileObject
;
2068 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject
,
2069 IN PDEVICE_OBJECT DeviceObject
)
2071 /* Call the newer function */
2072 return IoCreateStreamFileObjectEx(FileObject
, DeviceObject
, NULL
);
2080 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL
,
2081 IN PDEVICE_OBJECT DeviceObject OPTIONAL
)
2083 PFILE_OBJECT CreatedFileObject
;
2085 OBJECT_ATTRIBUTES ObjectAttributes
;
2087 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
2089 /* Choose Device Object */
2090 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
2092 /* Reference the device object and initialize attributes */
2093 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
2094 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2096 /* Create the File Object */
2097 Status
= ObCreateObject(KernelMode
,
2102 sizeof(FILE_OBJECT
),
2103 sizeof(FILE_OBJECT
),
2105 (PVOID
*)&CreatedFileObject
);
2106 if (!NT_SUCCESS(Status
))
2109 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
2110 ExRaiseStatus(Status
);
2113 /* Set File Object Data */
2114 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
2115 CreatedFileObject
->DeviceObject
= DeviceObject
;
2116 CreatedFileObject
->Type
= IO_TYPE_FILE
;
2117 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
2118 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
2120 /* Initialize the wait event */
2121 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
2123 /* Destroy create information */
2124 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->
2126 OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->ObjectCreateInfo
= NULL
;
2128 /* Set the handle created flag */
2129 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
2130 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
2132 /* Check if we have a VPB */
2133 if (DeviceObject
->Vpb
)
2136 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
2139 /* Return the file object */
2140 return CreatedFileObject
;
2148 IoGetFileObjectGenericMapping(VOID
)
2150 /* Return the mapping */
2151 return &IopFileMapping
;
2159 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject
)
2161 /* Return the flag status */
2162 return FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
2170 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2171 IN ACCESS_MASK DesiredAccess
,
2172 IN ULONG OpenOptions
,
2173 OUT PIO_STATUS_BLOCK IoStatus
,
2174 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer
)
2177 DUMMY_FILE_OBJECT DummyFileObject
;
2179 OPEN_PACKET OpenPacket
;
2181 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
2183 /* Setup the Open Packet */
2184 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
2185 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
2186 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
2187 OpenPacket
.CreateOptions
= OpenOptions
| FILE_OPEN_REPARSE_POINT
;
2188 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2189 OpenPacket
.Options
= IO_FORCE_ACCESS_CHECK
;
2190 OpenPacket
.Disposition
= FILE_OPEN
;
2191 OpenPacket
.NetworkInformation
= Buffer
;
2192 OpenPacket
.QueryOnly
= TRUE
;
2193 OpenPacket
.FullAttributes
= TRUE
;
2194 OpenPacket
.DummyFileObject
= &DummyFileObject
;
2197 * Attempt opening the file. This will call the I/O Parse Routine for
2198 * the File Object (IopParseDevice) which will use the dummy file obejct
2199 * send the IRP to its device object. Note that we have two statuses
2200 * to worry about: the Object Manager's status (in Status) and the I/O
2201 * status, which is in the Open Packet's Final Status, and determined
2202 * by the Parse Check member.
2204 Status
= ObOpenObjectByName(ObjectAttributes
,
2211 if (OpenPacket
.ParseCheck
!= TRUE
)
2214 IoStatus
->Status
= Status
;
2218 /* Use the Io status */
2219 IoStatus
->Status
= OpenPacket
.FinalStatus
;
2220 IoStatus
->Information
= OpenPacket
.Information
;
2223 /* Return success */
2232 IoUpdateShareAccess(IN PFILE_OBJECT FileObject
,
2233 OUT PSHARE_ACCESS ShareAccess
)
2237 /* Check if the file has an extension */
2238 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2240 /* Check if caller specified to ignore access checks */
2241 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2243 /* Don't update share access */
2248 /* Otherwise, check if there's any access present */
2249 if ((FileObject
->ReadAccess
) ||
2250 (FileObject
->WriteAccess
) ||
2251 (FileObject
->DeleteAccess
))
2253 /* Increase the open count */
2254 ShareAccess
->OpenCount
++;
2256 /* Add new share access */
2257 ShareAccess
->Readers
+= FileObject
->ReadAccess
;
2258 ShareAccess
->Writers
+= FileObject
->WriteAccess
;
2259 ShareAccess
->Deleters
+= FileObject
->DeleteAccess
;
2260 ShareAccess
->SharedRead
+= FileObject
->SharedRead
;
2261 ShareAccess
->SharedWrite
+= FileObject
->SharedWrite
;
2262 ShareAccess
->SharedDelete
+= FileObject
->SharedDelete
;
2271 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess
,
2272 IN ULONG DesiredShareAccess
,
2273 IN PFILE_OBJECT FileObject
,
2274 IN PSHARE_ACCESS ShareAccess
,
2278 BOOLEAN WriteAccess
;
2279 BOOLEAN DeleteAccess
;
2281 BOOLEAN SharedWrite
;
2282 BOOLEAN SharedDelete
;
2285 /* Get access masks */
2286 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
2287 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
2288 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
2290 /* Set them in the file object */
2291 FileObject
->ReadAccess
= ReadAccess
;
2292 FileObject
->WriteAccess
= WriteAccess
;
2293 FileObject
->DeleteAccess
= DeleteAccess
;
2295 /* Check if the file has an extension */
2296 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2298 /* Check if caller specified to ignore access checks */
2299 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2301 /* Don't check share access */
2302 return STATUS_SUCCESS
;
2306 /* Check if we have any access */
2307 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
2309 /* Get shared access masks */
2310 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
2311 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
2312 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
2315 FileObject
->SharedRead
= SharedRead
;
2316 FileObject
->SharedWrite
= SharedWrite
;
2317 FileObject
->SharedDelete
= SharedDelete
;
2319 /* Check if the shared access is violated */
2321 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
2323 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
2325 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
2326 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
2327 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
2328 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
2330 /* Sharing violation, fail */
2331 return STATUS_SHARING_VIOLATION
;
2334 /* It's not, check if caller wants us to update it */
2337 /* Increase open count */
2338 ShareAccess
->OpenCount
++;
2340 /* Update shared access */
2341 ShareAccess
->Readers
+= ReadAccess
;
2342 ShareAccess
->Writers
+= WriteAccess
;
2343 ShareAccess
->Deleters
+= DeleteAccess
;
2344 ShareAccess
->SharedRead
+= SharedRead
;
2345 ShareAccess
->SharedWrite
+= SharedWrite
;
2346 ShareAccess
->SharedDelete
+= SharedDelete
;
2350 /* Validation successful */
2351 return STATUS_SUCCESS
;
2359 IoRemoveShareAccess(IN PFILE_OBJECT FileObject
,
2360 IN PSHARE_ACCESS ShareAccess
)
2364 /* Check if the file has an extension */
2365 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2367 /* Check if caller specified to ignore access checks */
2368 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2370 /* Don't update share access */
2375 /* Otherwise, check if there's any access present */
2376 if ((FileObject
->ReadAccess
) ||
2377 (FileObject
->WriteAccess
) ||
2378 (FileObject
->DeleteAccess
))
2380 /* Decrement the open count */
2381 ShareAccess
->OpenCount
--;
2383 /* Remove share access */
2384 ShareAccess
->Readers
-= FileObject
->ReadAccess
;
2385 ShareAccess
->Writers
-= FileObject
->WriteAccess
;
2386 ShareAccess
->Deleters
-= FileObject
->DeleteAccess
;
2387 ShareAccess
->SharedRead
-= FileObject
->SharedRead
;
2388 ShareAccess
->SharedWrite
-= FileObject
->SharedWrite
;
2389 ShareAccess
->SharedDelete
-= FileObject
->SharedDelete
;
2398 IoSetShareAccess(IN ACCESS_MASK DesiredAccess
,
2399 IN ULONG DesiredShareAccess
,
2400 IN PFILE_OBJECT FileObject
,
2401 OUT PSHARE_ACCESS ShareAccess
)
2404 BOOLEAN WriteAccess
;
2405 BOOLEAN DeleteAccess
;
2407 BOOLEAN SharedWrite
;
2408 BOOLEAN SharedDelete
;
2409 BOOLEAN Update
= TRUE
;
2412 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
2413 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
2414 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
2416 /* Check if the file has an extension */
2417 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2419 /* Check if caller specified to ignore access checks */
2420 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2422 /* Don't update share access */
2427 /* Update basic access */
2428 FileObject
->ReadAccess
= ReadAccess
;
2429 FileObject
->WriteAccess
= WriteAccess
;
2430 FileObject
->DeleteAccess
= DeleteAccess
;
2432 /* Check if we have no access as all */
2433 if (!(ReadAccess
) && !(WriteAccess
) && !(DeleteAccess
))
2435 /* Check if we need to update the structure */
2436 if (!Update
) return;
2438 /* Otherwise, clear data */
2439 ShareAccess
->OpenCount
= 0;
2440 ShareAccess
->Readers
= 0;
2441 ShareAccess
->Writers
= 0;
2442 ShareAccess
->Deleters
= 0;
2443 ShareAccess
->SharedRead
= 0;
2444 ShareAccess
->SharedWrite
= 0;
2445 ShareAccess
->SharedDelete
= 0;
2449 /* Calculate shared access */
2450 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
2451 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
2452 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
2454 /* Set it in the FO */
2455 FileObject
->SharedRead
= SharedRead
;
2456 FileObject
->SharedWrite
= SharedWrite
;
2457 FileObject
->SharedDelete
= SharedDelete
;
2459 /* Check if we need to update the structure */
2460 if (!Update
) return;
2462 /* Otherwise, set data */
2463 ShareAccess
->OpenCount
= 1;
2464 ShareAccess
->Readers
= ReadAccess
;
2465 ShareAccess
->Writers
= WriteAccess
;
2466 ShareAccess
->Deleters
= DeleteAccess
;
2467 ShareAccess
->SharedRead
= SharedRead
;
2468 ShareAccess
->SharedWrite
= SharedWrite
;
2469 ShareAccess
->SharedDelete
= SharedDelete
;
2478 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject
,
2479 IN PFILE_OBJECT FileObject
)
2489 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject
,
2490 OUT POBJECT_NAME_INFORMATION
*ObjectNameInformation
)
2493 return STATUS_NOT_IMPLEMENTED
;
2501 IoSetFileOrigin(IN PFILE_OBJECT FileObject
,
2504 NTSTATUS Status
= STATUS_SUCCESS
;
2507 /* Get the flag status */
2508 FlagSet
= FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
2510 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
2511 if (Remote
&& !FlagSet
)
2514 FileObject
->Flags
|= FO_REMOTE_ORIGIN
;
2516 else if (!Remote
&& FlagSet
)
2518 /* Remove the flag */
2519 FileObject
->Flags
&= ~FO_REMOTE_ORIGIN
;
2524 Status
= STATUS_INVALID_PARAMETER_MIX
;
2536 NtCreateFile(PHANDLE FileHandle
,
2537 ACCESS_MASK DesiredAccess
,
2538 POBJECT_ATTRIBUTES ObjectAttributes
,
2539 PIO_STATUS_BLOCK IoStatusBlock
,
2540 PLARGE_INTEGER AllocateSize
,
2541 ULONG FileAttributes
,
2543 ULONG CreateDisposition
,
2544 ULONG CreateOptions
,
2548 /* Call the I/O Function */
2549 return IoCreateFile(FileHandle
,
2567 NtCreateMailslotFile(OUT PHANDLE FileHandle
,
2568 IN ACCESS_MASK DesiredAccess
,
2569 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2570 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2571 IN ULONG CreateOptions
,
2572 IN ULONG MailslotQuota
,
2573 IN ULONG MaxMessageSize
,
2574 IN PLARGE_INTEGER TimeOut
)
2576 MAILSLOT_CREATE_PARAMETERS Buffer
;
2579 /* Check for Timeout */
2582 /* check if the call came from user mode */
2583 if (KeGetPreviousMode() != KernelMode
)
2585 /* Enter SEH for Probe */
2588 /* Probe the timeout */
2589 Buffer
.ReadTimeout
= ProbeForReadLargeInteger(TimeOut
);
2591 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2593 /* Return the exception code */
2594 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2600 /* Otherwise, capture directly */
2601 Buffer
.ReadTimeout
= *TimeOut
;
2604 /* Set the correct setting */
2605 Buffer
.TimeoutSpecified
= TRUE
;
2609 /* Tell the FSD we don't have a timeout */
2610 Buffer
.TimeoutSpecified
= FALSE
;
2614 Buffer
.MailslotQuota
= MailslotQuota
;
2615 Buffer
.MaximumMessageSize
= MaxMessageSize
;
2618 return IoCreateFile(FileHandle
,
2624 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2629 CreateFileTypeMailslot
,
2636 NtCreateNamedPipeFile(OUT PHANDLE FileHandle
,
2637 IN ACCESS_MASK DesiredAccess
,
2638 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2639 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2640 IN ULONG ShareAccess
,
2641 IN ULONG CreateDisposition
,
2642 IN ULONG CreateOptions
,
2643 IN ULONG NamedPipeType
,
2645 IN ULONG CompletionMode
,
2646 IN ULONG MaximumInstances
,
2647 IN ULONG InboundQuota
,
2648 IN ULONG OutboundQuota
,
2649 IN PLARGE_INTEGER DefaultTimeout
)
2651 NAMED_PIPE_CREATE_PARAMETERS Buffer
;
2654 /* Check for Timeout */
2657 /* check if the call came from user mode */
2658 if (KeGetPreviousMode() != KernelMode
)
2660 /* Enter SEH for Probe */
2663 /* Probe the timeout */
2664 Buffer
.DefaultTimeout
=
2665 ProbeForReadLargeInteger(DefaultTimeout
);
2667 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2669 /* Return the exception code */
2670 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2676 /* Otherwise, capture directly */
2677 Buffer
.DefaultTimeout
= *DefaultTimeout
;
2680 /* Set the correct setting */
2681 Buffer
.TimeoutSpecified
= TRUE
;
2685 /* Tell the FSD we don't have a timeout */
2686 Buffer
.TimeoutSpecified
= FALSE
;
2690 Buffer
.NamedPipeType
= NamedPipeType
;
2691 Buffer
.ReadMode
= ReadMode
;
2692 Buffer
.CompletionMode
= CompletionMode
;
2693 Buffer
.MaximumInstances
= MaximumInstances
;
2694 Buffer
.InboundQuota
= InboundQuota
;
2695 Buffer
.OutboundQuota
= OutboundQuota
;
2698 return IoCreateFile(FileHandle
,
2709 CreateFileTypeNamedPipe
,
2716 NtFlushWriteBuffer(VOID
)
2720 /* Call the kernel */
2721 KeFlushWriteBuffer();
2722 return STATUS_SUCCESS
;
2730 NtOpenFile(OUT PHANDLE FileHandle
,
2731 IN ACCESS_MASK DesiredAccess
,
2732 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2733 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2734 IN ULONG ShareAccess
,
2735 IN ULONG OpenOptions
)
2737 /* Call the I/O Function */
2738 return IoCreateFile(FileHandle
,
2756 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2757 OUT PFILE_BASIC_INFORMATION FileInformation
)
2759 /* Call the internal helper API */
2760 return IopQueryAttributesFile(ObjectAttributes
,
2761 FileBasicInformation
,
2762 sizeof(FILE_BASIC_INFORMATION
),
2768 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2769 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
)
2771 /* Call the internal helper API */
2772 return IopQueryAttributesFile(ObjectAttributes
,
2773 FileNetworkOpenInformation
,
2774 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
2779 * @name NtCancelIoFile
2781 * Cancel all pending I/O operations in the current thread for specified
2785 * Handle to file object to cancel requests for. No specific
2786 * access rights are needed.
2787 * @param IoStatusBlock
2788 * Pointer to status block which is filled with final completition
2789 * status on successful return.
2797 NtCancelIoFile(IN HANDLE FileHandle
,
2798 OUT PIO_STATUS_BLOCK IoStatusBlock
)
2800 PFILE_OBJECT FileObject
;
2804 BOOLEAN OurIrpsInList
= FALSE
;
2805 LARGE_INTEGER Interval
;
2806 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
2808 PLIST_ENTRY ListHead
, NextEntry
;
2810 IOTRACE(IO_API_DEBUG
, "FileHandle: %p\n", FileHandle
);
2812 /* Check the previous mode */
2813 if (PreviousMode
!= KernelMode
)
2815 /* Enter SEH for probing */
2818 /* Probe the I/O Status Block */
2819 ProbeForWriteIoStatusBlock(IoStatusBlock
);
2821 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2823 /* Return the exception code */
2824 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2829 /* Reference the file object */
2830 Status
= ObReferenceObjectByHandle(FileHandle
,
2834 (PVOID
*)&FileObject
,
2836 if (!NT_SUCCESS(Status
)) return Status
;
2838 /* IRP cancellations are synchronized at APC_LEVEL. */
2839 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2841 /* Get the current thread */
2842 Thread
= PsGetCurrentThread();
2844 /* Update the operation counts */
2845 IopUpdateOperationCount(IopOtherTransfer
);
2848 ListHead
= &Thread
->IrpList
;
2849 NextEntry
= ListHead
->Flink
;
2850 while (ListHead
!= NextEntry
)
2852 /* Get the IRP and check if the File Object matches */
2853 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
2854 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
2856 /* Cancel this IRP and keep looping */
2858 OurIrpsInList
= TRUE
;
2861 /* Go to the next entry */
2862 NextEntry
= NextEntry
->Flink
;
2865 /* Lower the IRQL */
2866 KeLowerIrql(OldIrql
);
2868 /* Check if we had found an IRP */
2871 /* Setup a 10ms wait */
2872 Interval
.QuadPart
= -100000;
2875 while (OurIrpsInList
)
2878 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
2879 OurIrpsInList
= FALSE
;
2882 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2884 /* Now loop the list again */
2885 NextEntry
= ListHead
->Flink
;
2886 while (NextEntry
!= ListHead
)
2888 /* Get the IRP and check if the File Object matches */
2889 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
2890 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
2893 OurIrpsInList
= TRUE
;
2897 /* Go to the next entry */
2898 NextEntry
= NextEntry
->Flink
;
2901 /* Lower the IRQL */
2902 KeLowerIrql(OldIrql
);
2906 /* Enter SEH for writing back the I/O Status */
2910 IoStatusBlock
->Status
= STATUS_SUCCESS
;
2911 IoStatusBlock
->Information
= 0;
2913 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2915 /* Ignore exception */
2919 /* Dereference the file object and return success */
2920 ObDereferenceObject(FileObject
);
2921 return STATUS_SUCCESS
;
2929 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes
)
2932 DUMMY_FILE_OBJECT DummyFileObject
;
2934 KPROCESSOR_MODE AccessMode
= KeGetPreviousMode();
2935 OPEN_PACKET OpenPacket
;
2937 IOTRACE(IO_API_DEBUG
, "FileMame: %wZ\n", ObjectAttributes
->ObjectName
);
2939 /* Setup the Open Packet */
2940 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
2941 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
2942 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
2943 OpenPacket
.CreateOptions
= FILE_DELETE_ON_CLOSE
;
2944 OpenPacket
.ShareAccess
= FILE_SHARE_READ
|
2947 OpenPacket
.Disposition
= FILE_OPEN
;
2948 OpenPacket
.DeleteOnly
= TRUE
;
2949 OpenPacket
.DummyFileObject
= &DummyFileObject
;
2951 /* Update the operation counts */
2952 IopUpdateOperationCount(IopOtherTransfer
);
2955 * Attempt opening the file. This will call the I/O Parse Routine for
2956 * the File Object (IopParseDevice) which will use the dummy file obejct
2957 * send the IRP to its device object. Note that we have two statuses
2958 * to worry about: the Object Manager's status (in Status) and the I/O
2959 * status, which is in the Open Packet's Final Status, and determined
2960 * by the Parse Check member.
2962 Status
= ObOpenObjectByName(ObjectAttributes
,
2969 if (OpenPacket
.ParseCheck
!= TRUE
) return Status
;
2971 /* Retrn the Io status */
2972 return OpenPacket
.FinalStatus
;