2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/iomgr/file.c
5 * PURPOSE: Functions that deal with managing the FILE_OBJECT itself.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 * Filip Navara (navaraf@reactos.org)
13 /* INCLUDES *****************************************************************/
19 extern ERESOURCE IopSecurityResource
;
21 /* PRIVATE FUNCTIONS *********************************************************/
25 IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState
,
26 IN OUT PULONG CreateOptions
,
27 IN KPROCESSOR_MODE PreviousMode
,
30 ACCESS_MASK DesiredAccess
, ReadAccess
, WriteAccess
;
31 PRIVILEGE_SET Privileges
;
32 BOOLEAN AccessGranted
, HaveBackupPriv
= FALSE
, CheckRestore
= FALSE
;
35 /* Don't do anything if privileges were checked already */
36 if (AccessState
->Flags
& SE_BACKUP_PRIVILEGES_CHECKED
) return;
38 /* Check if the file was actually opened for backup purposes */
39 if (*CreateOptions
& FILE_OPEN_FOR_BACKUP_INTENT
)
41 /* Set the check flag since were doing it now */
42 AccessState
->Flags
|= SE_BACKUP_PRIVILEGES_CHECKED
;
44 /* Set the access masks required */
45 ReadAccess
= READ_CONTROL
|
46 ACCESS_SYSTEM_SECURITY
|
49 WriteAccess
= WRITE_DAC
|
51 ACCESS_SYSTEM_SECURITY
|
54 FILE_ADD_SUBDIRECTORY
|
56 DesiredAccess
= AccessState
->RemainingDesiredAccess
;
58 /* Check if desired access was the maximum */
59 if (DesiredAccess
& MAXIMUM_ALLOWED
)
61 /* Then add all the access masks required */
62 DesiredAccess
|= (ReadAccess
| WriteAccess
);
65 /* Check if the file already exists */
66 if (Disposition
& FILE_OPEN
)
68 /* Check if desired access has the read mask */
69 if (ReadAccess
& DesiredAccess
)
71 /* Setup the privilege check lookup */
72 Privileges
.PrivilegeCount
= 1;
73 Privileges
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
74 Privileges
.Privilege
[0].Luid
= SeBackupPrivilege
;
75 Privileges
.Privilege
[0].Attributes
= 0;
76 AccessGranted
= SePrivilegeCheck(&Privileges
,
78 SubjectSecurityContext
,
82 /* Remember that backup was allowed */
83 HaveBackupPriv
= TRUE
;
85 /* Append the privileges and update the access state */
86 SeAppendPrivileges(AccessState
, &Privileges
);
87 AccessState
->PreviouslyGrantedAccess
|= (DesiredAccess
& ReadAccess
);
88 AccessState
->RemainingDesiredAccess
&= ~ReadAccess
;
89 DesiredAccess
&= ~ReadAccess
;
91 /* Set backup privilege for the token */
92 AccessState
->Flags
|= TOKEN_HAS_BACKUP_PRIVILEGE
;
98 /* Caller is creating the file, check restore privileges later */
102 /* Check if caller wants write access or if it's creating a file */
103 if ((WriteAccess
& DesiredAccess
) || (CheckRestore
))
105 /* Setup the privilege lookup and do it */
106 Privileges
.PrivilegeCount
= 1;
107 Privileges
.Control
= PRIVILEGE_SET_ALL_NECESSARY
;
108 Privileges
.Privilege
[0].Luid
= SeRestorePrivilege
;
109 Privileges
.Privilege
[0].Attributes
= 0;
110 AccessGranted
= SePrivilegeCheck(&Privileges
,
111 &AccessState
->SubjectSecurityContext
,
115 /* Remember that privilege was given */
116 HaveBackupPriv
= TRUE
;
118 /* Append the privileges and update the access state */
119 SeAppendPrivileges(AccessState
, &Privileges
);
120 AccessState
->PreviouslyGrantedAccess
|= (DesiredAccess
& WriteAccess
);
121 AccessState
->RemainingDesiredAccess
&= ~WriteAccess
;
123 /* Set restore privilege for the token */
124 AccessState
->Flags
|= TOKEN_HAS_RESTORE_PRIVILEGE
;
128 /* If we don't have the privilege, remove the option */
129 if (!HaveBackupPriv
) *CreateOptions
&= ~FILE_OPEN_FOR_BACKUP_INTENT
;
135 IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket
,
136 IN PDEVICE_OBJECT DeviceObject
)
138 /* Make sure the object is valid */
139 if ((IoGetDevObjExtension(DeviceObject
)->ExtensionFlags
&
140 (DOE_UNLOAD_PENDING
|
143 DOE_REMOVE_PROCESSED
)) ||
144 (DeviceObject
->Flags
& DO_DEVICE_INITIALIZING
))
146 /* It's unloading or initializing, so fail */
147 DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
148 " sucks. Please fix it's AddDevice Routine\n",
149 &DeviceObject
->DriverObject
->DriverName
);
150 return STATUS_NO_SUCH_DEVICE
;
152 else if ((DeviceObject
->Flags
& DO_EXCLUSIVE
) &&
153 (DeviceObject
->ReferenceCount
) &&
154 !(OpenPacket
->RelatedFileObject
) &&
155 !(OpenPacket
->Options
& IO_ATTACH_DEVICE
))
157 return STATUS_ACCESS_DENIED
;
162 /* Increase reference count */
163 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
164 return STATUS_SUCCESS
;
170 IopDoNameTransmogrify(IN PIRP Irp
,
171 IN PFILE_OBJECT FileObject
,
172 IN PREPARSE_DATA_BUFFER DataBuffer
)
176 USHORT RequiredLength
;
181 ASSERT(Irp
->IoStatus
.Status
== STATUS_REPARSE
);
182 ASSERT(Irp
->IoStatus
.Information
== IO_REPARSE_TAG_MOUNT_POINT
);
183 ASSERT(Irp
->Tail
.Overlay
.AuxiliaryBuffer
!= NULL
);
184 ASSERT(DataBuffer
!= NULL
);
185 ASSERT(DataBuffer
->ReparseTag
== IO_REPARSE_TAG_MOUNT_POINT
);
186 ASSERT(DataBuffer
->ReparseDataLength
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
187 ASSERT(DataBuffer
->Reserved
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
189 /* First of all, validate data */
190 if (DataBuffer
->ReparseDataLength
< REPARSE_DATA_BUFFER_HEADER_SIZE
||
191 (DataBuffer
->SymbolicLinkReparseBuffer
.PrintNameLength
+
192 DataBuffer
->SymbolicLinkReparseBuffer
.SubstituteNameLength
+
193 FIELD_OFFSET(REPARSE_DATA_BUFFER
, MountPointReparseBuffer
.PathBuffer
[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE
)
195 Irp
->IoStatus
.Status
= STATUS_IO_REPARSE_DATA_INVALID
;
198 /* Everything went right */
199 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
201 /* Compute buffer & length */
202 Buffer
= (PWSTR
)((ULONG_PTR
)DataBuffer
->MountPointReparseBuffer
.PathBuffer
+
203 DataBuffer
->MountPointReparseBuffer
.SubstituteNameOffset
);
204 Length
= DataBuffer
->MountPointReparseBuffer
.SubstituteNameLength
;
206 /* Check we don't overflow */
207 if (((ULONG
)MAXUSHORT
- DataBuffer
->Reserved
) <= (Length
+ sizeof(UNICODE_NULL
)))
209 Irp
->IoStatus
.Status
= STATUS_IO_REPARSE_DATA_INVALID
;
213 /* Compute how much mem we'll need */
214 RequiredLength
= DataBuffer
->Reserved
+ Length
+ sizeof(UNICODE_NULL
);
216 /* Check if FileObject can already hold what we need */
217 if (FileObject
->FileName
.MaximumLength
>= RequiredLength
)
219 NewBuffer
= FileObject
->FileName
.Buffer
;
223 /* Allocate otherwise */
224 NewBuffer
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_IO_NAME
);
225 if (NewBuffer
== NULL
)
227 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
233 /* Everything went right */
234 if (NT_SUCCESS(Irp
->IoStatus
.Status
))
237 if (DataBuffer
->Reserved
)
239 RtlMoveMemory((PWSTR
)((ULONG_PTR
)NewBuffer
+ Length
),
240 (PWSTR
)((ULONG_PTR
)FileObject
->FileName
.Buffer
+ FileObject
->FileName
.Length
- DataBuffer
->Reserved
),
241 DataBuffer
->Reserved
);
247 RtlCopyMemory(NewBuffer
, Buffer
, Length
);
250 /* And finally replace buffer if new one was allocated */
251 FileObject
->FileName
.Length
= RequiredLength
- sizeof(UNICODE_NULL
);
252 if (NewBuffer
!= FileObject
->FileName
.Buffer
)
254 if (FileObject
->FileName
.Buffer
)
256 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
259 FileObject
->FileName
.Buffer
= NewBuffer
;
260 FileObject
->FileName
.MaximumLength
= RequiredLength
;
261 FileObject
->FileName
.Buffer
[RequiredLength
/ sizeof(WCHAR
) - 1] = UNICODE_NULL
;
265 /* We don't need them anymore - it was allocated by the driver */
266 ExFreePool(DataBuffer
);
270 IopCheckTopDeviceHint(IN OUT PDEVICE_OBJECT
* DeviceObject
,
271 IN POPEN_PACKET OpenPacket
,
274 PDEVICE_OBJECT LocalDevice
;
275 DEVICE_TYPE DeviceType
;
277 LocalDevice
= *DeviceObject
;
279 /* Direct open is not allowed */
282 return STATUS_INVALID_PARAMETER
;
285 /* Validate we have a file system device */
286 DeviceType
= LocalDevice
->DeviceType
;
287 if (DeviceType
!= FILE_DEVICE_DISK_FILE_SYSTEM
&&
288 DeviceType
!= FILE_DEVICE_CD_ROM_FILE_SYSTEM
&&
289 DeviceType
!= FILE_DEVICE_TAPE_FILE_SYSTEM
&&
290 DeviceType
!= FILE_DEVICE_NETWORK_FILE_SYSTEM
&&
291 DeviceType
!= FILE_DEVICE_DFS_FILE_SYSTEM
)
293 return STATUS_INVALID_PARAMETER
;
296 /* Verify the hint and if it's OK, return it */
297 if (IopVerifyDeviceObjectOnStack(LocalDevice
, OpenPacket
->TopDeviceObjectHint
))
299 *DeviceObject
= OpenPacket
->TopDeviceObjectHint
;
300 return STATUS_SUCCESS
;
303 /* Failure case here */
304 /* If we thought was had come through a mount point,
305 * actually update we didn't and return the error
307 if (OpenPacket
->TraversedMountPoint
)
309 OpenPacket
->TraversedMountPoint
= FALSE
;
310 return STATUS_MOUNT_POINT_NOT_RESOLVED
;
313 /* Otherwise, just return the fact the hint is invalid */
314 return STATUS_INVALID_DEVICE_OBJECT_PARAMETER
;
319 IopParseDevice(IN PVOID ParseObject
,
321 IN OUT PACCESS_STATE AccessState
,
322 IN KPROCESSOR_MODE AccessMode
,
324 IN OUT PUNICODE_STRING CompleteName
,
325 IN OUT PUNICODE_STRING RemainingName
,
326 IN OUT PVOID Context
,
327 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
330 POPEN_PACKET OpenPacket
= (POPEN_PACKET
)Context
;
331 PDEVICE_OBJECT OriginalDeviceObject
= (PDEVICE_OBJECT
)ParseObject
;
332 PDEVICE_OBJECT DeviceObject
, OwnerDevice
;
334 PFILE_OBJECT FileObject
;
337 PIO_STACK_LOCATION StackLoc
;
338 IO_SECURITY_CONTEXT SecurityContext
;
339 IO_STATUS_BLOCK IoStatusBlock
;
340 BOOLEAN DirectOpen
= FALSE
, OpenCancelled
, UseDummyFile
;
341 OBJECT_ATTRIBUTES ObjectAttributes
;
343 PDUMMY_FILE_OBJECT LocalFileObject
;
344 PFILE_BASIC_INFORMATION FileBasicInfo
;
346 KPROCESSOR_MODE CheckMode
;
347 BOOLEAN VolumeOpen
= FALSE
;
348 ACCESS_MASK DesiredAccess
, GrantedAccess
;
349 BOOLEAN AccessGranted
, LockHeld
= FALSE
;
350 PPRIVILEGE_SET Privileges
= NULL
;
351 UNICODE_STRING FileString
;
353 IOTRACE(IO_FILE_DEBUG
, "ParseObject: %p. RemainingName: %wZ\n",
354 ParseObject
, RemainingName
);
356 for (Attempt
= 0; Attempt
< IOP_MAX_REPARSE_TRAVERSAL
; ++Attempt
)
361 /* Validate the open packet */
362 if (!IopValidateOpenPacket(OpenPacket
)) return STATUS_OBJECT_TYPE_MISMATCH
;
364 /* Valide reparse point in case we traversed a mountpoint */
365 if (OpenPacket
->TraversedMountPoint
)
367 /* This is a reparse point we understand */
368 ASSERT(OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
);
370 /* Make sure we're dealing with correct DO */
371 if (OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_DISK
&&
372 OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_CD_ROM
&&
373 OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_VIRTUAL_DISK
&&
374 OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_TAPE
)
376 OpenPacket
->FinalStatus
= STATUS_IO_REPARSE_DATA_INVALID
;
377 return STATUS_IO_REPARSE_DATA_INVALID
;
381 /* Check if we have a related file object */
382 if (OpenPacket
->RelatedFileObject
)
384 /* Use the related file object's device object */
385 OriginalDeviceObject
= OpenPacket
->RelatedFileObject
->DeviceObject
;
388 /* Validate device status */
389 Status
= IopCheckDeviceAndDriver(OpenPacket
, OriginalDeviceObject
);
390 if (!NT_SUCCESS(Status
))
392 /* We failed, return status */
393 OpenPacket
->FinalStatus
= Status
;
397 /* Map the generic mask and set the new mapping in the access state */
398 RtlMapGenericMask(&AccessState
->RemainingDesiredAccess
,
399 &IoFileObjectType
->TypeInfo
.GenericMapping
);
400 RtlMapGenericMask(&AccessState
->OriginalDesiredAccess
,
401 &IoFileObjectType
->TypeInfo
.GenericMapping
);
402 SeSetAccessStateGenericMapping(AccessState
,
403 &IoFileObjectType
->TypeInfo
.GenericMapping
);
404 DesiredAccess
= AccessState
->RemainingDesiredAccess
;
406 /* Check what kind of access checks to do */
407 if ((AccessMode
!= KernelMode
) ||
408 (OpenPacket
->Options
& IO_FORCE_ACCESS_CHECK
))
410 /* Call is from user-mode or kernel is forcing checks */
411 CheckMode
= UserMode
;
415 /* Call is from the kernel */
416 CheckMode
= KernelMode
;
419 /* Check privilege for backup or restore operation */
420 IopCheckBackupRestorePrivilege(AccessState
,
421 &OpenPacket
->CreateOptions
,
423 OpenPacket
->Disposition
);
425 /* Check if we are re-parsing */
426 if (((OpenPacket
->Override
) && !(RemainingName
->Length
)) ||
427 (AccessState
->Flags
& SE_BACKUP_PRIVILEGES_CHECKED
))
429 /* Get granted access from the last call */
430 DesiredAccess
|= AccessState
->PreviouslyGrantedAccess
;
433 /* Check if this is a volume open */
434 if ((OpenPacket
->RelatedFileObject
) &&
435 (OpenPacket
->RelatedFileObject
->Flags
& FO_VOLUME_OPEN
) &&
436 !(RemainingName
->Length
))
442 /* Now check if we need access checks */
443 if (((AccessMode
!= KernelMode
) ||
444 (OpenPacket
->Options
& IO_FORCE_ACCESS_CHECK
)) &&
445 (!(OpenPacket
->RelatedFileObject
) || (VolumeOpen
)) &&
446 !(OpenPacket
->Override
))
448 KeEnterCriticalRegion();
449 ExAcquireResourceSharedLite(&IopSecurityResource
, TRUE
);
451 /* Check if a device object is being parsed */
452 if (!RemainingName
->Length
)
454 /* Lock the subject context */
455 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
458 /* Do access check */
459 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->
461 &AccessState
->SubjectSecurityContext
,
467 TypeInfo
.GenericMapping
,
473 /* Append and free the privileges */
474 SeAppendPrivileges(AccessState
, Privileges
);
475 SeFreePrivileges(Privileges
);
478 /* Check if we got access */
481 /* Update access state */
482 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
483 AccessState
->RemainingDesiredAccess
&= ~(GrantedAccess
|
485 OpenPacket
->Override
= TRUE
;
488 FileString
.Length
= 8;
489 FileString
.MaximumLength
= 8;
490 FileString
.Buffer
= L
"File";
492 /* Do Audit/Alarm for open operation */
493 SeOpenObjectAuditAlarm(&FileString
,
494 OriginalDeviceObject
,
496 OriginalDeviceObject
->SecurityDescriptor
,
501 &AccessState
->GenerateOnClose
);
505 /* Check if we need to do traverse validation */
506 if (!(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
) ||
507 ((OriginalDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
508 (OriginalDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
)))
510 /* Check if this is a restricted token */
511 if (!(AccessState
->Flags
& TOKEN_IS_RESTRICTED
))
513 /* Do the FAST traverse check */
514 AccessGranted
= SeFastTraverseCheck(OriginalDeviceObject
->SecurityDescriptor
,
522 AccessGranted
= FALSE
;
525 /* Check if we failed to get access */
528 /* Lock the subject context */
529 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
532 /* Do access check */
533 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->
535 &AccessState
->SubjectSecurityContext
,
541 TypeInfo
.GenericMapping
,
547 /* Append and free the privileges */
548 SeAppendPrivileges(AccessState
, Privileges
);
549 SeFreePrivileges(Privileges
);
553 /* FIXME: Do Audit/Alarm for traverse check */
557 /* Access automatically granted */
558 AccessGranted
= TRUE
;
562 ExReleaseResourceLite(&IopSecurityResource
);
563 KeLeaveCriticalRegion();
565 /* Check if we hold the lock */
569 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
572 /* Check if access failed */
575 /* Dereference the device and fail */
576 DPRINT1("Traverse access failed!\n");
577 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
578 return STATUS_ACCESS_DENIED
;
582 /* Check if we can simply use a dummy file */
583 UseDummyFile
= ((OpenPacket
->QueryOnly
) || (OpenPacket
->DeleteOnly
));
586 /* FIXME: Small hack still exists, have to check why...
587 * This is triggered multiple times by usetup and then once per boot.
589 if (ExpInTextModeSetup
&&
591 !(RemainingName
->Length
) &&
592 !(OpenPacket
->RelatedFileObject
) &&
593 ((wcsstr(CompleteName
->Buffer
, L
"Harddisk")) ||
594 (wcsstr(CompleteName
->Buffer
, L
"Floppy"))) &&
597 DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
598 DesiredAccess
& ~(SYNCHRONIZE
|
599 FILE_READ_ATTRIBUTES
|
601 ACCESS_SYSTEM_SECURITY
|
608 /* Check if this is a direct open */
609 if (!(RemainingName
->Length
) &&
610 !(OpenPacket
->RelatedFileObject
) &&
611 ((DesiredAccess
& ~(SYNCHRONIZE
|
612 FILE_READ_ATTRIBUTES
|
614 ACCESS_SYSTEM_SECURITY
|
619 /* Remember this for later */
623 /* Check if we have a related FO that wasn't a direct open */
624 if ((OpenPacket
->RelatedFileObject
) &&
625 !(OpenPacket
->RelatedFileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
627 /* The device object is the one we were given */
628 DeviceObject
= ParseObject
;
630 /* Check if the related FO had a VPB */
631 if (OpenPacket
->RelatedFileObject
->Vpb
)
633 /* Yes, remember it */
634 Vpb
= OpenPacket
->RelatedFileObject
->Vpb
;
637 InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
639 /* Check if we were given a specific top level device to use */
640 if (OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
)
642 DeviceObject
= Vpb
->DeviceObject
;
648 /* Check if it has a VPB */
649 if ((OriginalDeviceObject
->Vpb
) && !(DirectOpen
))
651 /* Check if the VPB is mounted, and mount it */
652 Vpb
= IopCheckVpbMounted(OpenPacket
,
653 OriginalDeviceObject
,
656 if (!Vpb
) return Status
;
658 /* Get the VPB's device object */
659 DeviceObject
= Vpb
->DeviceObject
;
663 /* The device object is the one we were given */
664 DeviceObject
= OriginalDeviceObject
;
667 /* If we weren't given a specific top level device, look for an attached device */
668 if (!(OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
) &&
669 DeviceObject
->AttachedDevice
)
671 /* Get the attached device */
672 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
676 if (OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
)
678 // FIXME: Verify our device object is good to use
679 ASSERT(DirectOpen
== FALSE
);
682 /* If we traversed a mount point, reset the information */
683 if (OpenPacket
->TraversedMountPoint
)
685 OpenPacket
->TraversedMountPoint
= FALSE
;
688 /* Check if this is a secure FSD */
689 if ((DeviceObject
->Characteristics
& FILE_DEVICE_SECURE_OPEN
) &&
690 ((OpenPacket
->RelatedFileObject
) || (RemainingName
->Length
)) &&
696 KeEnterCriticalRegion();
697 ExAcquireResourceSharedLite(&IopSecurityResource
, TRUE
);
699 /* Lock the subject context */
700 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
702 /* Do access check */
703 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->SecurityDescriptor
,
704 &AccessState
->SubjectSecurityContext
,
709 &IoFileObjectType
->TypeInfo
.GenericMapping
,
713 if (Privileges
!= NULL
)
715 /* Append and free the privileges */
716 SeAppendPrivileges(AccessState
, Privileges
);
717 SeFreePrivileges(Privileges
);
720 /* Check if we got access */
723 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
724 AccessState
->RemainingDesiredAccess
&= ~(GrantedAccess
| MAXIMUM_ALLOWED
);
727 FileString
.Length
= 8;
728 FileString
.MaximumLength
= 8;
729 FileString
.Buffer
= L
"File";
731 /* Do Audit/Alarm for open operation
732 * NOTA: we audit target device object
734 SeOpenObjectAuditAlarm(&FileString
,
737 OriginalDeviceObject
->SecurityDescriptor
,
742 &AccessState
->GenerateOnClose
);
744 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
746 ExReleaseResourceLite(&IopSecurityResource
);
747 KeLeaveCriticalRegion();
749 /* Check if access failed */
752 /* Dereference the device and fail */
753 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
754 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
755 return STATUS_ACCESS_DENIED
;
759 /* Allocate the IRP */
760 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
763 /* Dereference the device and VPB, then fail */
764 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
765 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
766 return STATUS_INSUFFICIENT_RESOURCES
;
769 /* Now set the IRP data */
770 Irp
->RequestorMode
= AccessMode
;
771 Irp
->Flags
= IRP_CREATE_OPERATION
| IRP_SYNCHRONOUS_API
| IRP_DEFER_IO_COMPLETION
;
772 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
773 Irp
->UserIosb
= &IoStatusBlock
;
774 Irp
->MdlAddress
= NULL
;
775 Irp
->PendingReturned
= FALSE
;
776 Irp
->UserEvent
= NULL
;
778 Irp
->CancelRoutine
= NULL
;
779 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
781 /* Setup the security context */
782 SecurityContext
.SecurityQos
= SecurityQos
;
783 SecurityContext
.AccessState
= AccessState
;
784 SecurityContext
.DesiredAccess
= AccessState
->RemainingDesiredAccess
;
785 SecurityContext
.FullCreateOptions
= OpenPacket
->CreateOptions
;
787 /* Get the I/O Stack location */
788 StackLoc
= IoGetNextIrpStackLocation(Irp
);
789 StackLoc
->Control
= 0;
791 /* Check what kind of file this is */
792 switch (OpenPacket
->CreateFileType
)
795 case CreateFileTypeNone
:
797 /* Set the major function and EA Length */
798 StackLoc
->MajorFunction
= IRP_MJ_CREATE
;
799 StackLoc
->Parameters
.Create
.EaLength
= OpenPacket
->EaLength
;
802 StackLoc
->Flags
= (UCHAR
)OpenPacket
->Options
;
803 StackLoc
->Flags
|= !(Attributes
& OBJ_CASE_INSENSITIVE
) ? SL_CASE_SENSITIVE
: 0;
807 case CreateFileTypeNamedPipe
:
809 /* Set the named pipe MJ and set the parameters */
810 StackLoc
->MajorFunction
= IRP_MJ_CREATE_NAMED_PIPE
;
811 StackLoc
->Parameters
.CreatePipe
.Parameters
= OpenPacket
->ExtraCreateParameters
;
815 case CreateFileTypeMailslot
:
817 /* Set the mailslot MJ and set the parameters */
818 StackLoc
->MajorFunction
= IRP_MJ_CREATE_MAILSLOT
;
819 StackLoc
->Parameters
.CreateMailslot
.Parameters
= OpenPacket
->ExtraCreateParameters
;
823 /* Set the common data */
824 Irp
->Overlay
.AllocationSize
= OpenPacket
->AllocationSize
;
825 Irp
->AssociatedIrp
.SystemBuffer
= OpenPacket
->EaBuffer
;
826 StackLoc
->Parameters
.Create
.Options
= (OpenPacket
->Disposition
<< 24) |
827 (OpenPacket
->CreateOptions
&
829 StackLoc
->Parameters
.Create
.FileAttributes
= OpenPacket
->FileAttributes
;
830 StackLoc
->Parameters
.Create
.ShareAccess
= OpenPacket
->ShareAccess
;
831 StackLoc
->Parameters
.Create
.SecurityContext
= &SecurityContext
;
833 /* Check if we really need to create an object */
836 ULONG ObjectSize
= sizeof(FILE_OBJECT
);
838 /* Tag on space for a file object extension */
839 if (OpenPacket
->InternalFlags
& IOP_CREATE_FILE_OBJECT_EXTENSION
)
840 ObjectSize
+= sizeof(FILE_OBJECT_EXTENSION
);
842 /* Create the actual file object */
843 InitializeObjectAttributes(&ObjectAttributes
,
848 Status
= ObCreateObject(KernelMode
,
856 (PVOID
*)&FileObject
);
857 if (!NT_SUCCESS(Status
))
859 /* Create failed, free the IRP */
862 /* Dereference the device and VPB */
863 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
864 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
866 /* We failed, return status */
867 OpenPacket
->FinalStatus
= Status
;
871 /* Clear the file object */
872 RtlZeroMemory(FileObject
, sizeof(FILE_OBJECT
));
874 /* Check if this is Synch I/O */
875 if (OpenPacket
->CreateOptions
&
876 (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
))
878 /* Set the synch flag */
879 FileObject
->Flags
|= FO_SYNCHRONOUS_IO
;
881 /* Check if it's also alertable */
882 if (OpenPacket
->CreateOptions
& FILE_SYNCHRONOUS_IO_ALERT
)
884 /* It is, set the alertable flag */
885 FileObject
->Flags
|= FO_ALERTABLE_IO
;
889 /* Check if this is synch I/O */
890 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
892 /* Initialize the event */
893 KeInitializeEvent(&FileObject
->Lock
, SynchronizationEvent
, FALSE
);
896 /* Check if the caller requested no intermediate buffering */
897 if (OpenPacket
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
)
899 /* Set the correct flag for the FSD to read */
900 FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
903 /* Check if the caller requested write through support */
904 if (OpenPacket
->CreateOptions
& FILE_WRITE_THROUGH
)
906 /* Set the correct flag for the FSD to read */
907 FileObject
->Flags
|= FO_WRITE_THROUGH
;
910 /* Check if the caller says the file will be only read sequentially */
911 if (OpenPacket
->CreateOptions
& FILE_SEQUENTIAL_ONLY
)
913 /* Set the correct flag for the FSD to read */
914 FileObject
->Flags
|= FO_SEQUENTIAL_ONLY
;
917 /* Check if the caller believes the file will be only read randomly */
918 if (OpenPacket
->CreateOptions
& FILE_RANDOM_ACCESS
)
920 /* Set the correct flag for the FSD to read */
921 FileObject
->Flags
|= FO_RANDOM_ACCESS
;
924 /* Check if we were asked to setup a file object extension */
925 if (OpenPacket
->InternalFlags
& IOP_CREATE_FILE_OBJECT_EXTENSION
)
927 PFILE_OBJECT_EXTENSION FileObjectExtension
;
929 /* Make sure the file object knows it has an extension */
930 FileObject
->Flags
|= FO_FILE_OBJECT_HAS_EXTENSION
;
932 FileObjectExtension
= (PFILE_OBJECT_EXTENSION
)(FileObject
+ 1);
933 FileObject
->FileObjectExtension
= FileObjectExtension
;
935 /* Add the top level device which we'll send the request to */
936 if (OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
)
938 FileObjectExtension
->TopDeviceObjectHint
= DeviceObject
;
944 /* Use the dummy object instead */
945 LocalFileObject
= OpenPacket
->LocalFileObject
;
946 RtlZeroMemory(LocalFileObject
, sizeof(DUMMY_FILE_OBJECT
));
949 FileObject
= (PFILE_OBJECT
)&LocalFileObject
->ObjectHeader
.Body
;
950 LocalFileObject
->ObjectHeader
.Type
= IoFileObjectType
;
951 LocalFileObject
->ObjectHeader
.PointerCount
= 1;
954 /* Setup the file header */
955 FileObject
->Type
= IO_TYPE_FILE
;
956 FileObject
->Size
= sizeof(FILE_OBJECT
);
957 FileObject
->RelatedFileObject
= OpenPacket
->RelatedFileObject
;
958 FileObject
->DeviceObject
= OriginalDeviceObject
;
960 /* Check if this is a direct device open */
961 if (DirectOpen
) FileObject
->Flags
|= FO_DIRECT_DEVICE_OPEN
;
963 /* Check if the caller wants case sensitivity */
964 if (!(Attributes
& OBJ_CASE_INSENSITIVE
))
966 /* Tell the driver about it */
967 FileObject
->Flags
|= FO_OPENED_CASE_SENSITIVE
;
970 /* Now set the file object */
971 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
972 StackLoc
->FileObject
= FileObject
;
974 /* Check if the file object has a name */
975 if (RemainingName
->Length
)
977 /* Setup the unicode string */
978 FileObject
->FileName
.MaximumLength
= RemainingName
->Length
+
980 FileObject
->FileName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
985 if (!FileObject
->FileName
.Buffer
)
987 /* Failed to allocate the name, free the IRP */
990 /* Dereference the device object and VPB */
991 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
992 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
994 /* Clear the FO and dereference it */
995 FileObject
->DeviceObject
= NULL
;
996 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
999 return STATUS_INSUFFICIENT_RESOURCES
;
1004 RtlCopyUnicodeString(&FileObject
->FileName
, RemainingName
);
1006 /* Initialize the File Object event and set the FO */
1007 KeInitializeEvent(&FileObject
->Event
, NotificationEvent
, FALSE
);
1008 OpenPacket
->FileObject
= FileObject
;
1010 /* Queue the IRP and call the driver */
1011 IopQueueIrpToThread(Irp
);
1012 Status
= IoCallDriver(DeviceObject
, Irp
);
1013 if (Status
== STATUS_PENDING
)
1015 /* Wait for the driver to complete the create */
1016 KeWaitForSingleObject(&FileObject
->Event
,
1022 /* Get the new status */
1023 Status
= IoStatusBlock
.Status
;
1027 /* We'll have to complete it ourselves */
1028 ASSERT(!Irp
->PendingReturned
);
1029 ASSERT(!Irp
->MdlAddress
);
1031 /* Handle name change if required */
1032 if (Status
== STATUS_REPARSE
)
1034 /* Check this is a mount point */
1035 if (Irp
->IoStatus
.Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1037 PREPARSE_DATA_BUFFER ReparseData
;
1039 /* Reparse point attributes were passed by the driver in the auxiliary buffer */
1040 ASSERT(Irp
->Tail
.Overlay
.AuxiliaryBuffer
!= NULL
);
1041 ReparseData
= (PREPARSE_DATA_BUFFER
)Irp
->Tail
.Overlay
.AuxiliaryBuffer
;
1043 ASSERT(ReparseData
->ReparseTag
== IO_REPARSE_TAG_MOUNT_POINT
);
1044 ASSERT(ReparseData
->ReparseDataLength
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
1045 ASSERT(ReparseData
->Reserved
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
1047 IopDoNameTransmogrify(Irp
, FileObject
, ReparseData
);
1051 /* Completion happens at APC_LEVEL */
1052 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1054 /* Get the new I/O Status block ourselves */
1055 IoStatusBlock
= Irp
->IoStatus
;
1056 Status
= IoStatusBlock
.Status
;
1058 /* Manually signal the even, we can't have any waiters */
1059 FileObject
->Event
.Header
.SignalState
= 1;
1061 /* Now that we've signaled the events, de-associate the IRP */
1062 IopUnQueueIrpFromThread(Irp
);
1064 /* Check if the IRP had an input buffer */
1065 if ((Irp
->Flags
& IRP_BUFFERED_IO
) &&
1066 (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
))
1068 /* Free it. A driver might've tacked one on */
1069 ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
1072 /* Free the IRP and bring the IRQL back down */
1074 KeLowerIrql(OldIrql
);
1077 /* Copy the I/O Status */
1078 OpenPacket
->Information
= IoStatusBlock
.Information
;
1080 /* The driver failed to create the file */
1081 if (!NT_SUCCESS(Status
))
1083 /* Check if we have a name */
1084 if (FileObject
->FileName
.Length
)
1087 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
1088 FileObject
->FileName
.Length
= 0;
1091 /* Clear its device object */
1092 FileObject
->DeviceObject
= NULL
;
1094 /* Save this now because the FO might go away */
1095 OpenCancelled
= FileObject
->Flags
& FO_FILE_OPEN_CANCELLED
?
1098 /* Clear the file object in the open packet */
1099 OpenPacket
->FileObject
= NULL
;
1101 /* Dereference the file object */
1102 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
1104 /* Dereference the device object */
1105 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
1107 /* Unless the driver cancelled the open, dereference the VPB */
1108 if (!(OpenCancelled
) && (Vpb
)) IopDereferenceVpbAndFree(Vpb
);
1110 /* Set the status and return */
1111 OpenPacket
->FinalStatus
= Status
;
1114 else if (Status
== STATUS_REPARSE
)
1116 if (OpenPacket
->Information
== IO_REPARSE
||
1117 OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1119 /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
1120 if (CompleteName
->MaximumLength
< FileObject
->FileName
.Length
)
1122 PWSTR NewCompleteName
;
1124 /* Allocate a new buffer for the string */
1125 NewCompleteName
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
, TAG_IO_NAME
);
1126 if (NewCompleteName
== NULL
)
1128 OpenPacket
->FinalStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1129 return STATUS_INSUFFICIENT_RESOURCES
;
1132 /* Release the old one */
1133 if (CompleteName
->Buffer
!= NULL
)
1135 ExFreePoolWithTag(CompleteName
->Buffer
, 0);
1138 /* And setup the new one */
1139 CompleteName
->Buffer
= NewCompleteName
;
1140 CompleteName
->MaximumLength
= FileObject
->FileName
.Length
;
1143 /* Copy our new complete name */
1144 RtlCopyUnicodeString(CompleteName
, &FileObject
->FileName
);
1146 if (OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1148 OpenPacket
->RelatedFileObject
= NULL
;
1152 /* Check if we have a name */
1153 if (FileObject
->FileName
.Length
)
1156 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1157 FileObject
->FileName
.Length
= 0;
1160 /* Clear its device object */
1161 FileObject
->DeviceObject
= NULL
;
1163 /* Clear the file object in the open packet */
1164 OpenPacket
->FileObject
= NULL
;
1166 /* Dereference the file object */
1167 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
1169 /* Dereference the device object */
1170 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
1172 /* Unless the driver cancelled the open, dereference the VPB */
1173 if (Vpb
!= NULL
) IopDereferenceVpbAndFree(Vpb
);
1175 if (OpenPacket
->Information
!= IO_REMOUNT
)
1177 OpenPacket
->RelatedFileObject
= NULL
;
1179 /* Inform we traversed a mount point for later attempt */
1180 if (OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1182 OpenPacket
->TraversedMountPoint
= 1;
1185 /* In case we override checks, but got this on volume open, fail hard */
1186 if (OpenPacket
->Override
)
1188 KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN
,
1189 (ULONG_PTR
)OriginalDeviceObject
,
1190 (ULONG_PTR
)DeviceObject
,
1191 (ULONG_PTR
)CompleteName
,
1192 OpenPacket
->Information
);
1195 /* Return to IO/OB so that information can be upgraded */
1196 return STATUS_REPARSE
;
1199 /* Loop again and reattempt an opening */
1206 if (Attempt
== IOP_MAX_REPARSE_TRAVERSAL
)
1207 return STATUS_UNSUCCESSFUL
;
1209 /* Get the owner of the File Object */
1210 OwnerDevice
= IoGetRelatedDeviceObject(FileObject
);
1213 * It's possible that the device to whom we sent the IRP to
1214 * isn't actually the device that ended opening the file object
1217 if (OwnerDevice
!= DeviceObject
)
1219 /* We have to de-reference the VPB we had associated */
1220 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
1222 /* And re-associate with the actual one */
1223 Vpb
= FileObject
->Vpb
;
1224 if (Vpb
) InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
1227 /* Make sure we are not using a dummy */
1230 /* Check if this was a volume open */
1231 if ((!(FileObject
->RelatedFileObject
) ||
1232 (FileObject
->RelatedFileObject
->Flags
& FO_VOLUME_OPEN
)) &&
1233 !(FileObject
->FileName
.Length
))
1235 /* All signs point to it, but make sure it was actually an FSD */
1236 if ((OwnerDevice
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1237 (OwnerDevice
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
1238 (OwnerDevice
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
) ||
1239 (OwnerDevice
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
))
1241 /* The owner device is an FSD, so this is a volume open for real */
1242 FileObject
->Flags
|= FO_VOLUME_OPEN
;
1246 /* Reference the object and set the parse check */
1247 ObReferenceObject(FileObject
);
1248 *Object
= FileObject
;
1249 OpenPacket
->FinalStatus
= IoStatusBlock
.Status
;
1250 OpenPacket
->ParseCheck
= TRUE
;
1251 return OpenPacket
->FinalStatus
;
1255 /* Check if this was a query */
1256 if (OpenPacket
->QueryOnly
)
1258 /* Check if the caller wants basic info only */
1259 if (!OpenPacket
->FullAttributes
)
1261 /* Allocate the buffer */
1262 FileBasicInfo
= ExAllocatePoolWithTag(NonPagedPool
,
1263 sizeof(*FileBasicInfo
),
1268 Status
= IoQueryFileInformation(FileObject
,
1269 FileBasicInformation
,
1270 sizeof(*FileBasicInfo
),
1273 if (NT_SUCCESS(Status
))
1276 RtlCopyMemory(OpenPacket
->BasicInformation
,
1281 /* Free our buffer */
1282 ExFreePoolWithTag(FileBasicInfo
, TAG_IO
);
1287 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1292 /* This is a full query */
1293 Status
= IoQueryFileInformation(
1295 FileNetworkOpenInformation
,
1296 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
1297 OpenPacket
->NetworkInformation
,
1299 if (!NT_SUCCESS(Status
)) ASSERT(Status
!= STATUS_NOT_IMPLEMENTED
);
1303 /* Delete the file object */
1304 IopDeleteFile(FileObject
);
1306 /* Clear out the file */
1307 OpenPacket
->FileObject
= NULL
;
1309 /* Set and return status */
1310 OpenPacket
->FinalStatus
= Status
;
1311 OpenPacket
->ParseCheck
= TRUE
;
1318 IopParseFile(IN PVOID ParseObject
,
1319 IN PVOID ObjectType
,
1320 IN OUT PACCESS_STATE AccessState
,
1321 IN KPROCESSOR_MODE AccessMode
,
1322 IN ULONG Attributes
,
1323 IN OUT PUNICODE_STRING CompleteName
,
1324 IN OUT PUNICODE_STRING RemainingName
,
1325 IN OUT PVOID Context OPTIONAL
,
1326 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
1330 POPEN_PACKET OpenPacket
= (POPEN_PACKET
)Context
;
1332 /* Validate the open packet */
1333 if (!IopValidateOpenPacket(OpenPacket
)) return STATUS_OBJECT_TYPE_MISMATCH
;
1335 /* Get the device object */
1336 DeviceObject
= IoGetRelatedDeviceObject(ParseObject
);
1337 OpenPacket
->RelatedFileObject
= ParseObject
;
1339 /* Call the main routine */
1340 return IopParseDevice(DeviceObject
,
1354 IopDeleteFile(IN PVOID ObjectBody
)
1356 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1358 PIO_STACK_LOCATION StackPtr
;
1361 PDEVICE_OBJECT DeviceObject
;
1362 BOOLEAN DereferenceDone
= FALSE
;
1365 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1367 /* Check if the file has a device object */
1368 if (FileObject
->DeviceObject
)
1370 /* Check if this is a direct open or not */
1371 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1373 /* Get the attached device */
1374 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1378 /* Use the file object's device object */
1379 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1383 ASSERT(!(FileObject
->Flags
& FO_SYNCHRONOUS_IO
) ||
1384 (InterlockedExchange((PLONG
)&FileObject
->Busy
, TRUE
) == FALSE
));
1386 /* Check if the handle wasn't created yet */
1387 if (!(FileObject
->Flags
& FO_HANDLE_CREATED
))
1389 /* Send the cleanup IRP */
1390 IopCloseFile(NULL
, ObjectBody
, 0, 1, 1);
1393 /* Clear and set up Events */
1394 KeClearEvent(&FileObject
->Event
);
1395 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1397 /* Allocate an IRP */
1398 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
1401 Irp
->UserEvent
= &Event
;
1402 Irp
->UserIosb
= &Irp
->IoStatus
;
1403 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1404 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1405 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
1407 /* Set up Stack Pointer Data */
1408 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1409 StackPtr
->MajorFunction
= IRP_MJ_CLOSE
;
1410 StackPtr
->FileObject
= FileObject
;
1413 IopQueueIrpToThread(Irp
);
1415 /* Get the VPB and check if this isn't a direct open */
1416 Vpb
= FileObject
->Vpb
;
1417 if ((Vpb
) && !(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1419 /* Dereference the VPB before the close */
1420 InterlockedDecrement((PLONG
)&Vpb
->ReferenceCount
);
1423 /* Check if the FS will never disappear by itself */
1424 if (FileObject
->DeviceObject
->Flags
& DO_NEVER_LAST_DEVICE
)
1426 /* Dereference it */
1427 InterlockedDecrement(&FileObject
->DeviceObject
->ReferenceCount
);
1428 DereferenceDone
= TRUE
;
1431 /* Call the FS Driver */
1432 Status
= IoCallDriver(DeviceObject
, Irp
);
1433 if (Status
== STATUS_PENDING
)
1435 /* Wait for completion */
1436 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1439 /* De-queue the IRP */
1440 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1441 IopUnQueueIrpFromThread(Irp
);
1442 KeLowerIrql(OldIrql
);
1447 /* Clear the file name */
1448 if (FileObject
->FileName
.Buffer
)
1450 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
1451 FileObject
->FileName
.Buffer
= NULL
;
1454 /* Check if the FO had a completion port */
1455 if (FileObject
->CompletionContext
)
1458 ObDereferenceObject(FileObject
->CompletionContext
->Port
);
1459 ExFreePool(FileObject
->CompletionContext
);
1462 /* Check if the FO had extension */
1463 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1465 /* Release filter context structure if any */
1466 FsRtlPTeardownPerFileObjectContexts(FileObject
);
1469 /* Check if dereference has been done yet */
1470 if (!DereferenceDone
)
1472 /* Dereference device object */
1473 IopDereferenceDeviceObject(FileObject
->DeviceObject
, FALSE
);
1480 IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject
)
1482 PDEVICE_OBJECT PDO
= DeviceObject
;
1484 /* Go down the stack to attempt to get the PDO */
1485 for (; ((PEXTENDED_DEVOBJ_EXTENSION
)PDO
->DeviceObjectExtension
)->AttachedTo
!= NULL
;
1486 PDO
= ((PEXTENDED_DEVOBJ_EXTENSION
)PDO
->DeviceObjectExtension
)->AttachedTo
);
1493 IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject
)
1498 ASSERT(DeviceObject
!= NULL
);
1500 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
1501 /* Get the base DO */
1502 PDO
= IopGetDeviceAttachmentBase(DeviceObject
);
1503 /* Check whether that's really a PDO and if so, keep it */
1504 if ((PDO
->Flags
& DO_BUS_ENUMERATED_DEVICE
) != DO_BUS_ENUMERATED_DEVICE
)
1510 ObReferenceObject(PDO
);
1512 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
1519 IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject
,
1520 IN PSECURITY_INFORMATION SecurityInformation
,
1521 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1522 IN POOL_TYPE PoolType
,
1523 IN PGENERIC_MAPPING GenericMapping
)
1526 PSECURITY_DESCRIPTOR OldSecurityDescriptor
, CachedSecurityDescriptor
, NewSecurityDescriptor
;
1530 /* Keep attempting till we find our old SD or fail */
1533 KeEnterCriticalRegion();
1534 ExAcquireResourceSharedLite(&IopSecurityResource
, TRUE
);
1536 /* Get our old SD and reference it */
1537 OldSecurityDescriptor
= DeviceObject
->SecurityDescriptor
;
1538 if (OldSecurityDescriptor
!= NULL
)
1540 ObReferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1543 ExReleaseResourceLite(&IopSecurityResource
);
1544 KeLeaveCriticalRegion();
1546 /* Set the SD information */
1547 NewSecurityDescriptor
= OldSecurityDescriptor
;
1548 Status
= SeSetSecurityDescriptorInfo(NULL
, SecurityInformation
,
1549 SecurityDescriptor
, &NewSecurityDescriptor
,
1550 PoolType
, GenericMapping
);
1552 if (!NT_SUCCESS(Status
))
1554 if (OldSecurityDescriptor
!= NULL
)
1556 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1562 /* Add the new DS to the internal cache */
1563 Status
= ObLogSecurityDescriptor(NewSecurityDescriptor
,
1564 &CachedSecurityDescriptor
, 1);
1565 ExFreePool(NewSecurityDescriptor
);
1566 if (!NT_SUCCESS(Status
))
1568 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1572 KeEnterCriticalRegion();
1573 ExAcquireResourceExclusiveLite(&IopSecurityResource
, TRUE
);
1574 /* Check if someone changed it in our back */
1575 if (DeviceObject
->SecurityDescriptor
== OldSecurityDescriptor
)
1577 /* We're clear, do the swap */
1578 DeviceObject
->SecurityDescriptor
= CachedSecurityDescriptor
;
1579 ExReleaseResourceLite(&IopSecurityResource
);
1580 KeLeaveCriticalRegion();
1582 /* And dereference old SD (twice - us + not in use) */
1583 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 2);
1587 ExReleaseResourceLite(&IopSecurityResource
);
1588 KeLeaveCriticalRegion();
1590 /* If so, try again */
1591 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1592 ObDereferenceSecurityDescriptor(CachedSecurityDescriptor
, 1);
1600 IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject
,
1601 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1602 IN PSECURITY_INFORMATION SecurityInformation
,
1603 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1604 IN POOL_TYPE PoolType
,
1605 IN PGENERIC_MAPPING GenericMapping
)
1607 PDEVICE_OBJECT CurrentDO
= PhysicalDeviceObject
, NextDevice
;
1608 NTSTATUS Status
= STATUS_SUCCESS
, TmpStatus
;
1612 ASSERT(PhysicalDeviceObject
!= NULL
);
1614 /* We always reference the DO we're working on */
1615 ObReferenceObject(CurrentDO
);
1617 /* Go up from PDO to latest DO */
1620 /* Attempt to set the new SD on it */
1621 TmpStatus
= IopSetDeviceSecurityDescriptor(CurrentDO
, SecurityInformation
,
1622 SecurityDescriptor
, PoolType
,
1624 /* Was our last one? Remember that status then */
1625 if (CurrentDO
== UpperDeviceObject
)
1630 /* Try to move to the next DO (and thus, reference it) */
1631 NextDevice
= CurrentDO
->AttachedDevice
;
1634 ObReferenceObject(NextDevice
);
1637 /* Dereference current DO and move to the next one */
1638 ObDereferenceObject(CurrentDO
);
1639 CurrentDO
= NextDevice
;
1641 while (CurrentDO
!= NULL
);
1648 IopGetSetSecurityObject(IN PVOID ObjectBody
,
1649 IN SECURITY_OPERATION_CODE OperationCode
,
1650 IN PSECURITY_INFORMATION SecurityInformation
,
1651 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1652 IN OUT PULONG BufferLength
,
1653 IN OUT PSECURITY_DESCRIPTOR
*OldSecurityDescriptor
,
1654 IN POOL_TYPE PoolType
,
1655 IN OUT PGENERIC_MAPPING GenericMapping
)
1657 IO_STATUS_BLOCK IoStatusBlock
;
1658 PIO_STACK_LOCATION StackPtr
;
1659 PFILE_OBJECT FileObject
;
1660 PDEVICE_OBJECT DeviceObject
;
1662 BOOLEAN LocalEvent
= FALSE
;
1664 NTSTATUS Status
= STATUS_SUCCESS
;
1666 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1668 /* Check if this is a device or file */
1669 if (((PFILE_OBJECT
)ObjectBody
)->Type
== IO_TYPE_DEVICE
)
1672 DeviceObject
= (PDEVICE_OBJECT
)ObjectBody
;
1678 FileObject
= (PFILE_OBJECT
)ObjectBody
;
1680 /* Check if this is a direct open */
1681 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1683 /* Get the Device Object */
1684 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1688 /* Otherwise, use the direct device*/
1689 DeviceObject
= FileObject
->DeviceObject
;
1693 /* Check if the request was for a device object */
1694 if (!(FileObject
) ||
1695 (!(FileObject
->FileName
.Length
) && !(FileObject
->RelatedFileObject
)) ||
1696 (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1698 /* Check what kind of request this was */
1699 if (OperationCode
== QuerySecurityDescriptor
)
1701 return SeQuerySecurityDescriptorInfo(SecurityInformation
,
1704 &DeviceObject
->SecurityDescriptor
);
1706 else if (OperationCode
== DeleteSecurityDescriptor
)
1708 /* Simply return success */
1709 return STATUS_SUCCESS
;
1711 else if (OperationCode
== AssignSecurityDescriptor
)
1713 Status
= STATUS_SUCCESS
;
1715 /* Make absolutely sure this is a device object */
1716 if (!(FileObject
) || !(FileObject
->Flags
& FO_STREAM_FILE
))
1718 PSECURITY_DESCRIPTOR CachedSecurityDescriptor
;
1720 /* Add the security descriptor in cache */
1721 Status
= ObLogSecurityDescriptor(SecurityDescriptor
, &CachedSecurityDescriptor
, 1);
1722 if (NT_SUCCESS(Status
))
1724 KeEnterCriticalRegion();
1725 ExAcquireResourceExclusiveLite(&IopSecurityResource
, TRUE
);
1727 /* Assign the Security Descriptor */
1728 DeviceObject
->SecurityDescriptor
= CachedSecurityDescriptor
;
1730 ExReleaseResourceLite(&IopSecurityResource
);
1731 KeLeaveCriticalRegion();
1738 else if (OperationCode
== SetSecurityDescriptor
)
1740 /* Get the Physical Device Object if any */
1741 PDEVICE_OBJECT PDO
= IopGetDevicePDO(DeviceObject
);
1745 /* Apply the new SD to any DO in the path from PDO to current DO */
1746 Status
= IopSetDeviceSecurityDescriptors(DeviceObject
, PDO
,
1747 SecurityInformation
,
1749 PoolType
, GenericMapping
);
1750 ObDereferenceObject(PDO
);
1754 /* Otherwise, just set for ourselves */
1755 Status
= IopSetDeviceSecurityDescriptor(DeviceObject
,
1756 SecurityInformation
,
1758 PoolType
, GenericMapping
);
1761 return STATUS_SUCCESS
;
1764 /* Shouldn't happen */
1765 return STATUS_SUCCESS
;
1767 else if (OperationCode
== DeleteSecurityDescriptor
)
1769 /* Same as for devices, do nothing */
1770 return STATUS_SUCCESS
;
1773 /* At this point, we know we're a file. Reference it */
1774 ObReferenceObject(FileObject
);
1776 /* Check if we should use Sync IO or not */
1777 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
1779 /* Lock the file object */
1780 Status
= IopLockFileObject(FileObject
, ExGetPreviousMode());
1781 if (Status
!= STATUS_SUCCESS
)
1783 ObDereferenceObject(FileObject
);
1789 /* Use local event */
1790 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1794 /* Clear the File Object event */
1795 KeClearEvent(&FileObject
->Event
);
1797 /* Get the device object */
1798 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1800 /* Allocate the IRP */
1801 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1802 if (!Irp
) return IopCleanupFailedIrp(FileObject
, NULL
, NULL
);
1805 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1806 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1807 Irp
->RequestorMode
= ExGetPreviousMode();
1808 Irp
->UserIosb
= &IoStatusBlock
;
1809 Irp
->UserEvent
= (LocalEvent
) ? &Event
: NULL
;
1810 Irp
->Flags
= (LocalEvent
) ? IRP_SYNCHRONOUS_API
: 0;
1811 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
1813 /* Set Stack Parameters */
1814 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1815 StackPtr
->FileObject
= FileObject
;
1817 /* Check if this is a query or set */
1818 if (OperationCode
== QuerySecurityDescriptor
)
1820 /* Set the major function and parameters */
1821 StackPtr
->MajorFunction
= IRP_MJ_QUERY_SECURITY
;
1822 StackPtr
->Parameters
.QuerySecurity
.SecurityInformation
=
1823 *SecurityInformation
;
1824 StackPtr
->Parameters
.QuerySecurity
.Length
= *BufferLength
;
1825 Irp
->UserBuffer
= SecurityDescriptor
;
1829 /* Set the major function and parameters for a set */
1830 StackPtr
->MajorFunction
= IRP_MJ_SET_SECURITY
;
1831 StackPtr
->Parameters
.SetSecurity
.SecurityInformation
=
1832 *SecurityInformation
;
1833 StackPtr
->Parameters
.SetSecurity
.SecurityDescriptor
=
1838 IopQueueIrpToThread(Irp
);
1840 /* Update operation counts */
1841 IopUpdateOperationCount(IopOtherTransfer
);
1843 /* Call the Driver */
1844 Status
= IoCallDriver(DeviceObject
, Irp
);
1846 /* Check if this was async I/O */
1849 /* Check if the IRP is pending completion */
1850 if (Status
== STATUS_PENDING
)
1852 /* Wait on the local event */
1853 KeWaitForSingleObject(&Event
,
1858 Status
= IoStatusBlock
.Status
;
1863 /* Check if the IRP is pending completion */
1864 if (Status
== STATUS_PENDING
)
1866 /* Wait on the file object */
1867 KeWaitForSingleObject(&FileObject
->Event
,
1872 Status
= FileObject
->FinalStatus
;
1875 /* Release the lock */
1876 IopUnlockFileObject(FileObject
);
1879 /* This Driver doesn't implement Security, so try to give it a default */
1880 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
1882 /* Was this a query? */
1883 if (OperationCode
== QuerySecurityDescriptor
)
1885 /* Set a World Security Descriptor */
1886 Status
= SeSetWorldSecurityDescriptor(*SecurityInformation
,
1892 /* It wasn't a query, so just fake success */
1893 Status
= STATUS_SUCCESS
;
1896 else if (OperationCode
== QuerySecurityDescriptor
)
1898 /* Callers usually expect the normalized form */
1899 if (Status
== STATUS_BUFFER_OVERFLOW
) Status
= STATUS_BUFFER_TOO_SMALL
;
1904 *BufferLength
= (ULONG
)IoStatusBlock
.Information
;
1906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1908 /* Get the exception code */
1909 Status
= _SEH2_GetExceptionCode();
1920 IopQueryName(IN PVOID ObjectBody
,
1922 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1924 OUT PULONG ReturnLength
,
1925 IN KPROCESSOR_MODE PreviousMode
)
1927 return IopQueryNameInternal(ObjectBody
,
1938 IopQueryNameInternal(IN PVOID ObjectBody
,
1940 IN BOOLEAN QueryDosName
,
1941 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1943 OUT PULONG ReturnLength
,
1944 IN KPROCESSOR_MODE PreviousMode
)
1946 POBJECT_NAME_INFORMATION LocalInfo
;
1947 PFILE_NAME_INFORMATION LocalFileInfo
;
1948 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1949 ULONG LocalReturnLength
, FileLength
;
1950 BOOLEAN LengthMismatch
= FALSE
;
1953 PDEVICE_OBJECT DeviceObject
;
1956 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1958 /* Validate length */
1959 if (Length
< sizeof(OBJECT_NAME_INFORMATION
))
1961 /* Wrong length, fail */
1962 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1963 return STATUS_INFO_LENGTH_MISMATCH
;
1966 /* Allocate Buffer */
1967 LocalInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_IO
);
1968 if (!LocalInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
1970 /* Query DOS name if the caller asked to */
1974 DeviceObject
= FileObject
->DeviceObject
;
1976 /* In case of a network file system, don't call mountmgr */
1977 if (DeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
)
1979 /* We'll store separator and terminator */
1980 LocalReturnLength
= sizeof(OBJECT_NAME_INFORMATION
) + 2 * sizeof(WCHAR
);
1981 if (Length
< LocalReturnLength
)
1983 Status
= STATUS_BUFFER_OVERFLOW
;
1987 LocalInfo
->Name
.Length
= sizeof(WCHAR
);
1988 LocalInfo
->Name
.MaximumLength
= sizeof(WCHAR
);
1989 LocalInfo
->Name
.Buffer
= (PVOID
)((ULONG_PTR
)LocalInfo
+ sizeof(OBJECT_NAME_INFORMATION
));
1990 LocalInfo
->Name
.Buffer
[0] = OBJ_NAME_PATH_SEPARATOR
;
1991 Status
= STATUS_SUCCESS
;
1994 /* Otherwise, call mountmgr to get DOS name */
1997 Status
= IoVolumeDeviceToDosName(DeviceObject
, &LocalInfo
->Name
);
1998 LocalReturnLength
= LocalInfo
->Name
.Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
2002 /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
2003 if (!QueryDosName
|| !NT_SUCCESS(Status
))
2005 /* Query the name */
2006 Status
= ObQueryNameString(FileObject
->DeviceObject
,
2009 &LocalReturnLength
);
2016 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_INFO_LENGTH_MISMATCH
))
2018 /* Free the buffer and fail */
2019 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
2023 /* Get buffer pointer */
2024 p
= (PWCHAR
)(ObjectNameInfo
+ 1);
2028 /* Copy the information */
2029 if (QueryDosName
&& NoObCall
)
2031 ASSERT(PreviousMode
== KernelMode
);
2033 /* Copy structure first */
2034 RtlCopyMemory(ObjectNameInfo
,
2036 (Length
>= LocalReturnLength
? sizeof(OBJECT_NAME_INFORMATION
) : Length
));
2038 RtlCopyMemory(p
, LocalInfo
->Name
.Buffer
,
2039 (Length
>= LocalReturnLength
? LocalInfo
->Name
.Length
: Length
- sizeof(OBJECT_NAME_INFORMATION
)));
2041 if (FileObject
->DeviceObject
->DeviceType
!= FILE_DEVICE_NETWORK_FILE_SYSTEM
)
2043 ExFreePool(LocalInfo
->Name
.Buffer
);
2048 RtlCopyMemory(ObjectNameInfo
,
2050 (LocalReturnLength
> Length
) ?
2051 Length
: LocalReturnLength
);
2054 /* Set buffer pointer */
2055 ObjectNameInfo
->Name
.Buffer
= p
;
2057 /* Advance in buffer */
2058 p
+= (LocalInfo
->Name
.Length
/ sizeof(WCHAR
));
2060 /* Check if this already filled our buffer */
2061 if (LocalReturnLength
> Length
)
2063 /* Set the length mismatch to true, so that we can return
2064 * the proper buffer size to the caller later
2066 LengthMismatch
= TRUE
;
2068 /* Save the initial buffer length value */
2069 *ReturnLength
= LocalReturnLength
;
2072 /* Now get the file name buffer and check the length needed */
2073 LocalFileInfo
= (PFILE_NAME_INFORMATION
)LocalInfo
;
2074 FileLength
= Length
-
2076 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2078 /* Query the File name */
2079 if (PreviousMode
== KernelMode
&&
2080 BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2082 Status
= IopGetFileInformation(FileObject
,
2083 LengthMismatch
? Length
: FileLength
,
2084 FileNameInformation
,
2086 &LocalReturnLength
);
2090 Status
= IoQueryFileInformation(FileObject
,
2091 FileNameInformation
,
2092 LengthMismatch
? Length
: FileLength
,
2094 &LocalReturnLength
);
2096 if (NT_ERROR(Status
))
2098 /* Allow status that would mean it's not implemented in the storage stack */
2099 if (Status
!= STATUS_INVALID_PARAMETER
&& Status
!= STATUS_INVALID_DEVICE_REQUEST
&&
2100 Status
!= STATUS_NOT_IMPLEMENTED
&& Status
!= STATUS_INVALID_INFO_CLASS
)
2105 /* In such case, zero output */
2106 LocalReturnLength
= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2107 LocalFileInfo
->FileNameLength
= 0;
2108 LocalFileInfo
->FileName
[0] = OBJ_NAME_PATH_SEPARATOR
;
2112 /* We'll at least return the name length */
2113 if (LocalReturnLength
< FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
))
2115 LocalReturnLength
= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2119 /* If the provided buffer is too small, return the required size */
2122 /* Add the required length */
2123 *ReturnLength
+= LocalFileInfo
->FileNameLength
;
2125 /* Free the allocated buffer and return failure */
2126 Status
= STATUS_BUFFER_OVERFLOW
;
2130 /* Now calculate the new lengths left */
2131 FileLength
= LocalReturnLength
-
2132 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2133 LocalReturnLength
= (ULONG
)((ULONG_PTR
)p
-
2134 (ULONG_PTR
)ObjectNameInfo
+
2135 LocalFileInfo
->FileNameLength
);
2137 /* Don't copy the name if it's not valid */
2138 if (LocalFileInfo
->FileName
[0] != OBJ_NAME_PATH_SEPARATOR
)
2140 /* Free the allocated buffer and return failure */
2141 Status
= STATUS_OBJECT_PATH_INVALID
;
2145 /* Write the Name and null-terminate it */
2146 RtlCopyMemory(p
, LocalFileInfo
->FileName
, FileLength
);
2147 p
+= (FileLength
/ sizeof(WCHAR
));
2149 LocalReturnLength
+= sizeof(UNICODE_NULL
);
2151 /* Return the length needed */
2152 *ReturnLength
= LocalReturnLength
;
2154 /* Setup the length and maximum length */
2155 FileLength
= (ULONG
)((ULONG_PTR
)p
- (ULONG_PTR
)ObjectNameInfo
);
2156 ObjectNameInfo
->Name
.Length
= (USHORT
)FileLength
-
2157 sizeof(OBJECT_NAME_INFORMATION
);
2158 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)ObjectNameInfo
->Name
.Length
+
2159 sizeof(UNICODE_NULL
);
2163 /* Free buffer and return */
2164 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
2172 IopCloseFile(IN PEPROCESS Process OPTIONAL
,
2173 IN PVOID ObjectBody
,
2174 IN ACCESS_MASK GrantedAccess
,
2175 IN ULONG HandleCount
,
2176 IN ULONG SystemHandleCount
)
2178 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
2181 PIO_STACK_LOCATION StackPtr
;
2183 PDEVICE_OBJECT DeviceObject
;
2185 IO_STATUS_BLOCK IoStatusBlock
;
2186 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
2188 /* If this isn't the last handle for the current process, quit */
2189 if (HandleCount
!= 1) return;
2191 /* Check if the file is locked and has more then one handle opened */
2192 if ((FileObject
->LockOperation
) && (SystemHandleCount
!= 1))
2194 /* Check if this is a direct open or not */
2195 if (BooleanFlagOn(FileObject
->Flags
, FO_DIRECT_DEVICE_OPEN
))
2197 /* Get the attached device */
2198 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
2202 /* Get the FO's device */
2203 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
2206 /* Check if this is a sync FO and lock it */
2207 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2209 (VOID
)IopLockFileObject(FileObject
, KernelMode
);
2212 /* Go the FastIO path if possible, otherwise fall back to IRP */
2213 if (DeviceObject
->DriverObject
->FastIoDispatch
== NULL
||
2214 DeviceObject
->DriverObject
->FastIoDispatch
->FastIoUnlockAll
== NULL
||
2215 !DeviceObject
->DriverObject
->FastIoDispatch
->FastIoUnlockAll(FileObject
, PsGetCurrentProcess(), &IoStatusBlock
, DeviceObject
))
2217 /* Clear and set up Events */
2218 KeClearEvent(&FileObject
->Event
);
2219 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
2221 /* Allocate an IRP */
2222 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
2225 Irp
->UserEvent
= &Event
;
2226 Irp
->UserIosb
= &Irp
->IoStatus
;
2227 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
2228 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
2229 Irp
->RequestorMode
= KernelMode
;
2230 Irp
->Flags
= IRP_SYNCHRONOUS_API
;
2231 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
2232 ObReferenceObject(FileObject
);
2234 /* Set up Stack Pointer Data */
2235 StackPtr
= IoGetNextIrpStackLocation(Irp
);
2236 StackPtr
->MajorFunction
= IRP_MJ_LOCK_CONTROL
;
2237 StackPtr
->MinorFunction
= IRP_MN_UNLOCK_ALL
;
2238 StackPtr
->FileObject
= FileObject
;
2241 IopQueueIrpToThread(Irp
);
2243 /* Call the FS Driver */
2244 Status
= IoCallDriver(DeviceObject
, Irp
);
2245 if (Status
== STATUS_PENDING
)
2247 /* Wait for completion */
2248 KeWaitForSingleObject(&Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
2251 /* IO will unqueue & free for us */
2254 /* Release the lock if we were holding it */
2255 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2257 IopUnlockFileObject(FileObject
);
2261 /* Make sure this is the last handle */
2262 if (SystemHandleCount
!= 1) return;
2264 /* Check if this is a direct open or not */
2265 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
2267 /* Get the attached device */
2268 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
2272 /* Get the FO's device */
2273 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
2276 /* Set the handle created flag */
2277 FileObject
->Flags
|= FO_HANDLE_CREATED
;
2279 /* Check if this is a sync FO and lock it */
2280 if (Process
!= NULL
&&
2281 BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2283 (VOID
)IopLockFileObject(FileObject
, KernelMode
);
2286 /* Clear and set up Events */
2287 KeClearEvent(&FileObject
->Event
);
2288 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
2290 /* Allocate an IRP */
2291 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
2294 Irp
->UserEvent
= &Event
;
2295 Irp
->UserIosb
= &Irp
->IoStatus
;
2296 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
2297 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
2298 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
2299 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
2301 /* Set up Stack Pointer Data */
2302 StackPtr
= IoGetNextIrpStackLocation(Irp
);
2303 StackPtr
->MajorFunction
= IRP_MJ_CLEANUP
;
2304 StackPtr
->FileObject
= FileObject
;
2307 IopQueueIrpToThread(Irp
);
2309 /* Update operation counts */
2310 IopUpdateOperationCount(IopOtherTransfer
);
2312 /* Call the FS Driver */
2313 Status
= IoCallDriver(DeviceObject
, Irp
);
2314 if (Status
== STATUS_PENDING
)
2316 /* Wait for completion */
2317 KeWaitForSingleObject(&Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
2320 /* Unqueue the IRP */
2321 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2322 IopUnQueueIrpFromThread(Irp
);
2323 KeLowerIrql(OldIrql
);
2328 /* Release the lock if we were holding it */
2329 if (Process
!= NULL
&&
2330 BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2332 IopUnlockFileObject(FileObject
);
2338 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2339 IN FILE_INFORMATION_CLASS FileInformationClass
,
2340 IN ULONG FileInformationSize
,
2341 OUT PVOID FileInformation
)
2344 KPROCESSOR_MODE AccessMode
= ExGetPreviousMode();
2345 DUMMY_FILE_OBJECT LocalFileObject
;
2346 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo
;
2348 OPEN_PACKET OpenPacket
;
2351 IOTRACE(IO_FILE_DEBUG
, "Class: %lx\n", FileInformationClass
);
2353 /* Check if the caller was user mode */
2354 if (AccessMode
!= KernelMode
)
2356 /* Protect probe in SEH */
2359 /* Probe the buffer */
2360 ProbeForWrite(FileInformation
, FileInformationSize
, sizeof(ULONG
));
2362 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2364 /* Return the exception code */
2365 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2370 /* Check if this is a basic or full request */
2371 IsBasic
= (FileInformationSize
== sizeof(FILE_BASIC_INFORMATION
));
2373 /* Setup the Open Packet */
2374 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
2375 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
2376 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
2377 OpenPacket
.CreateOptions
= FILE_OPEN_REPARSE_POINT
;
2378 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2379 OpenPacket
.Disposition
= FILE_OPEN
;
2380 OpenPacket
.BasicInformation
= IsBasic
? FileInformation
: NULL
;
2381 OpenPacket
.NetworkInformation
= IsBasic
? &NetworkOpenInfo
:
2382 (AccessMode
!= KernelMode
) ?
2383 &NetworkOpenInfo
: FileInformation
;
2384 OpenPacket
.QueryOnly
= TRUE
;
2385 OpenPacket
.FullAttributes
= IsBasic
? FALSE
: TRUE
;
2386 OpenPacket
.LocalFileObject
= &LocalFileObject
;
2388 /* Update the operation count */
2389 IopUpdateOperationCount(IopOtherTransfer
);
2392 * Attempt opening the file. This will call the I/O Parse Routine for
2393 * the File Object (IopParseDevice) which will use the dummy file obejct
2394 * send the IRP to its device object. Note that we have two statuses
2395 * to worry about: the Object Manager's status (in Status) and the I/O
2396 * status, which is in the Open Packet's Final Status, and determined
2397 * by the Parse Check member.
2399 Status
= ObOpenObjectByName(ObjectAttributes
,
2403 FILE_READ_ATTRIBUTES
,
2406 if (OpenPacket
.ParseCheck
== FALSE
)
2409 DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2410 ObjectAttributes
->ObjectName
, Status
);
2415 /* Use the Io status */
2416 Status
= OpenPacket
.FinalStatus
;
2419 /* Check if we were succesful and this was user mode and a full query */
2420 if ((NT_SUCCESS(Status
)) && (AccessMode
!= KernelMode
) && !(IsBasic
))
2422 /* Enter SEH for copy */
2425 /* Copy the buffer back */
2426 RtlCopyMemory(FileInformation
,
2428 FileInformationSize
);
2430 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2432 /* Get exception code */
2433 Status
= _SEH2_GetExceptionCode();
2444 IopAcquireFileObjectLock(
2445 _In_ PFILE_OBJECT FileObject
,
2446 _In_ KPROCESSOR_MODE WaitMode
,
2447 _In_ BOOLEAN Alertable
,
2448 _Out_ PBOOLEAN LockFailed
)
2454 InterlockedIncrement((PLONG
)&FileObject
->Waiters
);
2456 Status
= STATUS_SUCCESS
;
2459 if (!InterlockedExchange((PLONG
)&FileObject
->Busy
, TRUE
))
2463 Status
= KeWaitForSingleObject(&FileObject
->Lock
,
2468 } while (Status
== STATUS_SUCCESS
);
2470 InterlockedDecrement((PLONG
)&FileObject
->Waiters
);
2471 if (Status
== STATUS_SUCCESS
)
2473 ObReferenceObject(FileObject
);
2474 *LockFailed
= FALSE
;
2478 if (!FileObject
->Busy
&& FileObject
->Waiters
)
2480 KeSetEvent(&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2490 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject
)
2492 if (BooleanFlagOn(FileObject
->Flags
, FO_FILE_OBJECT_HAS_EXTENSION
))
2494 PFILE_OBJECT_EXTENSION FileObjectExtension
;
2496 FileObjectExtension
= FileObject
->FileObjectExtension
;
2497 return FileObjectExtension
->FilterContext
;
2505 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject
,
2506 IN PVOID FilterContext
,
2510 PFILE_OBJECT_EXTENSION FileObjectExtension
;
2512 if (!BooleanFlagOn(FileObject
->Flags
, FO_FILE_OBJECT_HAS_EXTENSION
))
2514 return STATUS_INVALID_PARAMETER
;
2517 FileObjectExtension
= FileObject
->FileObjectExtension
;
2520 /* If define, just set the new value if not value is set
2521 * Success will only contain old value. It is valid if it is NULL
2523 Success
= (ULONG_PTR
)InterlockedCompareExchangePointer(&FileObjectExtension
->FilterContext
, FilterContext
, NULL
);
2527 /* If not define, we want to reset filter context.
2528 * We will remove value (provided by the caller) and set NULL instead.
2529 * This will only success if caller provides correct previous value.
2530 * To catch whether it worked, we substract previous value to expect value:
2531 * If it matches (and thus, we reset), Success will contain 0
2532 * Otherwise, it will contain a non-zero value.
2534 Success
= (ULONG_PTR
)InterlockedCompareExchangePointer(&FileObjectExtension
->FilterContext
, NULL
, FilterContext
) - (ULONG_PTR
)FilterContext
;
2537 /* If success isn't 0, it means we failed somewhere (set or unset) */
2540 return STATUS_ALREADY_COMMITTED
;
2543 return STATUS_SUCCESS
;
2548 IopCreateFile(OUT PHANDLE FileHandle
,
2549 IN ACCESS_MASK DesiredAccess
,
2550 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2551 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2552 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
2553 IN ULONG FileAttributes
,
2554 IN ULONG ShareAccess
,
2555 IN ULONG Disposition
,
2556 IN ULONG CreateOptions
,
2557 IN PVOID EaBuffer OPTIONAL
,
2559 IN CREATE_FILE_TYPE CreateFileType
,
2560 IN PVOID ExtraCreateParameters OPTIONAL
,
2563 IN PDEVICE_OBJECT DeviceObject OPTIONAL
)
2565 KPROCESSOR_MODE AccessMode
;
2566 HANDLE LocalHandle
= 0;
2567 LARGE_INTEGER SafeAllocationSize
;
2568 NTSTATUS Status
= STATUS_SUCCESS
;
2569 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters
;
2570 POPEN_PACKET OpenPacket
;
2571 ULONG EaErrorOffset
;
2574 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
2577 /* Check if we have no parameter checking to do */
2578 if (Options
& IO_NO_PARAMETER_CHECKING
)
2580 /* Then force kernel-mode access to avoid checks */
2581 AccessMode
= KernelMode
;
2585 /* Otherwise, use the actual mode */
2586 AccessMode
= ExGetPreviousMode();
2589 /* Check if we need to do parameter checking */
2590 if ((AccessMode
!= KernelMode
) || (Options
& IO_CHECK_CREATE_PARAMETERS
))
2592 /* Validate parameters */
2593 if (FileAttributes
& ~FILE_ATTRIBUTE_VALID_FLAGS
)
2595 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2596 return STATUS_INVALID_PARAMETER
;
2599 if (ShareAccess
& ~FILE_SHARE_VALID_FLAGS
)
2601 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2602 return STATUS_INVALID_PARAMETER
;
2605 if (Disposition
> FILE_MAXIMUM_DISPOSITION
)
2607 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2608 return STATUS_INVALID_PARAMETER
;
2611 if (CreateOptions
& ~FILE_VALID_OPTION_FLAGS
)
2613 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2614 return STATUS_INVALID_PARAMETER
;
2617 if ((CreateOptions
& (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
)) &&
2618 (!(DesiredAccess
& SYNCHRONIZE
)))
2620 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2621 return STATUS_INVALID_PARAMETER
;
2624 if ((CreateOptions
& FILE_DELETE_ON_CLOSE
) && (!(DesiredAccess
& DELETE
)))
2626 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2627 return STATUS_INVALID_PARAMETER
;
2630 if ((CreateOptions
& (FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SYNCHRONOUS_IO_ALERT
)) ==
2631 (FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SYNCHRONOUS_IO_ALERT
))
2633 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2634 return STATUS_INVALID_PARAMETER
;
2637 if ((CreateOptions
& FILE_DIRECTORY_FILE
) && !(CreateOptions
& FILE_NON_DIRECTORY_FILE
) &&
2638 (CreateOptions
& ~(FILE_DIRECTORY_FILE
|
2639 FILE_SYNCHRONOUS_IO_ALERT
|
2640 FILE_SYNCHRONOUS_IO_NONALERT
|
2641 FILE_WRITE_THROUGH
|
2642 FILE_COMPLETE_IF_OPLOCKED
|
2643 FILE_OPEN_FOR_BACKUP_INTENT
|
2644 FILE_DELETE_ON_CLOSE
|
2645 FILE_OPEN_FOR_FREE_SPACE_QUERY
|
2646 FILE_OPEN_BY_FILE_ID
|
2647 FILE_NO_COMPRESSION
|
2648 FILE_OPEN_REPARSE_POINT
)))
2650 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2651 return STATUS_INVALID_PARAMETER
;
2654 if ((CreateOptions
& FILE_DIRECTORY_FILE
) && !(CreateOptions
& FILE_NON_DIRECTORY_FILE
) &&
2655 (Disposition
!= FILE_CREATE
) && (Disposition
!= FILE_OPEN
) && (Disposition
!= FILE_OPEN_IF
))
2657 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2658 return STATUS_INVALID_PARAMETER
;
2661 if ((CreateOptions
& FILE_COMPLETE_IF_OPLOCKED
) && (CreateOptions
& FILE_RESERVE_OPFILTER
))
2663 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2664 return STATUS_INVALID_PARAMETER
;
2667 if ((CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
) && (DesiredAccess
& FILE_APPEND_DATA
))
2669 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2670 return STATUS_INVALID_PARAMETER
;
2673 /* Now check if this is a named pipe */
2674 if (CreateFileType
== CreateFileTypeNamedPipe
)
2676 /* Make sure we have extra parameters */
2677 if (!ExtraCreateParameters
)
2679 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2680 return STATUS_INVALID_PARAMETER
;
2683 /* Get the parameters and validate them */
2684 NamedPipeCreateParameters
= ExtraCreateParameters
;
2685 if ((NamedPipeCreateParameters
->NamedPipeType
> FILE_PIPE_MESSAGE_TYPE
) ||
2686 (NamedPipeCreateParameters
->ReadMode
> FILE_PIPE_MESSAGE_MODE
) ||
2687 (NamedPipeCreateParameters
->CompletionMode
> FILE_PIPE_COMPLETE_OPERATION
) ||
2688 (ShareAccess
& FILE_SHARE_DELETE
) ||
2689 ((Disposition
< FILE_OPEN
) || (Disposition
> FILE_OPEN_IF
)) ||
2690 (CreateOptions
& ~FILE_VALID_PIPE_OPTION_FLAGS
))
2692 /* Invalid named pipe create */
2693 DPRINT1("Invalid named pipe create\n");
2694 return STATUS_INVALID_PARAMETER
;
2697 else if (CreateFileType
== CreateFileTypeMailslot
)
2699 /* Make sure we have extra parameters */
2700 if (!ExtraCreateParameters
)
2702 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2703 return STATUS_INVALID_PARAMETER
;
2706 /* Get the parameters and validate them */
2707 if ((ShareAccess
& FILE_SHARE_DELETE
) ||
2708 !(ShareAccess
& ~FILE_SHARE_WRITE
) ||
2709 (Disposition
!= FILE_CREATE
) ||
2710 (CreateOptions
& ~FILE_VALID_MAILSLOT_OPTION_FLAGS
))
2712 /* Invalid mailslot create */
2713 DPRINT1("Invalid mailslot create\n");
2714 return STATUS_INVALID_PARAMETER
;
2719 /* Allocate the open packet */
2720 OpenPacket
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*OpenPacket
), 'pOoI');
2721 if (!OpenPacket
) return STATUS_INSUFFICIENT_RESOURCES
;
2722 RtlZeroMemory(OpenPacket
, sizeof(*OpenPacket
));
2724 /* Check if the call came from user mode */
2725 if (AccessMode
!= KernelMode
)
2729 /* Probe the output parameters */
2730 ProbeForWriteHandle(FileHandle
);
2731 ProbeForWriteIoStatusBlock(IoStatusBlock
);
2733 /* Probe the allocation size if one was passed in */
2736 SafeAllocationSize
= ProbeForReadLargeInteger(AllocationSize
);
2740 SafeAllocationSize
.QuadPart
= 0;
2743 /* Make sure it's valid */
2744 if (SafeAllocationSize
.QuadPart
< 0)
2746 RtlRaiseStatus(STATUS_INVALID_PARAMETER
);
2749 /* Check if EA was passed in */
2750 if ((EaBuffer
) && (EaLength
))
2753 ProbeForRead(EaBuffer
, EaLength
, sizeof(ULONG
));
2755 /* And marshall it */
2756 OpenPacket
->EaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
2759 OpenPacket
->EaLength
= EaLength
;
2760 RtlCopyMemory(OpenPacket
->EaBuffer
, EaBuffer
, EaLength
);
2762 /* Validate the buffer */
2763 Status
= IoCheckEaBufferValidity(OpenPacket
->EaBuffer
,
2766 if (!NT_SUCCESS(Status
))
2768 /* Undo everything if it's invalid */
2769 DPRINT1("Invalid EA buffer\n");
2770 IoStatusBlock
->Status
= Status
;
2771 IoStatusBlock
->Information
= EaErrorOffset
;
2772 RtlRaiseStatus(Status
);
2776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2778 /* Return the exception code */
2779 if (OpenPacket
->EaBuffer
!= NULL
) ExFreePool(OpenPacket
->EaBuffer
);
2780 ExFreePool(OpenPacket
);
2781 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2787 /* Check if this is a device attach */
2788 if (CreateOptions
& IO_ATTACH_DEVICE_API
)
2790 /* Set the flag properly */
2791 Options
|= IO_ATTACH_DEVICE
;
2792 CreateOptions
&= ~IO_ATTACH_DEVICE_API
;
2795 /* Check if we have allocation size */
2799 SafeAllocationSize
= *AllocationSize
;
2803 /* Otherwise, no size */
2804 SafeAllocationSize
.QuadPart
= 0;
2807 /* Check if we have an EA packet */
2808 if ((EaBuffer
) && (EaLength
))
2810 /* Allocate the kernel copy */
2811 OpenPacket
->EaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
2814 if (!OpenPacket
->EaBuffer
)
2816 ExFreePool(OpenPacket
);
2817 DPRINT1("Failed to allocate open packet EA buffer\n");
2818 return STATUS_INSUFFICIENT_RESOURCES
;
2822 OpenPacket
->EaLength
= EaLength
;
2823 RtlCopyMemory(OpenPacket
->EaBuffer
, EaBuffer
, EaLength
);
2825 /* Validate the buffer */
2826 Status
= IoCheckEaBufferValidity(OpenPacket
->EaBuffer
,
2829 if (!NT_SUCCESS(Status
))
2831 /* Undo everything if it's invalid */
2832 DPRINT1("Invalid EA buffer\n");
2833 ExFreePool(OpenPacket
->EaBuffer
);
2834 IoStatusBlock
->Status
= Status
;
2835 IoStatusBlock
->Information
= EaErrorOffset
;
2836 ExFreePool(OpenPacket
);
2842 /* Setup the Open Packet */
2843 OpenPacket
->Type
= IO_TYPE_OPEN_PACKET
;
2844 OpenPacket
->Size
= sizeof(*OpenPacket
);
2845 OpenPacket
->AllocationSize
= SafeAllocationSize
;
2846 OpenPacket
->CreateOptions
= CreateOptions
;
2847 OpenPacket
->FileAttributes
= (USHORT
)FileAttributes
;
2848 OpenPacket
->ShareAccess
= (USHORT
)ShareAccess
;
2849 OpenPacket
->Options
= Options
;
2850 OpenPacket
->Disposition
= Disposition
;
2851 OpenPacket
->CreateFileType
= CreateFileType
;
2852 OpenPacket
->ExtraCreateParameters
= ExtraCreateParameters
;
2853 OpenPacket
->InternalFlags
= Flags
;
2854 OpenPacket
->TopDeviceObjectHint
= DeviceObject
;
2856 /* Update the operation count */
2857 IopUpdateOperationCount(IopOtherTransfer
);
2860 * Attempt opening the file. This will call the I/O Parse Routine for
2861 * the File Object (IopParseDevice) which will create the object and
2862 * send the IRP to its device object. Note that we have two statuses
2863 * to worry about: the Object Manager's status (in Status) and the I/O
2864 * status, which is in the Open Packet's Final Status, and determined
2865 * by the Parse Check member.
2867 Status
= ObOpenObjectByName(ObjectAttributes
,
2875 /* Free the EA Buffer */
2876 if (OpenPacket
->EaBuffer
) ExFreePool(OpenPacket
->EaBuffer
);
2878 /* Now check for Ob or Io failure */
2879 if (!(NT_SUCCESS(Status
)) || (OpenPacket
->ParseCheck
== FALSE
))
2881 /* Check if Ob thinks well went well */
2882 if (NT_SUCCESS(Status
))
2885 * Tell it otherwise. Because we didn't use an ObjectType,
2886 * it incorrectly returned us a handle to God knows what.
2888 ZwClose(LocalHandle
);
2889 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
2892 /* Now check the Io status */
2893 if (!NT_SUCCESS(OpenPacket
->FinalStatus
))
2895 /* Use this status instead of Ob's */
2896 Status
= OpenPacket
->FinalStatus
;
2898 /* Check if it was only a warning */
2899 if (NT_WARNING(Status
))
2901 /* Protect write with SEH */
2904 /* In this case, we copy the I/O Status back */
2905 IoStatusBlock
->Information
= OpenPacket
->Information
;
2906 IoStatusBlock
->Status
= OpenPacket
->FinalStatus
;
2908 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2910 /* Get exception code */
2911 Status
= _SEH2_GetExceptionCode();
2916 else if ((OpenPacket
->FileObject
) && (OpenPacket
->ParseCheck
== FALSE
))
2919 * This can happen in the very bizarre case where the parse routine
2920 * actually executed more then once (due to a reparse) and ended
2921 * up failing after already having created the File Object.
2923 if (OpenPacket
->FileObject
->FileName
.Length
)
2925 /* It had a name, free it */
2926 ExFreePoolWithTag(OpenPacket
->FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
2929 /* Clear the device object to invalidate the FO, and dereference */
2930 OpenPacket
->FileObject
->DeviceObject
= NULL
;
2931 ObDereferenceObject(OpenPacket
->FileObject
);
2936 /* We reached success and have a valid file handle */
2937 OpenPacket
->FileObject
->Flags
|= FO_HANDLE_CREATED
;
2938 ASSERT(OpenPacket
->FileObject
->Type
== IO_TYPE_FILE
);
2940 /* Enter SEH for write back */
2943 /* Write back the handle and I/O Status */
2944 *FileHandle
= LocalHandle
;
2945 IoStatusBlock
->Information
= OpenPacket
->Information
;
2946 IoStatusBlock
->Status
= OpenPacket
->FinalStatus
;
2948 /* Get the Io status */
2949 Status
= OpenPacket
->FinalStatus
;
2951 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2953 /* Get the exception status */
2954 Status
= _SEH2_GetExceptionCode();
2959 /* Check if we were 100% successful */
2960 if ((OpenPacket
->ParseCheck
!= FALSE
) && (OpenPacket
->FileObject
))
2962 /* Dereference the File Object */
2963 ObDereferenceObject(OpenPacket
->FileObject
);
2967 ExFreePool(OpenPacket
);
2971 /* FUNCTIONS *****************************************************************/
2978 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass
,
2980 IN BOOLEAN SetOperation
)
2983 return STATUS_NOT_IMPLEMENTED
;
2991 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer
,
2992 IN ULONG QuotaLength
,
2993 OUT PULONG ErrorOffset
)
2996 return STATUS_NOT_IMPLEMENTED
;
3004 IoCreateFile(OUT PHANDLE FileHandle
,
3005 IN ACCESS_MASK DesiredAccess
,
3006 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3007 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3008 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
3009 IN ULONG FileAttributes
,
3010 IN ULONG ShareAccess
,
3011 IN ULONG Disposition
,
3012 IN ULONG CreateOptions
,
3013 IN PVOID EaBuffer OPTIONAL
,
3015 IN CREATE_FILE_TYPE CreateFileType
,
3016 IN PVOID ExtraCreateParameters OPTIONAL
,
3021 return IopCreateFile(FileHandle
,
3033 ExtraCreateParameters
,
3044 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle
,
3045 IN ACCESS_MASK DesiredAccess
,
3046 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3047 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3048 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
3049 IN ULONG FileAttributes
,
3050 IN ULONG ShareAccess
,
3051 IN ULONG Disposition
,
3052 IN ULONG CreateOptions
,
3053 IN PVOID EaBuffer OPTIONAL
,
3055 IN CREATE_FILE_TYPE CreateFileType
,
3056 IN PVOID ExtraCreateParameters OPTIONAL
,
3058 IN PVOID DeviceObject
)
3064 /* Check if we were passed a device to send the create request to*/
3067 /* We'll tag this request into a file object extension */
3068 Flags
= (IOP_CREATE_FILE_OBJECT_EXTENSION
| IOP_USE_TOP_LEVEL_DEVICE_HINT
);
3071 return IopCreateFile(FileHandle
,
3083 ExtraCreateParameters
,
3084 Options
| IO_NO_PARAMETER_CHECKING
,
3094 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL
,
3095 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
3096 OUT PHANDLE FileObjectHandle OPTIONAL
)
3098 PFILE_OBJECT CreatedFileObject
;
3101 OBJECT_ATTRIBUTES ObjectAttributes
;
3103 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
3105 /* Choose Device Object */
3106 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
3108 /* Reference the device object and initialize attributes */
3109 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
3110 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
3112 /* Create the File Object */
3113 Status
= ObCreateObject(KernelMode
,
3118 sizeof(FILE_OBJECT
),
3119 sizeof(FILE_OBJECT
),
3121 (PVOID
*)&CreatedFileObject
);
3122 if (!NT_SUCCESS(Status
))
3125 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
3126 ExRaiseStatus(Status
);
3129 /* Set File Object Data */
3130 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
3131 CreatedFileObject
->DeviceObject
= DeviceObject
;
3132 CreatedFileObject
->Type
= IO_TYPE_FILE
;
3133 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
3134 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
3136 /* Initialize the wait event */
3137 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
3139 /* Insert it to create a handle for it */
3140 Status
= ObInsertObject(CreatedFileObject
,
3144 (PVOID
*)&CreatedFileObject
,
3146 if (!NT_SUCCESS(Status
)) ExRaiseStatus(Status
);
3148 /* Set the handle created flag */
3149 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
3150 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
3152 /* Check if we have a VPB */
3153 if (DeviceObject
->Vpb
)
3156 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
3159 /* Check if the caller wants the handle */
3160 if (FileObjectHandle
)
3163 *FileObjectHandle
= FileHandle
;
3164 ObDereferenceObject(CreatedFileObject
);
3168 /* Otherwise, close it */
3169 ObCloseHandle(FileHandle
, KernelMode
);
3172 /* Return the file object */
3173 return CreatedFileObject
;
3181 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject
,
3182 IN PDEVICE_OBJECT DeviceObject
)
3184 /* Call the newer function */
3185 return IoCreateStreamFileObjectEx(FileObject
, DeviceObject
, NULL
);
3193 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL
,
3194 IN PDEVICE_OBJECT DeviceObject OPTIONAL
)
3196 PFILE_OBJECT CreatedFileObject
;
3198 OBJECT_ATTRIBUTES ObjectAttributes
;
3200 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
3202 /* Choose Device Object */
3203 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
3205 /* Reference the device object and initialize attributes */
3206 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
3207 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
3209 /* Create the File Object */
3210 Status
= ObCreateObject(KernelMode
,
3215 sizeof(FILE_OBJECT
),
3216 sizeof(FILE_OBJECT
),
3218 (PVOID
*)&CreatedFileObject
);
3219 if (!NT_SUCCESS(Status
))
3222 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
3223 ExRaiseStatus(Status
);
3226 /* Set File Object Data */
3227 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
3228 CreatedFileObject
->DeviceObject
= DeviceObject
;
3229 CreatedFileObject
->Type
= IO_TYPE_FILE
;
3230 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
3231 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
3233 /* Initialize the wait event */
3234 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
3236 /* Destroy create information */
3237 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->
3239 OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->ObjectCreateInfo
= NULL
;
3241 /* Set the handle created flag */
3242 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
3243 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
3245 /* Check if we have a VPB */
3246 if (DeviceObject
->Vpb
)
3249 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
3252 /* Return the file object */
3253 return CreatedFileObject
;
3261 IoGetFileObjectGenericMapping(VOID
)
3263 /* Return the mapping */
3264 return &IopFileMapping
;
3272 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject
)
3274 /* Return the flag status */
3275 return FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
3283 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes
,
3284 IN ACCESS_MASK DesiredAccess
,
3285 IN ULONG OpenOptions
,
3286 OUT PIO_STATUS_BLOCK IoStatus
,
3287 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer
)
3290 DUMMY_FILE_OBJECT LocalFileObject
;
3292 OPEN_PACKET OpenPacket
;
3294 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
3296 /* Setup the Open Packet */
3297 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
3298 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
3299 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
3300 OpenPacket
.CreateOptions
= OpenOptions
| FILE_OPEN_REPARSE_POINT
;
3301 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
3302 OpenPacket
.Options
= IO_FORCE_ACCESS_CHECK
;
3303 OpenPacket
.Disposition
= FILE_OPEN
;
3304 OpenPacket
.NetworkInformation
= Buffer
;
3305 OpenPacket
.QueryOnly
= TRUE
;
3306 OpenPacket
.FullAttributes
= TRUE
;
3307 OpenPacket
.LocalFileObject
= &LocalFileObject
;
3310 * Attempt opening the file. This will call the I/O Parse Routine for
3311 * the File Object (IopParseDevice) which will use the dummy file obejct
3312 * send the IRP to its device object. Note that we have two statuses
3313 * to worry about: the Object Manager's status (in Status) and the I/O
3314 * status, which is in the Open Packet's Final Status, and determined
3315 * by the Parse Check member.
3317 Status
= ObOpenObjectByName(ObjectAttributes
,
3324 if (OpenPacket
.ParseCheck
== FALSE
)
3327 IoStatus
->Status
= Status
;
3331 /* Use the Io status */
3332 IoStatus
->Status
= OpenPacket
.FinalStatus
;
3333 IoStatus
->Information
= OpenPacket
.Information
;
3336 /* Return success */
3345 IoUpdateShareAccess(IN PFILE_OBJECT FileObject
,
3346 OUT PSHARE_ACCESS ShareAccess
)
3350 /* Check if the file has an extension */
3351 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3353 /* Check if caller specified to ignore access checks */
3354 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3356 /* Don't update share access */
3361 /* Otherwise, check if there's any access present */
3362 if ((FileObject
->ReadAccess
) ||
3363 (FileObject
->WriteAccess
) ||
3364 (FileObject
->DeleteAccess
))
3366 /* Increase the open count */
3367 ShareAccess
->OpenCount
++;
3369 /* Add new share access */
3370 ShareAccess
->Readers
+= FileObject
->ReadAccess
;
3371 ShareAccess
->Writers
+= FileObject
->WriteAccess
;
3372 ShareAccess
->Deleters
+= FileObject
->DeleteAccess
;
3373 ShareAccess
->SharedRead
+= FileObject
->SharedRead
;
3374 ShareAccess
->SharedWrite
+= FileObject
->SharedWrite
;
3375 ShareAccess
->SharedDelete
+= FileObject
->SharedDelete
;
3384 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess
,
3385 IN ULONG DesiredShareAccess
,
3386 IN PFILE_OBJECT FileObject
,
3387 IN PSHARE_ACCESS ShareAccess
,
3391 BOOLEAN WriteAccess
;
3392 BOOLEAN DeleteAccess
;
3394 BOOLEAN SharedWrite
;
3395 BOOLEAN SharedDelete
;
3398 /* Get access masks */
3399 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
3400 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
3401 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
3403 /* Set them in the file object */
3404 FileObject
->ReadAccess
= ReadAccess
;
3405 FileObject
->WriteAccess
= WriteAccess
;
3406 FileObject
->DeleteAccess
= DeleteAccess
;
3408 /* Check if the file has an extension */
3409 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3411 /* Check if caller specified to ignore access checks */
3412 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3414 /* Don't check share access */
3415 return STATUS_SUCCESS
;
3419 /* Check if we have any access */
3420 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
3422 /* Get shared access masks */
3423 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
3424 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
3425 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
3428 FileObject
->SharedRead
= SharedRead
;
3429 FileObject
->SharedWrite
= SharedWrite
;
3430 FileObject
->SharedDelete
= SharedDelete
;
3432 /* Check if the shared access is violated */
3434 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
3436 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
3438 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
3439 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
3440 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
3441 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
3443 /* Sharing violation, fail */
3444 return STATUS_SHARING_VIOLATION
;
3447 /* It's not, check if caller wants us to update it */
3450 /* Increase open count */
3451 ShareAccess
->OpenCount
++;
3453 /* Update shared access */
3454 ShareAccess
->Readers
+= ReadAccess
;
3455 ShareAccess
->Writers
+= WriteAccess
;
3456 ShareAccess
->Deleters
+= DeleteAccess
;
3457 ShareAccess
->SharedRead
+= SharedRead
;
3458 ShareAccess
->SharedWrite
+= SharedWrite
;
3459 ShareAccess
->SharedDelete
+= SharedDelete
;
3463 /* Validation successful */
3464 return STATUS_SUCCESS
;
3472 IoRemoveShareAccess(IN PFILE_OBJECT FileObject
,
3473 IN PSHARE_ACCESS ShareAccess
)
3477 /* Check if the file has an extension */
3478 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3480 /* Check if caller specified to ignore access checks */
3481 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3483 /* Don't update share access */
3488 /* Otherwise, check if there's any access present */
3489 if ((FileObject
->ReadAccess
) ||
3490 (FileObject
->WriteAccess
) ||
3491 (FileObject
->DeleteAccess
))
3493 /* Decrement the open count */
3494 ShareAccess
->OpenCount
--;
3496 /* Remove share access */
3497 ShareAccess
->Readers
-= FileObject
->ReadAccess
;
3498 ShareAccess
->Writers
-= FileObject
->WriteAccess
;
3499 ShareAccess
->Deleters
-= FileObject
->DeleteAccess
;
3500 ShareAccess
->SharedRead
-= FileObject
->SharedRead
;
3501 ShareAccess
->SharedWrite
-= FileObject
->SharedWrite
;
3502 ShareAccess
->SharedDelete
-= FileObject
->SharedDelete
;
3511 IoSetShareAccess(IN ACCESS_MASK DesiredAccess
,
3512 IN ULONG DesiredShareAccess
,
3513 IN PFILE_OBJECT FileObject
,
3514 OUT PSHARE_ACCESS ShareAccess
)
3517 BOOLEAN WriteAccess
;
3518 BOOLEAN DeleteAccess
;
3520 BOOLEAN SharedWrite
;
3521 BOOLEAN SharedDelete
;
3522 BOOLEAN Update
= TRUE
;
3525 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
3526 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
3527 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
3529 /* Check if the file has an extension */
3530 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3532 /* Check if caller specified to ignore access checks */
3533 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3535 /* Don't update share access */
3540 /* Update basic access */
3541 FileObject
->ReadAccess
= ReadAccess
;
3542 FileObject
->WriteAccess
= WriteAccess
;
3543 FileObject
->DeleteAccess
= DeleteAccess
;
3545 /* Check if we have no access as all */
3546 if (!(ReadAccess
) && !(WriteAccess
) && !(DeleteAccess
))
3548 /* Check if we need to update the structure */
3549 if (!Update
) return;
3551 /* Otherwise, clear data */
3552 ShareAccess
->OpenCount
= 0;
3553 ShareAccess
->Readers
= 0;
3554 ShareAccess
->Writers
= 0;
3555 ShareAccess
->Deleters
= 0;
3556 ShareAccess
->SharedRead
= 0;
3557 ShareAccess
->SharedWrite
= 0;
3558 ShareAccess
->SharedDelete
= 0;
3562 /* Calculate shared access */
3563 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
3564 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
3565 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
3567 /* Set it in the FO */
3568 FileObject
->SharedRead
= SharedRead
;
3569 FileObject
->SharedWrite
= SharedWrite
;
3570 FileObject
->SharedDelete
= SharedDelete
;
3572 /* Check if we need to update the structure */
3573 if (!Update
) return;
3575 /* Otherwise, set data */
3576 ShareAccess
->OpenCount
= 1;
3577 ShareAccess
->Readers
= ReadAccess
;
3578 ShareAccess
->Writers
= WriteAccess
;
3579 ShareAccess
->Deleters
= DeleteAccess
;
3580 ShareAccess
->SharedRead
= SharedRead
;
3581 ShareAccess
->SharedWrite
= SharedWrite
;
3582 ShareAccess
->SharedDelete
= SharedDelete
;
3591 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject
,
3592 IN PFILE_OBJECT FileObject
)
3598 PIO_STACK_LOCATION Stack
;
3600 /* Check if handles were already created for the
3601 * open file. If so, that's over.
3603 if (FileObject
->Flags
& FO_HANDLE_CREATED
)
3604 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN
,
3605 (ULONG_PTR
)FileObject
,
3606 (ULONG_PTR
)DeviceObject
, 0, 0);
3608 /* Reset the events */
3609 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
3610 KeClearEvent(&FileObject
->Event
);
3612 /* Allocate the IRP we'll use */
3613 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
3614 /* Properly set it */
3615 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
3616 Irp
->UserEvent
= &Event
;
3617 Irp
->UserIosb
= &Irp
->IoStatus
;
3618 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
3619 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
3620 Irp
->RequestorMode
= KernelMode
;
3621 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
3623 Stack
= IoGetNextIrpStackLocation(Irp
);
3624 Stack
->MajorFunction
= IRP_MJ_CLEANUP
;
3625 Stack
->FileObject
= FileObject
;
3627 /* Put on top of IRPs list of the thread */
3628 IopQueueIrpToThread(Irp
);
3630 /* Call the driver */
3631 Status
= IoCallDriver(DeviceObject
, Irp
);
3632 if (Status
== STATUS_PENDING
)
3634 KeWaitForSingleObject(&Event
, UserRequest
,
3635 KernelMode
, FALSE
, NULL
);
3638 /* Remove from IRPs list */
3639 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
3640 IopUnQueueIrpFromThread(Irp
);
3641 KeLowerIrql(OldIrql
);
3646 /* Clear the event */
3647 KeClearEvent(&FileObject
->Event
);
3648 /* And finally, mark the open operation as canceled */
3649 FileObject
->Flags
|= FO_FILE_OPEN_CANCELLED
;
3657 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject
,
3658 OUT POBJECT_NAME_INFORMATION
*ObjectNameInformation
)
3661 ULONG Length
, ReturnLength
;
3662 POBJECT_NAME_INFORMATION LocalInfo
;
3664 /* Start with a buffer length of 200 */
3667 * We'll loop until query works.
3668 * We will use returned length for next loop
3669 * iteration, trying to have a big enough buffer.
3671 for (Length
= 200; ; Length
= ReturnLength
)
3673 /* Allocate our work buffer */
3674 LocalInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, 'nDoI');
3675 if (LocalInfo
== NULL
)
3677 return STATUS_INSUFFICIENT_RESOURCES
;
3680 /* Query the DOS name */
3681 Status
= IopQueryNameInternal(FileObject
,
3688 /* If it succeed, nothing more to do */
3689 if (Status
== STATUS_SUCCESS
)
3694 /* Otherwise, prepare for re-allocation */
3695 ExFreePoolWithTag(LocalInfo
, 'nDoI');
3698 * If we failed because of something else
3699 * than memory, simply stop and fail here
3701 if (Status
!= STATUS_BUFFER_OVERFLOW
)
3707 /* Success case here: return our buffer */
3708 *ObjectNameInformation
= LocalInfo
;
3709 return STATUS_SUCCESS
;
3717 IoSetFileOrigin(IN PFILE_OBJECT FileObject
,
3720 NTSTATUS Status
= STATUS_SUCCESS
;
3723 /* Get the flag status */
3724 FlagSet
= FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
3726 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
3727 if (Remote
&& !FlagSet
)
3730 FileObject
->Flags
|= FO_REMOTE_ORIGIN
;
3732 else if (!Remote
&& FlagSet
)
3734 /* Remove the flag */
3735 FileObject
->Flags
&= ~FO_REMOTE_ORIGIN
;
3740 Status
= STATUS_INVALID_PARAMETER_MIX
;
3752 NtCreateFile(PHANDLE FileHandle
,
3753 ACCESS_MASK DesiredAccess
,
3754 POBJECT_ATTRIBUTES ObjectAttributes
,
3755 PIO_STATUS_BLOCK IoStatusBlock
,
3756 PLARGE_INTEGER AllocateSize
,
3757 ULONG FileAttributes
,
3759 ULONG CreateDisposition
,
3760 ULONG CreateOptions
,
3764 /* Call the I/O Function */
3765 return IoCreateFile(FileHandle
,
3783 NtCreateMailslotFile(OUT PHANDLE FileHandle
,
3784 IN ACCESS_MASK DesiredAccess
,
3785 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3786 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3787 IN ULONG CreateOptions
,
3788 IN ULONG MailslotQuota
,
3789 IN ULONG MaxMessageSize
,
3790 IN PLARGE_INTEGER TimeOut
)
3792 MAILSLOT_CREATE_PARAMETERS Buffer
;
3795 /* Check for Timeout */
3798 /* check if the call came from user mode */
3799 if (KeGetPreviousMode() != KernelMode
)
3801 /* Enter SEH for Probe */
3804 /* Probe the timeout */
3805 Buffer
.ReadTimeout
= ProbeForReadLargeInteger(TimeOut
);
3807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3809 /* Return the exception code */
3810 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3816 /* Otherwise, capture directly */
3817 Buffer
.ReadTimeout
= *TimeOut
;
3820 /* Set the correct setting */
3821 Buffer
.TimeoutSpecified
= TRUE
;
3825 /* Tell the FSD we don't have a timeout */
3826 Buffer
.TimeoutSpecified
= FALSE
;
3830 Buffer
.MailslotQuota
= MailslotQuota
;
3831 Buffer
.MaximumMessageSize
= MaxMessageSize
;
3834 return IoCreateFile(FileHandle
,
3840 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3845 CreateFileTypeMailslot
,
3852 NtCreateNamedPipeFile(OUT PHANDLE FileHandle
,
3853 IN ACCESS_MASK DesiredAccess
,
3854 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3855 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3856 IN ULONG ShareAccess
,
3857 IN ULONG CreateDisposition
,
3858 IN ULONG CreateOptions
,
3859 IN ULONG NamedPipeType
,
3861 IN ULONG CompletionMode
,
3862 IN ULONG MaximumInstances
,
3863 IN ULONG InboundQuota
,
3864 IN ULONG OutboundQuota
,
3865 IN PLARGE_INTEGER DefaultTimeout
)
3867 NAMED_PIPE_CREATE_PARAMETERS Buffer
;
3870 /* Check for Timeout */
3873 /* check if the call came from user mode */
3874 if (KeGetPreviousMode() != KernelMode
)
3876 /* Enter SEH for Probe */
3879 /* Probe the timeout */
3880 Buffer
.DefaultTimeout
=
3881 ProbeForReadLargeInteger(DefaultTimeout
);
3883 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3885 /* Return the exception code */
3886 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3892 /* Otherwise, capture directly */
3893 Buffer
.DefaultTimeout
= *DefaultTimeout
;
3896 /* Set the correct setting */
3897 Buffer
.TimeoutSpecified
= TRUE
;
3901 /* Tell the FSD we don't have a timeout */
3902 Buffer
.TimeoutSpecified
= FALSE
;
3906 Buffer
.NamedPipeType
= NamedPipeType
;
3907 Buffer
.ReadMode
= ReadMode
;
3908 Buffer
.CompletionMode
= CompletionMode
;
3909 Buffer
.MaximumInstances
= MaximumInstances
;
3910 Buffer
.InboundQuota
= InboundQuota
;
3911 Buffer
.OutboundQuota
= OutboundQuota
;
3914 return IoCreateFile(FileHandle
,
3925 CreateFileTypeNamedPipe
,
3932 NtFlushWriteBuffer(VOID
)
3936 /* Call the kernel */
3937 KeFlushWriteBuffer();
3938 return STATUS_SUCCESS
;
3946 NtOpenFile(OUT PHANDLE FileHandle
,
3947 IN ACCESS_MASK DesiredAccess
,
3948 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3949 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3950 IN ULONG ShareAccess
,
3951 IN ULONG OpenOptions
)
3953 /* Call the I/O Function */
3954 return IoCreateFile(FileHandle
,
3972 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
3973 OUT PFILE_BASIC_INFORMATION FileInformation
)
3975 /* Call the internal helper API */
3976 return IopQueryAttributesFile(ObjectAttributes
,
3977 FileBasicInformation
,
3978 sizeof(FILE_BASIC_INFORMATION
),
3984 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
3985 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
)
3987 /* Call the internal helper API */
3988 return IopQueryAttributesFile(ObjectAttributes
,
3989 FileNetworkOpenInformation
,
3990 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
3995 * @name NtCancelIoFile
3997 * Cancel all pending I/O operations in the current thread for specified
4001 * Handle to file object to cancel requests for. No specific
4002 * access rights are needed.
4003 * @param IoStatusBlock
4004 * Pointer to status block which is filled with final completition
4005 * status on successful return.
4013 NtCancelIoFile(IN HANDLE FileHandle
,
4014 OUT PIO_STATUS_BLOCK IoStatusBlock
)
4016 PFILE_OBJECT FileObject
;
4020 BOOLEAN OurIrpsInList
= FALSE
;
4021 LARGE_INTEGER Interval
;
4022 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
4024 PLIST_ENTRY ListHead
, NextEntry
;
4026 IOTRACE(IO_API_DEBUG
, "FileHandle: %p\n", FileHandle
);
4028 /* Check the previous mode */
4029 if (PreviousMode
!= KernelMode
)
4031 /* Enter SEH for probing */
4034 /* Probe the I/O Status Block */
4035 ProbeForWriteIoStatusBlock(IoStatusBlock
);
4037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4039 /* Return the exception code */
4040 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4045 /* Reference the file object */
4046 Status
= ObReferenceObjectByHandle(FileHandle
,
4050 (PVOID
*)&FileObject
,
4052 if (!NT_SUCCESS(Status
)) return Status
;
4054 /* IRP cancellations are synchronized at APC_LEVEL. */
4055 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
4057 /* Get the current thread */
4058 Thread
= PsGetCurrentThread();
4060 /* Update the operation counts */
4061 IopUpdateOperationCount(IopOtherTransfer
);
4064 ListHead
= &Thread
->IrpList
;
4065 NextEntry
= ListHead
->Flink
;
4066 while (ListHead
!= NextEntry
)
4068 /* Get the IRP and check if the File Object matches */
4069 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
4070 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
4072 /* Cancel this IRP and keep looping */
4074 OurIrpsInList
= TRUE
;
4077 /* Go to the next entry */
4078 NextEntry
= NextEntry
->Flink
;
4081 /* Lower the IRQL */
4082 KeLowerIrql(OldIrql
);
4084 /* Check if we had found an IRP */
4087 /* Setup a 10ms wait */
4088 Interval
.QuadPart
= -100000;
4091 while (OurIrpsInList
)
4094 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
4095 OurIrpsInList
= FALSE
;
4098 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
4100 /* Now loop the list again */
4101 NextEntry
= ListHead
->Flink
;
4102 while (NextEntry
!= ListHead
)
4104 /* Get the IRP and check if the File Object matches */
4105 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
4106 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
4109 OurIrpsInList
= TRUE
;
4113 /* Go to the next entry */
4114 NextEntry
= NextEntry
->Flink
;
4117 /* Lower the IRQL */
4118 KeLowerIrql(OldIrql
);
4122 /* Enter SEH for writing back the I/O Status */
4126 IoStatusBlock
->Status
= STATUS_SUCCESS
;
4127 IoStatusBlock
->Information
= 0;
4129 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4131 /* Ignore exception */
4135 /* Dereference the file object and return success */
4136 ObDereferenceObject(FileObject
);
4137 return STATUS_SUCCESS
;
4145 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes
)
4148 DUMMY_FILE_OBJECT LocalFileObject
;
4150 KPROCESSOR_MODE AccessMode
= KeGetPreviousMode();
4151 OPEN_PACKET OpenPacket
;
4153 IOTRACE(IO_API_DEBUG
, "FileMame: %wZ\n", ObjectAttributes
->ObjectName
);
4155 /* Setup the Open Packet */
4156 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
4157 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
4158 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
4159 OpenPacket
.CreateOptions
= FILE_DELETE_ON_CLOSE
;
4160 OpenPacket
.ShareAccess
= FILE_SHARE_READ
|
4163 OpenPacket
.Disposition
= FILE_OPEN
;
4164 OpenPacket
.DeleteOnly
= TRUE
;
4165 OpenPacket
.LocalFileObject
= &LocalFileObject
;
4167 /* Update the operation counts */
4168 IopUpdateOperationCount(IopOtherTransfer
);
4171 * Attempt opening the file. This will call the I/O Parse Routine for
4172 * the File Object (IopParseDevice) which will use the dummy file obejct
4173 * send the IRP to its device object. Note that we have two statuses
4174 * to worry about: the Object Manager's status (in Status) and the I/O
4175 * status, which is in the Open Packet's Final Status, and determined
4176 * by the Parse Check member.
4178 Status
= ObOpenObjectByName(ObjectAttributes
,
4185 if (OpenPacket
.ParseCheck
== FALSE
) return Status
;
4187 /* Retrn the Io status */
4188 return OpenPacket
.FinalStatus
;