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
);
271 IopParseDevice(IN PVOID ParseObject
,
273 IN OUT PACCESS_STATE AccessState
,
274 IN KPROCESSOR_MODE AccessMode
,
276 IN OUT PUNICODE_STRING CompleteName
,
277 IN OUT PUNICODE_STRING RemainingName
,
278 IN OUT PVOID Context
,
279 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
282 POPEN_PACKET OpenPacket
= (POPEN_PACKET
)Context
;
283 PDEVICE_OBJECT OriginalDeviceObject
= (PDEVICE_OBJECT
)ParseObject
;
284 PDEVICE_OBJECT DeviceObject
, OwnerDevice
;
286 PFILE_OBJECT FileObject
;
289 PIO_STACK_LOCATION StackLoc
;
290 IO_SECURITY_CONTEXT SecurityContext
;
291 IO_STATUS_BLOCK IoStatusBlock
;
292 BOOLEAN DirectOpen
= FALSE
, OpenCancelled
, UseDummyFile
;
293 OBJECT_ATTRIBUTES ObjectAttributes
;
295 PDUMMY_FILE_OBJECT LocalFileObject
;
296 PFILE_BASIC_INFORMATION FileBasicInfo
;
298 KPROCESSOR_MODE CheckMode
;
299 BOOLEAN VolumeOpen
= FALSE
;
300 ACCESS_MASK DesiredAccess
, GrantedAccess
;
301 BOOLEAN AccessGranted
, LockHeld
= FALSE
;
302 PPRIVILEGE_SET Privileges
= NULL
;
303 UNICODE_STRING FileString
;
305 IOTRACE(IO_FILE_DEBUG
, "ParseObject: %p. RemainingName: %wZ\n",
306 ParseObject
, RemainingName
);
308 for (Attempt
= 0; Attempt
< IOP_MAX_REPARSE_TRAVERSAL
; ++Attempt
)
313 /* Validate the open packet */
314 if (!IopValidateOpenPacket(OpenPacket
)) return STATUS_OBJECT_TYPE_MISMATCH
;
316 /* Valide reparse point in case we traversed a mountpoint */
317 if (OpenPacket
->TraversedMountPoint
)
319 /* This is a reparse point we understand */
320 ASSERT(OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
);
322 /* Make sure we're dealing with correct DO */
323 if (OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_DISK
&&
324 OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_CD_ROM
&&
325 OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_VIRTUAL_DISK
&&
326 OriginalDeviceObject
->DeviceType
!= FILE_DEVICE_TAPE
)
328 OpenPacket
->FinalStatus
= STATUS_IO_REPARSE_DATA_INVALID
;
329 return STATUS_IO_REPARSE_DATA_INVALID
;
333 /* Check if we have a related file object */
334 if (OpenPacket
->RelatedFileObject
)
336 /* Use the related file object's device object */
337 OriginalDeviceObject
= OpenPacket
->RelatedFileObject
->DeviceObject
;
340 /* Validate device status */
341 Status
= IopCheckDeviceAndDriver(OpenPacket
, OriginalDeviceObject
);
342 if (!NT_SUCCESS(Status
))
344 /* We failed, return status */
345 OpenPacket
->FinalStatus
= Status
;
349 /* Map the generic mask and set the new mapping in the access state */
350 RtlMapGenericMask(&AccessState
->RemainingDesiredAccess
,
351 &IoFileObjectType
->TypeInfo
.GenericMapping
);
352 RtlMapGenericMask(&AccessState
->OriginalDesiredAccess
,
353 &IoFileObjectType
->TypeInfo
.GenericMapping
);
354 SeSetAccessStateGenericMapping(AccessState
,
355 &IoFileObjectType
->TypeInfo
.GenericMapping
);
356 DesiredAccess
= AccessState
->RemainingDesiredAccess
;
358 /* Check what kind of access checks to do */
359 if ((AccessMode
!= KernelMode
) ||
360 (OpenPacket
->Options
& IO_FORCE_ACCESS_CHECK
))
362 /* Call is from user-mode or kernel is forcing checks */
363 CheckMode
= UserMode
;
367 /* Call is from the kernel */
368 CheckMode
= KernelMode
;
371 /* Check privilege for backup or restore operation */
372 IopCheckBackupRestorePrivilege(AccessState
,
373 &OpenPacket
->CreateOptions
,
375 OpenPacket
->Disposition
);
377 /* Check if we are re-parsing */
378 if (((OpenPacket
->Override
) && !(RemainingName
->Length
)) ||
379 (AccessState
->Flags
& SE_BACKUP_PRIVILEGES_CHECKED
))
381 /* Get granted access from the last call */
382 DesiredAccess
|= AccessState
->PreviouslyGrantedAccess
;
385 /* Check if this is a volume open */
386 if ((OpenPacket
->RelatedFileObject
) &&
387 (OpenPacket
->RelatedFileObject
->Flags
& FO_VOLUME_OPEN
) &&
388 !(RemainingName
->Length
))
394 /* Now check if we need access checks */
395 if (((AccessMode
!= KernelMode
) ||
396 (OpenPacket
->Options
& IO_FORCE_ACCESS_CHECK
)) &&
397 (!(OpenPacket
->RelatedFileObject
) || (VolumeOpen
)) &&
398 !(OpenPacket
->Override
))
400 KeEnterCriticalRegion();
401 ExAcquireResourceSharedLite(&IopSecurityResource
, TRUE
);
403 /* Check if a device object is being parsed */
404 if (!RemainingName
->Length
)
406 /* Lock the subject context */
407 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
410 /* Do access check */
411 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->
413 &AccessState
->SubjectSecurityContext
,
419 TypeInfo
.GenericMapping
,
425 /* Append and free the privileges */
426 SeAppendPrivileges(AccessState
, Privileges
);
427 SeFreePrivileges(Privileges
);
430 /* Check if we got access */
433 /* Update access state */
434 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
435 AccessState
->RemainingDesiredAccess
&= ~(GrantedAccess
|
437 OpenPacket
->Override
= TRUE
;
440 FileString
.Length
= 8;
441 FileString
.MaximumLength
= 8;
442 FileString
.Buffer
= L
"File";
444 /* Do Audit/Alarm for open operation */
445 SeOpenObjectAuditAlarm(&FileString
,
446 OriginalDeviceObject
,
448 OriginalDeviceObject
->SecurityDescriptor
,
453 &AccessState
->GenerateOnClose
);
457 /* Check if we need to do traverse validation */
458 if (!(AccessState
->Flags
& TOKEN_HAS_TRAVERSE_PRIVILEGE
) ||
459 ((OriginalDeviceObject
->DeviceType
== FILE_DEVICE_DISK
) ||
460 (OriginalDeviceObject
->DeviceType
== FILE_DEVICE_CD_ROM
)))
462 /* Check if this is a restricted token */
463 if (!(AccessState
->Flags
& TOKEN_IS_RESTRICTED
))
465 /* Do the FAST traverse check */
466 AccessGranted
= SeFastTraverseCheck(OriginalDeviceObject
->SecurityDescriptor
,
474 AccessGranted
= FALSE
;
477 /* Check if we failed to get access */
480 /* Lock the subject context */
481 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
484 /* Do access check */
485 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->
487 &AccessState
->SubjectSecurityContext
,
493 TypeInfo
.GenericMapping
,
499 /* Append and free the privileges */
500 SeAppendPrivileges(AccessState
, Privileges
);
501 SeFreePrivileges(Privileges
);
505 /* FIXME: Do Audit/Alarm for traverse check */
509 /* Access automatically granted */
510 AccessGranted
= TRUE
;
514 ExReleaseResourceLite(&IopSecurityResource
);
515 KeLeaveCriticalRegion();
517 /* Check if we hold the lock */
521 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
524 /* Check if access failed */
527 /* Dereference the device and fail */
528 DPRINT1("Traverse access failed!\n");
529 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
530 return STATUS_ACCESS_DENIED
;
534 /* Check if we can simply use a dummy file */
535 UseDummyFile
= ((OpenPacket
->QueryOnly
) || (OpenPacket
->DeleteOnly
));
538 /* FIXME: Small hack still exists, have to check why...
539 * This is triggered multiple times by usetup and then once per boot.
541 if (ExpInTextModeSetup
&&
543 !(RemainingName
->Length
) &&
544 !(OpenPacket
->RelatedFileObject
) &&
545 ((wcsstr(CompleteName
->Buffer
, L
"Harddisk")) ||
546 (wcsstr(CompleteName
->Buffer
, L
"Floppy"))) &&
549 DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
550 DesiredAccess
& ~(SYNCHRONIZE
|
551 FILE_READ_ATTRIBUTES
|
553 ACCESS_SYSTEM_SECURITY
|
560 /* Check if this is a direct open */
561 if (!(RemainingName
->Length
) &&
562 !(OpenPacket
->RelatedFileObject
) &&
563 ((DesiredAccess
& ~(SYNCHRONIZE
|
564 FILE_READ_ATTRIBUTES
|
566 ACCESS_SYSTEM_SECURITY
|
571 /* Remember this for later */
575 /* Check if we have a related FO that wasn't a direct open */
576 if ((OpenPacket
->RelatedFileObject
) &&
577 !(OpenPacket
->RelatedFileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
579 /* The device object is the one we were given */
580 DeviceObject
= ParseObject
;
582 /* Check if the related FO had a VPB */
583 if (OpenPacket
->RelatedFileObject
->Vpb
)
585 /* Yes, remember it */
586 Vpb
= OpenPacket
->RelatedFileObject
->Vpb
;
589 InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
591 /* Check if we were given a specific top level device to use */
592 if (OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
)
594 DeviceObject
= Vpb
->DeviceObject
;
600 /* Check if it has a VPB */
601 if ((OriginalDeviceObject
->Vpb
) && !(DirectOpen
))
603 /* Check if the VPB is mounted, and mount it */
604 Vpb
= IopCheckVpbMounted(OpenPacket
,
605 OriginalDeviceObject
,
608 if (!Vpb
) return Status
;
610 /* Get the VPB's device object */
611 DeviceObject
= Vpb
->DeviceObject
;
615 /* The device object is the one we were given */
616 DeviceObject
= OriginalDeviceObject
;
619 /* If we weren't given a specific top level device, look for an attached device */
620 if (!(OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
) &&
621 DeviceObject
->AttachedDevice
)
623 /* Get the attached device */
624 DeviceObject
= IoGetAttachedDevice(DeviceObject
);
628 if (OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
)
630 // FIXME: Verify our device object is good to use
631 ASSERT(DirectOpen
== FALSE
);
634 /* If we traversed a mount point, reset the information */
635 if (OpenPacket
->TraversedMountPoint
)
637 OpenPacket
->TraversedMountPoint
= FALSE
;
640 /* Check if this is a secure FSD */
641 if ((DeviceObject
->Characteristics
& FILE_DEVICE_SECURE_OPEN
) &&
642 ((OpenPacket
->RelatedFileObject
) || (RemainingName
->Length
)) &&
648 KeEnterCriticalRegion();
649 ExAcquireResourceSharedLite(&IopSecurityResource
, TRUE
);
651 /* Lock the subject context */
652 SeLockSubjectContext(&AccessState
->SubjectSecurityContext
);
654 /* Do access check */
655 AccessGranted
= SeAccessCheck(OriginalDeviceObject
->SecurityDescriptor
,
656 &AccessState
->SubjectSecurityContext
,
661 &IoFileObjectType
->TypeInfo
.GenericMapping
,
665 if (Privileges
!= NULL
)
667 /* Append and free the privileges */
668 SeAppendPrivileges(AccessState
, Privileges
);
669 SeFreePrivileges(Privileges
);
672 /* Check if we got access */
675 AccessState
->PreviouslyGrantedAccess
|= GrantedAccess
;
676 AccessState
->RemainingDesiredAccess
&= ~(GrantedAccess
| MAXIMUM_ALLOWED
);
679 FileString
.Length
= 8;
680 FileString
.MaximumLength
= 8;
681 FileString
.Buffer
= L
"File";
683 /* Do Audit/Alarm for open operation
684 * NOTA: we audit target device object
686 SeOpenObjectAuditAlarm(&FileString
,
689 OriginalDeviceObject
->SecurityDescriptor
,
694 &AccessState
->GenerateOnClose
);
696 SeUnlockSubjectContext(&AccessState
->SubjectSecurityContext
);
698 ExReleaseResourceLite(&IopSecurityResource
);
699 KeLeaveCriticalRegion();
701 /* Check if access failed */
704 /* Dereference the device and fail */
705 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
706 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
707 return STATUS_ACCESS_DENIED
;
711 /* Allocate the IRP */
712 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
715 /* Dereference the device and VPB, then fail */
716 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
717 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
718 return STATUS_INSUFFICIENT_RESOURCES
;
721 /* Now set the IRP data */
722 Irp
->RequestorMode
= AccessMode
;
723 Irp
->Flags
= IRP_CREATE_OPERATION
| IRP_SYNCHRONOUS_API
| IRP_DEFER_IO_COMPLETION
;
724 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
725 Irp
->UserIosb
= &IoStatusBlock
;
726 Irp
->MdlAddress
= NULL
;
727 Irp
->PendingReturned
= FALSE
;
728 Irp
->UserEvent
= NULL
;
730 Irp
->CancelRoutine
= NULL
;
731 Irp
->Tail
.Overlay
.AuxiliaryBuffer
= NULL
;
733 /* Setup the security context */
734 SecurityContext
.SecurityQos
= SecurityQos
;
735 SecurityContext
.AccessState
= AccessState
;
736 SecurityContext
.DesiredAccess
= AccessState
->RemainingDesiredAccess
;
737 SecurityContext
.FullCreateOptions
= OpenPacket
->CreateOptions
;
739 /* Get the I/O Stack location */
740 StackLoc
= IoGetNextIrpStackLocation(Irp
);
741 StackLoc
->Control
= 0;
743 /* Check what kind of file this is */
744 switch (OpenPacket
->CreateFileType
)
747 case CreateFileTypeNone
:
749 /* Set the major function and EA Length */
750 StackLoc
->MajorFunction
= IRP_MJ_CREATE
;
751 StackLoc
->Parameters
.Create
.EaLength
= OpenPacket
->EaLength
;
754 StackLoc
->Flags
= (UCHAR
)OpenPacket
->Options
;
755 StackLoc
->Flags
|= !(Attributes
& OBJ_CASE_INSENSITIVE
) ? SL_CASE_SENSITIVE
: 0;
759 case CreateFileTypeNamedPipe
:
761 /* Set the named pipe MJ and set the parameters */
762 StackLoc
->MajorFunction
= IRP_MJ_CREATE_NAMED_PIPE
;
763 StackLoc
->Parameters
.CreatePipe
.Parameters
= OpenPacket
->ExtraCreateParameters
;
767 case CreateFileTypeMailslot
:
769 /* Set the mailslot MJ and set the parameters */
770 StackLoc
->MajorFunction
= IRP_MJ_CREATE_MAILSLOT
;
771 StackLoc
->Parameters
.CreateMailslot
.Parameters
= OpenPacket
->ExtraCreateParameters
;
775 /* Set the common data */
776 Irp
->Overlay
.AllocationSize
= OpenPacket
->AllocationSize
;
777 Irp
->AssociatedIrp
.SystemBuffer
= OpenPacket
->EaBuffer
;
778 StackLoc
->Parameters
.Create
.Options
= (OpenPacket
->Disposition
<< 24) |
779 (OpenPacket
->CreateOptions
&
781 StackLoc
->Parameters
.Create
.FileAttributes
= OpenPacket
->FileAttributes
;
782 StackLoc
->Parameters
.Create
.ShareAccess
= OpenPacket
->ShareAccess
;
783 StackLoc
->Parameters
.Create
.SecurityContext
= &SecurityContext
;
785 /* Check if we really need to create an object */
788 ULONG ObjectSize
= sizeof(FILE_OBJECT
);
790 /* Tag on space for a file object extension */
791 if (OpenPacket
->InternalFlags
& IOP_CREATE_FILE_OBJECT_EXTENSION
)
792 ObjectSize
+= sizeof(FILE_OBJECT_EXTENSION
);
794 /* Create the actual file object */
795 InitializeObjectAttributes(&ObjectAttributes
,
800 Status
= ObCreateObject(KernelMode
,
808 (PVOID
*)&FileObject
);
809 if (!NT_SUCCESS(Status
))
811 /* Create failed, free the IRP */
814 /* Dereference the device and VPB */
815 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
816 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
818 /* We failed, return status */
819 OpenPacket
->FinalStatus
= Status
;
823 /* Clear the file object */
824 RtlZeroMemory(FileObject
, sizeof(FILE_OBJECT
));
826 /* Check if this is Synch I/O */
827 if (OpenPacket
->CreateOptions
&
828 (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
))
830 /* Set the synch flag */
831 FileObject
->Flags
|= FO_SYNCHRONOUS_IO
;
833 /* Check if it's also alertable */
834 if (OpenPacket
->CreateOptions
& FILE_SYNCHRONOUS_IO_ALERT
)
836 /* It is, set the alertable flag */
837 FileObject
->Flags
|= FO_ALERTABLE_IO
;
841 /* Check if this is synch I/O */
842 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
844 /* Initialize the event */
845 KeInitializeEvent(&FileObject
->Lock
, SynchronizationEvent
, FALSE
);
848 /* Check if the caller requested no intermediate buffering */
849 if (OpenPacket
->CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
)
851 /* Set the correct flag for the FSD to read */
852 FileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
855 /* Check if the caller requested write through support */
856 if (OpenPacket
->CreateOptions
& FILE_WRITE_THROUGH
)
858 /* Set the correct flag for the FSD to read */
859 FileObject
->Flags
|= FO_WRITE_THROUGH
;
862 /* Check if the caller says the file will be only read sequentially */
863 if (OpenPacket
->CreateOptions
& FILE_SEQUENTIAL_ONLY
)
865 /* Set the correct flag for the FSD to read */
866 FileObject
->Flags
|= FO_SEQUENTIAL_ONLY
;
869 /* Check if the caller believes the file will be only read randomly */
870 if (OpenPacket
->CreateOptions
& FILE_RANDOM_ACCESS
)
872 /* Set the correct flag for the FSD to read */
873 FileObject
->Flags
|= FO_RANDOM_ACCESS
;
876 /* Check if we were asked to setup a file object extension */
877 if (OpenPacket
->InternalFlags
& IOP_CREATE_FILE_OBJECT_EXTENSION
)
879 PFILE_OBJECT_EXTENSION FileObjectExtension
;
881 /* Make sure the file object knows it has an extension */
882 FileObject
->Flags
|= FO_FILE_OBJECT_HAS_EXTENSION
;
884 FileObjectExtension
= (PFILE_OBJECT_EXTENSION
)(FileObject
+ 1);
885 FileObject
->FileObjectExtension
= FileObjectExtension
;
887 /* Add the top level device which we'll send the request to */
888 if (OpenPacket
->InternalFlags
& IOP_USE_TOP_LEVEL_DEVICE_HINT
)
890 FileObjectExtension
->TopDeviceObjectHint
= DeviceObject
;
896 /* Use the dummy object instead */
897 LocalFileObject
= OpenPacket
->LocalFileObject
;
898 RtlZeroMemory(LocalFileObject
, sizeof(DUMMY_FILE_OBJECT
));
901 FileObject
= (PFILE_OBJECT
)&LocalFileObject
->ObjectHeader
.Body
;
902 LocalFileObject
->ObjectHeader
.Type
= IoFileObjectType
;
903 LocalFileObject
->ObjectHeader
.PointerCount
= 1;
906 /* Setup the file header */
907 FileObject
->Type
= IO_TYPE_FILE
;
908 FileObject
->Size
= sizeof(FILE_OBJECT
);
909 FileObject
->RelatedFileObject
= OpenPacket
->RelatedFileObject
;
910 FileObject
->DeviceObject
= OriginalDeviceObject
;
912 /* Check if this is a direct device open */
913 if (DirectOpen
) FileObject
->Flags
|= FO_DIRECT_DEVICE_OPEN
;
915 /* Check if the caller wants case sensitivity */
916 if (!(Attributes
& OBJ_CASE_INSENSITIVE
))
918 /* Tell the driver about it */
919 FileObject
->Flags
|= FO_OPENED_CASE_SENSITIVE
;
922 /* Now set the file object */
923 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
924 StackLoc
->FileObject
= FileObject
;
926 /* Check if the file object has a name */
927 if (RemainingName
->Length
)
929 /* Setup the unicode string */
930 FileObject
->FileName
.MaximumLength
= RemainingName
->Length
+
932 FileObject
->FileName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
937 if (!FileObject
->FileName
.Buffer
)
939 /* Failed to allocate the name, free the IRP */
942 /* Dereference the device object and VPB */
943 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
944 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
946 /* Clear the FO and dereference it */
947 FileObject
->DeviceObject
= NULL
;
948 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
951 return STATUS_INSUFFICIENT_RESOURCES
;
956 RtlCopyUnicodeString(&FileObject
->FileName
, RemainingName
);
958 /* Initialize the File Object event and set the FO */
959 KeInitializeEvent(&FileObject
->Event
, NotificationEvent
, FALSE
);
960 OpenPacket
->FileObject
= FileObject
;
962 /* Queue the IRP and call the driver */
963 IopQueueIrpToThread(Irp
);
964 Status
= IoCallDriver(DeviceObject
, Irp
);
965 if (Status
== STATUS_PENDING
)
967 /* Wait for the driver to complete the create */
968 KeWaitForSingleObject(&FileObject
->Event
,
974 /* Get the new status */
975 Status
= IoStatusBlock
.Status
;
979 /* We'll have to complete it ourselves */
980 ASSERT(!Irp
->PendingReturned
);
981 ASSERT(!Irp
->MdlAddress
);
983 /* Handle name change if required */
984 if (Status
== STATUS_REPARSE
)
986 /* Check this is a mount point */
987 if (Irp
->IoStatus
.Information
== IO_REPARSE_TAG_MOUNT_POINT
)
989 PREPARSE_DATA_BUFFER ReparseData
;
991 /* Reparse point attributes were passed by the driver in the auxiliary buffer */
992 ASSERT(Irp
->Tail
.Overlay
.AuxiliaryBuffer
!= NULL
);
993 ReparseData
= (PREPARSE_DATA_BUFFER
)Irp
->Tail
.Overlay
.AuxiliaryBuffer
;
995 ASSERT(ReparseData
->ReparseTag
== IO_REPARSE_TAG_MOUNT_POINT
);
996 ASSERT(ReparseData
->ReparseDataLength
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
997 ASSERT(ReparseData
->Reserved
< MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
999 IopDoNameTransmogrify(Irp
, FileObject
, ReparseData
);
1003 /* Completion happens at APC_LEVEL */
1004 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1006 /* Get the new I/O Status block ourselves */
1007 IoStatusBlock
= Irp
->IoStatus
;
1008 Status
= IoStatusBlock
.Status
;
1010 /* Manually signal the even, we can't have any waiters */
1011 FileObject
->Event
.Header
.SignalState
= 1;
1013 /* Now that we've signaled the events, de-associate the IRP */
1014 IopUnQueueIrpFromThread(Irp
);
1016 /* Check if the IRP had an input buffer */
1017 if ((Irp
->Flags
& IRP_BUFFERED_IO
) &&
1018 (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
))
1020 /* Free it. A driver might've tacked one on */
1021 ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
1024 /* Free the IRP and bring the IRQL back down */
1026 KeLowerIrql(OldIrql
);
1029 /* Copy the I/O Status */
1030 OpenPacket
->Information
= IoStatusBlock
.Information
;
1032 /* The driver failed to create the file */
1033 if (!NT_SUCCESS(Status
))
1035 /* Check if we have a name */
1036 if (FileObject
->FileName
.Length
)
1039 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
1040 FileObject
->FileName
.Length
= 0;
1043 /* Clear its device object */
1044 FileObject
->DeviceObject
= NULL
;
1046 /* Save this now because the FO might go away */
1047 OpenCancelled
= FileObject
->Flags
& FO_FILE_OPEN_CANCELLED
?
1050 /* Clear the file object in the open packet */
1051 OpenPacket
->FileObject
= NULL
;
1053 /* Dereference the file object */
1054 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
1056 /* Dereference the device object */
1057 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
1059 /* Unless the driver cancelled the open, dereference the VPB */
1060 if (!(OpenCancelled
) && (Vpb
)) IopDereferenceVpbAndFree(Vpb
);
1062 /* Set the status and return */
1063 OpenPacket
->FinalStatus
= Status
;
1066 else if (Status
== STATUS_REPARSE
)
1068 if (OpenPacket
->Information
== IO_REPARSE
||
1069 OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1071 /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
1072 if (CompleteName
->MaximumLength
< FileObject
->FileName
.Length
)
1074 PWSTR NewCompleteName
;
1076 /* Allocate a new buffer for the string */
1077 NewCompleteName
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
, TAG_IO_NAME
);
1078 if (NewCompleteName
== NULL
)
1080 OpenPacket
->FinalStatus
= STATUS_INSUFFICIENT_RESOURCES
;
1081 return STATUS_INSUFFICIENT_RESOURCES
;
1084 /* Release the old one */
1085 if (CompleteName
->Buffer
!= NULL
)
1087 ExFreePoolWithTag(CompleteName
->Buffer
, 0);
1090 /* And setup the new one */
1091 CompleteName
->Buffer
= NewCompleteName
;
1092 CompleteName
->MaximumLength
= FileObject
->FileName
.Length
;
1095 /* Copy our new complete name */
1096 RtlCopyUnicodeString(CompleteName
, &FileObject
->FileName
);
1098 if (OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1100 OpenPacket
->RelatedFileObject
= NULL
;
1104 /* Check if we have a name */
1105 if (FileObject
->FileName
.Length
)
1108 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1109 FileObject
->FileName
.Length
= 0;
1112 /* Clear its device object */
1113 FileObject
->DeviceObject
= NULL
;
1115 /* Clear the file object in the open packet */
1116 OpenPacket
->FileObject
= NULL
;
1118 /* Dereference the file object */
1119 if (!UseDummyFile
) ObDereferenceObject(FileObject
);
1121 /* Dereference the device object */
1122 IopDereferenceDeviceObject(OriginalDeviceObject
, FALSE
);
1124 /* Unless the driver cancelled the open, dereference the VPB */
1125 if (Vpb
!= NULL
) IopDereferenceVpbAndFree(Vpb
);
1127 if (OpenPacket
->Information
!= IO_REMOUNT
)
1129 OpenPacket
->RelatedFileObject
= NULL
;
1131 /* Inform we traversed a mount point for later attempt */
1132 if (OpenPacket
->Information
== IO_REPARSE_TAG_MOUNT_POINT
)
1134 OpenPacket
->TraversedMountPoint
= 1;
1137 /* In case we override checks, but got this on volume open, fail hard */
1138 if (OpenPacket
->Override
)
1140 KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN
,
1141 (ULONG_PTR
)OriginalDeviceObject
,
1142 (ULONG_PTR
)DeviceObject
,
1143 (ULONG_PTR
)CompleteName
,
1144 OpenPacket
->Information
);
1147 /* Return to IO/OB so that information can be upgraded */
1148 return STATUS_REPARSE
;
1151 /* Loop again and reattempt an opening */
1158 if (Attempt
== IOP_MAX_REPARSE_TRAVERSAL
)
1159 return STATUS_UNSUCCESSFUL
;
1161 /* Get the owner of the File Object */
1162 OwnerDevice
= IoGetRelatedDeviceObject(FileObject
);
1165 * It's possible that the device to whom we sent the IRP to
1166 * isn't actually the device that ended opening the file object
1169 if (OwnerDevice
!= DeviceObject
)
1171 /* We have to de-reference the VPB we had associated */
1172 if (Vpb
) IopDereferenceVpbAndFree(Vpb
);
1174 /* And re-associate with the actual one */
1175 Vpb
= FileObject
->Vpb
;
1176 if (Vpb
) InterlockedIncrement((PLONG
)&Vpb
->ReferenceCount
);
1179 /* Make sure we are not using a dummy */
1182 /* Check if this was a volume open */
1183 if ((!(FileObject
->RelatedFileObject
) ||
1184 (FileObject
->RelatedFileObject
->Flags
& FO_VOLUME_OPEN
)) &&
1185 !(FileObject
->FileName
.Length
))
1187 /* All signs point to it, but make sure it was actually an FSD */
1188 if ((OwnerDevice
->DeviceType
== FILE_DEVICE_DISK_FILE_SYSTEM
) ||
1189 (OwnerDevice
->DeviceType
== FILE_DEVICE_CD_ROM_FILE_SYSTEM
) ||
1190 (OwnerDevice
->DeviceType
== FILE_DEVICE_TAPE_FILE_SYSTEM
) ||
1191 (OwnerDevice
->DeviceType
== FILE_DEVICE_FILE_SYSTEM
))
1193 /* The owner device is an FSD, so this is a volume open for real */
1194 FileObject
->Flags
|= FO_VOLUME_OPEN
;
1198 /* Reference the object and set the parse check */
1199 ObReferenceObject(FileObject
);
1200 *Object
= FileObject
;
1201 OpenPacket
->FinalStatus
= IoStatusBlock
.Status
;
1202 OpenPacket
->ParseCheck
= TRUE
;
1203 return OpenPacket
->FinalStatus
;
1207 /* Check if this was a query */
1208 if (OpenPacket
->QueryOnly
)
1210 /* Check if the caller wants basic info only */
1211 if (!OpenPacket
->FullAttributes
)
1213 /* Allocate the buffer */
1214 FileBasicInfo
= ExAllocatePoolWithTag(NonPagedPool
,
1215 sizeof(*FileBasicInfo
),
1220 Status
= IoQueryFileInformation(FileObject
,
1221 FileBasicInformation
,
1222 sizeof(*FileBasicInfo
),
1225 if (NT_SUCCESS(Status
))
1228 RtlCopyMemory(OpenPacket
->BasicInformation
,
1233 /* Free our buffer */
1234 ExFreePoolWithTag(FileBasicInfo
, TAG_IO
);
1239 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1244 /* This is a full query */
1245 Status
= IoQueryFileInformation(
1247 FileNetworkOpenInformation
,
1248 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
1249 OpenPacket
->NetworkInformation
,
1251 if (!NT_SUCCESS(Status
)) ASSERT(Status
!= STATUS_NOT_IMPLEMENTED
);
1255 /* Delete the file object */
1256 IopDeleteFile(FileObject
);
1258 /* Clear out the file */
1259 OpenPacket
->FileObject
= NULL
;
1261 /* Set and return status */
1262 OpenPacket
->FinalStatus
= Status
;
1263 OpenPacket
->ParseCheck
= TRUE
;
1270 IopParseFile(IN PVOID ParseObject
,
1271 IN PVOID ObjectType
,
1272 IN OUT PACCESS_STATE AccessState
,
1273 IN KPROCESSOR_MODE AccessMode
,
1274 IN ULONG Attributes
,
1275 IN OUT PUNICODE_STRING CompleteName
,
1276 IN OUT PUNICODE_STRING RemainingName
,
1277 IN OUT PVOID Context OPTIONAL
,
1278 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL
,
1282 POPEN_PACKET OpenPacket
= (POPEN_PACKET
)Context
;
1284 /* Validate the open packet */
1285 if (!IopValidateOpenPacket(OpenPacket
)) return STATUS_OBJECT_TYPE_MISMATCH
;
1287 /* Get the device object */
1288 DeviceObject
= IoGetRelatedDeviceObject(ParseObject
);
1289 OpenPacket
->RelatedFileObject
= ParseObject
;
1291 /* Call the main routine */
1292 return IopParseDevice(DeviceObject
,
1306 IopDeleteFile(IN PVOID ObjectBody
)
1308 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1310 PIO_STACK_LOCATION StackPtr
;
1313 PDEVICE_OBJECT DeviceObject
;
1314 BOOLEAN DereferenceDone
= FALSE
;
1317 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1319 /* Check if the file has a device object */
1320 if (FileObject
->DeviceObject
)
1322 /* Check if this is a direct open or not */
1323 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1325 /* Get the attached device */
1326 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1330 /* Use the file object's device object */
1331 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1335 ASSERT(!(FileObject
->Flags
& FO_SYNCHRONOUS_IO
) ||
1336 (InterlockedExchange((PLONG
)&FileObject
->Busy
, TRUE
) == FALSE
));
1338 /* Check if the handle wasn't created yet */
1339 if (!(FileObject
->Flags
& FO_HANDLE_CREATED
))
1341 /* Send the cleanup IRP */
1342 IopCloseFile(NULL
, ObjectBody
, 0, 1, 1);
1345 /* Clear and set up Events */
1346 KeClearEvent(&FileObject
->Event
);
1347 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1349 /* Allocate an IRP */
1350 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
1353 Irp
->UserEvent
= &Event
;
1354 Irp
->UserIosb
= &Irp
->IoStatus
;
1355 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1356 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1357 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
1359 /* Set up Stack Pointer Data */
1360 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1361 StackPtr
->MajorFunction
= IRP_MJ_CLOSE
;
1362 StackPtr
->FileObject
= FileObject
;
1365 IopQueueIrpToThread(Irp
);
1367 /* Get the VPB and check if this isn't a direct open */
1368 Vpb
= FileObject
->Vpb
;
1369 if ((Vpb
) && !(FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1371 /* Dereference the VPB before the close */
1372 InterlockedDecrement((PLONG
)&Vpb
->ReferenceCount
);
1375 /* Check if the FS will never disappear by itself */
1376 if (FileObject
->DeviceObject
->Flags
& DO_NEVER_LAST_DEVICE
)
1378 /* Dereference it */
1379 InterlockedDecrement(&FileObject
->DeviceObject
->ReferenceCount
);
1380 DereferenceDone
= TRUE
;
1383 /* Call the FS Driver */
1384 Status
= IoCallDriver(DeviceObject
, Irp
);
1385 if (Status
== STATUS_PENDING
)
1387 /* Wait for completion */
1388 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
1391 /* De-queue the IRP */
1392 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
1393 IopUnQueueIrpFromThread(Irp
);
1394 KeLowerIrql(OldIrql
);
1399 /* Clear the file name */
1400 if (FileObject
->FileName
.Buffer
)
1402 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
1403 FileObject
->FileName
.Buffer
= NULL
;
1406 /* Check if the FO had a completion port */
1407 if (FileObject
->CompletionContext
)
1410 ObDereferenceObject(FileObject
->CompletionContext
->Port
);
1411 ExFreePool(FileObject
->CompletionContext
);
1414 /* Check if the FO had extension */
1415 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
1417 /* Release filter context structure if any */
1418 FsRtlPTeardownPerFileObjectContexts(FileObject
);
1421 /* Check if dereference has been done yet */
1422 if (!DereferenceDone
)
1424 /* Dereference device object */
1425 IopDereferenceDeviceObject(FileObject
->DeviceObject
, FALSE
);
1432 IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject
)
1434 PDEVICE_OBJECT PDO
= DeviceObject
;
1436 /* Go down the stack to attempt to get the PDO */
1437 for (; ((PEXTENDED_DEVOBJ_EXTENSION
)PDO
->DeviceObjectExtension
)->AttachedTo
!= NULL
;
1438 PDO
= ((PEXTENDED_DEVOBJ_EXTENSION
)PDO
->DeviceObjectExtension
)->AttachedTo
);
1445 IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject
)
1450 ASSERT(DeviceObject
!= NULL
);
1452 OldIrql
= KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock
);
1453 /* Get the base DO */
1454 PDO
= IopGetDeviceAttachmentBase(DeviceObject
);
1455 /* Check whether that's really a PDO and if so, keep it */
1456 if ((PDO
->Flags
& DO_BUS_ENUMERATED_DEVICE
) != DO_BUS_ENUMERATED_DEVICE
)
1462 ObReferenceObject(PDO
);
1464 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock
, OldIrql
);
1471 IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject
,
1472 IN PSECURITY_INFORMATION SecurityInformation
,
1473 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1474 IN POOL_TYPE PoolType
,
1475 IN PGENERIC_MAPPING GenericMapping
)
1478 PSECURITY_DESCRIPTOR OldSecurityDescriptor
, CachedSecurityDescriptor
, NewSecurityDescriptor
;
1482 /* Keep attempting till we find our old SD or fail */
1485 KeEnterCriticalRegion();
1486 ExAcquireResourceSharedLite(&IopSecurityResource
, TRUE
);
1488 /* Get our old SD and reference it */
1489 OldSecurityDescriptor
= DeviceObject
->SecurityDescriptor
;
1490 if (OldSecurityDescriptor
!= NULL
)
1492 ObReferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1495 ExReleaseResourceLite(&IopSecurityResource
);
1496 KeLeaveCriticalRegion();
1498 /* Set the SD information */
1499 NewSecurityDescriptor
= OldSecurityDescriptor
;
1500 Status
= SeSetSecurityDescriptorInfo(NULL
, SecurityInformation
,
1501 SecurityDescriptor
, &NewSecurityDescriptor
,
1502 PoolType
, GenericMapping
);
1504 if (!NT_SUCCESS(Status
))
1506 if (OldSecurityDescriptor
!= NULL
)
1508 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1514 /* Add the new DS to the internal cache */
1515 Status
= ObLogSecurityDescriptor(NewSecurityDescriptor
,
1516 &CachedSecurityDescriptor
, 1);
1517 ExFreePool(NewSecurityDescriptor
);
1518 if (!NT_SUCCESS(Status
))
1520 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1524 KeEnterCriticalRegion();
1525 ExAcquireResourceExclusiveLite(&IopSecurityResource
, TRUE
);
1526 /* Check if someone changed it in our back */
1527 if (DeviceObject
->SecurityDescriptor
== OldSecurityDescriptor
)
1529 /* We're clear, do the swap */
1530 DeviceObject
->SecurityDescriptor
= CachedSecurityDescriptor
;
1531 ExReleaseResourceLite(&IopSecurityResource
);
1532 KeLeaveCriticalRegion();
1534 /* And dereference old SD (twice - us + not in use) */
1535 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 2);
1539 ExReleaseResourceLite(&IopSecurityResource
);
1540 KeLeaveCriticalRegion();
1542 /* If so, try again */
1543 ObDereferenceSecurityDescriptor(OldSecurityDescriptor
, 1);
1544 ObDereferenceSecurityDescriptor(CachedSecurityDescriptor
, 1);
1552 IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject
,
1553 IN PDEVICE_OBJECT PhysicalDeviceObject
,
1554 IN PSECURITY_INFORMATION SecurityInformation
,
1555 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1556 IN POOL_TYPE PoolType
,
1557 IN PGENERIC_MAPPING GenericMapping
)
1559 PDEVICE_OBJECT CurrentDO
= PhysicalDeviceObject
, NextDevice
;
1560 NTSTATUS Status
= STATUS_SUCCESS
, TmpStatus
;
1564 ASSERT(PhysicalDeviceObject
!= NULL
);
1566 /* We always reference the DO we're working on */
1567 ObReferenceObject(CurrentDO
);
1569 /* Go up from PDO to latest DO */
1572 /* Attempt to set the new SD on it */
1573 TmpStatus
= IopSetDeviceSecurityDescriptor(CurrentDO
, SecurityInformation
,
1574 SecurityDescriptor
, PoolType
,
1576 /* Was our last one? Remember that status then */
1577 if (CurrentDO
== UpperDeviceObject
)
1582 /* Try to move to the next DO (and thus, reference it) */
1583 NextDevice
= CurrentDO
->AttachedDevice
;
1586 ObReferenceObject(NextDevice
);
1589 /* Dereference current DO and move to the next one */
1590 ObDereferenceObject(CurrentDO
);
1591 CurrentDO
= NextDevice
;
1593 while (CurrentDO
!= NULL
);
1600 IopGetSetSecurityObject(IN PVOID ObjectBody
,
1601 IN SECURITY_OPERATION_CODE OperationCode
,
1602 IN PSECURITY_INFORMATION SecurityInformation
,
1603 IN PSECURITY_DESCRIPTOR SecurityDescriptor
,
1604 IN OUT PULONG BufferLength
,
1605 IN OUT PSECURITY_DESCRIPTOR
*OldSecurityDescriptor
,
1606 IN POOL_TYPE PoolType
,
1607 IN OUT PGENERIC_MAPPING GenericMapping
)
1609 IO_STATUS_BLOCK IoStatusBlock
;
1610 PIO_STACK_LOCATION StackPtr
;
1611 PFILE_OBJECT FileObject
;
1612 PDEVICE_OBJECT DeviceObject
;
1614 BOOLEAN LocalEvent
= FALSE
;
1616 NTSTATUS Status
= STATUS_SUCCESS
;
1618 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1620 /* Check if this is a device or file */
1621 if (((PFILE_OBJECT
)ObjectBody
)->Type
== IO_TYPE_DEVICE
)
1624 DeviceObject
= (PDEVICE_OBJECT
)ObjectBody
;
1630 FileObject
= (PFILE_OBJECT
)ObjectBody
;
1632 /* Check if this is a direct open */
1633 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
1635 /* Get the Device Object */
1636 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
1640 /* Otherwise, use the direct device*/
1641 DeviceObject
= FileObject
->DeviceObject
;
1645 /* Check if the request was for a device object */
1646 if (!(FileObject
) ||
1647 (!(FileObject
->FileName
.Length
) && !(FileObject
->RelatedFileObject
)) ||
1648 (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
))
1650 /* Check what kind of request this was */
1651 if (OperationCode
== QuerySecurityDescriptor
)
1653 return SeQuerySecurityDescriptorInfo(SecurityInformation
,
1656 &DeviceObject
->SecurityDescriptor
);
1658 else if (OperationCode
== DeleteSecurityDescriptor
)
1660 /* Simply return success */
1661 return STATUS_SUCCESS
;
1663 else if (OperationCode
== AssignSecurityDescriptor
)
1665 Status
= STATUS_SUCCESS
;
1667 /* Make absolutely sure this is a device object */
1668 if (!(FileObject
) || !(FileObject
->Flags
& FO_STREAM_FILE
))
1670 PSECURITY_DESCRIPTOR CachedSecurityDescriptor
;
1672 /* Add the security descriptor in cache */
1673 Status
= ObLogSecurityDescriptor(SecurityDescriptor
, &CachedSecurityDescriptor
, 1);
1674 if (NT_SUCCESS(Status
))
1676 KeEnterCriticalRegion();
1677 ExAcquireResourceExclusiveLite(&IopSecurityResource
, TRUE
);
1679 /* Assign the Security Descriptor */
1680 DeviceObject
->SecurityDescriptor
= CachedSecurityDescriptor
;
1682 ExReleaseResourceLite(&IopSecurityResource
);
1683 KeLeaveCriticalRegion();
1690 else if (OperationCode
== SetSecurityDescriptor
)
1692 /* Get the Physical Device Object if any */
1693 PDEVICE_OBJECT PDO
= IopGetDevicePDO(DeviceObject
);
1697 /* Apply the new SD to any DO in the path from PDO to current DO */
1698 Status
= IopSetDeviceSecurityDescriptors(DeviceObject
, PDO
,
1699 SecurityInformation
,
1701 PoolType
, GenericMapping
);
1702 ObDereferenceObject(PDO
);
1706 /* Otherwise, just set for ourselves */
1707 Status
= IopSetDeviceSecurityDescriptor(DeviceObject
,
1708 SecurityInformation
,
1710 PoolType
, GenericMapping
);
1713 return STATUS_SUCCESS
;
1716 /* Shouldn't happen */
1717 return STATUS_SUCCESS
;
1719 else if (OperationCode
== DeleteSecurityDescriptor
)
1721 /* Same as for devices, do nothing */
1722 return STATUS_SUCCESS
;
1725 /* At this point, we know we're a file. Reference it */
1726 ObReferenceObject(FileObject
);
1728 /* Check if we should use Sync IO or not */
1729 if (FileObject
->Flags
& FO_SYNCHRONOUS_IO
)
1731 /* Lock the file object */
1732 Status
= IopLockFileObject(FileObject
, ExGetPreviousMode());
1733 if (Status
!= STATUS_SUCCESS
)
1735 ObDereferenceObject(FileObject
);
1741 /* Use local event */
1742 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
1746 /* Clear the File Object event */
1747 KeClearEvent(&FileObject
->Event
);
1749 /* Get the device object */
1750 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1752 /* Allocate the IRP */
1753 Irp
= IoAllocateIrp(DeviceObject
->StackSize
, FALSE
);
1754 if (!Irp
) return IopCleanupFailedIrp(FileObject
, NULL
, NULL
);
1757 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1758 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1759 Irp
->RequestorMode
= ExGetPreviousMode();
1760 Irp
->UserIosb
= &IoStatusBlock
;
1761 Irp
->UserEvent
= (LocalEvent
) ? &Event
: NULL
;
1762 Irp
->Flags
= (LocalEvent
) ? IRP_SYNCHRONOUS_API
: 0;
1763 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
1765 /* Set Stack Parameters */
1766 StackPtr
= IoGetNextIrpStackLocation(Irp
);
1767 StackPtr
->FileObject
= FileObject
;
1769 /* Check if this is a query or set */
1770 if (OperationCode
== QuerySecurityDescriptor
)
1772 /* Set the major function and parameters */
1773 StackPtr
->MajorFunction
= IRP_MJ_QUERY_SECURITY
;
1774 StackPtr
->Parameters
.QuerySecurity
.SecurityInformation
=
1775 *SecurityInformation
;
1776 StackPtr
->Parameters
.QuerySecurity
.Length
= *BufferLength
;
1777 Irp
->UserBuffer
= SecurityDescriptor
;
1781 /* Set the major function and parameters for a set */
1782 StackPtr
->MajorFunction
= IRP_MJ_SET_SECURITY
;
1783 StackPtr
->Parameters
.SetSecurity
.SecurityInformation
=
1784 *SecurityInformation
;
1785 StackPtr
->Parameters
.SetSecurity
.SecurityDescriptor
=
1790 IopQueueIrpToThread(Irp
);
1792 /* Update operation counts */
1793 IopUpdateOperationCount(IopOtherTransfer
);
1795 /* Call the Driver */
1796 Status
= IoCallDriver(DeviceObject
, Irp
);
1798 /* Check if this was async I/O */
1801 /* Check if the IRP is pending completion */
1802 if (Status
== STATUS_PENDING
)
1804 /* Wait on the local event */
1805 KeWaitForSingleObject(&Event
,
1810 Status
= IoStatusBlock
.Status
;
1815 /* Check if the IRP is pending completion */
1816 if (Status
== STATUS_PENDING
)
1818 /* Wait on the file object */
1819 KeWaitForSingleObject(&FileObject
->Event
,
1824 Status
= FileObject
->FinalStatus
;
1827 /* Release the lock */
1828 IopUnlockFileObject(FileObject
);
1831 /* This Driver doesn't implement Security, so try to give it a default */
1832 if (Status
== STATUS_INVALID_DEVICE_REQUEST
)
1834 /* Was this a query? */
1835 if (OperationCode
== QuerySecurityDescriptor
)
1837 /* Set a World Security Descriptor */
1838 Status
= SeSetWorldSecurityDescriptor(*SecurityInformation
,
1844 /* It wasn't a query, so just fake success */
1845 Status
= STATUS_SUCCESS
;
1848 else if (OperationCode
== QuerySecurityDescriptor
)
1850 /* Callers usually expect the normalized form */
1851 if (Status
== STATUS_BUFFER_OVERFLOW
) Status
= STATUS_BUFFER_TOO_SMALL
;
1856 *BufferLength
= (ULONG
)IoStatusBlock
.Information
;
1858 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1860 /* Get the exception code */
1861 Status
= _SEH2_GetExceptionCode();
1872 IopQueryName(IN PVOID ObjectBody
,
1874 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1876 OUT PULONG ReturnLength
,
1877 IN KPROCESSOR_MODE PreviousMode
)
1879 return IopQueryNameInternal(ObjectBody
,
1890 IopQueryNameInternal(IN PVOID ObjectBody
,
1892 IN BOOLEAN QueryDosName
,
1893 OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
1895 OUT PULONG ReturnLength
,
1896 IN KPROCESSOR_MODE PreviousMode
)
1898 POBJECT_NAME_INFORMATION LocalInfo
;
1899 PFILE_NAME_INFORMATION LocalFileInfo
;
1900 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
1901 ULONG LocalReturnLength
, FileLength
;
1902 BOOLEAN LengthMismatch
= FALSE
;
1905 PDEVICE_OBJECT DeviceObject
;
1908 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
1910 /* Validate length */
1911 if (Length
< sizeof(OBJECT_NAME_INFORMATION
))
1913 /* Wrong length, fail */
1914 *ReturnLength
= sizeof(OBJECT_NAME_INFORMATION
);
1915 return STATUS_INFO_LENGTH_MISMATCH
;
1918 /* Allocate Buffer */
1919 LocalInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_IO
);
1920 if (!LocalInfo
) return STATUS_INSUFFICIENT_RESOURCES
;
1922 /* Query DOS name if the caller asked to */
1926 DeviceObject
= FileObject
->DeviceObject
;
1928 /* In case of a network file system, don't call mountmgr */
1929 if (DeviceObject
->DeviceType
== FILE_DEVICE_NETWORK_FILE_SYSTEM
)
1931 /* We'll store separator and terminator */
1932 LocalReturnLength
= sizeof(OBJECT_NAME_INFORMATION
) + 2 * sizeof(WCHAR
);
1933 if (Length
< LocalReturnLength
)
1935 Status
= STATUS_BUFFER_OVERFLOW
;
1939 LocalInfo
->Name
.Length
= sizeof(WCHAR
);
1940 LocalInfo
->Name
.MaximumLength
= sizeof(WCHAR
);
1941 LocalInfo
->Name
.Buffer
= (PVOID
)((ULONG_PTR
)LocalInfo
+ sizeof(OBJECT_NAME_INFORMATION
));
1942 LocalInfo
->Name
.Buffer
[0] = OBJ_NAME_PATH_SEPARATOR
;
1943 Status
= STATUS_SUCCESS
;
1946 /* Otherwise, call mountmgr to get DOS name */
1949 Status
= IoVolumeDeviceToDosName(DeviceObject
, &LocalInfo
->Name
);
1950 LocalReturnLength
= LocalInfo
->Name
.Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
1954 /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
1955 if (!QueryDosName
|| !NT_SUCCESS(Status
))
1957 /* Query the name */
1958 Status
= ObQueryNameString(FileObject
->DeviceObject
,
1961 &LocalReturnLength
);
1968 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_INFO_LENGTH_MISMATCH
))
1970 /* Free the buffer and fail */
1971 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
1975 /* Get buffer pointer */
1976 p
= (PWCHAR
)(ObjectNameInfo
+ 1);
1978 /* Copy the information */
1979 if (QueryDosName
&& NoObCall
)
1981 ASSERT(PreviousMode
== KernelMode
);
1983 /* Copy structure first */
1984 RtlCopyMemory(ObjectNameInfo
,
1986 (Length
>= LocalReturnLength
? sizeof(OBJECT_NAME_INFORMATION
) : Length
));
1988 RtlCopyMemory(p
, LocalInfo
->Name
.Buffer
,
1989 (Length
>= LocalReturnLength
? LocalInfo
->Name
.Length
: Length
- sizeof(OBJECT_NAME_INFORMATION
)));
1991 if (FileObject
->DeviceObject
->DeviceType
!= FILE_DEVICE_NETWORK_FILE_SYSTEM
)
1993 ExFreePool(LocalInfo
->Name
.Buffer
);
1998 RtlCopyMemory(ObjectNameInfo
,
2000 (LocalReturnLength
> Length
) ?
2001 Length
: LocalReturnLength
);
2004 /* Set buffer pointer */
2005 ObjectNameInfo
->Name
.Buffer
= p
;
2007 /* Advance in buffer */
2008 p
+= (LocalInfo
->Name
.Length
/ sizeof(WCHAR
));
2010 /* Check if this already filled our buffer */
2011 if (LocalReturnLength
> Length
)
2013 /* Set the length mismatch to true, so that we can return
2014 * the proper buffer size to the caller later
2016 LengthMismatch
= TRUE
;
2018 /* Save the initial buffer length value */
2019 *ReturnLength
= LocalReturnLength
;
2022 /* Now get the file name buffer and check the length needed */
2023 LocalFileInfo
= (PFILE_NAME_INFORMATION
)LocalInfo
;
2024 FileLength
= Length
-
2026 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2028 /* Query the File name */
2029 if (PreviousMode
== KernelMode
&&
2030 BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2032 Status
= IopGetFileInformation(FileObject
,
2033 LengthMismatch
? Length
: FileLength
,
2034 FileNameInformation
,
2036 &LocalReturnLength
);
2040 Status
= IoQueryFileInformation(FileObject
,
2041 FileNameInformation
,
2042 LengthMismatch
? Length
: FileLength
,
2044 &LocalReturnLength
);
2046 if (NT_ERROR(Status
))
2048 /* Allow status that would mean it's not implemented in the storage stack */
2049 if (Status
!= STATUS_INVALID_PARAMETER
&& Status
!= STATUS_INVALID_DEVICE_REQUEST
&&
2050 Status
!= STATUS_NOT_IMPLEMENTED
&& Status
!= STATUS_INVALID_INFO_CLASS
)
2052 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
2056 /* In such case, zero output */
2057 LocalReturnLength
= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2058 LocalFileInfo
->FileNameLength
= 0;
2059 LocalFileInfo
->FileName
[0] = OBJ_NAME_PATH_SEPARATOR
;
2063 /* We'll at least return the name length */
2064 if (LocalReturnLength
< FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
))
2066 LocalReturnLength
= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2070 /* If the provided buffer is too small, return the required size */
2073 /* Add the required length */
2074 *ReturnLength
+= LocalFileInfo
->FileNameLength
;
2076 /* Free the allocated buffer and return failure */
2077 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
2078 return STATUS_BUFFER_OVERFLOW
;
2081 /* Now calculate the new lengths left */
2082 FileLength
= LocalReturnLength
-
2083 FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
2084 LocalReturnLength
= (ULONG
)((ULONG_PTR
)p
-
2085 (ULONG_PTR
)ObjectNameInfo
+
2086 LocalFileInfo
->FileNameLength
);
2088 /* Don't copy the name if it's not valid */
2089 if (LocalFileInfo
->FileName
[0] != OBJ_NAME_PATH_SEPARATOR
)
2091 /* Free the allocated buffer and return failure */
2092 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
2093 return STATUS_OBJECT_PATH_INVALID
;
2096 /* Write the Name and null-terminate it */
2097 RtlCopyMemory(p
, LocalFileInfo
->FileName
, FileLength
);
2098 p
+= (FileLength
/ sizeof(WCHAR
));
2100 LocalReturnLength
+= sizeof(UNICODE_NULL
);
2102 /* Return the length needed */
2103 *ReturnLength
= LocalReturnLength
;
2105 /* Setup the length and maximum length */
2106 FileLength
= (ULONG
)((ULONG_PTR
)p
- (ULONG_PTR
)ObjectNameInfo
);
2107 ObjectNameInfo
->Name
.Length
= (USHORT
)FileLength
-
2108 sizeof(OBJECT_NAME_INFORMATION
);
2109 ObjectNameInfo
->Name
.MaximumLength
= (USHORT
)ObjectNameInfo
->Name
.Length
+
2110 sizeof(UNICODE_NULL
);
2112 /* Free buffer and return */
2113 ExFreePoolWithTag(LocalInfo
, TAG_IO
);
2119 IopCloseFile(IN PEPROCESS Process OPTIONAL
,
2120 IN PVOID ObjectBody
,
2121 IN ACCESS_MASK GrantedAccess
,
2122 IN ULONG HandleCount
,
2123 IN ULONG SystemHandleCount
)
2125 PFILE_OBJECT FileObject
= (PFILE_OBJECT
)ObjectBody
;
2128 PIO_STACK_LOCATION StackPtr
;
2130 PDEVICE_OBJECT DeviceObject
;
2132 IO_STATUS_BLOCK IoStatusBlock
;
2133 IOTRACE(IO_FILE_DEBUG
, "ObjectBody: %p\n", ObjectBody
);
2135 /* If this isn't the last handle for the current process, quit */
2136 if (HandleCount
!= 1) return;
2138 /* Check if the file is locked and has more then one handle opened */
2139 if ((FileObject
->LockOperation
) && (SystemHandleCount
!= 1))
2141 /* Check if this is a direct open or not */
2142 if (BooleanFlagOn(FileObject
->Flags
, FO_DIRECT_DEVICE_OPEN
))
2144 /* Get the attached device */
2145 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
2149 /* Get the FO's device */
2150 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
2153 /* Check if this is a sync FO and lock it */
2154 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2156 (VOID
)IopLockFileObject(FileObject
, KernelMode
);
2159 /* Go the FastIO path if possible, otherwise fall back to IRP */
2160 if (DeviceObject
->DriverObject
->FastIoDispatch
== NULL
||
2161 DeviceObject
->DriverObject
->FastIoDispatch
->FastIoUnlockAll
== NULL
||
2162 !DeviceObject
->DriverObject
->FastIoDispatch
->FastIoUnlockAll(FileObject
, PsGetCurrentProcess(), &IoStatusBlock
, DeviceObject
))
2164 /* Clear and set up Events */
2165 KeClearEvent(&FileObject
->Event
);
2166 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
2168 /* Allocate an IRP */
2169 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
2172 Irp
->UserEvent
= &Event
;
2173 Irp
->UserIosb
= &Irp
->IoStatus
;
2174 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
2175 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
2176 Irp
->RequestorMode
= KernelMode
;
2177 Irp
->Flags
= IRP_SYNCHRONOUS_API
;
2178 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
2179 ObReferenceObject(FileObject
);
2181 /* Set up Stack Pointer Data */
2182 StackPtr
= IoGetNextIrpStackLocation(Irp
);
2183 StackPtr
->MajorFunction
= IRP_MJ_LOCK_CONTROL
;
2184 StackPtr
->MinorFunction
= IRP_MN_UNLOCK_ALL
;
2185 StackPtr
->FileObject
= FileObject
;
2188 IopQueueIrpToThread(Irp
);
2190 /* Call the FS Driver */
2191 Status
= IoCallDriver(DeviceObject
, Irp
);
2192 if (Status
== STATUS_PENDING
)
2194 /* Wait for completion */
2195 KeWaitForSingleObject(&Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
2198 /* IO will unqueue & free for us */
2201 /* Release the lock if we were holding it */
2202 if (BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2204 IopUnlockFileObject(FileObject
);
2208 /* Make sure this is the last handle */
2209 if (SystemHandleCount
!= 1) return;
2211 /* Check if this is a direct open or not */
2212 if (FileObject
->Flags
& FO_DIRECT_DEVICE_OPEN
)
2214 /* Get the attached device */
2215 DeviceObject
= IoGetAttachedDevice(FileObject
->DeviceObject
);
2219 /* Get the FO's device */
2220 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
2223 /* Set the handle created flag */
2224 FileObject
->Flags
|= FO_HANDLE_CREATED
;
2226 /* Check if this is a sync FO and lock it */
2227 if (Process
!= NULL
&&
2228 BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2230 (VOID
)IopLockFileObject(FileObject
, KernelMode
);
2233 /* Clear and set up Events */
2234 KeClearEvent(&FileObject
->Event
);
2235 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
2237 /* Allocate an IRP */
2238 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
2241 Irp
->UserEvent
= &Event
;
2242 Irp
->UserIosb
= &Irp
->IoStatus
;
2243 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
2244 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
2245 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
2246 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
2248 /* Set up Stack Pointer Data */
2249 StackPtr
= IoGetNextIrpStackLocation(Irp
);
2250 StackPtr
->MajorFunction
= IRP_MJ_CLEANUP
;
2251 StackPtr
->FileObject
= FileObject
;
2254 IopQueueIrpToThread(Irp
);
2256 /* Update operation counts */
2257 IopUpdateOperationCount(IopOtherTransfer
);
2259 /* Call the FS Driver */
2260 Status
= IoCallDriver(DeviceObject
, Irp
);
2261 if (Status
== STATUS_PENDING
)
2263 /* Wait for completion */
2264 KeWaitForSingleObject(&Event
, UserRequest
, KernelMode
, FALSE
, NULL
);
2267 /* Unqueue the IRP */
2268 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
2269 IopUnQueueIrpFromThread(Irp
);
2270 KeLowerIrql(OldIrql
);
2275 /* Release the lock if we were holding it */
2276 if (Process
!= NULL
&&
2277 BooleanFlagOn(FileObject
->Flags
, FO_SYNCHRONOUS_IO
))
2279 IopUnlockFileObject(FileObject
);
2285 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
2286 IN FILE_INFORMATION_CLASS FileInformationClass
,
2287 IN ULONG FileInformationSize
,
2288 OUT PVOID FileInformation
)
2291 KPROCESSOR_MODE AccessMode
= ExGetPreviousMode();
2292 DUMMY_FILE_OBJECT LocalFileObject
;
2293 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo
;
2295 OPEN_PACKET OpenPacket
;
2298 IOTRACE(IO_FILE_DEBUG
, "Class: %lx\n", FileInformationClass
);
2300 /* Check if the caller was user mode */
2301 if (AccessMode
!= KernelMode
)
2303 /* Protect probe in SEH */
2306 /* Probe the buffer */
2307 ProbeForWrite(FileInformation
, FileInformationSize
, sizeof(ULONG
));
2309 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2311 /* Return the exception code */
2312 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2317 /* Check if this is a basic or full request */
2318 IsBasic
= (FileInformationSize
== sizeof(FILE_BASIC_INFORMATION
));
2320 /* Setup the Open Packet */
2321 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
2322 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
2323 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
2324 OpenPacket
.CreateOptions
= FILE_OPEN_REPARSE_POINT
;
2325 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
2326 OpenPacket
.Disposition
= FILE_OPEN
;
2327 OpenPacket
.BasicInformation
= IsBasic
? FileInformation
: NULL
;
2328 OpenPacket
.NetworkInformation
= IsBasic
? &NetworkOpenInfo
:
2329 (AccessMode
!= KernelMode
) ?
2330 &NetworkOpenInfo
: FileInformation
;
2331 OpenPacket
.QueryOnly
= TRUE
;
2332 OpenPacket
.FullAttributes
= IsBasic
? FALSE
: TRUE
;
2333 OpenPacket
.LocalFileObject
= &LocalFileObject
;
2335 /* Update the operation count */
2336 IopUpdateOperationCount(IopOtherTransfer
);
2339 * Attempt opening the file. This will call the I/O Parse Routine for
2340 * the File Object (IopParseDevice) which will use the dummy file obejct
2341 * send the IRP to its device object. Note that we have two statuses
2342 * to worry about: the Object Manager's status (in Status) and the I/O
2343 * status, which is in the Open Packet's Final Status, and determined
2344 * by the Parse Check member.
2346 Status
= ObOpenObjectByName(ObjectAttributes
,
2350 FILE_READ_ATTRIBUTES
,
2353 if (OpenPacket
.ParseCheck
== FALSE
)
2356 DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2357 ObjectAttributes
->ObjectName
, Status
);
2362 /* Use the Io status */
2363 Status
= OpenPacket
.FinalStatus
;
2366 /* Check if we were succesful and this was user mode and a full query */
2367 if ((NT_SUCCESS(Status
)) && (AccessMode
!= KernelMode
) && !(IsBasic
))
2369 /* Enter SEH for copy */
2372 /* Copy the buffer back */
2373 RtlCopyMemory(FileInformation
,
2375 FileInformationSize
);
2377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2379 /* Get exception code */
2380 Status
= _SEH2_GetExceptionCode();
2391 IopAcquireFileObjectLock(
2392 _In_ PFILE_OBJECT FileObject
,
2393 _In_ KPROCESSOR_MODE WaitMode
,
2394 _In_ BOOLEAN Alertable
,
2395 _Out_ PBOOLEAN LockFailed
)
2401 InterlockedIncrement((PLONG
)&FileObject
->Waiters
);
2403 Status
= STATUS_SUCCESS
;
2406 if (!InterlockedExchange((PLONG
)&FileObject
->Busy
, TRUE
))
2410 Status
= KeWaitForSingleObject(&FileObject
->Lock
,
2415 } while (Status
== STATUS_SUCCESS
);
2417 InterlockedDecrement((PLONG
)&FileObject
->Waiters
);
2418 if (Status
== STATUS_SUCCESS
)
2420 ObReferenceObject(FileObject
);
2421 *LockFailed
= FALSE
;
2425 if (!FileObject
->Busy
&& FileObject
->Waiters
)
2427 KeSetEvent(&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2437 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject
)
2439 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
2442 /* FIXME: return NULL for the moment ~ */
2451 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject
,
2452 IN PVOID FilterContext
,
2455 if (!(FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
))
2457 return STATUS_INVALID_PARAMETER
;
2462 return STATUS_NOT_IMPLEMENTED
;
2467 IopCreateFile(OUT PHANDLE FileHandle
,
2468 IN ACCESS_MASK DesiredAccess
,
2469 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2470 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2471 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
2472 IN ULONG FileAttributes
,
2473 IN ULONG ShareAccess
,
2474 IN ULONG Disposition
,
2475 IN ULONG CreateOptions
,
2476 IN PVOID EaBuffer OPTIONAL
,
2478 IN CREATE_FILE_TYPE CreateFileType
,
2479 IN PVOID ExtraCreateParameters OPTIONAL
,
2482 IN PDEVICE_OBJECT DeviceObject OPTIONAL
)
2484 KPROCESSOR_MODE AccessMode
;
2485 HANDLE LocalHandle
= 0;
2486 LARGE_INTEGER SafeAllocationSize
;
2487 NTSTATUS Status
= STATUS_SUCCESS
;
2488 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters
;
2489 POPEN_PACKET OpenPacket
;
2490 ULONG EaErrorOffset
;
2493 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
2496 /* Check if we have no parameter checking to do */
2497 if (Options
& IO_NO_PARAMETER_CHECKING
)
2499 /* Then force kernel-mode access to avoid checks */
2500 AccessMode
= KernelMode
;
2504 /* Otherwise, use the actual mode */
2505 AccessMode
= ExGetPreviousMode();
2508 /* Check if we need to do parameter checking */
2509 if ((AccessMode
!= KernelMode
) || (Options
& IO_CHECK_CREATE_PARAMETERS
))
2511 /* Validate parameters */
2512 if (FileAttributes
& ~FILE_ATTRIBUTE_VALID_FLAGS
)
2514 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2515 return STATUS_INVALID_PARAMETER
;
2518 if (ShareAccess
& ~FILE_SHARE_VALID_FLAGS
)
2520 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2521 return STATUS_INVALID_PARAMETER
;
2524 if (Disposition
> FILE_MAXIMUM_DISPOSITION
)
2526 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2527 return STATUS_INVALID_PARAMETER
;
2530 if (CreateOptions
& ~FILE_VALID_OPTION_FLAGS
)
2532 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2533 return STATUS_INVALID_PARAMETER
;
2536 if ((CreateOptions
& (FILE_SYNCHRONOUS_IO_ALERT
| FILE_SYNCHRONOUS_IO_NONALERT
)) &&
2537 (!(DesiredAccess
& SYNCHRONIZE
)))
2539 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2540 return STATUS_INVALID_PARAMETER
;
2543 if ((CreateOptions
& FILE_DELETE_ON_CLOSE
) && (!(DesiredAccess
& DELETE
)))
2545 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2546 return STATUS_INVALID_PARAMETER
;
2549 if ((CreateOptions
& (FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SYNCHRONOUS_IO_ALERT
)) ==
2550 (FILE_SYNCHRONOUS_IO_NONALERT
| FILE_SYNCHRONOUS_IO_ALERT
))
2552 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2553 return STATUS_INVALID_PARAMETER
;
2556 if ((CreateOptions
& FILE_DIRECTORY_FILE
) && !(CreateOptions
& FILE_NON_DIRECTORY_FILE
) &&
2557 (CreateOptions
& ~(FILE_DIRECTORY_FILE
|
2558 FILE_SYNCHRONOUS_IO_ALERT
|
2559 FILE_SYNCHRONOUS_IO_NONALERT
|
2560 FILE_WRITE_THROUGH
|
2561 FILE_COMPLETE_IF_OPLOCKED
|
2562 FILE_OPEN_FOR_BACKUP_INTENT
|
2563 FILE_DELETE_ON_CLOSE
|
2564 FILE_OPEN_FOR_FREE_SPACE_QUERY
|
2565 FILE_OPEN_BY_FILE_ID
|
2566 FILE_NO_COMPRESSION
|
2567 FILE_OPEN_REPARSE_POINT
)))
2569 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2570 return STATUS_INVALID_PARAMETER
;
2573 if ((CreateOptions
& FILE_DIRECTORY_FILE
) && !(CreateOptions
& FILE_NON_DIRECTORY_FILE
) &&
2574 (Disposition
!= FILE_CREATE
) && (Disposition
!= FILE_OPEN
) && (Disposition
!= FILE_OPEN_IF
))
2576 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2577 return STATUS_INVALID_PARAMETER
;
2580 if ((CreateOptions
& FILE_COMPLETE_IF_OPLOCKED
) && (CreateOptions
& FILE_RESERVE_OPFILTER
))
2582 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2583 return STATUS_INVALID_PARAMETER
;
2586 if ((CreateOptions
& FILE_NO_INTERMEDIATE_BUFFERING
) && (DesiredAccess
& FILE_APPEND_DATA
))
2588 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2589 return STATUS_INVALID_PARAMETER
;
2592 /* Now check if this is a named pipe */
2593 if (CreateFileType
== CreateFileTypeNamedPipe
)
2595 /* Make sure we have extra parameters */
2596 if (!ExtraCreateParameters
)
2598 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2599 return STATUS_INVALID_PARAMETER
;
2602 /* Get the parameters and validate them */
2603 NamedPipeCreateParameters
= ExtraCreateParameters
;
2604 if ((NamedPipeCreateParameters
->NamedPipeType
> FILE_PIPE_MESSAGE_TYPE
) ||
2605 (NamedPipeCreateParameters
->ReadMode
> FILE_PIPE_MESSAGE_MODE
) ||
2606 (NamedPipeCreateParameters
->CompletionMode
> FILE_PIPE_COMPLETE_OPERATION
) ||
2607 (ShareAccess
& FILE_SHARE_DELETE
) ||
2608 ((Disposition
< FILE_OPEN
) || (Disposition
> FILE_OPEN_IF
)) ||
2609 (CreateOptions
& ~FILE_VALID_PIPE_OPTION_FLAGS
))
2611 /* Invalid named pipe create */
2612 DPRINT1("Invalid named pipe create\n");
2613 return STATUS_INVALID_PARAMETER
;
2616 else if (CreateFileType
== CreateFileTypeMailslot
)
2618 /* Make sure we have extra parameters */
2619 if (!ExtraCreateParameters
)
2621 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2622 return STATUS_INVALID_PARAMETER
;
2625 /* Get the parameters and validate them */
2626 if ((ShareAccess
& FILE_SHARE_DELETE
) ||
2627 !(ShareAccess
& ~FILE_SHARE_WRITE
) ||
2628 (Disposition
!= FILE_CREATE
) ||
2629 (CreateOptions
& ~FILE_VALID_MAILSLOT_OPTION_FLAGS
))
2631 /* Invalid mailslot create */
2632 DPRINT1("Invalid mailslot create\n");
2633 return STATUS_INVALID_PARAMETER
;
2638 /* Allocate the open packet */
2639 OpenPacket
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*OpenPacket
), 'pOoI');
2640 if (!OpenPacket
) return STATUS_INSUFFICIENT_RESOURCES
;
2641 RtlZeroMemory(OpenPacket
, sizeof(*OpenPacket
));
2643 /* Check if the call came from user mode */
2644 if (AccessMode
!= KernelMode
)
2648 /* Probe the output parameters */
2649 ProbeForWriteHandle(FileHandle
);
2650 ProbeForWriteIoStatusBlock(IoStatusBlock
);
2652 /* Probe the allocation size if one was passed in */
2655 SafeAllocationSize
= ProbeForReadLargeInteger(AllocationSize
);
2659 SafeAllocationSize
.QuadPart
= 0;
2662 /* Make sure it's valid */
2663 if (SafeAllocationSize
.QuadPart
< 0)
2665 RtlRaiseStatus(STATUS_INVALID_PARAMETER
);
2668 /* Check if EA was passed in */
2669 if ((EaBuffer
) && (EaLength
))
2672 ProbeForRead(EaBuffer
, EaLength
, sizeof(ULONG
));
2674 /* And marshall it */
2675 OpenPacket
->EaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
2678 OpenPacket
->EaLength
= EaLength
;
2679 RtlCopyMemory(OpenPacket
->EaBuffer
, EaBuffer
, EaLength
);
2681 /* Validate the buffer */
2682 Status
= IoCheckEaBufferValidity(OpenPacket
->EaBuffer
,
2685 if (!NT_SUCCESS(Status
))
2687 /* Undo everything if it's invalid */
2688 DPRINT1("Invalid EA buffer\n");
2689 IoStatusBlock
->Status
= Status
;
2690 IoStatusBlock
->Information
= EaErrorOffset
;
2691 RtlRaiseStatus(Status
);
2695 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2697 /* Return the exception code */
2698 if (OpenPacket
->EaBuffer
!= NULL
) ExFreePool(OpenPacket
->EaBuffer
);
2699 ExFreePool(OpenPacket
);
2700 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2706 /* Check if this is a device attach */
2707 if (CreateOptions
& IO_ATTACH_DEVICE_API
)
2709 /* Set the flag properly */
2710 Options
|= IO_ATTACH_DEVICE
;
2711 CreateOptions
&= ~IO_ATTACH_DEVICE_API
;
2714 /* Check if we have allocation size */
2718 SafeAllocationSize
= *AllocationSize
;
2722 /* Otherwise, no size */
2723 SafeAllocationSize
.QuadPart
= 0;
2726 /* Check if we have an EA packet */
2727 if ((EaBuffer
) && (EaLength
))
2729 /* Allocate the kernel copy */
2730 OpenPacket
->EaBuffer
= ExAllocatePoolWithTag(NonPagedPool
,
2733 if (!OpenPacket
->EaBuffer
)
2735 ExFreePool(OpenPacket
);
2736 DPRINT1("Failed to allocate open packet EA buffer\n");
2737 return STATUS_INSUFFICIENT_RESOURCES
;
2741 OpenPacket
->EaLength
= EaLength
;
2742 RtlCopyMemory(OpenPacket
->EaBuffer
, EaBuffer
, EaLength
);
2744 /* Validate the buffer */
2745 Status
= IoCheckEaBufferValidity(OpenPacket
->EaBuffer
,
2748 if (!NT_SUCCESS(Status
))
2750 /* Undo everything if it's invalid */
2751 DPRINT1("Invalid EA buffer\n");
2752 ExFreePool(OpenPacket
->EaBuffer
);
2753 IoStatusBlock
->Status
= Status
;
2754 IoStatusBlock
->Information
= EaErrorOffset
;
2755 ExFreePool(OpenPacket
);
2761 /* Setup the Open Packet */
2762 OpenPacket
->Type
= IO_TYPE_OPEN_PACKET
;
2763 OpenPacket
->Size
= sizeof(*OpenPacket
);
2764 OpenPacket
->AllocationSize
= SafeAllocationSize
;
2765 OpenPacket
->CreateOptions
= CreateOptions
;
2766 OpenPacket
->FileAttributes
= (USHORT
)FileAttributes
;
2767 OpenPacket
->ShareAccess
= (USHORT
)ShareAccess
;
2768 OpenPacket
->Options
= Options
;
2769 OpenPacket
->Disposition
= Disposition
;
2770 OpenPacket
->CreateFileType
= CreateFileType
;
2771 OpenPacket
->ExtraCreateParameters
= ExtraCreateParameters
;
2772 OpenPacket
->InternalFlags
= Flags
;
2773 OpenPacket
->TopDeviceObjectHint
= DeviceObject
;
2775 /* Update the operation count */
2776 IopUpdateOperationCount(IopOtherTransfer
);
2779 * Attempt opening the file. This will call the I/O Parse Routine for
2780 * the File Object (IopParseDevice) which will create the object and
2781 * send the IRP to its device object. Note that we have two statuses
2782 * to worry about: the Object Manager's status (in Status) and the I/O
2783 * status, which is in the Open Packet's Final Status, and determined
2784 * by the Parse Check member.
2786 Status
= ObOpenObjectByName(ObjectAttributes
,
2794 /* Free the EA Buffer */
2795 if (OpenPacket
->EaBuffer
) ExFreePool(OpenPacket
->EaBuffer
);
2797 /* Now check for Ob or Io failure */
2798 if (!(NT_SUCCESS(Status
)) || (OpenPacket
->ParseCheck
== FALSE
))
2800 /* Check if Ob thinks well went well */
2801 if (NT_SUCCESS(Status
))
2804 * Tell it otherwise. Because we didn't use an ObjectType,
2805 * it incorrectly returned us a handle to God knows what.
2807 ZwClose(LocalHandle
);
2808 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
2811 /* Now check the Io status */
2812 if (!NT_SUCCESS(OpenPacket
->FinalStatus
))
2814 /* Use this status instead of Ob's */
2815 Status
= OpenPacket
->FinalStatus
;
2817 /* Check if it was only a warning */
2818 if (NT_WARNING(Status
))
2820 /* Protect write with SEH */
2823 /* In this case, we copy the I/O Status back */
2824 IoStatusBlock
->Information
= OpenPacket
->Information
;
2825 IoStatusBlock
->Status
= OpenPacket
->FinalStatus
;
2827 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2829 /* Get exception code */
2830 Status
= _SEH2_GetExceptionCode();
2835 else if ((OpenPacket
->FileObject
) && (OpenPacket
->ParseCheck
== FALSE
))
2838 * This can happen in the very bizarre case where the parse routine
2839 * actually executed more then once (due to a reparse) and ended
2840 * up failing after already having created the File Object.
2842 if (OpenPacket
->FileObject
->FileName
.Length
)
2844 /* It had a name, free it */
2845 ExFreePoolWithTag(OpenPacket
->FileObject
->FileName
.Buffer
, TAG_IO_NAME
);
2848 /* Clear the device object to invalidate the FO, and dereference */
2849 OpenPacket
->FileObject
->DeviceObject
= NULL
;
2850 ObDereferenceObject(OpenPacket
->FileObject
);
2855 /* We reached success and have a valid file handle */
2856 OpenPacket
->FileObject
->Flags
|= FO_HANDLE_CREATED
;
2857 ASSERT(OpenPacket
->FileObject
->Type
== IO_TYPE_FILE
);
2859 /* Enter SEH for write back */
2862 /* Write back the handle and I/O Status */
2863 *FileHandle
= LocalHandle
;
2864 IoStatusBlock
->Information
= OpenPacket
->Information
;
2865 IoStatusBlock
->Status
= OpenPacket
->FinalStatus
;
2867 /* Get the Io status */
2868 Status
= OpenPacket
->FinalStatus
;
2870 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2872 /* Get the exception status */
2873 Status
= _SEH2_GetExceptionCode();
2878 /* Check if we were 100% successful */
2879 if ((OpenPacket
->ParseCheck
!= FALSE
) && (OpenPacket
->FileObject
))
2881 /* Dereference the File Object */
2882 ObDereferenceObject(OpenPacket
->FileObject
);
2886 ExFreePool(OpenPacket
);
2890 /* FUNCTIONS *****************************************************************/
2897 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass
,
2899 IN BOOLEAN SetOperation
)
2902 return STATUS_NOT_IMPLEMENTED
;
2910 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer
,
2911 IN ULONG QuotaLength
,
2912 OUT PULONG ErrorOffset
)
2915 return STATUS_NOT_IMPLEMENTED
;
2923 IoCreateFile(OUT PHANDLE FileHandle
,
2924 IN ACCESS_MASK DesiredAccess
,
2925 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2926 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2927 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
2928 IN ULONG FileAttributes
,
2929 IN ULONG ShareAccess
,
2930 IN ULONG Disposition
,
2931 IN ULONG CreateOptions
,
2932 IN PVOID EaBuffer OPTIONAL
,
2934 IN CREATE_FILE_TYPE CreateFileType
,
2935 IN PVOID ExtraCreateParameters OPTIONAL
,
2940 return IopCreateFile(FileHandle
,
2952 ExtraCreateParameters
,
2963 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle
,
2964 IN ACCESS_MASK DesiredAccess
,
2965 IN POBJECT_ATTRIBUTES ObjectAttributes
,
2966 OUT PIO_STATUS_BLOCK IoStatusBlock
,
2967 IN PLARGE_INTEGER AllocationSize OPTIONAL
,
2968 IN ULONG FileAttributes
,
2969 IN ULONG ShareAccess
,
2970 IN ULONG Disposition
,
2971 IN ULONG CreateOptions
,
2972 IN PVOID EaBuffer OPTIONAL
,
2974 IN CREATE_FILE_TYPE CreateFileType
,
2975 IN PVOID ExtraCreateParameters OPTIONAL
,
2977 IN PVOID DeviceObject
)
2983 /* Check if we were passed a device to send the create request to*/
2986 /* We'll tag this request into a file object extension */
2987 Flags
= (IOP_CREATE_FILE_OBJECT_EXTENSION
| IOP_USE_TOP_LEVEL_DEVICE_HINT
);
2990 return IopCreateFile(FileHandle
,
3002 ExtraCreateParameters
,
3003 Options
| IO_NO_PARAMETER_CHECKING
,
3013 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL
,
3014 IN PDEVICE_OBJECT DeviceObject OPTIONAL
,
3015 OUT PHANDLE FileObjectHandle OPTIONAL
)
3017 PFILE_OBJECT CreatedFileObject
;
3020 OBJECT_ATTRIBUTES ObjectAttributes
;
3022 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
3024 /* Choose Device Object */
3025 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
3027 /* Reference the device object and initialize attributes */
3028 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
3029 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
3031 /* Create the File Object */
3032 Status
= ObCreateObject(KernelMode
,
3037 sizeof(FILE_OBJECT
),
3038 sizeof(FILE_OBJECT
),
3040 (PVOID
*)&CreatedFileObject
);
3041 if (!NT_SUCCESS(Status
))
3044 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
3045 ExRaiseStatus(Status
);
3048 /* Set File Object Data */
3049 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
3050 CreatedFileObject
->DeviceObject
= DeviceObject
;
3051 CreatedFileObject
->Type
= IO_TYPE_FILE
;
3052 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
3053 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
3055 /* Initialize the wait event */
3056 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
3058 /* Insert it to create a handle for it */
3059 Status
= ObInsertObject(CreatedFileObject
,
3063 (PVOID
*)&CreatedFileObject
,
3065 if (!NT_SUCCESS(Status
)) ExRaiseStatus(Status
);
3067 /* Set the handle created flag */
3068 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
3069 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
3071 /* Check if we have a VPB */
3072 if (DeviceObject
->Vpb
)
3075 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
3078 /* Check if the caller wants the handle */
3079 if (FileObjectHandle
)
3082 *FileObjectHandle
= FileHandle
;
3083 ObDereferenceObject(CreatedFileObject
);
3087 /* Otherwise, close it */
3088 ObCloseHandle(FileHandle
, KernelMode
);
3091 /* Return the file object */
3092 return CreatedFileObject
;
3100 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject
,
3101 IN PDEVICE_OBJECT DeviceObject
)
3103 /* Call the newer function */
3104 return IoCreateStreamFileObjectEx(FileObject
, DeviceObject
, NULL
);
3112 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL
,
3113 IN PDEVICE_OBJECT DeviceObject OPTIONAL
)
3115 PFILE_OBJECT CreatedFileObject
;
3117 OBJECT_ATTRIBUTES ObjectAttributes
;
3119 IOTRACE(IO_FILE_DEBUG
, "FileObject: %p\n", FileObject
);
3121 /* Choose Device Object */
3122 if (FileObject
) DeviceObject
= FileObject
->DeviceObject
;
3124 /* Reference the device object and initialize attributes */
3125 InterlockedIncrement(&DeviceObject
->ReferenceCount
);
3126 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
3128 /* Create the File Object */
3129 Status
= ObCreateObject(KernelMode
,
3134 sizeof(FILE_OBJECT
),
3135 sizeof(FILE_OBJECT
),
3137 (PVOID
*)&CreatedFileObject
);
3138 if (!NT_SUCCESS(Status
))
3141 IopDereferenceDeviceObject(DeviceObject
, FALSE
);
3142 ExRaiseStatus(Status
);
3145 /* Set File Object Data */
3146 RtlZeroMemory(CreatedFileObject
, sizeof(FILE_OBJECT
));
3147 CreatedFileObject
->DeviceObject
= DeviceObject
;
3148 CreatedFileObject
->Type
= IO_TYPE_FILE
;
3149 CreatedFileObject
->Size
= sizeof(FILE_OBJECT
);
3150 CreatedFileObject
->Flags
= FO_STREAM_FILE
;
3152 /* Initialize the wait event */
3153 KeInitializeEvent(&CreatedFileObject
->Event
, SynchronizationEvent
, FALSE
);
3155 /* Destroy create information */
3156 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->
3158 OBJECT_TO_OBJECT_HEADER(CreatedFileObject
)->ObjectCreateInfo
= NULL
;
3160 /* Set the handle created flag */
3161 CreatedFileObject
->Flags
|= FO_HANDLE_CREATED
;
3162 ASSERT(CreatedFileObject
->Type
== IO_TYPE_FILE
);
3164 /* Check if we have a VPB */
3165 if (DeviceObject
->Vpb
)
3168 InterlockedIncrement((PLONG
)&DeviceObject
->Vpb
->ReferenceCount
);
3171 /* Return the file object */
3172 return CreatedFileObject
;
3180 IoGetFileObjectGenericMapping(VOID
)
3182 /* Return the mapping */
3183 return &IopFileMapping
;
3191 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject
)
3193 /* Return the flag status */
3194 return FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
3202 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes
,
3203 IN ACCESS_MASK DesiredAccess
,
3204 IN ULONG OpenOptions
,
3205 OUT PIO_STATUS_BLOCK IoStatus
,
3206 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer
)
3209 DUMMY_FILE_OBJECT LocalFileObject
;
3211 OPEN_PACKET OpenPacket
;
3213 IOTRACE(IO_FILE_DEBUG
, "FileName: %wZ\n", ObjectAttributes
->ObjectName
);
3215 /* Setup the Open Packet */
3216 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
3217 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
3218 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
3219 OpenPacket
.CreateOptions
= OpenOptions
| FILE_OPEN_REPARSE_POINT
;
3220 OpenPacket
.ShareAccess
= FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
;
3221 OpenPacket
.Options
= IO_FORCE_ACCESS_CHECK
;
3222 OpenPacket
.Disposition
= FILE_OPEN
;
3223 OpenPacket
.NetworkInformation
= Buffer
;
3224 OpenPacket
.QueryOnly
= TRUE
;
3225 OpenPacket
.FullAttributes
= TRUE
;
3226 OpenPacket
.LocalFileObject
= &LocalFileObject
;
3229 * Attempt opening the file. This will call the I/O Parse Routine for
3230 * the File Object (IopParseDevice) which will use the dummy file obejct
3231 * send the IRP to its device object. Note that we have two statuses
3232 * to worry about: the Object Manager's status (in Status) and the I/O
3233 * status, which is in the Open Packet's Final Status, and determined
3234 * by the Parse Check member.
3236 Status
= ObOpenObjectByName(ObjectAttributes
,
3243 if (OpenPacket
.ParseCheck
== FALSE
)
3246 IoStatus
->Status
= Status
;
3250 /* Use the Io status */
3251 IoStatus
->Status
= OpenPacket
.FinalStatus
;
3252 IoStatus
->Information
= OpenPacket
.Information
;
3255 /* Return success */
3264 IoUpdateShareAccess(IN PFILE_OBJECT FileObject
,
3265 OUT PSHARE_ACCESS ShareAccess
)
3269 /* Check if the file has an extension */
3270 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3272 /* Check if caller specified to ignore access checks */
3273 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3275 /* Don't update share access */
3280 /* Otherwise, check if there's any access present */
3281 if ((FileObject
->ReadAccess
) ||
3282 (FileObject
->WriteAccess
) ||
3283 (FileObject
->DeleteAccess
))
3285 /* Increase the open count */
3286 ShareAccess
->OpenCount
++;
3288 /* Add new share access */
3289 ShareAccess
->Readers
+= FileObject
->ReadAccess
;
3290 ShareAccess
->Writers
+= FileObject
->WriteAccess
;
3291 ShareAccess
->Deleters
+= FileObject
->DeleteAccess
;
3292 ShareAccess
->SharedRead
+= FileObject
->SharedRead
;
3293 ShareAccess
->SharedWrite
+= FileObject
->SharedWrite
;
3294 ShareAccess
->SharedDelete
+= FileObject
->SharedDelete
;
3303 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess
,
3304 IN ULONG DesiredShareAccess
,
3305 IN PFILE_OBJECT FileObject
,
3306 IN PSHARE_ACCESS ShareAccess
,
3310 BOOLEAN WriteAccess
;
3311 BOOLEAN DeleteAccess
;
3313 BOOLEAN SharedWrite
;
3314 BOOLEAN SharedDelete
;
3317 /* Get access masks */
3318 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
3319 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
3320 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
3322 /* Set them in the file object */
3323 FileObject
->ReadAccess
= ReadAccess
;
3324 FileObject
->WriteAccess
= WriteAccess
;
3325 FileObject
->DeleteAccess
= DeleteAccess
;
3327 /* Check if the file has an extension */
3328 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3330 /* Check if caller specified to ignore access checks */
3331 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3333 /* Don't check share access */
3334 return STATUS_SUCCESS
;
3338 /* Check if we have any access */
3339 if ((ReadAccess
) || (WriteAccess
) || (DeleteAccess
))
3341 /* Get shared access masks */
3342 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
3343 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
3344 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
3347 FileObject
->SharedRead
= SharedRead
;
3348 FileObject
->SharedWrite
= SharedWrite
;
3349 FileObject
->SharedDelete
= SharedDelete
;
3351 /* Check if the shared access is violated */
3353 (ShareAccess
->SharedRead
< ShareAccess
->OpenCount
)) ||
3355 (ShareAccess
->SharedWrite
< ShareAccess
->OpenCount
)) ||
3357 (ShareAccess
->SharedDelete
< ShareAccess
->OpenCount
)) ||
3358 ((ShareAccess
->Readers
!= 0) && !SharedRead
) ||
3359 ((ShareAccess
->Writers
!= 0) && !SharedWrite
) ||
3360 ((ShareAccess
->Deleters
!= 0) && !SharedDelete
))
3362 /* Sharing violation, fail */
3363 return STATUS_SHARING_VIOLATION
;
3366 /* It's not, check if caller wants us to update it */
3369 /* Increase open count */
3370 ShareAccess
->OpenCount
++;
3372 /* Update shared access */
3373 ShareAccess
->Readers
+= ReadAccess
;
3374 ShareAccess
->Writers
+= WriteAccess
;
3375 ShareAccess
->Deleters
+= DeleteAccess
;
3376 ShareAccess
->SharedRead
+= SharedRead
;
3377 ShareAccess
->SharedWrite
+= SharedWrite
;
3378 ShareAccess
->SharedDelete
+= SharedDelete
;
3382 /* Validation successful */
3383 return STATUS_SUCCESS
;
3391 IoRemoveShareAccess(IN PFILE_OBJECT FileObject
,
3392 IN PSHARE_ACCESS ShareAccess
)
3396 /* Check if the file has an extension */
3397 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3399 /* Check if caller specified to ignore access checks */
3400 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3402 /* Don't update share access */
3407 /* Otherwise, check if there's any access present */
3408 if ((FileObject
->ReadAccess
) ||
3409 (FileObject
->WriteAccess
) ||
3410 (FileObject
->DeleteAccess
))
3412 /* Decrement the open count */
3413 ShareAccess
->OpenCount
--;
3415 /* Remove share access */
3416 ShareAccess
->Readers
-= FileObject
->ReadAccess
;
3417 ShareAccess
->Writers
-= FileObject
->WriteAccess
;
3418 ShareAccess
->Deleters
-= FileObject
->DeleteAccess
;
3419 ShareAccess
->SharedRead
-= FileObject
->SharedRead
;
3420 ShareAccess
->SharedWrite
-= FileObject
->SharedWrite
;
3421 ShareAccess
->SharedDelete
-= FileObject
->SharedDelete
;
3430 IoSetShareAccess(IN ACCESS_MASK DesiredAccess
,
3431 IN ULONG DesiredShareAccess
,
3432 IN PFILE_OBJECT FileObject
,
3433 OUT PSHARE_ACCESS ShareAccess
)
3436 BOOLEAN WriteAccess
;
3437 BOOLEAN DeleteAccess
;
3439 BOOLEAN SharedWrite
;
3440 BOOLEAN SharedDelete
;
3441 BOOLEAN Update
= TRUE
;
3444 ReadAccess
= (DesiredAccess
& (FILE_READ_DATA
| FILE_EXECUTE
)) != 0;
3445 WriteAccess
= (DesiredAccess
& (FILE_WRITE_DATA
| FILE_APPEND_DATA
)) != 0;
3446 DeleteAccess
= (DesiredAccess
& DELETE
) != 0;
3448 /* Check if the file has an extension */
3449 if (FileObject
->Flags
& FO_FILE_OBJECT_HAS_EXTENSION
)
3451 /* Check if caller specified to ignore access checks */
3452 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3454 /* Don't update share access */
3459 /* Update basic access */
3460 FileObject
->ReadAccess
= ReadAccess
;
3461 FileObject
->WriteAccess
= WriteAccess
;
3462 FileObject
->DeleteAccess
= DeleteAccess
;
3464 /* Check if we have no access as all */
3465 if (!(ReadAccess
) && !(WriteAccess
) && !(DeleteAccess
))
3467 /* Check if we need to update the structure */
3468 if (!Update
) return;
3470 /* Otherwise, clear data */
3471 ShareAccess
->OpenCount
= 0;
3472 ShareAccess
->Readers
= 0;
3473 ShareAccess
->Writers
= 0;
3474 ShareAccess
->Deleters
= 0;
3475 ShareAccess
->SharedRead
= 0;
3476 ShareAccess
->SharedWrite
= 0;
3477 ShareAccess
->SharedDelete
= 0;
3481 /* Calculate shared access */
3482 SharedRead
= (DesiredShareAccess
& FILE_SHARE_READ
) != 0;
3483 SharedWrite
= (DesiredShareAccess
& FILE_SHARE_WRITE
) != 0;
3484 SharedDelete
= (DesiredShareAccess
& FILE_SHARE_DELETE
) != 0;
3486 /* Set it in the FO */
3487 FileObject
->SharedRead
= SharedRead
;
3488 FileObject
->SharedWrite
= SharedWrite
;
3489 FileObject
->SharedDelete
= SharedDelete
;
3491 /* Check if we need to update the structure */
3492 if (!Update
) return;
3494 /* Otherwise, set data */
3495 ShareAccess
->OpenCount
= 1;
3496 ShareAccess
->Readers
= ReadAccess
;
3497 ShareAccess
->Writers
= WriteAccess
;
3498 ShareAccess
->Deleters
= DeleteAccess
;
3499 ShareAccess
->SharedRead
= SharedRead
;
3500 ShareAccess
->SharedWrite
= SharedWrite
;
3501 ShareAccess
->SharedDelete
= SharedDelete
;
3510 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject
,
3511 IN PFILE_OBJECT FileObject
)
3517 PIO_STACK_LOCATION Stack
;
3519 /* Check if handles were already created for the
3520 * open file. If so, that's over.
3522 if (FileObject
->Flags
& FO_HANDLE_CREATED
)
3523 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN
,
3524 (ULONG_PTR
)FileObject
,
3525 (ULONG_PTR
)DeviceObject
, 0, 0);
3527 /* Reset the events */
3528 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
3529 KeClearEvent(&FileObject
->Event
);
3531 /* Allocate the IRP we'll use */
3532 Irp
= IopAllocateIrpMustSucceed(DeviceObject
->StackSize
);
3533 /* Properly set it */
3534 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
3535 Irp
->UserEvent
= &Event
;
3536 Irp
->UserIosb
= &Irp
->IoStatus
;
3537 Irp
->Overlay
.AsynchronousParameters
.UserApcRoutine
= NULL
;
3538 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
3539 Irp
->RequestorMode
= KernelMode
;
3540 Irp
->Flags
= IRP_CLOSE_OPERATION
| IRP_SYNCHRONOUS_API
;
3542 Stack
= IoGetNextIrpStackLocation(Irp
);
3543 Stack
->MajorFunction
= IRP_MJ_CLEANUP
;
3544 Stack
->FileObject
= FileObject
;
3546 /* Put on top of IRPs list of the thread */
3547 IopQueueIrpToThread(Irp
);
3549 /* Call the driver */
3550 Status
= IoCallDriver(DeviceObject
, Irp
);
3551 if (Status
== STATUS_PENDING
)
3553 KeWaitForSingleObject(&Event
, UserRequest
,
3554 KernelMode
, FALSE
, NULL
);
3557 /* Remove from IRPs list */
3558 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
3559 IopUnQueueIrpFromThread(Irp
);
3560 KeLowerIrql(OldIrql
);
3565 /* Clear the event */
3566 KeClearEvent(&FileObject
->Event
);
3567 /* And finally, mark the open operation as canceled */
3568 FileObject
->Flags
|= FO_FILE_OPEN_CANCELLED
;
3576 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject
,
3577 OUT POBJECT_NAME_INFORMATION
*ObjectNameInformation
)
3580 ULONG Length
, ReturnLength
;
3581 POBJECT_NAME_INFORMATION LocalInfo
;
3583 /* Start with a buffer length of 200 */
3586 * We'll loop until query works.
3587 * We will use returned length for next loop
3588 * iteration, trying to have a big enough buffer.
3590 for (Length
= 200; ; Length
= ReturnLength
)
3592 /* Allocate our work buffer */
3593 LocalInfo
= ExAllocatePoolWithTag(PagedPool
, Length
, 'nDoI');
3594 if (LocalInfo
== NULL
)
3596 return STATUS_INSUFFICIENT_RESOURCES
;
3599 /* Query the DOS name */
3600 Status
= IopQueryNameInternal(FileObject
,
3607 /* If it succeed, nothing more to do */
3608 if (Status
== STATUS_SUCCESS
)
3613 /* Otherwise, prepare for re-allocation */
3614 ExFreePoolWithTag(LocalInfo
, 'nDoI');
3617 * If we failed because of something else
3618 * than memory, simply stop and fail here
3620 if (Status
!= STATUS_BUFFER_OVERFLOW
)
3622 return STATUS_BUFFER_OVERFLOW
;
3626 /* Success case here: return our buffer */
3627 *ObjectNameInformation
= LocalInfo
;
3628 return STATUS_SUCCESS
;
3636 IoSetFileOrigin(IN PFILE_OBJECT FileObject
,
3639 NTSTATUS Status
= STATUS_SUCCESS
;
3642 /* Get the flag status */
3643 FlagSet
= FileObject
->Flags
& FO_REMOTE_ORIGIN
? TRUE
: FALSE
;
3645 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
3646 if (Remote
&& !FlagSet
)
3649 FileObject
->Flags
|= FO_REMOTE_ORIGIN
;
3651 else if (!Remote
&& FlagSet
)
3653 /* Remove the flag */
3654 FileObject
->Flags
&= ~FO_REMOTE_ORIGIN
;
3659 Status
= STATUS_INVALID_PARAMETER_MIX
;
3671 NtCreateFile(PHANDLE FileHandle
,
3672 ACCESS_MASK DesiredAccess
,
3673 POBJECT_ATTRIBUTES ObjectAttributes
,
3674 PIO_STATUS_BLOCK IoStatusBlock
,
3675 PLARGE_INTEGER AllocateSize
,
3676 ULONG FileAttributes
,
3678 ULONG CreateDisposition
,
3679 ULONG CreateOptions
,
3683 /* Call the I/O Function */
3684 return IoCreateFile(FileHandle
,
3702 NtCreateMailslotFile(OUT PHANDLE FileHandle
,
3703 IN ACCESS_MASK DesiredAccess
,
3704 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3705 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3706 IN ULONG CreateOptions
,
3707 IN ULONG MailslotQuota
,
3708 IN ULONG MaxMessageSize
,
3709 IN PLARGE_INTEGER TimeOut
)
3711 MAILSLOT_CREATE_PARAMETERS Buffer
;
3714 /* Check for Timeout */
3717 /* check if the call came from user mode */
3718 if (KeGetPreviousMode() != KernelMode
)
3720 /* Enter SEH for Probe */
3723 /* Probe the timeout */
3724 Buffer
.ReadTimeout
= ProbeForReadLargeInteger(TimeOut
);
3726 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3728 /* Return the exception code */
3729 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3735 /* Otherwise, capture directly */
3736 Buffer
.ReadTimeout
= *TimeOut
;
3739 /* Set the correct setting */
3740 Buffer
.TimeoutSpecified
= TRUE
;
3744 /* Tell the FSD we don't have a timeout */
3745 Buffer
.TimeoutSpecified
= FALSE
;
3749 Buffer
.MailslotQuota
= MailslotQuota
;
3750 Buffer
.MaximumMessageSize
= MaxMessageSize
;
3753 return IoCreateFile(FileHandle
,
3759 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
3764 CreateFileTypeMailslot
,
3771 NtCreateNamedPipeFile(OUT PHANDLE FileHandle
,
3772 IN ACCESS_MASK DesiredAccess
,
3773 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3774 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3775 IN ULONG ShareAccess
,
3776 IN ULONG CreateDisposition
,
3777 IN ULONG CreateOptions
,
3778 IN ULONG NamedPipeType
,
3780 IN ULONG CompletionMode
,
3781 IN ULONG MaximumInstances
,
3782 IN ULONG InboundQuota
,
3783 IN ULONG OutboundQuota
,
3784 IN PLARGE_INTEGER DefaultTimeout
)
3786 NAMED_PIPE_CREATE_PARAMETERS Buffer
;
3789 /* Check for Timeout */
3792 /* check if the call came from user mode */
3793 if (KeGetPreviousMode() != KernelMode
)
3795 /* Enter SEH for Probe */
3798 /* Probe the timeout */
3799 Buffer
.DefaultTimeout
=
3800 ProbeForReadLargeInteger(DefaultTimeout
);
3802 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3804 /* Return the exception code */
3805 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3811 /* Otherwise, capture directly */
3812 Buffer
.DefaultTimeout
= *DefaultTimeout
;
3815 /* Set the correct setting */
3816 Buffer
.TimeoutSpecified
= TRUE
;
3820 /* Tell the FSD we don't have a timeout */
3821 Buffer
.TimeoutSpecified
= FALSE
;
3825 Buffer
.NamedPipeType
= NamedPipeType
;
3826 Buffer
.ReadMode
= ReadMode
;
3827 Buffer
.CompletionMode
= CompletionMode
;
3828 Buffer
.MaximumInstances
= MaximumInstances
;
3829 Buffer
.InboundQuota
= InboundQuota
;
3830 Buffer
.OutboundQuota
= OutboundQuota
;
3833 return IoCreateFile(FileHandle
,
3844 CreateFileTypeNamedPipe
,
3851 NtFlushWriteBuffer(VOID
)
3855 /* Call the kernel */
3856 KeFlushWriteBuffer();
3857 return STATUS_SUCCESS
;
3865 NtOpenFile(OUT PHANDLE FileHandle
,
3866 IN ACCESS_MASK DesiredAccess
,
3867 IN POBJECT_ATTRIBUTES ObjectAttributes
,
3868 OUT PIO_STATUS_BLOCK IoStatusBlock
,
3869 IN ULONG ShareAccess
,
3870 IN ULONG OpenOptions
)
3872 /* Call the I/O Function */
3873 return IoCreateFile(FileHandle
,
3891 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
3892 OUT PFILE_BASIC_INFORMATION FileInformation
)
3894 /* Call the internal helper API */
3895 return IopQueryAttributesFile(ObjectAttributes
,
3896 FileBasicInformation
,
3897 sizeof(FILE_BASIC_INFORMATION
),
3903 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes
,
3904 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation
)
3906 /* Call the internal helper API */
3907 return IopQueryAttributesFile(ObjectAttributes
,
3908 FileNetworkOpenInformation
,
3909 sizeof(FILE_NETWORK_OPEN_INFORMATION
),
3914 * @name NtCancelIoFile
3916 * Cancel all pending I/O operations in the current thread for specified
3920 * Handle to file object to cancel requests for. No specific
3921 * access rights are needed.
3922 * @param IoStatusBlock
3923 * Pointer to status block which is filled with final completition
3924 * status on successful return.
3932 NtCancelIoFile(IN HANDLE FileHandle
,
3933 OUT PIO_STATUS_BLOCK IoStatusBlock
)
3935 PFILE_OBJECT FileObject
;
3939 BOOLEAN OurIrpsInList
= FALSE
;
3940 LARGE_INTEGER Interval
;
3941 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
3943 PLIST_ENTRY ListHead
, NextEntry
;
3945 IOTRACE(IO_API_DEBUG
, "FileHandle: %p\n", FileHandle
);
3947 /* Check the previous mode */
3948 if (PreviousMode
!= KernelMode
)
3950 /* Enter SEH for probing */
3953 /* Probe the I/O Status Block */
3954 ProbeForWriteIoStatusBlock(IoStatusBlock
);
3956 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3958 /* Return the exception code */
3959 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3964 /* Reference the file object */
3965 Status
= ObReferenceObjectByHandle(FileHandle
,
3969 (PVOID
*)&FileObject
,
3971 if (!NT_SUCCESS(Status
)) return Status
;
3973 /* IRP cancellations are synchronized at APC_LEVEL. */
3974 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
3976 /* Get the current thread */
3977 Thread
= PsGetCurrentThread();
3979 /* Update the operation counts */
3980 IopUpdateOperationCount(IopOtherTransfer
);
3983 ListHead
= &Thread
->IrpList
;
3984 NextEntry
= ListHead
->Flink
;
3985 while (ListHead
!= NextEntry
)
3987 /* Get the IRP and check if the File Object matches */
3988 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
3989 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
3991 /* Cancel this IRP and keep looping */
3993 OurIrpsInList
= TRUE
;
3996 /* Go to the next entry */
3997 NextEntry
= NextEntry
->Flink
;
4000 /* Lower the IRQL */
4001 KeLowerIrql(OldIrql
);
4003 /* Check if we had found an IRP */
4006 /* Setup a 10ms wait */
4007 Interval
.QuadPart
= -100000;
4010 while (OurIrpsInList
)
4013 KeDelayExecutionThread(KernelMode
, FALSE
, &Interval
);
4014 OurIrpsInList
= FALSE
;
4017 KeRaiseIrql(APC_LEVEL
, &OldIrql
);
4019 /* Now loop the list again */
4020 NextEntry
= ListHead
->Flink
;
4021 while (NextEntry
!= ListHead
)
4023 /* Get the IRP and check if the File Object matches */
4024 Irp
= CONTAINING_RECORD(NextEntry
, IRP
, ThreadListEntry
);
4025 if (Irp
->Tail
.Overlay
.OriginalFileObject
== FileObject
)
4028 OurIrpsInList
= TRUE
;
4032 /* Go to the next entry */
4033 NextEntry
= NextEntry
->Flink
;
4036 /* Lower the IRQL */
4037 KeLowerIrql(OldIrql
);
4041 /* Enter SEH for writing back the I/O Status */
4045 IoStatusBlock
->Status
= STATUS_SUCCESS
;
4046 IoStatusBlock
->Information
= 0;
4048 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4050 /* Ignore exception */
4054 /* Dereference the file object and return success */
4055 ObDereferenceObject(FileObject
);
4056 return STATUS_SUCCESS
;
4064 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes
)
4067 DUMMY_FILE_OBJECT LocalFileObject
;
4069 KPROCESSOR_MODE AccessMode
= KeGetPreviousMode();
4070 OPEN_PACKET OpenPacket
;
4072 IOTRACE(IO_API_DEBUG
, "FileMame: %wZ\n", ObjectAttributes
->ObjectName
);
4074 /* Setup the Open Packet */
4075 RtlZeroMemory(&OpenPacket
, sizeof(OPEN_PACKET
));
4076 OpenPacket
.Type
= IO_TYPE_OPEN_PACKET
;
4077 OpenPacket
.Size
= sizeof(OPEN_PACKET
);
4078 OpenPacket
.CreateOptions
= FILE_DELETE_ON_CLOSE
;
4079 OpenPacket
.ShareAccess
= FILE_SHARE_READ
|
4082 OpenPacket
.Disposition
= FILE_OPEN
;
4083 OpenPacket
.DeleteOnly
= TRUE
;
4084 OpenPacket
.LocalFileObject
= &LocalFileObject
;
4086 /* Update the operation counts */
4087 IopUpdateOperationCount(IopOtherTransfer
);
4090 * Attempt opening the file. This will call the I/O Parse Routine for
4091 * the File Object (IopParseDevice) which will use the dummy file obejct
4092 * send the IRP to its device object. Note that we have two statuses
4093 * to worry about: the Object Manager's status (in Status) and the I/O
4094 * status, which is in the Open Packet's Final Status, and determined
4095 * by the Parse Check member.
4097 Status
= ObOpenObjectByName(ObjectAttributes
,
4104 if (OpenPacket
.ParseCheck
== FALSE
) return Status
;
4106 /* Retrn the Io status */
4107 return OpenPacket
.FinalStatus
;