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 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 OPTIONAL
,
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"))) &&
414 DPRINT1("Using IopParseDevice() hack\n");
418 /* Check if we have a related FO that wasn't a direct open */
419 if ((OpenPacket
->RelatedFileObject
) &&
420 !(OpenPacket
->RelatedFileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
422 /* The device object is the one we were given */
423 DeviceObject
= ParseObject
;
425 /* Check if the related FO had a VPB */
426 if (OpenPacket
->RelatedFileObject
->Vpb
)
428 /* Yes, remember it */
429 Vpb
= OpenPacket
->RelatedFileObject
->Vpb
;
432 InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
437 /* The device object is the one we were given */
438 DeviceObject
= OriginalDeviceObject
;
440 /* Check if it has a VPB */
441 if ((OriginalDeviceObject
->Vpb
) && !(DirectOpen
))
443 /* Check if the VPB is mounted, and mount it */
444 Vpb
= IopCheckVpbMounted(OpenPacket
,
445 OriginalDeviceObject
,
448 if (!Vpb
) return Status
;
450 /* Get the VPB's device object */
451 DeviceObject
= Vpb
->DeviceObject
;
454 /* Check if there's an attached device */
455 if (DeviceObject
->AttachedDevice
)
457 /* Get the attached device */
458 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
462 /* Check if this is a secure FSD */
463 if ((DeviceObject
->Characteristics
& FILE_DEVICE_SECURE_OPEN
) &&
464 ((OpenPacket
->RelatedFileObject
) || (RemainingName
->Length
)) &&
467 DPRINT1("Fix Secure FSD support!!!\n");
470 /* Allocate the IRP */
471 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
474 /* Dereference the device and VPB, then fail */
475 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
476 if (Vpb
) IopDereferenceVpb(Vpb
);
477 return STATUS_INSUFFICIENT_RESOURCES
;
480 /* Now set the IRP data */
481 Irp
->RequestorMode
= AccessMode
;
482 Irp
->Flags
= IRP_CREATE_OPERATION
|
483 IRP_SYNCHRONOUS_API
|
484 IRP_DEFER_IO_COMPLETION
;
485 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
486 Irp
->UserIosb
= &IoStatusBlock
;
487 Irp
->MdlAddress
= NULL
;
488 Irp
->PendingReturned
= FALSE
;
489 Irp
->UserEvent
= NULL
;
491 Irp
->CancelRoutine
= NULL
;
492 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
494 /* Setup the security context */
495 SecurityContext
.SecurityQos
= SecurityQos
;
496 SecurityContext
.AccessState
= AccessState
;
497 SecurityContext
.DesiredAccess
= AccessState
->RemainingDesiredAccess
;
498 SecurityContext
.FullCreateOptions
= OpenPacket
->CreateOptions
;
500 /* Get the I/O Stack location */
501 StackLoc
= (PEXTENDED_IO_STACK_LOCATION
)IoGetNextIrpStackLocation(Irp
);
502 StackLoc
->Control
= 0;
504 /* Check what kind of file this is */
505 switch (OpenPacket
->CreateFileType
)
508 case CreateFileTypeNone
:
510 /* Set the major function and EA Length */
511 StackLoc
->MajorFunction
= IRP_MJ_CREATE
;
512 StackLoc
->Parameters
.Create
.EaLength
= OpenPacket
->EaLength
;
515 StackLoc
->Flags
= (UCHAR
)OpenPacket
->Options
;
516 StackLoc
->Flags
|= !(Attributes
& OBJ_CASE_INSENSITIVE
) ?
517 SL_CASE_SENSITIVE
: 0;
521 case CreateFileTypeNamedPipe
:
523 /* Set the named pipe MJ and set the parameters */
524 StackLoc
->MajorFunction
= IRP_MJ_CREATE_NAMED_PIPE
;
525 StackLoc
->Parameters
.CreatePipe
.Parameters
=
526 OpenPacket
->MailslotOrPipeParameters
;
530 case CreateFileTypeMailslot
:
532 /* Set the mailslot MJ and set the parameters */
533 StackLoc
->MajorFunction
= IRP_MJ_CREATE_MAILSLOT
;
534 StackLoc
->Parameters
.CreateMailslot
.Parameters
=
535 OpenPacket
->MailslotOrPipeParameters
;
539 /* Set the common data */
540 Irp
->Overlay
.AllocationSize
= OpenPacket
->AllocationSize
;
541 Irp
->AssociatedIrp
.SystemBuffer
= OpenPacket
->EaBuffer
;
542 StackLoc
->Parameters
.Create
.Options
= (OpenPacket
->Disposition
<< 24) |
543 (OpenPacket
->CreateOptions
&
545 StackLoc
->Parameters
.Create
.FileAttributes
= OpenPacket
->FileAttributes
;
546 StackLoc
->Parameters
.Create
.ShareAccess
= OpenPacket
->ShareAccess
;
547 StackLoc
->Parameters
.Create
.SecurityContext
= &SecurityContext
;
549 /* Check if we really need to create an object */
552 /* Create the actual file object */
553 InitializeObjectAttributes(&ObjectAttributes
,
558 Status
= ObCreateObject(KernelMode
,
566 (PVOID
*)&FileObject
);
567 if (!NT_SUCCESS(Status
))
569 /* Create failed, free the IRP */
572 /* Dereference the device and VPB */
573 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
574 if (Vpb
) IopDereferenceVpb(Vpb
);
576 /* We failed, return status */
577 OpenPacket
->FinalStatus
= Status
;
581 /* Clear the file object */
582 RtlZeroMemory(FileObject
, sizeof(FILE_OBJECT
));
584 /* Check if this is Synch I/O */
585 if (OpenPacket
->CreateOptions
&
586 (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
))
588 /* Set the synch flag */
589 FileObject
->Flags
|= FO_SYNCHRONOUS_IO
;
591 /* Check if it's also alertable */
592 if (OpenPacket
->CreateOptions
& FILE_SYNCHRONOUS_IO_ALERT
)
594 /* It is, set the alertable flag */
595 FileObject
->Flags
|= FO_ALERTABLE_IO
;
599 /* Check if this is synch I/O */
600 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
602 /* Initialize the event */
603 KeInitializeEvent(&FileObject
->Lock
, SynchronizationEvent
, FALSE
);
606 /* Check if the caller requested no intermediate buffering */
607 if (OpenPacket
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
)
609 /* Set the correct flag for the FSD to read */
610 FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
613 /* Check if the caller requested write through support */
614 if (OpenPacket
->CreateOptions
& FILE_WRITE_THROUGH
)
616 /* Set the correct flag for the FSD to read */
617 FileObject
->Flags
|= FO_WRITE_THROUGH
;
620 /* Check if the caller says the file will be only read sequentially */
621 if (OpenPacket
->CreateOptions
& FILE_SEQUENTIAL_ONLY
)
623 /* Set the correct flag for the FSD to read */
624 FileObject
->Flags
|= FO_SEQUENTIAL_ONLY
;
627 /* Check if the caller believes the file will be only read randomly */
628 if (OpenPacket
->CreateOptions
& FILE_RANDOM_ACCESS
)
630 /* Set the correct flag for the FSD to read */
631 FileObject
->Flags
|= FO_RANDOM_ACCESS
;
636 /* Use the dummy object instead */
637 DummyFileObject
= OpenPacket
->DummyFileObject
;
638 RtlZeroMemory(DummyFileObject
, sizeof(DUMMY_FILE_OBJECT
));
641 FileObject
= (PFILE_OBJECT
)&DummyFileObject
->ObjectHeader
.Body
;
642 DummyFileObject
->ObjectHeader
.Type
= IoFileObjectType
;
643 DummyFileObject
->ObjectHeader
.PointerCount
= 1;
646 /* Setup the file header */
647 FileObject
->Type
= IO_TYPE_FILE
;
648 FileObject
->Size
= sizeof(FILE_OBJECT
);
649 FileObject
->RelatedFileObject
= OpenPacket
->RelatedFileObject
;
650 FileObject
->DeviceObject
= OriginalDeviceObject
;
652 /* Check if this is a direct device open */
653 if (DirectOpen
) FileObject
->Flags
|= FO_DIRECT_DEVICE_OPEN
;
655 /* Check if the caller wants case sensitivity */
656 if (!(Attributes
& OBJ_CASE_INSENSITIVE
))
658 /* Tell the driver about it */
659 FileObject
->Flags
|= FO_OPENED_CASE_SENSITIVE
;
662 /* Now set the file object */
663 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
664 StackLoc
->FileObject
= FileObject
;
666 /* Check if the file object has a name */
667 if (RemainingName
->Length
)
669 /* Setup the unicode string */
670 FileObject
->FileName
.MaximumLength
= RemainingName
->Length
+
672 FileObject
->FileName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
677 if (!FileObject
->FileName
.Buffer
)
679 /* Failed to allocate the name, free the IRP */
682 /* Dereference the device object and VPB */
683 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
684 if (Vpb
) IopDereferenceVpb(Vpb
);
686 /* Clear the FO and dereference it */
687 FileObject
->DeviceObject
= NULL
;
688 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
691 return STATUS_INSUFFICIENT_RESOURCES
;
696 RtlCopyUnicodeString(&FileObject
->FileName
, RemainingName
);
698 /* Initialize the File Object event and set the FO */
699 KeInitializeEvent(&FileObject
->Event
, NotificationEvent
, FALSE
);
700 OpenPacket
->FileObject
= FileObject
;
702 /* Queue the IRP and call the driver */
703 IopQueueIrpToThread(Irp
);
704 Status
= IoCallDriver(DeviceObject
, Irp
);
705 if (Status
== STATUS_PENDING
)
707 /* Wait for the driver to complete the create */
708 KeWaitForSingleObject(&FileObject
->Event
,
714 /* Get the new status */
715 Status
= IoStatusBlock
.Status
;
719 /* We'll have to complete it ourselves */
720 ASSERT(!Irp
->PendingReturned
);
721 ASSERT(!Irp
->MdlAddress
);
723 /* Completion happens at APC_LEVEL */
724 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
726 /* Get the new I/O Status block ourselves */
727 IoStatusBlock
= Irp
->IoStatus
;
728 Status
= IoStatusBlock
.Status
;
730 /* Manually signal the even, we can't have any waiters */
731 FileObject
->Event
.Header
.SignalState
= 1;
733 /* Now that we've signaled the events, de-associate the IRP */
734 IopUnQueueIrpFromThread(Irp
);
736 /* Check if the IRP had an input buffer */
737 if ((Irp
->Flags
& IRP_BUFFERED_IO
) &&
738 (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
))
740 /* Free it. A driver might've tacked one on */
741 ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
744 /* Free the IRP and bring the IRQL back down */
746 KeLowerIrql(OldIrql
);
749 /* Copy the I/O Status */
750 OpenPacket
->Information
= IoStatusBlock
.Information
;
752 /* The driver failed to create the file */
753 if (!NT_SUCCESS(Status
))
755 /* Check if we have a name */
756 if (FileObject
->FileName
.Length
)
759 ExFreePool(FileObject
->FileName
.Buffer
);
760 FileObject
->FileName
.Length
= 0;
763 /* Clear its device object */
764 FileObject
->DeviceObject
= NULL
;
766 /* Save this now because the FO might go away */
767 OpenCancelled
= FileObject
->Flags
& FO_FILE_OPEN_CANCELLED
?
770 /* Clear the file object in the open packet */
771 OpenPacket
->FileObject
= NULL
;
773 /* Dereference the file object */
774 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
776 /* Dereference the device object */
777 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
779 /* Unless the driver cancelled the open, dereference the VPB */
780 if (!(OpenCancelled
) && (Vpb
)) IopDereferenceVpb(Vpb
);
782 /* Set the status and return */
783 OpenPacket
->FinalStatus
= Status
;
786 else if (Status
== STATUS_REPARSE
)
788 /* FIXME: We don't handle this at all! */
792 /* Get the owner of the File Object */
793 OwnerDevice
= IoGetRelatedDeviceObject(FileObject
);
796 * It's possible that the device to whom we sent the IRP to
797 * isn't actually the device that ended opening the file object
800 if (OwnerDevice
!= DeviceObject
)
802 /* We have to de-reference the VPB we had associated */
803 if (Vpb
) IopDereferenceVpb(Vpb
);
805 /* And re-associate with the actual one */
806 Vpb
= FileObject
->Vpb
;
807 if (Vpb
) InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
810 /* Make sure we are not using a dummy */
813 /* Check if this was a volume open */
814 if ((!(FileObject
->RelatedFileObject
) ||
815 (FileObject
->RelatedFileObject
->Flags
& FO_VOLUME_OPEN
)) &&
816 !(FileObject
->FileName
.Length
))
818 /* All signs point to it, but make sure it was actually an FSD */
819 if ((OwnerDevice
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
820 (OwnerDevice
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
821 (OwnerDevice
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
) ||
822 (OwnerDevice
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
))
824 /* The owner device is an FSD, so this is a volume open for real */
825 FileObject
->Flags
|= FO_VOLUME_OPEN
;
829 /* Reference the object and set the parse check */
830 ObReferenceObject(FileObject
);
831 *Object
= FileObject
;
832 OpenPacket
->FinalStatus
= IoStatusBlock
.Status
;
833 OpenPacket
->ParseCheck
= TRUE
;
834 return OpenPacket
->FinalStatus
;
838 /* Check if this was a query */
839 if (OpenPacket
->QueryOnly
)
841 /* Check if the caller wants basic info only */
842 if (!OpenPacket
->FullAttributes
)
844 /* Allocate the buffer */
845 FileBasicInfo
= ExAllocatePoolWithTag(NonPagedPool
,
846 sizeof(*FileBasicInfo
),
851 Status
= IoQueryFileInformation(FileObject
,
852 FileBasicInformation
,
853 sizeof(*FileBasicInfo
),
856 if (NT_SUCCESS(Status
))
859 RtlCopyMemory(OpenPacket
->BasicInformation
,
864 /* Free our buffer */
865 ExFreePool(FileBasicInfo
);
870 Status
= STATUS_INSUFFICIENT_RESOURCES
;
875 /* This is a full query */
876 Status
= IoQueryFileInformation(
878 FileNetworkOpenInformation
,
879 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
880 OpenPacket
->NetworkInformation
,
882 if (!NT_SUCCESS(Status
)) ASSERT(Status
!= STATUS_NOT_IMPLEMENTED
);
886 /* Delete the file object */
887 IopDeleteFile(FileObject
);
889 /* Clear out the file */
890 OpenPacket
->FileObject
= NULL
;
892 /* Set and return status */
893 OpenPacket
->FinalStatus
= Status
;
894 OpenPacket
->ParseCheck
= TRUE
;
901 IopParseFile(IN PVOID ParseObject
,
903 IN OUT PACCESS_STATE AccessState
,
904 IN KPROCESSOR_MODE AccessMode
,
906 IN OUT PUNICODE_STRING CompleteName
,
907 IN OUT PUNICODE_STRING RemainingName
,
908 IN OUT PVOID Context OPTIONAL
,
909 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
913 POPEN_PACKET OpenPacket
= (POPEN_PACKET
)Context
;
915 /* Validate the open packet */
916 if (!IopValidateOpenPacket(OpenPacket
)) return STATUS_OBJECT_TYPE_MISMATCH
;
918 /* Get the device object */
919 DeviceObject
= IoGetRelatedDeviceObject(ParseObject
);
920 OpenPacket
->RelatedFileObject
= ParseObject
;
922 /* Call the main routine */
923 return IopParseDevice(DeviceObject
,
937 IopDeleteFile(IN PVOID ObjectBody
)
939 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
941 PIO_STACK_LOCATION StackPtr
;
944 PDEVICE_OBJECT DeviceObject
;
945 BOOLEAN DereferenceDone
= FALSE
;
948 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
950 /* Check if the file has a device object */
951 if (FileObject
->DeviceObject
)
953 /* Check if this is a direct open or not */
954 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
956 /* Get the attached device */
957 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
961 /* Use the file object's device object */
962 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
966 ASSERT(!(FileObject
->Flags
& FO_SYNCHRONOUS_IO
) ||
967 (InterlockedExchange((PLONG
)&FileObject
->Busy
, TRUE
) == FALSE
));
969 /* Check if the handle wasn't created yet */
970 if (!(FileObject
->Flags
& FO_HANDLE_CREATED
))
972 /* Send the cleanup IRP */
973 IopCloseFile(NULL
, ObjectBody
, 0, 1, 1);
976 /* Clear and set up Events */
977 KeClearEvent(&FileObject
->Event
);
978 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
980 /* Allocate an IRP */
981 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
985 Irp
->UserEvent
= &Event
;
986 Irp
->UserIosb
= &Irp
->IoStatus
;
987 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
988 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
989 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
991 /* Set up Stack Pointer Data */
992 StackPtr
= IoGetNextIrpStackLocation(Irp
);
993 StackPtr
->MajorFunction
= IRP_MJ_CLOSE
;
994 StackPtr
->FileObject
= FileObject
;
997 IopQueueIrpToThread(Irp
);
999 /* Get the VPB and check if this isn't a direct open */
1000 Vpb
= FileObject
->Vpb
;
1001 if ((Vpb
) && !(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1003 /* Dereference the VPB before the close */
1004 InterlockedDecrement((PLONG
)&Vpb
->ReferenceCount
);
1007 /* Check if the FS will never disappear by itself */
1008 if (FileObject
->DeviceObject
->Flags
& DO_NEVER_LAST_DEVICE
)
1010 /* Dereference it */
1011 InterlockedDecrement(&FileObject
->DeviceObject
->ReferenceCount
);
1012 DereferenceDone
= TRUE
;
1015 /* Call the FS Driver */
1016 Status
= IoCallDriver(DeviceObject
, Irp
);
1017 if (Status
== STATUS_PENDING
)
1019 /* Wait for completion */
1020 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1023 /* De-queue the IRP */
1024 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1025 IopUnQueueIrpFromThread(Irp
);
1026 KeLowerIrql(OldIrql
);
1031 /* Clear the file name */
1032 if (FileObject
->FileName
.Buffer
)
1034 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
1035 FileObject
->FileName
.Buffer
= NULL
;
1038 /* Check if the FO had a completion port */
1039 if (FileObject
->CompletionContext
)
1042 ObDereferenceObject(FileObject
->CompletionContext
->Port
);
1043 ExFreePool(FileObject
->CompletionContext
);
1046 /* Check if dereference has been done yet */
1047 if (!DereferenceDone
)
1049 /* Dereference device object */
1050 IopDereferenceDeviceObject(FileObject
->DeviceObject
, FALSE
);
1057 IopSecurityFile(IN PVOID ObjectBody
,
1058 IN SECURITY_OPERATION_CODE OperationCode
,
1059 IN PSECURITY_INFORMATION SecurityInformation
,
1060 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1061 IN OUT PULONG BufferLength
,
1062 IN OUT PSECURITY_DESCRIPTOR
*OldSecurityDescriptor
,
1063 IN POOL_TYPE PoolType
,
1064 IN OUT PGENERIC_MAPPING GenericMapping
)
1066 IO_STATUS_BLOCK IoStatusBlock
;
1067 PIO_STACK_LOCATION StackPtr
;
1068 PFILE_OBJECT FileObject
;
1069 PDEVICE_OBJECT DeviceObject
;
1071 BOOLEAN LocalEvent
= FALSE
;
1073 NTSTATUS Status
= STATUS_SUCCESS
;
1075 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1077 /* Check if this is a device or file */
1078 if (((PFILE_OBJECT
)ObjectBody
)->Type
== IO_TYPE_DEVICE
)
1081 DeviceObject
= (PDEVICE_OBJECT
)ObjectBody
;
1087 FileObject
= (PFILE_OBJECT
)ObjectBody
;
1089 /* Check if this is a direct open */
1090 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1092 /* Get the Device Object */
1093 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1097 /* Otherwise, use the direct device*/
1098 DeviceObject
= FileObject
->DeviceObject
;
1102 /* Check if the request was for a device object */
1103 if (!(FileObject
) ||
1104 (!(FileObject
->FileName
.Length
) && !(FileObject
->RelatedFileObject
)) ||
1105 (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1107 /* Check what kind of request this was */
1108 if (OperationCode
== QuerySecurityDescriptor
)
1110 return SeQuerySecurityDescriptorInfo(SecurityInformation
,
1113 &DeviceObject
->SecurityDescriptor
);
1115 else if (OperationCode
== DeleteSecurityDescriptor
)
1117 /* Simply return success */
1118 return STATUS_SUCCESS
;
1120 else if (OperationCode
== AssignSecurityDescriptor
)
1122 /* Make absolutely sure this is a device object */
1123 if (!(FileObject
) || !(FileObject
->Flags
& FO_STREAM_FILE
))
1125 /* Assign the Security Descriptor */
1126 DeviceObject
->SecurityDescriptor
= SecurityDescriptor
;
1129 /* Return success */
1130 return STATUS_SUCCESS
;
1134 DPRINT1("FIXME: Set SD unimplemented for Devices\n");
1135 return STATUS_SUCCESS
;
1138 else if (OperationCode
== DeleteSecurityDescriptor
)
1140 /* Same as for devices, do nothing */
1141 return STATUS_SUCCESS
;
1144 /* At this point, we know we're a file. Reference it */
1145 ObReferenceObject(FileObject
);
1147 /* Check if we should use Sync IO or not */
1148 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
1150 /* Lock the file object */
1151 IopLockFileObject(FileObject
);
1155 /* Use local event */
1156 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1160 /* Clear the File Object event */
1161 KeClearEvent(&FileObject
->Event
);
1163 /* Get the device object */
1164 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1166 /* Allocate the IRP */
1167 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1168 if (!Irp
) return IopCleanupFailedIrp(FileObject
, NULL
, NULL
);
1171 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1172 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1173 Irp
->RequestorMode
= ExGetPreviousMode();
1174 Irp
->UserIosb
= &IoStatusBlock
;
1175 Irp
->UserEvent
= (LocalEvent
) ? &Event
: NULL
;
1176 Irp
->Flags
= (LocalEvent
) ? IRP_SYNCHRONOUS_API
: 0;
1177 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
1179 /* Set Stack Parameters */
1180 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1181 StackPtr
->FileObject
= FileObject
;
1183 /* Check if this is a query or set */
1184 if (OperationCode
== QuerySecurityDescriptor
)
1186 /* Set the major function and parameters */
1187 StackPtr
->MajorFunction
= IRP_MJ_QUERY_SECURITY
;
1188 StackPtr
->Parameters
.QuerySecurity
.SecurityInformation
=
1189 *SecurityInformation
;
1190 StackPtr
->Parameters
.QuerySecurity
.Length
= *BufferLength
;
1191 Irp
->UserBuffer
= SecurityDescriptor
;
1195 /* Set the major function and parameters for a set */
1196 StackPtr
->MajorFunction
= IRP_MJ_SET_SECURITY
;
1197 StackPtr
->Parameters
.SetSecurity
.SecurityInformation
=
1198 *SecurityInformation
;
1199 StackPtr
->Parameters
.SetSecurity
.SecurityDescriptor
=
1204 IopQueueIrpToThread(Irp
);
1206 /* Update operation counts */
1207 IopUpdateOperationCount(IopOtherTransfer
);
1209 /* Call the Driver */
1210 Status
= IoCallDriver(DeviceObject
, Irp
);
1212 /* Check if this was async I/O */
1215 /* Check if the IRP is pending completion */
1216 if (Status
== STATUS_PENDING
)
1218 /* Wait on the local event */
1219 KeWaitForSingleObject(&Event
,
1224 Status
= IoStatusBlock
.Status
;
1229 /* Check if the IRP is pending completion */
1230 if (Status
== STATUS_PENDING
)
1232 /* Wait on the file object */
1233 KeWaitForSingleObject(&FileObject
->Event
,
1238 Status
= FileObject
->FinalStatus
;
1241 /* Release the lock */
1242 IopUnlockFileObject(FileObject
);
1245 /* This Driver doesn't implement Security, so try to give it a default */
1246 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
1248 /* Was this a query? */
1249 if (OperationCode
== QuerySecurityDescriptor
)
1251 /* Set a World Security Descriptor */
1252 Status
= SeSetWorldSecurityDescriptor(*SecurityInformation
,
1258 /* It wasn't a query, so just fake success */
1259 Status
= STATUS_SUCCESS
;
1262 else if (OperationCode
== QuerySecurityDescriptor
)
1264 /* Callers usually expect the normalized form */
1265 if (Status
== STATUS_BUFFER_OVERFLOW
) Status
= STATUS_BUFFER_TOO_SMALL
;
1270 *BufferLength
= IoStatusBlock
.Information
;
1272 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1274 Status
= _SEH2_GetExceptionCode();
1285 IopQueryNameFile(IN PVOID ObjectBody
,
1287 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1289 OUT PULONG ReturnLength
,
1290 IN KPROCESSOR_MODE PreviousMode
)
1292 POBJECT_NAME_INFORMATION LocalInfo
;
1293 PFILE_NAME_INFORMATION LocalFileInfo
;
1294 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1295 ULONG LocalReturnLength
, FileLength
;
1296 BOOLEAN LengthMismatch
= FALSE
;
1299 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1301 /* Validate length */
1302 if (Length
< sizeof(OBJECT_NAME_INFORMATION
))
1304 /* Wrong length, fail */
1305 return STATUS_INFO_LENGTH_MISMATCH
;
1308 /* Allocate Buffer */
1309 LocalInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_IO
);
1310 if (!LocalInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
1312 /* Query the name */
1313 Status
= ObQueryNameString(FileObject
->DeviceObject
,
1316 &LocalReturnLength
);
1317 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_INFO_LENGTH_MISMATCH
))
1319 /* Free the buffer and fail */
1320 ExFreePool(LocalInfo
);
1324 /* Copy the information */
1325 RtlCopyMemory(ObjectNameInfo
,
1327 (LocalReturnLength
> Length
) ?
1328 Length
: LocalReturnLength
);
1330 /* Set buffer pointer */
1331 p
= (PWCHAR
)(ObjectNameInfo
+ 1);
1332 ObjectNameInfo
->Name
.Buffer
= p
;
1334 /* Advance in buffer */
1335 p
+= (LocalInfo
->Name
.Length
/ sizeof(WCHAR
));
1337 /* Check if this already filled our buffer */
1338 if (LocalReturnLength
> Length
)
1340 /* Set the length mismatch to true, so that we can return
1341 * the proper buffer size to the caller later
1343 LengthMismatch
= TRUE
;
1345 /* Save the initial buffer length value */
1346 *ReturnLength
= LocalReturnLength
;
1349 /* Now get the file name buffer and check the length needed */
1350 LocalFileInfo
= (PFILE_NAME_INFORMATION
)LocalInfo
;
1351 FileLength
= Length
-
1353 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
1355 /* Query the File name */
1356 Status
= IoQueryFileInformation(FileObject
,
1357 FileNameInformation
,
1358 LengthMismatch
? Length
: FileLength
,
1360 &LocalReturnLength
);
1361 if (NT_ERROR(Status
))
1363 /* Fail on errors only, allow warnings */
1364 ExFreePool(LocalInfo
);
1368 /* If the provided buffer is too small, return the required size */
1371 /* Add the required length */
1372 *ReturnLength
+= LocalFileInfo
->FileNameLength
;
1374 /* Free the allocated buffer and return failure */
1375 ExFreePool(LocalInfo
);
1376 return STATUS_BUFFER_OVERFLOW
;
1379 /* Now calculate the new lengths left */
1380 FileLength
= LocalReturnLength
-
1381 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
1382 LocalReturnLength
= (ULONG_PTR
)p
-
1383 (ULONG_PTR
)ObjectNameInfo
+
1384 LocalFileInfo
->FileNameLength
;
1386 /* Write the Name and null-terminate it */
1387 RtlCopyMemory(p
, LocalFileInfo
->FileName
, FileLength
);
1388 p
+= (FileLength
/ sizeof(WCHAR
));
1390 LocalReturnLength
+= sizeof(UNICODE_NULL
);
1392 /* Return the length needed */
1393 *ReturnLength
= LocalReturnLength
;
1395 /* Setup the length and maximum length */
1396 FileLength
= (ULONG_PTR
)p
- (ULONG_PTR
)ObjectNameInfo
;
1397 ObjectNameInfo
->Name
.Length
= (USHORT
)FileLength
-
1398 sizeof(OBJECT_NAME_INFORMATION
);
1399 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)ObjectNameInfo
->Name
.Length
+
1400 sizeof(UNICODE_NULL
);
1402 /* Free buffer and return */
1403 ExFreePool(LocalInfo
);
1409 IopCloseFile(IN PEPROCESS Process OPTIONAL
,
1410 IN PVOID ObjectBody
,
1411 IN ACCESS_MASK GrantedAccess
,
1412 IN ULONG HandleCount
,
1413 IN ULONG SystemHandleCount
)
1415 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1418 PIO_STACK_LOCATION StackPtr
;
1420 PDEVICE_OBJECT DeviceObject
;
1422 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1424 /* If this isn't the last handle for the current process, quit */
1425 if (HandleCount
!= 1) return;
1427 /* Check if the file is locked and has more then one handle opened */
1428 if ((FileObject
->LockOperation
) && (SystemHandleCount
!= 1))
1430 DPRINT1("We need to unlock this file!\n");
1434 /* Make sure this is the last handle */
1435 if (SystemHandleCount
!= 1) return;
1437 /* Check if this is a direct open or not */
1438 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1440 /* Get the attached device */
1441 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1445 /* Get the FO's device */
1446 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1449 /* Set the handle created flag */
1450 FileObject
->Flags
|= FO_HANDLE_CREATED
;
1452 /* Check if this is a sync FO and lock it */
1453 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
) IopLockFileObject(FileObject
);
1455 /* Clear and set up Events */
1456 KeClearEvent(&FileObject
->Event
);
1457 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1459 /* Allocate an IRP */
1460 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1464 Irp
->UserEvent
= &Event
;
1465 Irp
->UserIosb
= &Irp
->IoStatus
;
1466 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1467 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1468 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
1469 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
1471 /* Set up Stack Pointer Data */
1472 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1473 StackPtr
->MajorFunction
= IRP_MJ_CLEANUP
;
1474 StackPtr
->FileObject
= FileObject
;
1477 IopQueueIrpToThread(Irp
);
1479 /* Update operation counts */
1480 IopUpdateOperationCount(IopOtherTransfer
);
1482 /* Call the FS Driver */
1483 Status
= IoCallDriver(DeviceObject
, Irp
);
1484 if (Status
== STATUS_PENDING
)
1486 /* Wait for completion */
1487 KeWaitForSingleObject(&Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
1490 /* Unqueue the IRP */
1491 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1492 IopUnQueueIrpFromThread(Irp
);
1493 KeLowerIrql(OldIrql
);
1498 /* Release the lock if we were holding it */
1499 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
) IopUnlockFileObject(FileObject
);
1504 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
1505 IN FILE_INFORMATION_CLASS FileInformationClass
,
1506 IN ULONG FileInformationSize
,
1507 OUT PVOID FileInformation
)
1509 NTSTATUS Status
= STATUS_SUCCESS
;
1510 KPROCESSOR_MODE AccessMode
= ExGetPreviousMode();
1511 DUMMY_FILE_OBJECT DummyFileObject
;
1512 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo
;
1514 OPEN_PACKET OpenPacket
;
1517 IOTRACE(IO_FILE_DEBUG
, "Class: %lx\n", FileInformationClass
);
1519 /* Check if the caller was user mode */
1520 if (AccessMode
!= KernelMode
)
1522 /* Protect probe in SEH */
1525 /* Probe the buffer */
1526 ProbeForWrite(FileInformation
, FileInformationSize
, sizeof(ULONG
));
1528 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1530 /* Get the exception code */
1531 Status
= _SEH2_GetExceptionCode();
1535 /* Fail on exception */
1536 if (!NT_SUCCESS(Status
))return Status
;
1539 /* Check if this is a basic or full request */
1540 IsBasic
= (FileInformationSize
== sizeof(FILE_BASIC_INFORMATION
));
1542 /* Setup the Open Packet */
1543 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
1544 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
1545 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
1546 OpenPacket
.CreateOptions
= FILE_OPEN_REPARSE_POINT
;
1547 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
1548 OpenPacket
.Disposition
= FILE_OPEN
;
1549 OpenPacket
.BasicInformation
= IsBasic
? FileInformation
: NULL
;
1550 OpenPacket
.NetworkInformation
= IsBasic
? &NetworkOpenInfo
:
1551 (AccessMode
!= KernelMode
) ?
1552 &NetworkOpenInfo
: FileInformation
;
1553 OpenPacket
.QueryOnly
= TRUE
;
1554 OpenPacket
.FullAttributes
= IsBasic
? FALSE
: TRUE
;
1555 OpenPacket
.DummyFileObject
= &DummyFileObject
;
1557 /* Update the operation count */
1558 IopUpdateOperationCount(IopOtherTransfer
);
1561 * Attempt opening the file. This will call the I/O Parse Routine for
1562 * the File Object (IopParseDevice) which will use the dummy file obejct
1563 * send the IRP to its device object. Note that we have two statuses
1564 * to worry about: the Object Manager's status (in Status) and the I/O
1565 * status, which is in the Open Packet's Final Status, and determined
1566 * by the Parse Check member.
1568 Status
= ObOpenObjectByName(ObjectAttributes
,
1572 FILE_READ_ATTRIBUTES
,
1575 if (OpenPacket
.ParseCheck
!= TRUE
)
1582 /* Use the Io status */
1583 Status
= OpenPacket
.FinalStatus
;
1586 /* Check if we were succesful and this was user mode and a full query */
1587 if ((NT_SUCCESS(Status
)) && (AccessMode
!= KernelMode
) && !(IsBasic
))
1589 /* Enter SEH for copy */
1592 /* Copy the buffer back */
1593 RtlCopyMemory(FileInformation
,
1595 FileInformationSize
);
1597 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1599 /* Get exception code */
1600 Status
= _SEH2_GetExceptionCode();
1609 /* FUNCTIONS *****************************************************************/
1616 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass
,
1618 IN BOOLEAN SetOperation
)
1621 return STATUS_NOT_IMPLEMENTED
;
1629 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer
,
1630 IN ULONG QuotaLength
,
1631 OUT PULONG ErrorOffset
)
1634 return STATUS_NOT_IMPLEMENTED
;
1642 IoCreateFile(OUT PHANDLE FileHandle
,
1643 IN ACCESS_MASK DesiredAccess
,
1644 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1645 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1646 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
1647 IN ULONG FileAttributes
,
1648 IN ULONG ShareAccess
,
1649 IN ULONG Disposition
,
1650 IN ULONG CreateOptions
,
1651 IN PVOID EaBuffer OPTIONAL
,
1653 IN CREATE_FILE_TYPE CreateFileType
,
1654 IN PVOID ExtraCreateParameters OPTIONAL
,
1657 KPROCESSOR_MODE AccessMode
;
1658 HANDLE LocalHandle
= 0;
1659 LARGE_INTEGER SafeAllocationSize
;
1660 PVOID SystemEaBuffer
= NULL
;
1661 NTSTATUS Status
= STATUS_SUCCESS
;
1662 OPEN_PACKET OpenPacket
;
1663 ULONG EaErrorOffset
;
1666 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
1668 /* Check if we have no parameter checking to do */
1669 if (Options
& IO_NO_PARAMETER_CHECKING
)
1671 /* Then force kernel-mode access to avoid checks */
1672 AccessMode
= KernelMode
;
1676 /* Otherwise, use the actual mode */
1677 AccessMode
= ExGetPreviousMode();
1680 /* Check if the call came from user mode */
1681 if (AccessMode
!= KernelMode
)
1685 ProbeForWriteHandle(FileHandle
);
1686 ProbeForWriteIoStatusBlock(IoStatusBlock
);
1689 SafeAllocationSize
= ProbeForReadLargeInteger(AllocationSize
);
1693 SafeAllocationSize
.QuadPart
= 0;
1696 if ((EaBuffer
) && (EaLength
))
1698 ProbeForRead(EaBuffer
,
1702 /* marshal EaBuffer */
1703 SystemEaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1708 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1712 RtlCopyMemory(SystemEaBuffer
, EaBuffer
, EaLength
);
1714 /* Validate the buffer */
1715 Status
= IoCheckEaBufferValidity(SystemEaBuffer
,
1718 if (!NT_SUCCESS(Status
))
1720 DPRINT1("FIXME: IoCheckEaBufferValidity() failed with "
1721 "Status: %lx\n",Status
);
1725 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1727 Status
= _SEH2_GetExceptionCode();
1731 if(!NT_SUCCESS(Status
))
1733 /* Free SystemEaBuffer if needed */
1734 if (SystemEaBuffer
) ExFreePoolWithTag(SystemEaBuffer
, TAG_EA
);
1736 /* Return failure status */
1742 /* Check if this is a device attach */
1743 if (CreateOptions
& IO_ATTACH_DEVICE_API
)
1745 /* Set the flag properly */
1746 Options
|= IO_ATTACH_DEVICE
;
1747 CreateOptions
&= ~IO_ATTACH_DEVICE_API
;
1750 /* Check if we have allocation size */
1754 SafeAllocationSize
= *AllocationSize
;
1758 /* Otherwise, no size */
1759 SafeAllocationSize
.QuadPart
= 0;
1762 /* Check if we have an EA packet */
1763 if ((EaBuffer
) && (EaLength
))
1765 /* Allocate the kernel copy */
1766 SystemEaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
1769 if (!SystemEaBuffer
) return STATUS_INSUFFICIENT_RESOURCES
;
1772 RtlCopyMemory(SystemEaBuffer
, EaBuffer
, EaLength
);
1774 /* Validate the buffer */
1775 Status
= IoCheckEaBufferValidity(SystemEaBuffer
,
1778 if (!NT_SUCCESS(Status
))
1780 DPRINT1("FIXME: IoCheckEaBufferValidity() failed with "
1781 "Status: %lx\n",Status
);
1786 /* Setup the Open Packet */
1787 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
1788 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
1789 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
1790 OpenPacket
.OriginalAttributes
= *ObjectAttributes
;
1791 OpenPacket
.AllocationSize
= SafeAllocationSize
;
1792 OpenPacket
.CreateOptions
= CreateOptions
;
1793 OpenPacket
.FileAttributes
= (USHORT
)FileAttributes
;
1794 OpenPacket
.ShareAccess
= (USHORT
)ShareAccess
;
1795 OpenPacket
.EaBuffer
= SystemEaBuffer
;
1796 OpenPacket
.EaLength
= EaLength
;
1797 OpenPacket
.Options
= Options
;
1798 OpenPacket
.Disposition
= Disposition
;
1799 OpenPacket
.CreateFileType
= CreateFileType
;
1800 OpenPacket
.MailslotOrPipeParameters
= ExtraCreateParameters
;
1802 /* Update the operation count */
1803 IopUpdateOperationCount(IopOtherTransfer
);
1806 * Attempt opening the file. This will call the I/O Parse Routine for
1807 * the File Object (IopParseDevice) which will create the object and
1808 * send the IRP to its device object. Note that we have two statuses
1809 * to worry about: the Object Manager's status (in Status) and the I/O
1810 * status, which is in the Open Packet's Final Status, and determined
1811 * by the Parse Check member.
1813 Status
= ObOpenObjectByName(ObjectAttributes
,
1821 /* Free the EA Buffer */
1822 if (OpenPacket
.EaBuffer
) ExFreePool(OpenPacket
.EaBuffer
);
1824 /* Now check for Ob or Io failure */
1825 if (!(NT_SUCCESS(Status
)) || (OpenPacket
.ParseCheck
!= TRUE
))
1827 /* Check if Ob thinks well went well */
1828 if (NT_SUCCESS(Status
))
1831 * Tell it otherwise. Because we didn't use an ObjectType,
1832 * it incorrectly returned us a handle to God knows what.
1834 ZwClose(LocalHandle
);
1835 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
1838 /* Now check the Io status */
1839 if (!NT_SUCCESS(OpenPacket
.FinalStatus
))
1841 /* Use this status instead of Ob's */
1842 Status
= OpenPacket
.FinalStatus
;
1844 /* Check if it was only a warning */
1845 if (NT_WARNING(Status
))
1847 /* Protect write with SEH */
1850 /* In this case, we copy the I/O Status back */
1851 IoStatusBlock
->Information
= OpenPacket
.Information
;
1852 IoStatusBlock
->Status
= OpenPacket
.FinalStatus
;
1854 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1856 /* Get exception code */
1857 Status
= _SEH2_GetExceptionCode();
1862 else if ((OpenPacket
.FileObject
) && (OpenPacket
.ParseCheck
!= 1))
1865 * This can happen in the very bizarre case where the parse routine
1866 * actually executed more then once (due to a reparse) and ended
1867 * up failing after already having created the File Object.
1869 if (OpenPacket
.FileObject
->FileName
.Length
)
1871 /* It had a name, free it */
1872 ExFreePool(OpenPacket
.FileObject
->FileName
.Buffer
);
1875 /* Clear the device object to invalidate the FO, and dereference */
1876 OpenPacket
.FileObject
->DeviceObject
= NULL
;
1877 ObDereferenceObject(OpenPacket
.FileObject
);
1882 /* We reached success and have a valid file handle */
1883 OpenPacket
.FileObject
->Flags
|= FO_HANDLE_CREATED
;
1885 /* Enter SEH for write back */
1888 /* Write back the handle and I/O Status */
1889 *FileHandle
= LocalHandle
;
1890 IoStatusBlock
->Information
= OpenPacket
.Information
;
1891 IoStatusBlock
->Status
= OpenPacket
.FinalStatus
;
1893 /* Get the Io status */
1894 Status
= OpenPacket
.FinalStatus
;
1896 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1898 /* Get the exception status */
1899 Status
= _SEH2_GetExceptionCode();
1904 /* Check if we were 100% successful */
1905 if ((OpenPacket
.ParseCheck
== TRUE
) && (OpenPacket
.FileObject
))
1907 /* Dereference the File Object */
1908 ObDereferenceObject(OpenPacket
.FileObject
);
1920 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle
,
1921 IN ACCESS_MASK DesiredAccess
,
1922 IN POBJECT_ATTRIBUTES ObjectAttributes
,
1923 OUT PIO_STATUS_BLOCK IoStatusBlock
,
1924 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
1925 IN ULONG FileAttributes
,
1926 IN ULONG ShareAccess
,
1927 IN ULONG Disposition
,
1928 IN ULONG CreateOptions
,
1929 IN PVOID EaBuffer OPTIONAL
,
1931 IN CREATE_FILE_TYPE CreateFileType
,
1932 IN PVOID ExtraCreateParameters OPTIONAL
,
1934 IN PVOID DeviceObject
)
1937 return STATUS_NOT_IMPLEMENTED
;
1945 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL
,
1946 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
1947 OUT PHANDLE FileObjectHandle OPTIONAL
)
1949 PFILE_OBJECT CreatedFileObject
;
1952 OBJECT_ATTRIBUTES ObjectAttributes
;
1954 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
1956 /* Choose Device Object */
1957 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
1959 /* Reference the device object and initialize attributes */
1960 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
1961 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
1963 /* Create the File Object */
1964 Status
= ObCreateObject(KernelMode
,
1969 sizeof(FILE_OBJECT
),
1970 sizeof(FILE_OBJECT
),
1972 (PVOID
*)&CreatedFileObject
);
1973 if (!NT_SUCCESS(Status
))
1976 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
1977 ExRaiseStatus(Status
);
1980 /* Set File Object Data */
1981 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
1982 CreatedFileObject
->DeviceObject
= DeviceObject
;
1983 CreatedFileObject
->Type
= IO_TYPE_FILE
;
1984 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
1985 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
1987 /* Initialize the wait event */
1988 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
1990 /* Insert it to create a handle for it */
1991 Status
= ObInsertObject(CreatedFileObject
,
1995 (PVOID
*)&CreatedFileObject
,
1997 if (!NT_SUCCESS(Status
)) ExRaiseStatus(Status
);
1999 /* Set the handle created flag */
2000 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
2001 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
2003 /* Check if we have a VPB */
2004 if (DeviceObject
->Vpb
)
2007 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
2010 /* Check if the caller wants the handle */
2011 if (FileObjectHandle
)
2014 *FileObjectHandle
= FileHandle
;
2015 ObDereferenceObject(CreatedFileObject
);
2019 /* Otherwise, close it */
2020 ObCloseHandle(FileHandle
, KernelMode
);
2023 /* Return the file object */
2024 return CreatedFileObject
;
2032 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject
,
2033 IN PDEVICE_OBJECT DeviceObject
)
2035 /* Call the newer function */
2036 return IoCreateStreamFileObjectEx(FileObject
, DeviceObject
, NULL
);
2044 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL
,
2045 IN PDEVICE_OBJECT DeviceObject OPTIONAL
)
2047 PFILE_OBJECT CreatedFileObject
;
2049 OBJECT_ATTRIBUTES ObjectAttributes
;
2051 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
2053 /* Choose Device Object */
2054 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
2056 /* Reference the device object and initialize attributes */
2057 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
2058 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
2060 /* Create the File Object */
2061 Status
= ObCreateObject(KernelMode
,
2066 sizeof(FILE_OBJECT
),
2067 sizeof(FILE_OBJECT
),
2069 (PVOID
*)&CreatedFileObject
);
2070 if (!NT_SUCCESS(Status
))
2073 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
2074 ExRaiseStatus(Status
);
2077 /* Set File Object Data */
2078 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
2079 CreatedFileObject
->DeviceObject
= DeviceObject
;
2080 CreatedFileObject
->Type
= IO_TYPE_FILE
;
2081 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
2082 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
2084 /* Initialize the wait event */
2085 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
2087 /* Destroy create information */
2088 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->
2090 OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->ObjectCreateInfo
= NULL
;
2092 /* Set the handle created flag */
2093 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
2094 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
2096 /* Check if we have a VPB */
2097 if (DeviceObject
->Vpb
)
2100 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
2103 /* Return the file object */
2104 return CreatedFileObject
;
2112 IoGetFileObjectGenericMapping(VOID
)
2114 /* Return the mapping */
2115 return &IopFileMapping
;
2123 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject
)
2125 /* Return the flag status */
2126 return FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
2134 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2135 IN ACCESS_MASK DesiredAccess
,
2136 IN ULONG OpenOptions
,
2137 OUT PIO_STATUS_BLOCK IoStatus
,
2138 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer
)
2141 DUMMY_FILE_OBJECT DummyFileObject
;
2143 OPEN_PACKET OpenPacket
;
2145 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
2147 /* Setup the Open Packet */
2148 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
2149 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
2150 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
2151 OpenPacket
.CreateOptions
= OpenOptions
| FILE_OPEN_REPARSE_POINT
;
2152 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2153 OpenPacket
.Options
= IO_FORCE_ACCESS_CHECK
;
2154 OpenPacket
.Disposition
= FILE_OPEN
;
2155 OpenPacket
.NetworkInformation
= Buffer
;
2156 OpenPacket
.QueryOnly
= TRUE
;
2157 OpenPacket
.FullAttributes
= TRUE
;
2158 OpenPacket
.DummyFileObject
= &DummyFileObject
;
2161 * Attempt opening the file. This will call the I/O Parse Routine for
2162 * the File Object (IopParseDevice) which will use the dummy file obejct
2163 * send the IRP to its device object. Note that we have two statuses
2164 * to worry about: the Object Manager's status (in Status) and the I/O
2165 * status, which is in the Open Packet's Final Status, and determined
2166 * by the Parse Check member.
2168 Status
= ObOpenObjectByName(ObjectAttributes
,
2175 if (OpenPacket
.ParseCheck
!= TRUE
)
2178 IoStatus
->Status
= Status
;
2182 /* Use the Io status */
2183 IoStatus
->Status
= OpenPacket
.FinalStatus
;
2184 IoStatus
->Information
= OpenPacket
.Information
;
2187 /* Return success */
2196 IoUpdateShareAccess(IN PFILE_OBJECT FileObject
,
2197 OUT PSHARE_ACCESS ShareAccess
)
2201 /* Check if the file has an extension */
2202 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2204 /* Check if caller specified to ignore access checks */
2205 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2207 /* Don't update share access */
2212 /* Otherwise, check if there's any access present */
2213 if ((FileObject
->ReadAccess
) ||
2214 (FileObject
->WriteAccess
) ||
2215 (FileObject
->DeleteAccess
))
2217 /* Increase the open count */
2218 ShareAccess
->OpenCount
++;
2220 /* Add new share access */
2221 ShareAccess
->Readers
+= FileObject
->ReadAccess
;
2222 ShareAccess
->Writers
+= FileObject
->WriteAccess
;
2223 ShareAccess
->Deleters
+= FileObject
->DeleteAccess
;
2224 ShareAccess
->SharedRead
+= FileObject
->SharedRead
;
2225 ShareAccess
->SharedWrite
+= FileObject
->SharedWrite
;
2226 ShareAccess
->SharedDelete
+= FileObject
->SharedDelete
;
2235 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess
,
2236 IN ULONG DesiredShareAccess
,
2237 IN PFILE_OBJECT FileObject
,
2238 IN PSHARE_ACCESS ShareAccess
,
2242 BOOLEAN WriteAccess
;
2243 BOOLEAN DeleteAccess
;
2245 BOOLEAN SharedWrite
;
2246 BOOLEAN SharedDelete
;
2249 /* Get access masks */
2250 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
2251 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
2252 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
2254 /* Set them in the file object */
2255 FileObject
->ReadAccess
= ReadAccess
;
2256 FileObject
->WriteAccess
= WriteAccess
;
2257 FileObject
->DeleteAccess
= DeleteAccess
;
2259 /* Check if the file has an extension */
2260 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2262 /* Check if caller specified to ignore access checks */
2263 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2265 /* Don't check share access */
2266 return STATUS_SUCCESS
;
2270 /* Check if we have any access */
2271 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
2273 /* Get shared access masks */
2274 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
2275 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
2276 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
2279 FileObject
->SharedRead
= SharedRead
;
2280 FileObject
->SharedWrite
= SharedWrite
;
2281 FileObject
->SharedDelete
= SharedDelete
;
2283 /* Check if the shared access is violated */
2285 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
2287 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
2289 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
2290 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
2291 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
2292 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
2294 /* Sharing violation, fail */
2295 return STATUS_SHARING_VIOLATION
;
2298 /* It's not, check if caller wants us to update it */
2301 /* Increase open count */
2302 ShareAccess
->OpenCount
++;
2304 /* Update shared access */
2305 ShareAccess
->Readers
+= ReadAccess
;
2306 ShareAccess
->Writers
+= WriteAccess
;
2307 ShareAccess
->Deleters
+= DeleteAccess
;
2308 ShareAccess
->SharedRead
+= SharedRead
;
2309 ShareAccess
->SharedWrite
+= SharedWrite
;
2310 ShareAccess
->SharedDelete
+= SharedDelete
;
2314 /* Validation successful */
2315 return STATUS_SUCCESS
;
2323 IoRemoveShareAccess(IN PFILE_OBJECT FileObject
,
2324 IN PSHARE_ACCESS ShareAccess
)
2328 /* Check if the file has an extension */
2329 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2331 /* Check if caller specified to ignore access checks */
2332 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2334 /* Don't update share access */
2339 /* Otherwise, check if there's any access present */
2340 if ((FileObject
->ReadAccess
) ||
2341 (FileObject
->WriteAccess
) ||
2342 (FileObject
->DeleteAccess
))
2344 /* Decrement the open count */
2345 ShareAccess
->OpenCount
--;
2347 /* Remove share access */
2348 ShareAccess
->Readers
-= FileObject
->ReadAccess
;
2349 ShareAccess
->Writers
-= FileObject
->WriteAccess
;
2350 ShareAccess
->Deleters
-= FileObject
->DeleteAccess
;
2351 ShareAccess
->SharedRead
-= FileObject
->SharedRead
;
2352 ShareAccess
->SharedWrite
-= FileObject
->SharedWrite
;
2353 ShareAccess
->SharedDelete
-= FileObject
->SharedDelete
;
2362 IoSetShareAccess(IN ACCESS_MASK DesiredAccess
,
2363 IN ULONG DesiredShareAccess
,
2364 IN PFILE_OBJECT FileObject
,
2365 OUT PSHARE_ACCESS ShareAccess
)
2368 BOOLEAN WriteAccess
;
2369 BOOLEAN DeleteAccess
;
2371 BOOLEAN SharedWrite
;
2372 BOOLEAN SharedDelete
;
2373 BOOLEAN Update
= TRUE
;
2376 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
2377 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
2378 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
2380 /* Check if the file has an extension */
2381 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2383 /* Check if caller specified to ignore access checks */
2384 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2386 /* Don't update share access */
2391 /* Update basic access */
2392 FileObject
->ReadAccess
= ReadAccess
;
2393 FileObject
->WriteAccess
= WriteAccess
;
2394 FileObject
->DeleteAccess
= DeleteAccess
;
2396 /* Check if we have no access as all */
2397 if (!(ReadAccess
) && !(WriteAccess
) && !(DeleteAccess
))
2399 /* Check if we need to update the structure */
2400 if (!Update
) return;
2402 /* Otherwise, clear data */
2403 ShareAccess
->OpenCount
= 0;
2404 ShareAccess
->Readers
= 0;
2405 ShareAccess
->Writers
= 0;
2406 ShareAccess
->Deleters
= 0;
2407 ShareAccess
->SharedRead
= 0;
2408 ShareAccess
->SharedWrite
= 0;
2409 ShareAccess
->SharedDelete
= 0;
2413 /* Calculate shared access */
2414 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
2415 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
2416 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
2418 /* Set it in the FO */
2419 FileObject
->SharedRead
= SharedRead
;
2420 FileObject
->SharedWrite
= SharedWrite
;
2421 FileObject
->SharedDelete
= SharedDelete
;
2423 /* Check if we need to update the structure */
2424 if (!Update
) return;
2426 /* Otherwise, set data */
2427 ShareAccess
->OpenCount
= 1;
2428 ShareAccess
->Readers
= ReadAccess
;
2429 ShareAccess
->Writers
= WriteAccess
;
2430 ShareAccess
->Deleters
= DeleteAccess
;
2431 ShareAccess
->SharedRead
= SharedRead
;
2432 ShareAccess
->SharedWrite
= SharedWrite
;
2433 ShareAccess
->SharedDelete
= SharedDelete
;
2442 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject
,
2443 IN PFILE_OBJECT FileObject
)
2453 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject
,
2454 OUT POBJECT_NAME_INFORMATION
*ObjectNameInformation
)
2457 return STATUS_NOT_IMPLEMENTED
;
2465 IoSetFileOrigin(IN PFILE_OBJECT FileObject
,
2468 NTSTATUS Status
= STATUS_SUCCESS
;
2471 /* Get the flag status */
2472 FlagSet
= FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
2474 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
2475 if (Remote
&& !FlagSet
)
2478 FileObject
->Flags
|= FO_REMOTE_ORIGIN
;
2480 else if (!Remote
&& FlagSet
)
2482 /* Remove the flag */
2483 FileObject
->Flags
&= ~FO_REMOTE_ORIGIN
;
2488 Status
= STATUS_INVALID_PARAMETER_MIX
;
2500 NtCreateFile(PHANDLE FileHandle
,
2501 ACCESS_MASK DesiredAccess
,
2502 POBJECT_ATTRIBUTES ObjectAttributes
,
2503 PIO_STATUS_BLOCK IoStatusBlock
,
2504 PLARGE_INTEGER AllocateSize
,
2505 ULONG FileAttributes
,
2507 ULONG CreateDisposition
,
2508 ULONG CreateOptions
,
2512 /* Call the I/O Function */
2513 return IoCreateFile(FileHandle
,
2531 NtCreateMailslotFile(OUT PHANDLE FileHandle
,
2532 IN ACCESS_MASK DesiredAccess
,
2533 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2534 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2535 IN ULONG CreateOptions
,
2536 IN ULONG MailslotQuota
,
2537 IN ULONG MaxMessageSize
,
2538 IN PLARGE_INTEGER TimeOut
)
2540 MAILSLOT_CREATE_PARAMETERS Buffer
;
2541 NTSTATUS Status
= STATUS_SUCCESS
;
2544 /* Check for Timeout */
2547 /* check if the call came from user mode */
2548 if (KeGetPreviousMode() != KernelMode
)
2550 /* Enter SEH for Probe */
2553 /* Probe the timeout */
2554 Buffer
.ReadTimeout
= ProbeForReadLargeInteger(TimeOut
);
2556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2558 /* Get exception code */
2559 Status
= _SEH2_GetExceptionCode();
2563 /* Return the exception */
2564 if (!NT_SUCCESS(Status
)) return Status
;
2568 /* Otherwise, capture directly */
2569 Buffer
.ReadTimeout
= *TimeOut
;
2572 /* Set the correct setting */
2573 Buffer
.TimeoutSpecified
= TRUE
;
2577 /* Tell the FSD we don't have a timeout */
2578 Buffer
.TimeoutSpecified
= FALSE
;
2582 Buffer
.MailslotQuota
= MailslotQuota
;
2583 Buffer
.MaximumMessageSize
= MaxMessageSize
;
2586 return IoCreateFile(FileHandle
,
2592 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
2597 CreateFileTypeMailslot
,
2604 NtCreateNamedPipeFile(OUT PHANDLE FileHandle
,
2605 IN ACCESS_MASK DesiredAccess
,
2606 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2607 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2608 IN ULONG ShareAccess
,
2609 IN ULONG CreateDisposition
,
2610 IN ULONG CreateOptions
,
2611 IN ULONG NamedPipeType
,
2613 IN ULONG CompletionMode
,
2614 IN ULONG MaximumInstances
,
2615 IN ULONG InboundQuota
,
2616 IN ULONG OutboundQuota
,
2617 IN PLARGE_INTEGER DefaultTimeout
)
2619 NAMED_PIPE_CREATE_PARAMETERS Buffer
;
2620 NTSTATUS Status
= STATUS_SUCCESS
;
2623 /* Check for Timeout */
2626 /* check if the call came from user mode */
2627 if (KeGetPreviousMode() != KernelMode
)
2629 /* Enter SEH for Probe */
2632 /* Probe the timeout */
2633 Buffer
.DefaultTimeout
=
2634 ProbeForReadLargeInteger(DefaultTimeout
);
2636 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2638 /* Get exception code */
2639 Status
= _SEH2_GetExceptionCode();
2643 /* Return the exception */
2644 if (!NT_SUCCESS(Status
)) return Status
;
2648 /* Otherwise, capture directly */
2649 Buffer
.DefaultTimeout
= *DefaultTimeout
;
2652 /* Set the correct setting */
2653 Buffer
.TimeoutSpecified
= TRUE
;
2657 /* Tell the FSD we don't have a timeout */
2658 Buffer
.TimeoutSpecified
= FALSE
;
2662 Buffer
.NamedPipeType
= NamedPipeType
;
2663 Buffer
.ReadMode
= ReadMode
;
2664 Buffer
.CompletionMode
= CompletionMode
;
2665 Buffer
.MaximumInstances
= MaximumInstances
;
2666 Buffer
.InboundQuota
= InboundQuota
;
2667 Buffer
.OutboundQuota
= OutboundQuota
;
2670 return IoCreateFile(FileHandle
,
2681 CreateFileTypeNamedPipe
,
2688 NtFlushWriteBuffer(VOID
)
2692 /* Call the kernel */
2693 KeFlushWriteBuffer();
2694 return STATUS_SUCCESS
;
2702 NtOpenFile(OUT PHANDLE FileHandle
,
2703 IN ACCESS_MASK DesiredAccess
,
2704 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2705 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2706 IN ULONG ShareAccess
,
2707 IN ULONG OpenOptions
)
2709 /* Call the I/O Function */
2710 return IoCreateFile(FileHandle
,
2728 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2729 OUT PFILE_BASIC_INFORMATION FileInformation
)
2731 /* Call the internal helper API */
2732 return IopQueryAttributesFile(ObjectAttributes
,
2733 FileBasicInformation
,
2734 sizeof(FILE_BASIC_INFORMATION
),
2740 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2741 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
)
2743 /* Call the internal helper API */
2744 return IopQueryAttributesFile(ObjectAttributes
,
2745 FileNetworkOpenInformation
,
2746 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
2751 * @name NtCancelIoFile
2753 * Cancel all pending I/O operations in the current thread for specified
2757 * Handle to file object to cancel requests for. No specific
2758 * access rights are needed.
2759 * @param IoStatusBlock
2760 * Pointer to status block which is filled with final completition
2761 * status on successful return.
2769 NtCancelIoFile(IN HANDLE FileHandle
,
2770 OUT PIO_STATUS_BLOCK IoStatusBlock
)
2772 PFILE_OBJECT FileObject
;
2776 BOOLEAN OurIrpsInList
= FALSE
;
2777 LARGE_INTEGER Interval
;
2778 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
2779 NTSTATUS Status
= STATUS_SUCCESS
;
2780 PLIST_ENTRY ListHead
, NextEntry
;
2782 IOTRACE(IO_API_DEBUG
, "FileHandle: %p\n", FileHandle
);
2784 /* Check the previous mode */
2785 if (PreviousMode
!= KernelMode
)
2787 /* Enter SEH for probing */
2790 /* Probe the I/O Status Block */
2791 ProbeForWriteIoStatusBlock(IoStatusBlock
);
2793 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2795 /* Get the exception code */
2796 Status
= _SEH2_GetExceptionCode();
2800 /* Return exception code on failure */
2801 if (!NT_SUCCESS(Status
)) return Status
;
2804 /* Reference the file object */
2805 Status
= ObReferenceObjectByHandle(FileHandle
,
2809 (PVOID
*)&FileObject
,
2811 if (!NT_SUCCESS(Status
)) return Status
;
2813 /* IRP cancellations are synchronized at APC_LEVEL. */
2814 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2816 /* Get the current thread */
2817 Thread
= PsGetCurrentThread();
2819 /* Update the operation counts */
2820 IopUpdateOperationCount(IopOtherTransfer
);
2823 ListHead
= &Thread
->IrpList
;
2824 NextEntry
= ListHead
->Flink
;
2825 while (ListHead
!= NextEntry
)
2827 /* Get the IRP and check if the File Object matches */
2828 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
2829 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
2831 /* Cancel this IRP and keep looping */
2833 OurIrpsInList
= TRUE
;
2836 /* Go to the next entry */
2837 NextEntry
= NextEntry
->Flink
;
2840 /* Lower the IRQL */
2841 KeLowerIrql(OldIrql
);
2843 /* Check if we had found an IRP */
2846 /* Setup a 10ms wait */
2847 Interval
.QuadPart
= -100000;
2850 while (OurIrpsInList
)
2853 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
2854 OurIrpsInList
= FALSE
;
2857 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2859 /* Now loop the list again */
2860 NextEntry
= ListHead
->Flink
;
2861 while (NextEntry
!= ListHead
)
2863 /* Get the IRP and check if the File Object matches */
2864 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
2865 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
2868 OurIrpsInList
= TRUE
;
2872 /* Go to the next entry */
2873 NextEntry
= NextEntry
->Flink
;
2876 /* Lower the IRQL */
2877 KeLowerIrql(OldIrql
);
2881 /* Enter SEH for writing back the I/O Status */
2885 IoStatusBlock
->Status
= STATUS_SUCCESS
;
2886 IoStatusBlock
->Information
= 0;
2888 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2894 /* Dereference the file object and return success */
2895 ObDereferenceObject(FileObject
);
2896 return STATUS_SUCCESS
;
2904 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes
)
2907 DUMMY_FILE_OBJECT DummyFileObject
;
2909 KPROCESSOR_MODE AccessMode
= KeGetPreviousMode();
2910 OPEN_PACKET OpenPacket
;
2912 IOTRACE(IO_API_DEBUG
, "FileMame: %wZ\n", ObjectAttributes
->ObjectName
);
2914 /* Setup the Open Packet */
2915 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
2916 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
2917 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
2918 OpenPacket
.CreateOptions
= FILE_DELETE_ON_CLOSE
;
2919 OpenPacket
.ShareAccess
= FILE_SHARE_READ
|
2922 OpenPacket
.Disposition
= FILE_OPEN
;
2923 OpenPacket
.DeleteOnly
= TRUE
;
2924 OpenPacket
.DummyFileObject
= &DummyFileObject
;
2926 /* Update the operation counts */
2927 IopUpdateOperationCount(IopOtherTransfer
);
2930 * Attempt opening the file. This will call the I/O Parse Routine for
2931 * the File Object (IopParseDevice) which will use the dummy file obejct
2932 * send the IRP to its device object. Note that we have two statuses
2933 * to worry about: the Object Manager's status (in Status) and the I/O
2934 * status, which is in the Open Packet's Final Status, and determined
2935 * by the Parse Check member.
2937 Status
= ObOpenObjectByName(ObjectAttributes
,
2944 if (OpenPacket
.ParseCheck
!= TRUE
) return Status
;
2946 /* Retrn the Io status */
2947 return OpenPacket
.FinalStatus
;