/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/io/file.c
+ * FILE: ntoskrnl/io/iomgr/file.c
* PURPOSE: Functions that deal with managing the FILE_OBJECT itself.
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
* Gunnar Dalsnes
* Eric Kohl
* Filip Navara (navaraf@reactos.org)
+ * Pierre Schweitzer
*/
/* INCLUDES *****************************************************************/
#define NDEBUG
#include <debug.h>
+extern ERESOURCE IopSecurityResource;
+
/* PRIVATE FUNCTIONS *********************************************************/
VOID
}
}
+VOID
+NTAPI
+IopDoNameTransmogrify(IN PIRP Irp,
+ IN PFILE_OBJECT FileObject,
+ IN PREPARSE_DATA_BUFFER DataBuffer)
+{
+ PWSTR Buffer;
+ USHORT Length;
+ USHORT RequiredLength;
+ PWSTR NewBuffer;
+
+ PAGED_CODE();
+
+ ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
+ ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+ ASSERT(DataBuffer != NULL);
+ ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+
+ /* First of all, validate data */
+ if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
+ (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
+ DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
+ {
+ Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+ }
+
+ /* Everything went right */
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ /* Compute buffer & length */
+ Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
+ DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
+ Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
+
+ /* Check we don't overflow */
+ if (((ULONG)MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
+ {
+ Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
+ }
+ else
+ {
+ /* Compute how much mem we'll need */
+ RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
+
+ /* Check if FileObject can already hold what we need */
+ if (FileObject->FileName.MaximumLength >= RequiredLength)
+ {
+ NewBuffer = FileObject->FileName.Buffer;
+ }
+ else
+ {
+ /* Allocate otherwise */
+ NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_IO_NAME);
+ if (NewBuffer == NULL)
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ }
+ }
+
+ /* Everything went right */
+ if (NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ /* Copy reserved */
+ if (DataBuffer->Reserved)
+ {
+ RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
+ (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer + FileObject->FileName.Length - DataBuffer->Reserved),
+ DataBuffer->Reserved);
+ }
+
+ /* Then, buffer */
+ if (Length)
+ {
+ RtlCopyMemory(NewBuffer, Buffer, Length);
+ }
+
+ /* And finally replace buffer if new one was allocated */
+ FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
+ if (NewBuffer != FileObject->FileName.Buffer)
+ {
+ if (FileObject->FileName.Buffer)
+ {
+ ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+ }
+
+ FileObject->FileName.Buffer = NewBuffer;
+ FileObject->FileName.MaximumLength = RequiredLength;
+ FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
+ }
+ }
+
+ /* We don't need them anymore - it was allocated by the driver */
+ ExFreePool(DataBuffer);
+}
+
NTSTATUS
NTAPI
IopParseDevice(IN PVOID ParseObject,
PFILE_OBJECT FileObject;
PVPB Vpb = NULL;
PIRP Irp;
- PEXTENDED_IO_STACK_LOCATION StackLoc;
+ PIO_STACK_LOCATION StackLoc;
IO_SECURITY_CONTEXT SecurityContext;
IO_STATUS_BLOCK IoStatusBlock;
BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
BOOLEAN AccessGranted, LockHeld = FALSE;
PPRIVILEGE_SET Privileges = NULL;
UNICODE_STRING FileString;
+ USHORT Attempt;
IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
ParseObject, RemainingName);
- /* Assume failure */
- *Object = NULL;
+ for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt)
+ {
+ /* Assume failure */
+ *Object = NULL;
- /* Validate the open packet */
- if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
+ /* Validate the open packet */
+ if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
- /* Check if we have a related file object */
- if (OpenPacket->RelatedFileObject)
- {
- /* Use the related file object's device object */
- OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
- }
+ /* Valide reparse point in case we traversed a mountpoint */
+ if (OpenPacket->TraversedMountPoint)
+ {
+ /* This is a reparse point we understand */
+ ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
- /* Validate device status */
- Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
- if (!NT_SUCCESS(Status))
- {
- /* We failed, return status */
- OpenPacket->FinalStatus = Status;
- return Status;
- }
+ /* Make sure we're dealing with correct DO */
+ if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
+ OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
+ {
+ OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
+ return STATUS_IO_REPARSE_DATA_INVALID;
+ }
+ }
- /* Map the generic mask and set the new mapping in the access state */
- RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
- &IoFileObjectType->TypeInfo.GenericMapping);
- RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
- &IoFileObjectType->TypeInfo.GenericMapping);
- SeSetAccessStateGenericMapping(AccessState,
- &IoFileObjectType->TypeInfo.GenericMapping);
- DesiredAccess = AccessState->RemainingDesiredAccess;
+ /* Check if we have a related file object */
+ if (OpenPacket->RelatedFileObject)
+ {
+ /* Use the related file object's device object */
+ OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
+ }
- /* Check what kind of access checks to do */
- if ((AccessMode != KernelMode) ||
- (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
- {
- /* Call is from user-mode or kernel is forcing checks */
- CheckMode = UserMode;
- }
- else
- {
- /* Call is from the kernel */
- CheckMode = KernelMode;
- }
+ /* Validate device status */
+ Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed, return status */
+ OpenPacket->FinalStatus = Status;
+ return Status;
+ }
- /* Check privilege for backup or restore operation */
- IopCheckBackupRestorePrivilege(AccessState,
- &OpenPacket->CreateOptions,
- CheckMode,
- OpenPacket->Disposition);
+ /* Map the generic mask and set the new mapping in the access state */
+ RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
+ &IoFileObjectType->TypeInfo.GenericMapping);
+ RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
+ &IoFileObjectType->TypeInfo.GenericMapping);
+ SeSetAccessStateGenericMapping(AccessState,
+ &IoFileObjectType->TypeInfo.GenericMapping);
+ DesiredAccess = AccessState->RemainingDesiredAccess;
- /* Check if we are re-parsing */
- if (((OpenPacket->Override) && !(RemainingName->Length)) ||
- (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
- {
- /* Get granted access from the last call */
- DesiredAccess |= AccessState->PreviouslyGrantedAccess;
- }
+ /* Check what kind of access checks to do */
+ if ((AccessMode != KernelMode) ||
+ (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
+ {
+ /* Call is from user-mode or kernel is forcing checks */
+ CheckMode = UserMode;
+ }
+ else
+ {
+ /* Call is from the kernel */
+ CheckMode = KernelMode;
+ }
- /* Check if this is a volume open */
- if ((OpenPacket->RelatedFileObject) &&
- (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
- !(RemainingName->Length))
- {
- /* It is */
- VolumeOpen = TRUE;
- }
+ /* Check privilege for backup or restore operation */
+ IopCheckBackupRestorePrivilege(AccessState,
+ &OpenPacket->CreateOptions,
+ CheckMode,
+ OpenPacket->Disposition);
- /* Now check if we need access checks */
- if (((AccessMode != KernelMode) ||
- (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
- (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
- !(OpenPacket->Override))
- {
- /* Check if a device object is being parsed */
- if (!RemainingName->Length)
+ /* Check if we are re-parsing */
+ if (((OpenPacket->Override) && !(RemainingName->Length)) ||
+ (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
{
+ /* Get granted access from the last call */
+ DesiredAccess |= AccessState->PreviouslyGrantedAccess;
+ }
+
+ /* Check if this is a volume open */
+ if ((OpenPacket->RelatedFileObject) &&
+ (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
+ !(RemainingName->Length))
+ {
+ /* It is */
+ VolumeOpen = TRUE;
+ }
+
+ /* Now check if we need access checks */
+ if (((AccessMode != KernelMode) ||
+ (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
+ (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
+ !(OpenPacket->Override))
+ {
+ KeEnterCriticalRegion();
+ ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
+
+ /* Check if a device object is being parsed */
+ if (!RemainingName->Length)
+ {
+ /* Lock the subject context */
+ SeLockSubjectContext(&AccessState->SubjectSecurityContext);
+ LockHeld = TRUE;
+
+ /* Do access check */
+ AccessGranted = SeAccessCheck(OriginalDeviceObject->
+ SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ LockHeld,
+ DesiredAccess,
+ 0,
+ &Privileges,
+ &IoFileObjectType->
+ TypeInfo.GenericMapping,
+ UserMode,
+ &GrantedAccess,
+ &Status);
+ if (Privileges)
+ {
+ /* Append and free the privileges */
+ SeAppendPrivileges(AccessState, Privileges);
+ SeFreePrivileges(Privileges);
+ }
+
+ /* Check if we got access */
+ if (AccessGranted)
+ {
+ /* Update access state */
+ AccessState->PreviouslyGrantedAccess |= GrantedAccess;
+ AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
+ MAXIMUM_ALLOWED);
+ OpenPacket->Override= TRUE;
+ }
+
+ FileString.Length = 8;
+ FileString.MaximumLength = 8;
+ FileString.Buffer = L"File";
+
+ /* Do Audit/Alarm for open operation */
+ SeOpenObjectAuditAlarm(&FileString,
+ OriginalDeviceObject,
+ CompleteName,
+ OriginalDeviceObject->SecurityDescriptor,
+ AccessState,
+ FALSE,
+ AccessGranted,
+ UserMode,
+ &AccessState->GenerateOnClose);
+ }
+ else
+ {
+ /* Check if we need to do traverse validation */
+ if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
+ ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
+ (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
+ {
+ /* Check if this is a restricted token */
+ if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
+ {
+ /* Do the FAST traverse check */
+ AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
+ AccessState,
+ FILE_TRAVERSE,
+ UserMode);
+ }
+ else
+ {
+ /* Fail */
+ AccessGranted = FALSE;
+ }
+
+ /* Check if we failed to get access */
+ if (!AccessGranted)
+ {
+ /* Lock the subject context */
+ SeLockSubjectContext(&AccessState->SubjectSecurityContext);
+ LockHeld = TRUE;
+
+ /* Do access check */
+ AccessGranted = SeAccessCheck(OriginalDeviceObject->
+ SecurityDescriptor,
+ &AccessState->SubjectSecurityContext,
+ LockHeld,
+ FILE_TRAVERSE,
+ 0,
+ &Privileges,
+ &IoFileObjectType->
+ TypeInfo.GenericMapping,
+ UserMode,
+ &GrantedAccess,
+ &Status);
+ if (Privileges)
+ {
+ /* Append and free the privileges */
+ SeAppendPrivileges(AccessState, Privileges);
+ SeFreePrivileges(Privileges);
+ }
+ }
+
+ /* FIXME: Do Audit/Alarm for traverse check */
+ }
+ else
+ {
+ /* Access automatically granted */
+ AccessGranted = TRUE;
+ }
+ }
+
+ ExReleaseResourceLite(&IopSecurityResource);
+ KeLeaveCriticalRegion();
+
+ /* Check if we hold the lock */
+ if (LockHeld)
+ {
+ /* Release it */
+ SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
+ }
+
+ /* Check if access failed */
+ if (!AccessGranted)
+ {
+ /* Dereference the device and fail */
+ DPRINT1("Traverse access failed!\n");
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+
+ /* Check if we can simply use a dummy file */
+ UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
+
+#if 1
+ /* FIXME: Small hack still exists, have to check why...
+ * This is triggered multiple times by usetup and then once per boot.
+ */
+ if (ExpInTextModeSetup &&
+ !(DirectOpen) &&
+ !(RemainingName->Length) &&
+ !(OpenPacket->RelatedFileObject) &&
+ ((wcsstr(CompleteName->Buffer, L"Harddisk")) ||
+ (wcsstr(CompleteName->Buffer, L"Floppy"))) &&
+ !(UseDummyFile))
+ {
+ DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
+ DesiredAccess & ~(SYNCHRONIZE |
+ FILE_READ_ATTRIBUTES |
+ READ_CONTROL |
+ ACCESS_SYSTEM_SECURITY |
+ WRITE_OWNER |
+ WRITE_DAC));
+ DirectOpen = TRUE;
+ }
+#endif
+
+ /* Check if this is a direct open */
+ if (!(RemainingName->Length) &&
+ !(OpenPacket->RelatedFileObject) &&
+ ((DesiredAccess & ~(SYNCHRONIZE |
+ FILE_READ_ATTRIBUTES |
+ READ_CONTROL |
+ ACCESS_SYSTEM_SECURITY |
+ WRITE_OWNER |
+ WRITE_DAC)) == 0) &&
+ !(UseDummyFile))
+ {
+ /* Remember this for later */
+ DirectOpen = TRUE;
+ }
+
+ /* Check if we have a related FO that wasn't a direct open */
+ if ((OpenPacket->RelatedFileObject) &&
+ !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
+ {
+ /* The device object is the one we were given */
+ DeviceObject = ParseObject;
+
+ /* Check if the related FO had a VPB */
+ if (OpenPacket->RelatedFileObject->Vpb)
+ {
+ /* Yes, remember it */
+ Vpb = OpenPacket->RelatedFileObject->Vpb;
+
+ /* Reference it */
+ InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
+
+ /* Check if we were given a specific top level device to use */
+ if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
+ {
+ DeviceObject = Vpb->DeviceObject;
+ }
+ }
+ }
+ else
+ {
+ /* Check if it has a VPB */
+ if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
+ {
+ /* Check if the VPB is mounted, and mount it */
+ Vpb = IopCheckVpbMounted(OpenPacket,
+ OriginalDeviceObject,
+ RemainingName,
+ &Status);
+ if (!Vpb) return Status;
+
+ /* Get the VPB's device object */
+ DeviceObject = Vpb->DeviceObject;
+ }
+ else
+ {
+ /* The device object is the one we were given */
+ DeviceObject = OriginalDeviceObject;
+ }
+
+ /* If we weren't given a specific top level device, look for an attached device */
+ if (!(OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT) &&
+ DeviceObject->AttachedDevice)
+ {
+ /* Get the attached device */
+ DeviceObject = IoGetAttachedDevice(DeviceObject);
+ }
+ }
+
+ if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
+ {
+ // FIXME: Verify our device object is good to use
+ ASSERT(DirectOpen == FALSE);
+ }
+
+ /* If we traversed a mount point, reset the information */
+ if (OpenPacket->TraversedMountPoint)
+ {
+ OpenPacket->TraversedMountPoint = FALSE;
+ }
+
+ /* Check if this is a secure FSD */
+ if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
+ ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
+ (!VolumeOpen))
+ {
+ Privileges = NULL;
+ GrantedAccess = 0;
+
+ KeEnterCriticalRegion();
+ ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
+
/* Lock the subject context */
SeLockSubjectContext(&AccessState->SubjectSecurityContext);
- LockHeld = TRUE;
/* Do access check */
- AccessGranted = SeAccessCheck(OriginalDeviceObject->
- SecurityDescriptor,
+ AccessGranted = SeAccessCheck(OriginalDeviceObject->SecurityDescriptor,
&AccessState->SubjectSecurityContext,
- LockHeld,
+ TRUE,
DesiredAccess,
0,
&Privileges,
- &IoFileObjectType->
- TypeInfo.GenericMapping,
+ &IoFileObjectType->TypeInfo.GenericMapping,
UserMode,
&GrantedAccess,
&Status);
- if (Privileges)
+ if (Privileges != NULL)
{
/* Append and free the privileges */
SeAppendPrivileges(AccessState, Privileges);
}
/* Check if we got access */
- if (AccessGranted)
+ if (GrantedAccess)
{
- /* Update access state */
AccessState->PreviouslyGrantedAccess |= GrantedAccess;
- AccessState->RemainingDesiredAccess &= ~(GrantedAccess &
- MAXIMUM_ALLOWED);
- OpenPacket->Override= TRUE;
+ AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
}
FileString.Length = 8;
FileString.MaximumLength = 8;
FileString.Buffer = L"File";
- /* Do Audit/Alarm for open operation */
+ /* Do Audit/Alarm for open operation
+ * NOTA: we audit target device object
+ */
SeOpenObjectAuditAlarm(&FileString,
- OriginalDeviceObject,
+ DeviceObject,
CompleteName,
OriginalDeviceObject->SecurityDescriptor,
AccessState,
AccessGranted,
UserMode,
&AccessState->GenerateOnClose);
- }
- else
- {
- /* Check if we need to do traverse validation */
- if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
- ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
- (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
- {
- /* Check if this is a restricted token */
- if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
- {
- /* Do the FAST traverse check */
- AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
- AccessState,
- FILE_TRAVERSE,
- UserMode);
- }
- else
- {
- /* Fail */
- AccessGranted = FALSE;
- }
- /* Check if we failed to get access */
- if (!AccessGranted)
- {
- /* Lock the subject context */
- SeLockSubjectContext(&AccessState->SubjectSecurityContext);
- LockHeld = TRUE;
+ SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
- /* Do access check */
- AccessGranted = SeAccessCheck(OriginalDeviceObject->
- SecurityDescriptor,
- &AccessState->SubjectSecurityContext,
- LockHeld,
- FILE_TRAVERSE,
- 0,
- &Privileges,
- &IoFileObjectType->
- TypeInfo.GenericMapping,
- UserMode,
- &GrantedAccess,
- &Status);
- if (Privileges)
- {
- /* Append and free the privileges */
- SeAppendPrivileges(AccessState, Privileges);
- SeFreePrivileges(Privileges);
- }
- }
+ ExReleaseResourceLite(&IopSecurityResource);
+ KeLeaveCriticalRegion();
- /* FIXME: Do Audit/Alarm for traverse check */
- }
- else
+ /* Check if access failed */
+ if (!AccessGranted)
{
- /* Access automatically granted */
- AccessGranted = TRUE;
+ /* Dereference the device and fail */
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+ if (Vpb) IopDereferenceVpbAndFree(Vpb);
+ return STATUS_ACCESS_DENIED;
}
}
- /* Check if we hold the lock */
- if (LockHeld)
+ /* Allocate the IRP */
+ Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
+ if (!Irp)
{
- /* Release it */
- SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
- }
-
- /* Check if access failed */
- if (!AccessGranted)
- {
- /* Dereference the device and fail */
- DPRINT1("Traverse access failed!\n");
+ /* Dereference the device and VPB, then fail */
IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
- return STATUS_ACCESS_DENIED;
+ if (Vpb) IopDereferenceVpbAndFree(Vpb);
+ return STATUS_INSUFFICIENT_RESOURCES;
}
- }
- /* Check if we can simply use a dummy file */
- UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
-
- /* Check if this is a direct open */
- if (!(RemainingName->Length) &&
- !(OpenPacket->RelatedFileObject) &&
- ((DesiredAccess & ~(SYNCHRONIZE |
- FILE_READ_ATTRIBUTES |
- READ_CONTROL |
- ACCESS_SYSTEM_SECURITY |
- WRITE_OWNER |
- WRITE_DAC)) == 0) &&
- !(UseDummyFile))
- {
- /* Remember this for later */
- DirectOpen = TRUE;
- }
-
- /* FIXME: Small hack still exists, have to check why...
- * This is triggered multiple times by usetup and then once per boot.
- */
- if (!(DirectOpen) &&
- !(RemainingName->Length) &&
- !(OpenPacket->RelatedFileObject) &&
- ((wcsstr(CompleteName->Buffer, L"Harddisk")) ||
- (wcsstr(CompleteName->Buffer, L"Floppy"))) &&
- !(UseDummyFile))
- {
- DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
- DesiredAccess & ~(SYNCHRONIZE |
- FILE_READ_ATTRIBUTES |
- READ_CONTROL |
- ACCESS_SYSTEM_SECURITY |
- WRITE_OWNER |
- WRITE_DAC));
- DirectOpen = TRUE;
- }
-
- /* Check if we have a related FO that wasn't a direct open */
- if ((OpenPacket->RelatedFileObject) &&
- !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
- {
- /* The device object is the one we were given */
- DeviceObject = ParseObject;
+ /* Now set the IRP data */
+ Irp->RequestorMode = AccessMode;
+ Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
+ Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ Irp->UserIosb = &IoStatusBlock;
+ Irp->MdlAddress = NULL;
+ Irp->PendingReturned = FALSE;
+ Irp->UserEvent = NULL;
+ Irp->Cancel = FALSE;
+ Irp->CancelRoutine = NULL;
+ Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
+
+ /* Setup the security context */
+ SecurityContext.SecurityQos = SecurityQos;
+ SecurityContext.AccessState = AccessState;
+ SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
+ SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
+
+ /* Get the I/O Stack location */
+ StackLoc = IoGetNextIrpStackLocation(Irp);
+ StackLoc->Control = 0;
+
+ /* Check what kind of file this is */
+ switch (OpenPacket->CreateFileType)
+ {
+ /* Normal file */
+ case CreateFileTypeNone:
+
+ /* Set the major function and EA Length */
+ StackLoc->MajorFunction = IRP_MJ_CREATE;
+ StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
+
+ /* Set the flags */
+ StackLoc->Flags = (UCHAR)OpenPacket->Options;
+ StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
+ break;
+
+ /* Named pipe */
+ case CreateFileTypeNamedPipe:
+
+ /* Set the named pipe MJ and set the parameters */
+ StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
+ StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
+ break;
+
+ /* Mailslot */
+ case CreateFileTypeMailslot:
+
+ /* Set the mailslot MJ and set the parameters */
+ StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
+ StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
+ break;
+ }
+
+ /* Set the common data */
+ Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
+ Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
+ StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
+ (OpenPacket->CreateOptions &
+ 0xFFFFFF);
+ StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
+ StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
+ StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
+
+ /* Check if we really need to create an object */
+ if (!UseDummyFile)
+ {
+ ULONG ObjectSize = sizeof(FILE_OBJECT);
+
+ /* Tag on space for a file object extension */
+ if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
+ ObjectSize += sizeof(FILE_OBJECT_EXTENSION);
+
+ /* Create the actual file object */
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ Attributes,
+ NULL,
+ NULL);
+ Status = ObCreateObject(KernelMode,
+ IoFileObjectType,
+ &ObjectAttributes,
+ AccessMode,
+ NULL,
+ ObjectSize,
+ 0,
+ 0,
+ (PVOID*)&FileObject);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Create failed, free the IRP */
+ IoFreeIrp(Irp);
- /* Check if the related FO had a VPB */
- if (OpenPacket->RelatedFileObject->Vpb)
- {
- /* Yes, remember it */
- Vpb = OpenPacket->RelatedFileObject->Vpb;
+ /* Dereference the device and VPB */
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+ if (Vpb) IopDereferenceVpbAndFree(Vpb);
- /* Reference it */
- InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
- }
- }
- else
- {
- /* The device object is the one we were given */
- DeviceObject = OriginalDeviceObject;
+ /* We failed, return status */
+ OpenPacket->FinalStatus = Status;
+ return Status;
+ }
- /* Check if it has a VPB */
- if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
- {
- /* Check if the VPB is mounted, and mount it */
- Vpb = IopCheckVpbMounted(OpenPacket,
- OriginalDeviceObject,
- RemainingName,
- &Status);
- if (!Vpb) return Status;
+ /* Clear the file object */
+ RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
- /* Get the VPB's device object */
- DeviceObject = Vpb->DeviceObject;
- }
+ /* Check if this is Synch I/O */
+ if (OpenPacket->CreateOptions &
+ (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
+ {
+ /* Set the synch flag */
+ FileObject->Flags |= FO_SYNCHRONOUS_IO;
- /* Check if there's an attached device */
- if (DeviceObject->AttachedDevice)
- {
- /* Get the attached device */
- DeviceObject = IoGetAttachedDevice(DeviceObject);
- }
- }
+ /* Check if it's also alertable */
+ if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
+ {
+ /* It is, set the alertable flag */
+ FileObject->Flags |= FO_ALERTABLE_IO;
+ }
+ }
- /* Check if this is a secure FSD */
- if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
- ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
- (!VolumeOpen))
- {
- DPRINT("Fix Secure FSD support!!!\n");
- }
+ /* Check if this is synch I/O */
+ if (FileObject->Flags & FO_SYNCHRONOUS_IO)
+ {
+ /* Initialize the event */
+ KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
+ }
- /* Allocate the IRP */
- Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
- if (!Irp)
- {
- /* Dereference the device and VPB, then fail */
- IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
- if (Vpb) IopDereferenceVpbAndFree(Vpb);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
+ /* Check if the caller requested no intermediate buffering */
+ if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
+ }
- /* Now set the IRP data */
- Irp->RequestorMode = AccessMode;
- Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
- Irp->Tail.Overlay.Thread = PsGetCurrentThread();
- Irp->UserIosb = &IoStatusBlock;
- Irp->MdlAddress = NULL;
- Irp->PendingReturned = FALSE;
- Irp->UserEvent = NULL;
- Irp->Cancel = FALSE;
- Irp->CancelRoutine = NULL;
- Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
-
- /* Setup the security context */
- SecurityContext.SecurityQos = SecurityQos;
- SecurityContext.AccessState = AccessState;
- SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
- SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
-
- /* Get the I/O Stack location */
- StackLoc = (PEXTENDED_IO_STACK_LOCATION)IoGetNextIrpStackLocation(Irp);
- StackLoc->Control = 0;
-
- /* Check what kind of file this is */
- switch (OpenPacket->CreateFileType)
- {
- /* Normal file */
- case CreateFileTypeNone:
-
- /* Set the major function and EA Length */
- StackLoc->MajorFunction = IRP_MJ_CREATE;
- StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
-
- /* Set the flags */
- StackLoc->Flags = (UCHAR)OpenPacket->Options;
- StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
- break;
+ /* Check if the caller requested write through support */
+ if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_WRITE_THROUGH;
+ }
- /* Named pipe */
- case CreateFileTypeNamedPipe:
+ /* Check if the caller says the file will be only read sequentially */
+ if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_SEQUENTIAL_ONLY;
+ }
- /* Set the named pipe MJ and set the parameters */
- StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
- StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
- break;
+ /* Check if the caller believes the file will be only read randomly */
+ if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
+ {
+ /* Set the correct flag for the FSD to read */
+ FileObject->Flags |= FO_RANDOM_ACCESS;
+ }
- /* Mailslot */
- case CreateFileTypeMailslot:
+ /* Check if we were asked to setup a file object extension */
+ if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
+ {
+ PFILE_OBJECT_EXTENSION FileObjectExtension;
- /* Set the mailslot MJ and set the parameters */
- StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
- StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
- break;
- }
+ /* Make sure the file object knows it has an extension */
+ FileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
- /* Set the common data */
- Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
- Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
- StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
- (OpenPacket->CreateOptions &
- 0xFFFFFF);
- StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
- StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
- StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
+ FileObjectExtension = (PFILE_OBJECT_EXTENSION)(FileObject + 1);
+ FileObject->FileObjectExtension = FileObjectExtension;
- /* Check if we really need to create an object */
- if (!UseDummyFile)
- {
- /* Create the actual file object */
- InitializeObjectAttributes(&ObjectAttributes,
- NULL,
- Attributes,
- NULL,
- NULL);
- Status = ObCreateObject(KernelMode,
- IoFileObjectType,
- &ObjectAttributes,
- AccessMode,
- NULL,
- sizeof(FILE_OBJECT),
- 0,
- 0,
- (PVOID*)&FileObject);
- if (!NT_SUCCESS(Status))
+ /* Add the top level device which we'll send the request to */
+ if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
+ {
+ FileObjectExtension->TopDeviceObjectHint = DeviceObject;
+ }
+ }
+ }
+ else
{
- /* Create failed, free the IRP */
- IoFreeIrp(Irp);
+ /* Use the dummy object instead */
+ LocalFileObject = OpenPacket->LocalFileObject;
+ RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
- /* Dereference the device and VPB */
- IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
- if (Vpb) IopDereferenceVpbAndFree(Vpb);
-
- /* We failed, return status */
- OpenPacket->FinalStatus = Status;
- return Status;
+ /* Set it up */
+ FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
+ LocalFileObject->ObjectHeader.Type = IoFileObjectType;
+ LocalFileObject->ObjectHeader.PointerCount = 1;
}
- /* Clear the file object */
- RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
+ /* Setup the file header */
+ FileObject->Type = IO_TYPE_FILE;
+ FileObject->Size = sizeof(FILE_OBJECT);
+ FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
+ FileObject->DeviceObject = OriginalDeviceObject;
+
+ /* Check if this is a direct device open */
+ if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
- /* Check if this is Synch I/O */
- if (OpenPacket->CreateOptions &
- (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
+ /* Check if the caller wants case sensitivity */
+ if (!(Attributes & OBJ_CASE_INSENSITIVE))
{
- /* Set the synch flag */
- FileObject->Flags |= FO_SYNCHRONOUS_IO;
+ /* Tell the driver about it */
+ FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
+ }
- /* Check if it's also alertable */
- if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
+ /* Now set the file object */
+ Irp->Tail.Overlay.OriginalFileObject = FileObject;
+ StackLoc->FileObject = FileObject;
+
+ /* Check if the file object has a name */
+ if (RemainingName->Length)
+ {
+ /* Setup the unicode string */
+ FileObject->FileName.MaximumLength = RemainingName->Length +
+ sizeof(WCHAR);
+ FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
+ FileObject->
+ FileName.
+ MaximumLength,
+ TAG_IO_NAME);
+ if (!FileObject->FileName.Buffer)
{
- /* It is, set the alertable flag */
- FileObject->Flags |= FO_ALERTABLE_IO;
+ /* Failed to allocate the name, free the IRP */
+ IoFreeIrp(Irp);
+
+ /* Dereference the device object and VPB */
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+ if (Vpb) IopDereferenceVpbAndFree(Vpb);
+
+ /* Clear the FO and dereference it */
+ FileObject->DeviceObject = NULL;
+ if (!UseDummyFile) ObDereferenceObject(FileObject);
+
+ /* Fail */
+ return STATUS_INSUFFICIENT_RESOURCES;
}
}
- /* Check if this is synch I/O */
- if (FileObject->Flags & FO_SYNCHRONOUS_IO)
- {
- /* Initialize the event */
- KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
- }
+ /* Copy the name */
+ RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
- /* Check if the caller requested no intermediate buffering */
- if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
- {
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
- }
+ /* Initialize the File Object event and set the FO */
+ KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
+ OpenPacket->FileObject = FileObject;
- /* Check if the caller requested write through support */
- if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
+ /* Queue the IRP and call the driver */
+ IopQueueIrpToThread(Irp);
+ Status = IoCallDriver(DeviceObject, Irp);
+ if (Status == STATUS_PENDING)
{
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_WRITE_THROUGH;
- }
+ /* Wait for the driver to complete the create */
+ KeWaitForSingleObject(&FileObject->Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
- /* Check if the caller says the file will be only read sequentially */
- if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
- {
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_SEQUENTIAL_ONLY;
+ /* Get the new status */
+ Status = IoStatusBlock.Status;
}
-
- /* Check if the caller believes the file will be only read randomly */
- if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
+ else
{
- /* Set the correct flag for the FSD to read */
- FileObject->Flags |= FO_RANDOM_ACCESS;
- }
- }
- else
- {
- /* Use the dummy object instead */
- LocalFileObject = OpenPacket->LocalFileObject;
- RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
+ /* We'll have to complete it ourselves */
+ ASSERT(!Irp->PendingReturned);
+ ASSERT(!Irp->MdlAddress);
- /* Set it up */
- FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
- LocalFileObject->ObjectHeader.Type = IoFileObjectType;
- LocalFileObject->ObjectHeader.PointerCount = 1;
- }
+ /* Handle name change if required */
+ if (Status == STATUS_REPARSE)
+ {
+ /* Check this is a mount point */
+ if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ PREPARSE_DATA_BUFFER ReparseData;
- /* Setup the file header */
- FileObject->Type = IO_TYPE_FILE;
- FileObject->Size = sizeof(FILE_OBJECT);
- FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
- FileObject->DeviceObject = OriginalDeviceObject;
+ /* Reparse point attributes were passed by the driver in the auxiliary buffer */
+ ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
+ ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
- /* Check if this is a direct device open */
- if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
+ ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+ ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+ ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
- /* Check if the caller wants case sensitivity */
- if (!(Attributes & OBJ_CASE_INSENSITIVE))
- {
- /* Tell the driver about it */
- FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
- }
+ IopDoNameTransmogrify(Irp, FileObject, ReparseData);
+ }
+ }
- /* Now set the file object */
- Irp->Tail.Overlay.OriginalFileObject = FileObject;
- StackLoc->FileObject = FileObject;
-
- /* Check if the file object has a name */
- if (RemainingName->Length)
- {
- /* Setup the unicode string */
- FileObject->FileName.MaximumLength = RemainingName->Length +
- sizeof(WCHAR);
- FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
- FileObject->
- FileName.
- MaximumLength,
- TAG_IO_NAME);
- if (!FileObject->FileName.Buffer)
- {
- /* Failed to allocate the name, free the IRP */
+ /* Completion happens at APC_LEVEL */
+ KeRaiseIrql(APC_LEVEL, &OldIrql);
+
+ /* Get the new I/O Status block ourselves */
+ IoStatusBlock = Irp->IoStatus;
+ Status = IoStatusBlock.Status;
+
+ /* Manually signal the even, we can't have any waiters */
+ FileObject->Event.Header.SignalState = 1;
+
+ /* Now that we've signaled the events, de-associate the IRP */
+ IopUnQueueIrpFromThread(Irp);
+
+ /* Check if the IRP had an input buffer */
+ if ((Irp->Flags & IRP_BUFFERED_IO) &&
+ (Irp->Flags & IRP_DEALLOCATE_BUFFER))
+ {
+ /* Free it. A driver might've tacked one on */
+ ExFreePool(Irp->AssociatedIrp.SystemBuffer);
+ }
+
+ /* Free the IRP and bring the IRQL back down */
IoFreeIrp(Irp);
+ KeLowerIrql(OldIrql);
+ }
- /* Dereference the device object and VPB */
- IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
- if (Vpb) IopDereferenceVpbAndFree(Vpb);
+ /* Copy the I/O Status */
+ OpenPacket->Information = IoStatusBlock.Information;
+
+ /* The driver failed to create the file */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Check if we have a name */
+ if (FileObject->FileName.Length)
+ {
+ /* Free it */
+ ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+ FileObject->FileName.Length = 0;
+ }
- /* Clear the FO and dereference it */
+ /* Clear its device object */
FileObject->DeviceObject = NULL;
+
+ /* Save this now because the FO might go away */
+ OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
+ TRUE : FALSE;
+
+ /* Clear the file object in the open packet */
+ OpenPacket->FileObject = NULL;
+
+ /* Dereference the file object */
if (!UseDummyFile) ObDereferenceObject(FileObject);
- /* Fail */
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- }
+ /* Dereference the device object */
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
- /* Copy the name */
- RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
+ /* Unless the driver cancelled the open, dereference the VPB */
+ if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
- /* Initialize the File Object event and set the FO */
- KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
- OpenPacket->FileObject = FileObject;
+ /* Set the status and return */
+ OpenPacket->FinalStatus = Status;
+ return Status;
+ }
+ else if (Status == STATUS_REPARSE)
+ {
+ if (OpenPacket->Information == IO_REPARSE ||
+ OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
+ if (CompleteName->MaximumLength < FileObject->FileName.Length)
+ {
+ PWSTR NewCompleteName;
- /* Queue the IRP and call the driver */
- IopQueueIrpToThread(Irp);
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
- {
- /* Wait for the driver to complete the create */
- KeWaitForSingleObject(&FileObject->Event,
- Executive,
- KernelMode,
- FALSE,
- NULL);
+ /* Allocate a new buffer for the string */
+ NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
+ if (NewCompleteName == NULL)
+ {
+ OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- /* Get the new status */
- Status = IoStatusBlock.Status;
- }
- else
- {
- /* We'll have to complete it ourselves */
- ASSERT(!Irp->PendingReturned);
- ASSERT(!Irp->MdlAddress);
+ /* Release the old one */
+ if (CompleteName->Buffer != NULL)
+ {
+ ExFreePoolWithTag(CompleteName->Buffer, 0);
+ }
- /* Completion happens at APC_LEVEL */
- KeRaiseIrql(APC_LEVEL, &OldIrql);
+ /* And setup the new one */
+ CompleteName->Buffer = NewCompleteName;
+ CompleteName->MaximumLength = FileObject->FileName.Length;
+ }
- /* Get the new I/O Status block ourselves */
- IoStatusBlock = Irp->IoStatus;
- Status = IoStatusBlock.Status;
+ /* Copy our new complete name */
+ RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
- /* Manually signal the even, we can't have any waiters */
- FileObject->Event.Header.SignalState = 1;
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ OpenPacket->RelatedFileObject = NULL;
+ }
+ }
- /* Now that we've signaled the events, de-associate the IRP */
- IopUnQueueIrpFromThread(Irp);
+ /* Check if we have a name */
+ if (FileObject->FileName.Length)
+ {
+ /* Free it */
+ ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
+ FileObject->FileName.Length = 0;
+ }
- /* Check if the IRP had an input buffer */
- if ((Irp->Flags & IRP_BUFFERED_IO) &&
- (Irp->Flags & IRP_DEALLOCATE_BUFFER))
- {
- /* Free it. A driver might've tacked one on */
- ExFreePool(Irp->AssociatedIrp.SystemBuffer);
- }
+ /* Clear its device object */
+ FileObject->DeviceObject = NULL;
- /* Free the IRP and bring the IRQL back down */
- IoFreeIrp(Irp);
- KeLowerIrql(OldIrql);
- }
+ /* Clear the file object in the open packet */
+ OpenPacket->FileObject = NULL;
- /* Copy the I/O Status */
- OpenPacket->Information = IoStatusBlock.Information;
+ /* Dereference the file object */
+ if (!UseDummyFile) ObDereferenceObject(FileObject);
- /* The driver failed to create the file */
- if (!NT_SUCCESS(Status))
- {
- /* Check if we have a name */
- if (FileObject->FileName.Length)
- {
- /* Free it */
- ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
- FileObject->FileName.Length = 0;
- }
+ /* Dereference the device object */
+ IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
- /* Clear its device object */
- FileObject->DeviceObject = NULL;
+ /* Unless the driver cancelled the open, dereference the VPB */
+ if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
- /* Save this now because the FO might go away */
- OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
- TRUE : FALSE;
+ if (OpenPacket->Information != IO_REMOUNT)
+ {
+ OpenPacket->RelatedFileObject = NULL;
- /* Clear the file object in the open packet */
- OpenPacket->FileObject = NULL;
+ /* Inform we traversed a mount point for later attempt */
+ if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ OpenPacket->TraversedMountPoint = 1;
+ }
- /* Dereference the file object */
- if (!UseDummyFile) ObDereferenceObject(FileObject);
+ /* In case we override checks, but got this on volume open, fail hard */
+ if (OpenPacket->Override)
+ {
+ KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
+ (ULONG_PTR)OriginalDeviceObject,
+ (ULONG_PTR)DeviceObject,
+ (ULONG_PTR)CompleteName,
+ OpenPacket->Information);
+ }
- /* Dereference the device object */
- IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
+ /* Return to IO/OB so that information can be upgraded */
+ return STATUS_REPARSE;
+ }
- /* Unless the driver cancelled the open, dereference the VPB */
- if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
+ /* Loop again and reattempt an opening */
+ continue;
+ }
- /* Set the status and return */
- OpenPacket->FinalStatus = Status;
- return Status;
- }
- else if (Status == STATUS_REPARSE)
- {
- /* FIXME: We don't handle this at all! */
- ASSERT(FALSE);
+ break;
}
+ if (Attempt == IOP_MAX_REPARSE_TRAVERSAL)
+ return STATUS_UNSUCCESSFUL;
+
/* Get the owner of the File Object */
OwnerDevice = IoGetRelatedDeviceObject(FileObject);
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
/* Allocate an IRP */
- Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return;
+ Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
/* Set it up */
Irp->UserEvent = &Event;
Vpb = FileObject->Vpb;
if ((Vpb) && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
{
- /* Dereference the VPB before the close */
- InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
+ /* Dereference the VPB before the close */
+ InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
+ }
+
+ /* Check if the FS will never disappear by itself */
+ if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
+ {
+ /* Dereference it */
+ InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
+ DereferenceDone = TRUE;
+ }
+
+ /* Call the FS Driver */
+ Status = IoCallDriver(DeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait for completion */
+ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ }
+
+ /* De-queue the IRP */
+ KeRaiseIrql(APC_LEVEL, &OldIrql);
+ IopUnQueueIrpFromThread(Irp);
+ KeLowerIrql(OldIrql);
+
+ /* Free the IRP */
+ IoFreeIrp(Irp);
+
+ /* Clear the file name */
+ if (FileObject->FileName.Buffer)
+ {
+ ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
+ FileObject->FileName.Buffer = NULL;
+ }
+
+ /* Check if the FO had a completion port */
+ if (FileObject->CompletionContext)
+ {
+ /* Free it */
+ ObDereferenceObject(FileObject->CompletionContext->Port);
+ ExFreePool(FileObject->CompletionContext);
+ }
+
+ /* Check if the FO had extension */
+ if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
+ {
+ /* Release filter context structure if any */
+ FsRtlPTeardownPerFileObjectContexts(FileObject);
+ }
+
+ /* Check if dereference has been done yet */
+ if (!DereferenceDone)
+ {
+ /* Dereference device object */
+ IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
+ }
+ }
+}
+
+PDEVICE_OBJECT
+NTAPI
+IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)
+{
+ PDEVICE_OBJECT PDO = DeviceObject;
+
+ /* Go down the stack to attempt to get the PDO */
+ for (; ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo != NULL;
+ PDO = ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo);
+
+ return PDO;
+}
+
+PDEVICE_OBJECT
+NTAPI
+IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)
+{
+ KIRQL OldIrql;
+ PDEVICE_OBJECT PDO;
+
+ ASSERT(DeviceObject != NULL);
+
+ OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
+ /* Get the base DO */
+ PDO = IopGetDeviceAttachmentBase(DeviceObject);
+ /* Check whether that's really a PDO and if so, keep it */
+ if ((PDO->Flags & DO_BUS_ENUMERATED_DEVICE) != DO_BUS_ENUMERATED_DEVICE)
+ {
+ PDO = NULL;
+ }
+ else
+ {
+ ObReferenceObject(PDO);
+ }
+ KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
+
+ return PDO;
+}
+
+NTSTATUS
+NTAPI
+IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,
+ IN PSECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN POOL_TYPE PoolType,
+ IN PGENERIC_MAPPING GenericMapping)
+{
+ NTSTATUS Status;
+ PSECURITY_DESCRIPTOR OldSecurityDescriptor, CachedSecurityDescriptor, NewSecurityDescriptor;
+
+ PAGED_CODE();
+
+ /* Keep attempting till we find our old SD or fail */
+ while (TRUE)
+ {
+ KeEnterCriticalRegion();
+ ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
+
+ /* Get our old SD and reference it */
+ OldSecurityDescriptor = DeviceObject->SecurityDescriptor;
+ if (OldSecurityDescriptor != NULL)
+ {
+ ObReferenceSecurityDescriptor(OldSecurityDescriptor, 1);
}
- /* Check if the FS will never disappear by itself */
- if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
+ ExReleaseResourceLite(&IopSecurityResource);
+ KeLeaveCriticalRegion();
+
+ /* Set the SD information */
+ NewSecurityDescriptor = OldSecurityDescriptor;
+ Status = SeSetSecurityDescriptorInfo(NULL, SecurityInformation,
+ SecurityDescriptor, &NewSecurityDescriptor,
+ PoolType, GenericMapping);
+
+ if (!NT_SUCCESS(Status))
{
- /* Dereference it */
- InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
- DereferenceDone = TRUE;
+ if (OldSecurityDescriptor != NULL)
+ {
+ ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
+ }
+
+ break;
}
- /* Call the FS Driver */
- Status = IoCallDriver(DeviceObject, Irp);
- if (Status == STATUS_PENDING)
+ /* Add the new DS to the internal cache */
+ Status = ObLogSecurityDescriptor(NewSecurityDescriptor,
+ &CachedSecurityDescriptor, 1);
+ ExFreePool(NewSecurityDescriptor);
+ if (!NT_SUCCESS(Status))
{
- /* Wait for completion */
- KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+ ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
+ break;
}
- /* De-queue the IRP */
- KeRaiseIrql(APC_LEVEL, &OldIrql);
- IopUnQueueIrpFromThread(Irp);
- KeLowerIrql(OldIrql);
+ KeEnterCriticalRegion();
+ ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
+ /* Check if someone changed it in our back */
+ if (DeviceObject->SecurityDescriptor == OldSecurityDescriptor)
+ {
+ /* We're clear, do the swap */
+ DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
+ ExReleaseResourceLite(&IopSecurityResource);
+ KeLeaveCriticalRegion();
- /* Free the IRP */
- IoFreeIrp(Irp);
+ /* And dereference old SD (twice - us + not in use) */
+ ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 2);
- /* Clear the file name */
- if (FileObject->FileName.Buffer)
- {
- ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
- FileObject->FileName.Buffer = NULL;
+ break;
}
+ ExReleaseResourceLite(&IopSecurityResource);
+ KeLeaveCriticalRegion();
- /* Check if the FO had a completion port */
- if (FileObject->CompletionContext)
- {
- /* Free it */
- ObDereferenceObject(FileObject->CompletionContext->Port);
- ExFreePool(FileObject->CompletionContext);
- }
+ /* If so, try again */
+ ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
+ ObDereferenceSecurityDescriptor(CachedSecurityDescriptor, 1);
+ }
- /* Check if the FO had extension */
- if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,
+ IN PDEVICE_OBJECT PhysicalDeviceObject,
+ IN PSECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN POOL_TYPE PoolType,
+ IN PGENERIC_MAPPING GenericMapping)
+{
+ PDEVICE_OBJECT CurrentDO = PhysicalDeviceObject, NextDevice;
+ NTSTATUS Status = STATUS_SUCCESS, TmpStatus;
+
+ PAGED_CODE();
+
+ ASSERT(PhysicalDeviceObject != NULL);
+
+ /* We always reference the DO we're working on */
+ ObReferenceObject(CurrentDO);
+
+ /* Go up from PDO to latest DO */
+ do
+ {
+ /* Attempt to set the new SD on it */
+ TmpStatus = IopSetDeviceSecurityDescriptor(CurrentDO, SecurityInformation,
+ SecurityDescriptor, PoolType,
+ GenericMapping);
+ /* Was our last one? Remember that status then */
+ if (CurrentDO == UpperDeviceObject)
{
- /* Release filter context structure if any */
- FsRtlPTeardownPerFileObjectContexts(FileObject);
+ Status = TmpStatus;
}
- /* Check if dereference has been done yet */
- if (!DereferenceDone)
+ /* Try to move to the next DO (and thus, reference it) */
+ NextDevice = CurrentDO->AttachedDevice;
+ if (NextDevice)
{
- /* Dereference device object */
- IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
+ ObReferenceObject(NextDevice);
}
+
+ /* Dereference current DO and move to the next one */
+ ObDereferenceObject(CurrentDO);
+ CurrentDO = NextDevice;
}
+ while (CurrentDO != NULL);
+
+ return Status;
}
NTSTATUS
NTAPI
-IopSecurityFile(IN PVOID ObjectBody,
- IN SECURITY_OPERATION_CODE OperationCode,
- IN PSECURITY_INFORMATION SecurityInformation,
- IN PSECURITY_DESCRIPTOR SecurityDescriptor,
- IN OUT PULONG BufferLength,
- IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
- IN POOL_TYPE PoolType,
- IN OUT PGENERIC_MAPPING GenericMapping)
+IopGetSetSecurityObject(IN PVOID ObjectBody,
+ IN SECURITY_OPERATION_CODE OperationCode,
+ IN PSECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN OUT PULONG BufferLength,
+ IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
+ IN POOL_TYPE PoolType,
+ IN OUT PGENERIC_MAPPING GenericMapping)
{
IO_STATUS_BLOCK IoStatusBlock;
PIO_STACK_LOCATION StackPtr;
}
else if (OperationCode == AssignSecurityDescriptor)
{
+ Status = STATUS_SUCCESS;
+
/* Make absolutely sure this is a device object */
if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
{
- /* Assign the Security Descriptor */
- DeviceObject->SecurityDescriptor = SecurityDescriptor;
+ PSECURITY_DESCRIPTOR CachedSecurityDescriptor;
+
+ /* Add the security descriptor in cache */
+ Status = ObLogSecurityDescriptor(SecurityDescriptor, &CachedSecurityDescriptor, 1);
+ if (NT_SUCCESS(Status))
+ {
+ KeEnterCriticalRegion();
+ ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
+
+ /* Assign the Security Descriptor */
+ DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
+
+ ExReleaseResourceLite(&IopSecurityResource);
+ KeLeaveCriticalRegion();
+ }
}
- /* Return success */
- return STATUS_SUCCESS;
+ /* Return status */
+ return Status;
}
- else
+ else if (OperationCode == SetSecurityDescriptor)
{
- DPRINT1("FIXME: Set SD unimplemented for Devices\n");
+ /* Get the Physical Device Object if any */
+ PDEVICE_OBJECT PDO = IopGetDevicePDO(DeviceObject);
+
+ if (PDO != NULL)
+ {
+ /* Apply the new SD to any DO in the path from PDO to current DO */
+ Status = IopSetDeviceSecurityDescriptors(DeviceObject, PDO,
+ SecurityInformation,
+ SecurityDescriptor,
+ PoolType, GenericMapping);
+ ObDereferenceObject(PDO);
+ }
+ else
+ {
+ /* Otherwise, just set for ourselves */
+ Status = IopSetDeviceSecurityDescriptor(DeviceObject,
+ SecurityInformation,
+ SecurityDescriptor,
+ PoolType, GenericMapping);
+ }
+
return STATUS_SUCCESS;
}
+
+ /* Shouldn't happen */
+ return STATUS_SUCCESS;
}
else if (OperationCode == DeleteSecurityDescriptor)
{
if (FileObject->Flags & FO_SYNCHRONOUS_IO)
{
/* Lock the file object */
- IopLockFileObject(FileObject);
+ Status = IopLockFileObject(FileObject, ExGetPreviousMode());
+ if (Status != STATUS_SUCCESS)
+ {
+ ObDereferenceObject(FileObject);
+ return Status;
+ }
}
else
{
NTSTATUS
NTAPI
-IopQueryNameFile(IN PVOID ObjectBody,
- IN BOOLEAN HasName,
- OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
- IN ULONG Length,
- OUT PULONG ReturnLength,
- IN KPROCESSOR_MODE PreviousMode)
+IopQueryNameInternal(IN PVOID ObjectBody,
+ IN BOOLEAN HasName,
+ OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+ IN ULONG Length,
+ OUT PULONG ReturnLength,
+ IN KPROCESSOR_MODE PreviousMode)
{
POBJECT_NAME_INFORMATION LocalInfo;
PFILE_NAME_INFORMATION LocalFileInfo;
FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
/* Query the File name */
- Status = IoQueryFileInformation(FileObject,
- FileNameInformation,
- LengthMismatch ? Length : FileLength,
- LocalFileInfo,
- &LocalReturnLength);
+ if (PreviousMode == KernelMode &&
+ BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ {
+ Status = IopGetFileInformation(FileObject,
+ LengthMismatch ? Length : FileLength,
+ FileNameInformation,
+ LocalFileInfo,
+ &LocalReturnLength);
+ }
+ else
+ {
+ Status = IoQueryFileInformation(FileObject,
+ FileNameInformation,
+ LengthMismatch ? Length : FileLength,
+ LocalFileInfo,
+ &LocalReturnLength);
+ }
if (NT_ERROR(Status))
{
/* Fail on errors only, allow warnings */
NTSTATUS Status;
PDEVICE_OBJECT DeviceObject;
KIRQL OldIrql;
+ IO_STATUS_BLOCK IoStatusBlock;
IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
/* If this isn't the last handle for the current process, quit */
/* Check if the file is locked and has more then one handle opened */
if ((FileObject->LockOperation) && (SystemHandleCount != 1))
{
- DPRINT1("We need to unlock this file!\n");
- ASSERT(FALSE);
+ /* Check if this is a direct open or not */
+ if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN))
+ {
+ /* Get the attached device */
+ DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
+ }
+ else
+ {
+ /* Get the FO's device */
+ DeviceObject = IoGetRelatedDeviceObject(FileObject);
+ }
+
+ /* Check if this is a sync FO and lock it */
+ if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ {
+ (VOID)IopLockFileObject(FileObject, KernelMode);
+ }
+
+ /* Go the FastIO path if possible, otherwise fall back to IRP */
+ if (DeviceObject->DriverObject->FastIoDispatch == NULL ||
+ DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll == NULL ||
+ !DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll(FileObject, PsGetCurrentProcess(), &IoStatusBlock, DeviceObject))
+ {
+ /* Clear and set up Events */
+ KeClearEvent(&FileObject->Event);
+ KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+
+ /* Allocate an IRP */
+ Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
+
+ /* Set it up */
+ Irp->UserEvent = &Event;
+ Irp->UserIosb = &Irp->IoStatus;
+ Irp->Tail.Overlay.Thread = PsGetCurrentThread();
+ Irp->Tail.Overlay.OriginalFileObject = FileObject;
+ Irp->RequestorMode = KernelMode;
+ Irp->Flags = IRP_SYNCHRONOUS_API;
+ Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
+ ObReferenceObject(FileObject);
+
+ /* Set up Stack Pointer Data */
+ StackPtr = IoGetNextIrpStackLocation(Irp);
+ StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
+ StackPtr->MinorFunction = IRP_MN_UNLOCK_ALL;
+ StackPtr->FileObject = FileObject;
+
+ /* Queue the IRP */
+ IopQueueIrpToThread(Irp);
+
+ /* Call the FS Driver */
+ Status = IoCallDriver(DeviceObject, Irp);
+ if (Status == STATUS_PENDING)
+ {
+ /* Wait for completion */
+ KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
+ }
+
+ /* IO will unqueue & free for us */
+ }
+
+ /* Release the lock if we were holding it */
+ if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ {
+ IopUnlockFileObject(FileObject);
+ }
}
/* Make sure this is the last handle */
FileObject->Flags |= FO_HANDLE_CREATED;
/* Check if this is a sync FO and lock it */
- if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopLockFileObject(FileObject);
+ if (Process != NULL &&
+ BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ {
+ (VOID)IopLockFileObject(FileObject, KernelMode);
+ }
/* Clear and set up Events */
KeClearEvent(&FileObject->Event);
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
/* Allocate an IRP */
- Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
- if (!Irp) return;
+ Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
/* Set it up */
Irp->UserEvent = &Event;
IoFreeIrp(Irp);
/* Release the lock if we were holding it */
- if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
+ if (Process != NULL &&
+ BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ {
+ IopUnlockFileObject(FileObject);
+ }
}
NTSTATUS
FILE_READ_ATTRIBUTES,
&OpenPacket,
&Handle);
- if (OpenPacket.ParseCheck != TRUE)
+ if (OpenPacket.ParseCheck == FALSE)
{
/* Parse failed */
+ DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
+ ObjectAttributes->ObjectName, Status);
return Status;
}
else
return Status;
}
+NTSTATUS
+NTAPI
+IopAcquireFileObjectLock(
+ _In_ PFILE_OBJECT FileObject,
+ _In_ KPROCESSOR_MODE WaitMode,
+ _In_ BOOLEAN Alertable,
+ _Out_ PBOOLEAN LockFailed)
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ InterlockedIncrement((PLONG)&FileObject->Waiters);
+
+ Status = STATUS_SUCCESS;
+ do
+ {
+ if (!InterlockedExchange((PLONG)&FileObject->Busy, TRUE))
+ {
+ break;
+ }
+ Status = KeWaitForSingleObject(&FileObject->Lock,
+ Executive,
+ WaitMode,
+ Alertable,
+ NULL);
+ } while (Status == STATUS_SUCCESS);
+
+ InterlockedDecrement((PLONG)&FileObject->Waiters);
+ if (Status == STATUS_SUCCESS)
+ {
+ ObReferenceObject(FileObject);
+ *LockFailed = FALSE;
+ }
+ else
+ {
+ if (!FileObject->Busy && FileObject->Waiters)
+ {
+ KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
+ }
+ *LockFailed = TRUE;
+ }
+
+ return Status;
+}
+
PVOID
NTAPI
IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
return STATUS_NOT_IMPLEMENTED;
}
-/* FUNCTIONS *****************************************************************/
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
- IN ULONG Length,
- IN BOOLEAN SetOperation)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
- IN ULONG QuotaLength,
- OUT PULONG ErrorOffset)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @implemented
- */
NTSTATUS
NTAPI
-IoCreateFile(OUT PHANDLE FileHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- OUT PIO_STATUS_BLOCK IoStatusBlock,
- IN PLARGE_INTEGER AllocationSize OPTIONAL,
- IN ULONG FileAttributes,
- IN ULONG ShareAccess,
- IN ULONG Disposition,
- IN ULONG CreateOptions,
- IN PVOID EaBuffer OPTIONAL,
- IN ULONG EaLength,
- IN CREATE_FILE_TYPE CreateFileType,
- IN PVOID ExtraCreateParameters OPTIONAL,
- IN ULONG Options)
+IopCreateFile(OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG Disposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer OPTIONAL,
+ IN ULONG EaLength,
+ IN CREATE_FILE_TYPE CreateFileType,
+ IN PVOID ExtraCreateParameters OPTIONAL,
+ IN ULONG Options,
+ IN ULONG Flags,
+ IN PDEVICE_OBJECT DeviceObject OPTIONAL)
{
KPROCESSOR_MODE AccessMode;
HANDLE LocalHandle = 0;
POPEN_PACKET OpenPacket;
ULONG EaErrorOffset;
PAGED_CODE();
+
IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
/* Make sure we have extra parameters */
if (!ExtraCreateParameters)
{
+ DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
return STATUS_INVALID_PARAMETER;
}
(CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
{
/* Invalid named pipe create */
+ DPRINT1("Invalid named pipe create\n");
return STATUS_INVALID_PARAMETER;
}
}
/* Make sure we have extra parameters */
if (!ExtraCreateParameters)
{
+ DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
return STATUS_INVALID_PARAMETER;
}
(CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
{
/* Invalid mailslot create */
+ DPRINT1("Invalid mailslot create\n");
return STATUS_INVALID_PARAMETER;
}
}
if (!OpenPacket->EaBuffer)
{
ExFreePool(OpenPacket);
+ DPRINT1("Failed to allocate open packet EA buffer\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
OpenPacket->Disposition = Disposition;
OpenPacket->CreateFileType = CreateFileType;
OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
+ OpenPacket->InternalFlags = Flags;
+ OpenPacket->TopDeviceObjectHint = DeviceObject;
/* Update the operation count */
IopUpdateOperationCount(IopOtherTransfer);
if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
/* Now check for Ob or Io failure */
- if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck != TRUE))
+ if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
{
/* Check if Ob thinks well went well */
if (NT_SUCCESS(Status))
_SEH2_END;
}
}
- else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck != 1))
+ else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
{
/*
* This can happen in the very bizarre case where the parse routine
}
/* Check if we were 100% successful */
- if ((OpenPacket->ParseCheck == TRUE) && (OpenPacket->FileObject))
+ if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
{
/* Dereference the File Object */
ObDereferenceObject(OpenPacket->FileObject);
return Status;
}
+/* FUNCTIONS *****************************************************************/
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
+ IN ULONG Length,
+ IN BOOLEAN SetOperation)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
+ IN ULONG QuotaLength,
+ OUT PULONG ErrorOffset)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+IoCreateFile(OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG Disposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer OPTIONAL,
+ IN ULONG EaLength,
+ IN CREATE_FILE_TYPE CreateFileType,
+ IN PVOID ExtraCreateParameters OPTIONAL,
+ IN ULONG Options)
+{
+ PAGED_CODE();
+
+ return IopCreateFile(FileHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ IoStatusBlock,
+ AllocationSize,
+ FileAttributes,
+ ShareAccess,
+ Disposition,
+ CreateOptions,
+ EaBuffer,
+ EaLength,
+ CreateFileType,
+ ExtraCreateParameters,
+ Options,
+ 0,
+ NULL);
+}
+
/*
* @unimplemented
*/
IN ULONG Options,
IN PVOID DeviceObject)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ ULONG Flags = 0;
+
+ PAGED_CODE();
+
+ /* Check if we were passed a device to send the create request to*/
+ if (DeviceObject)
+ {
+ /* We'll tag this request into a file object extension */
+ Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
+ }
+
+ return IopCreateFile(FileHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ IoStatusBlock,
+ AllocationSize,
+ FileAttributes,
+ ShareAccess,
+ Disposition,
+ CreateOptions,
+ EaBuffer,
+ EaLength,
+ CreateFileType,
+ ExtraCreateParameters,
+ Options | IO_NO_PARAMETER_CHECKING,
+ Flags,
+ DeviceObject);
}
/*
DesiredAccess,
&OpenPacket,
&Handle);
- if (OpenPacket.ParseCheck != TRUE)
+ if (OpenPacket.ParseCheck == FALSE)
{
/* Parse failed */
IoStatus->Status = Status;
DELETE,
&OpenPacket,
&Handle);
- if (OpenPacket.ParseCheck != TRUE) return Status;
+ if (OpenPacket.ParseCheck == FALSE) return Status;
/* Retrn the Io status */
return OpenPacket.FinalStatus;