Author: ion Date: Thu Jul 6 07:40:16 2006 New Revision: 22882
URL: http://svn.reactos.org/svn/reactos?rev=22882&view=rev Log: - Allocate a copy of the EA buffer even for kernel-mode requests, also make the call use a tagged buffer. - Document call to ObOpenObjectByName - Properly handle and document all possible cases (parse failures vs I/o failures vs both), and handle dereferencing and status codes nicely. - Detect if the FSD is reparsing, which we don't support now (we'll bugcheck for now, so we can quickly detect this later instead of handling it wrong).
Modified: trunk/reactos/ntoskrnl/include/internal/tag.h trunk/reactos/ntoskrnl/io/iomgr/file.c
Modified: trunk/reactos/ntoskrnl/include/internal/tag.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/t... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/tag.h (original) +++ trunk/reactos/ntoskrnl/include/internal/tag.h Thu Jul 6 07:40:16 2006 @@ -52,6 +52,7 @@ #define TAG_APC TAG('K', 'A', 'P', 'C') #define TAG_IO TAG('I', 'o', ' ', ' ') #define TAG_ERROR_LOG TAG('I', 'o', 'E', 'r') +#define TAG_EA TAG('I', 'o', 'E', 'a')
/* formerly located in io/work.c */ #define TAG_IOWI TAG('I', 'O', 'W', 'I')
Modified: trunk/reactos/ntoskrnl/io/iomgr/file.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/file.c?re... ============================================================================== --- trunk/reactos/ntoskrnl/io/iomgr/file.c (original) +++ trunk/reactos/ntoskrnl/io/iomgr/file.c Thu Jul 6 07:40:16 2006 @@ -47,6 +47,9 @@ CompleteName, RemainingName);
+ /* Assume failure */ + *Object = NULL; + /* Validate the open packet */ if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
@@ -99,7 +102,6 @@ { /* Couldn't mount, fail the lookup */ ObDereferenceObject(FileObject); - *Object = NULL; return STATUS_UNSUCCESSFUL; } } @@ -220,6 +222,7 @@
/* Reference the file object and call the driver */ ObReferenceObject(FileObject); + OpenPacket->FileObject = FileObject; Status = IoCallDriver(FileObject->DeviceObject, Irp );
/* Copy the status block */ @@ -252,16 +255,45 @@ KeLowerIrql(OldIrql); } #endif + + /* The driver failed to create the file */ if (!NT_SUCCESS(Status)) { + /* Check if we have a name */ + if (FileObject->FileName.Length) + { + /* Free it */ + ExFreePool(FileObject->FileName.Buffer); + FileObject->FileName.Length = 0; + } + + /* Clear its device object */ FileObject->DeviceObject = NULL; - FileObject->Vpb = NULL; - FileObject = NULL; - //ObDereferenceObject(FileObject); - } - + + /* Clear the file object in the open packet */ + OpenPacket->FileObject = NULL; + + /* Dereference the file object */ + ObDereferenceObject(FileObject); + + /* Set the status and return */ + OpenPacket->FinalStatus = Status; + return Status; + } + else if (Status == STATUS_REPARSE) + { + /* FIXME: We don't handle this at all! */ + KEBUGCHECK(0); + } + + /* Otherwise, we were successful. Reference the object, set status */ + ObReferenceObject(FileObject); + OpenPacket->FinalStatus = IoStatusBlock.Status; + OpenPacket->ParseCheck = TRUE; + + /* Return the object and status */ *Object = FileObject; - return Status; + return OpenPacket->FinalStatus; }
NTSTATUS @@ -992,7 +1024,9 @@ sizeof(ULONG));
/* marshal EaBuffer */ - SystemEaBuffer = ExAllocatePool(NonPagedPool, EaLength); + SystemEaBuffer = ExAllocatePoolWithTag(NonPagedPool, + EaLength, + TAG_EA); if(!SystemEaBuffer) { Status = STATUS_INSUFFICIENT_RESOURCES; @@ -1021,7 +1055,13 @@ SafeAllocationSize.QuadPart = 0; }
- if ((EaBuffer) && (EaLength)) SystemEaBuffer = EaBuffer; + if ((EaBuffer) && (EaLength)) + { + SystemEaBuffer = ExAllocatePoolWithTag(NonPagedPool, + EaLength, + TAG_EA); + RtlCopyMemory(SystemEaBuffer, EaBuffer, EaLength); + } }
if(Options & IO_CHECK_CREATE_PARAMETERS) @@ -1057,7 +1097,14 @@ OpenPacket.DummyFileObject = NULL; OpenPacket.InternalFlags = 0;
- /* First try to open an existing named object */ + /* + * Attempt opening the file. This will call the I/O Parse Routine for + * the File Object (IopParseDevice) which will create the object and + * send the IRP to its device object. Note that we have two statuses + * to worry about: the Object Manager's status (in Status) and the I/O + * status, which is in the Open Packet's Final Status, and determined + * by the Parse Check member. + */ Status = ObOpenObjectByName(ObjectAttributes, NULL, AccessMode, @@ -1066,26 +1113,97 @@ &OpenPacket, &LocalHandle);
- DPRINT1("Status: %lx %lx\n", Status, LocalHandle); - - _SEH_TRY - { - *FileHandle = LocalHandle; - IoStatusBlock->Information = OpenPacket.Information; - IoStatusBlock->Status = OpenPacket.FinalStatus; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - /* cleanup EABuffer if captured */ - if (AccessMode != KernelMode && (SystemEaBuffer)) - { - ExFreePool(SystemEaBuffer); - } - + /* Free the EA Buffer */ + if (OpenPacket.EaBuffer) ExFreePool(OpenPacket.EaBuffer); + + /* Now check for Ob or Io failure */ + if (!(NT_SUCCESS(Status)) || (OpenPacket.ParseCheck != TRUE)) + { + /* Check if Ob thinks well went well */ + if (NT_SUCCESS(Status)) + { + /* + * Tell it otherwise. Because we didn't use an ObjectType, + * it incorrectly returned us a handle to God knows what. + */ + ZwClose(LocalHandle); + Status = STATUS_OBJECT_TYPE_MISMATCH; + } + + /* Now check the Io status */ + if (!NT_SUCCESS(OpenPacket.FinalStatus)) + { + /* Use this status instead of Ob's */ + Status = OpenPacket.FinalStatus; + + /* Check if it was only a warning */ + if (NT_WARNING(Status)) + { + /* Protect write with SEH */ + _SEH_TRY + { + /* In this case, we copy the I/O Status back */ + IoStatusBlock->Information = OpenPacket.Information; + IoStatusBlock->Status = OpenPacket.FinalStatus; + } + _SEH_HANDLE + { + /* Get exception code */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + } + else if ((OpenPacket.FileObject) && (OpenPacket.ParseCheck != 1)) + { + /* + * This can happen in the very bizare case where the parse routine + * actually executed more then once (due to a reparse) and ended + * up failing after already having created the File Object. + */ + if (OpenPacket.FileObject->FileName.Length) + { + /* It had a name, free it */ + ExFreePool(OpenPacket.FileObject->FileName.Buffer); + } + + /* Clear the device object to invalidate the FO, and dereference */ + OpenPacket.FileObject->DeviceObject = NULL; + ObDereferenceObject(OpenPacket.FileObject); + } + } + else + { + /* We reached success and have a valid file handle */ + OpenPacket.FileObject->Flags |= FO_HANDLE_CREATED; + + /* Enter SEH for write back */ + _SEH_TRY + { + /* Write back the handle and I/O Status */ + *FileHandle = LocalHandle; + IoStatusBlock->Information = OpenPacket.Information; + IoStatusBlock->Status = OpenPacket.FinalStatus; + + /* Get the Io status */ + Status = OpenPacket.FinalStatus; + } + _SEH_HANDLE + { + /* Get the exception status */ + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + /* Check if we were 100% successful */ + if ((OpenPacket.ParseCheck == TRUE) && (OpenPacket.FileObject)) + { + /* Dereference the File Object */ + ObDereferenceObject(OpenPacket.FileObject); + } + + /* Return status */ return Status; }