/*
 * COPYRIGHT:        See COPYRIGHT.TXT
 * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
 * FILE:             fastio.c
 * PROGRAMMER:       Matt Wu <mattwu@163.com>
 * HOMEPAGE:         http://www.ext2fsd.com
 * UPDATE HISTORY:
 */

/* INCLUDES *****************************************************************/

#include "ext2fs.h"

/* GLOBALS ***************************************************************/

extern PEXT2_GLOBAL Ext2Global;

/* DEFINITIONS *************************************************************/

#define FASTIO_DEBUG_LEVEL DL_NVR


#ifdef ALLOC_PRAGMA

#pragma alloc_text(PAGE, Ext2FastIoRead)
#pragma alloc_text(PAGE, Ext2FastIoWrite)
#pragma alloc_text(PAGE, Ext2FastIoCheckIfPossible)
#pragma alloc_text(PAGE, Ext2FastIoQueryBasicInfo)
#pragma alloc_text(PAGE, Ext2FastIoQueryStandardInfo)
#pragma alloc_text(PAGE, Ext2FastIoQueryNetworkOpenInfo)
#pragma alloc_text(PAGE, Ext2FastIoLock)
#pragma alloc_text(PAGE, Ext2FastIoUnlockSingle)
#pragma alloc_text(PAGE, Ext2FastIoUnlockAll)
#pragma alloc_text(PAGE, Ext2FastIoUnlockAll)
#endif

FAST_IO_POSSIBLE
Ext2IsFastIoPossible(
    IN PEXT2_FCB Fcb
)
{
    FAST_IO_POSSIBLE IsPossible = FastIoIsNotPossible;

    if (!Fcb || !FsRtlOplockIsFastIoPossible(&Fcb->Oplock))
        return IsPossible;

    IsPossible = FastIoIsQuestionable;

    if (!FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor)) {
        if (!IsVcbReadOnly(Fcb->Vcb) && !FlagOn(Fcb->Vcb->Flags, VCB_VOLUME_LOCKED)) {
            IsPossible = FastIoIsPossible;
        }
    }

    return IsPossible;
}


BOOLEAN
Ext2FastIoCheckIfPossible (
    IN PFILE_OBJECT         FileObject,
    IN PLARGE_INTEGER       FileOffset,
    IN ULONG                Length,
    IN BOOLEAN              Wait,
    IN ULONG                LockKey,
    IN BOOLEAN              CheckForReadOperation,
    OUT PIO_STATUS_BLOCK    IoStatus,
    IN PDEVICE_OBJECT       DeviceObject
)
{
    BOOLEAN          bPossible = FastIoIsNotPossible;
    PEXT2_FCB        Fcb;
    PEXT2_CCB        Ccb;
    LARGE_INTEGER    lLength;

    lLength.QuadPart = Length;

    __try {

        FsRtlEnterFileSystem();

        __try {

            if (IsExt2FsDevice(DeviceObject)) {
                __leave;
            }

            Fcb = (PEXT2_FCB) FileObject->FsContext;
            if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
                __leave;
            }

            ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                   (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

            /* do nothing if target fie was deleted */
            if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
                __leave;
            }

            if (IsDirectory(Fcb)) {
                __leave;
            }

            Ccb = (PEXT2_CCB) FileObject->FsContext2;
            if (Ccb == NULL) {
                __leave;
            }

            if (CheckForReadOperation) {

                bPossible = FsRtlFastCheckLockForRead(
                                &Fcb->FileLockAnchor,
                                FileOffset,
                                &lLength,
                                LockKey,
                                FileObject,
                                PsGetCurrentProcess());

            } else {

                if (!IsVcbReadOnly(Fcb->Vcb)) {
                    bPossible = FsRtlFastCheckLockForWrite(
                                    &Fcb->FileLockAnchor,
                                    FileOffset,
                                    &lLength,
                                    LockKey,
                                    FileObject,
                                    PsGetCurrentProcess());
                }
            }

#if EXT2_DEBUG
            DEBUG(DL_INF, ("Ext2FastIIOCheckPossible: %s %s %wZ\n",
                           Ext2GetCurrentProcessName(),
                           "FASTIO_CHECK_IF_POSSIBLE",
                           &Fcb->Mcb->FullName
                          ));

            DEBUG(DL_INF, (
                      "Ext2FastIIOCheckPossible: Offset: %I64xg Length: %xh Key: %u %s %s\n",
                      FileOffset->QuadPart,
                      Length,
                      LockKey,
                      (CheckForReadOperation ? "CheckForReadOperation:" :
                       "CheckForWriteOperation:"),
                      (bPossible ? "Succeeded" : "Failed")));
#endif

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            bPossible = FastIoIsNotPossible;
        }

    } __finally {

        FsRtlExitFileSystem();
    }

    return bPossible;
}


BOOLEAN
Ext2FastIoRead (IN PFILE_OBJECT         FileObject,
                IN PLARGE_INTEGER       FileOffset,
                IN ULONG                Length,
                IN BOOLEAN              Wait,
                IN ULONG                LockKey,
                OUT PVOID               Buffer,
                OUT PIO_STATUS_BLOCK    IoStatus,
                IN PDEVICE_OBJECT       DeviceObject)
{
    PEXT2_FCB    Fcb;
    BOOLEAN      Status = FALSE;

    Fcb = (PEXT2_FCB) FileObject->FsContext;
    if (Fcb == NULL) {
        return FALSE;
    }

    ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
           (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

    Status = FsRtlCopyRead (
                 FileObject, FileOffset, Length, Wait,
                 LockKey, Buffer, IoStatus, DeviceObject);

    DEBUG(DL_IO, ("Ext2FastIoRead: %wZ Offset: %I64xh Length: %xh Key: %u Status: %d\n",
                  &Fcb->Mcb->ShortName, FileOffset->QuadPart, Length, LockKey, Status));

    return Status;
}

BOOLEAN
Ext2FastIoWrite (
    IN PFILE_OBJECT         FileObject,
    IN PLARGE_INTEGER       FileOffset,
    IN ULONG                Length,
    IN BOOLEAN              Wait,
    IN ULONG                LockKey,
    OUT PVOID               Buffer,
    OUT PIO_STATUS_BLOCK    IoStatus,
    IN PDEVICE_OBJECT       DeviceObject)
{
    PEXT2_FCB   Fcb = NULL;
    BOOLEAN     Status = FALSE;
    BOOLEAN     Locked = FALSE;

    Fcb = (PEXT2_FCB) FileObject->FsContext;
    if (Fcb == NULL)
        return FALSE;

    __try {

        FsRtlEnterFileSystem();

        ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
               (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

        if (IsVcbReadOnly(Fcb->Vcb)) {
            __leave;
        }

        if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait)) {
            __leave;
        }
        Locked = TRUE;

        if (IsWritingToEof(*FileOffset) ||
            Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length ||
            Fcb->Header.FileSize.QuadPart < FileOffset->QuadPart + Length ) {
            Status = FALSE;
            __leave;
        }

        if (Locked) {
            ExReleaseResourceLite(Fcb->Header.Resource);
            Locked = FALSE;
        }

        Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait,
                                LockKey, Buffer, IoStatus, DeviceObject);
        if (Status) {
            if (IoStatus)
                Length = (ULONG)IoStatus->Information;
        }

    } __finally {

        if (Locked) {
            ExReleaseResourceLite(Fcb->Header.Resource);
        }

        FsRtlExitFileSystem();
    }

    DEBUG(DL_IO, ("Ext2FastIoWrite: %wZ Offset: %I64xh Length: %xh Key: %xh Status=%d\n",
                  &Fcb->Mcb->ShortName,  FileOffset->QuadPart, Length, LockKey, Status));

    return Status;
}

BOOLEAN
Ext2FastIoQueryBasicInfo (
    IN PFILE_OBJECT             FileObject,
    IN BOOLEAN                  Wait,
    OUT PFILE_BASIC_INFORMATION Buffer,
    OUT PIO_STATUS_BLOCK        IoStatus,
    IN PDEVICE_OBJECT           DeviceObject)
{
    PEXT2_FCB   Fcb = NULL;
    PEXT2_CCB   Ccb = NULL;
    PEXT2_MCB   Mcb = NULL;
    BOOLEAN     Status = FALSE;
    BOOLEAN     FcbMainResourceAcquired = FALSE;

    __try {

        FsRtlEnterFileSystem();

        __try {

            if (IsExt2FsDevice(DeviceObject)) {
                IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
                __leave;
            }

            Fcb = (PEXT2_FCB) FileObject->FsContext;
            if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }
            Ccb = (PEXT2_CCB) FileObject->FsContext2;
            Mcb = Fcb->Mcb;
            ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                   (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
#if EXT2_DEBUG
            DEBUG(DL_INF, (
                      "Ext2FastIoQueryBasicInfo: %s %s %wZ\n",
                      Ext2GetCurrentProcessName(),
                      "FASTIO_QUERY_BASIC_INFO",
                      &Fcb->Mcb->FullName
                  ));
#endif
            if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE)) {
                if (!ExAcquireResourceSharedLite(
                            &Fcb->MainResource,
                            Wait)) {
                    __leave;
                }
                FcbMainResourceAcquired = TRUE;
            }

            RtlZeroMemory(Buffer, sizeof(FILE_BASIC_INFORMATION));

            /*
            typedef struct _FILE_BASIC_INFORMATION {
            LARGE_INTEGER   CreationTime;
            LARGE_INTEGER   LastAccessTime;
            LARGE_INTEGER   LastWriteTime;
            LARGE_INTEGER   ChangeTime;
            ULONG           FileAttributes;
            } FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
            */

            Buffer->CreationTime = Mcb->CreationTime;
            Buffer->LastAccessTime = Mcb->LastAccessTime;
            Buffer->LastWriteTime = Mcb->LastWriteTime;
            Buffer->ChangeTime = Mcb->ChangeTime;
            Buffer->FileAttributes = Mcb->FileAttr;
            if (Buffer->FileAttributes == 0) {
                Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
            }

            IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
            IoStatus->Status = STATUS_SUCCESS;

            Status =  TRUE;

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            IoStatus->Status = GetExceptionCode();
        }

    } __finally {

        if (FcbMainResourceAcquired) {
            ExReleaseResourceLite(&Fcb->MainResource);
        }

        FsRtlExitFileSystem();
    }

#if EXT2_DEBUG

    if (Status == FALSE) {

        DEBUG(DL_ERR, ("Ext2FastIoQueryBasicInfo: %s %s Status: FALSE ***\n",
                       Ext2GetCurrentProcessName(),
                       "FASTIO_QUERY_BASIC_INFO"));

    } else if (IoStatus->Status != STATUS_SUCCESS) {

        DEBUG(DL_ERR, (
                  "Ext2FastIoQueryBasicInfo: %s %s Status: %#x ***\n",
                  Ext2FastIoQueryBasicInfo,
                  "FASTIO_QUERY_BASIC_INFO",
                  IoStatus->Status
              ));
    }
#endif

    return Status;
}

BOOLEAN
Ext2FastIoQueryStandardInfo (
    IN PFILE_OBJECT                 FileObject,
    IN BOOLEAN                      Wait,
    OUT PFILE_STANDARD_INFORMATION  Buffer,
    OUT PIO_STATUS_BLOCK            IoStatus,
    IN PDEVICE_OBJECT               DeviceObject
)
{

    BOOLEAN     Status = FALSE;
    PEXT2_VCB   Vcb = NULL;
    PEXT2_FCB   Fcb = NULL;
    BOOLEAN     FcbMainResourceAcquired = FALSE;

    __try {

        FsRtlEnterFileSystem();

        __try {

            if (IsExt2FsDevice(DeviceObject)) {
                IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
                __leave;
            }

            Fcb = (PEXT2_FCB) FileObject->FsContext;
            if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB)  {
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }

            ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                   (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

#if EXT2_DEBUG
            DEBUG(DL_INF, (
                      "Ext2FastIoQueryStandardInfo: %s %s %wZ\n",
                      Ext2GetCurrentProcessName(),
                      "FASTIO_QUERY_STANDARD_INFO",
                      &Fcb->Mcb->FullName ));
#endif
            Vcb = Fcb->Vcb;

            if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE)) {
                if (!ExAcquireResourceSharedLite(
                            &Fcb->MainResource,
                            Wait        )) {
                    __leave;
                }
                FcbMainResourceAcquired = TRUE;
            }

            RtlZeroMemory(Buffer, sizeof(FILE_STANDARD_INFORMATION));

            /*
            typedef struct _FILE_STANDARD_INFORMATION {
            LARGE_INTEGER   AllocationSize;
            LARGE_INTEGER   EndOfFile;
            ULONG           NumberOfLinks;
            BOOLEAN         DeletePending;
            BOOLEAN         Directory;
            } FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
            */

            Buffer->NumberOfLinks = Fcb->Inode->i_nlink;
            Buffer->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING);

            if (IsDirectory(Fcb)) {
                Buffer->Directory = IsDirectory(Fcb);
                Buffer->AllocationSize.QuadPart = 0;
                Buffer->EndOfFile.QuadPart = 0;
            } else {
                Buffer->Directory = FALSE;
                Buffer->AllocationSize = Fcb->Header.AllocationSize;
                Buffer->EndOfFile = Fcb->Header.FileSize;
            }

            IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
            IoStatus->Status = STATUS_SUCCESS;
#if EXT2_DEBUG
            DEBUG(DL_INF, ( "Ext2FastIoQueryStandInfo: AllocatieonSize = %I64xh FileSize = %I64xh\n",
                            Buffer->AllocationSize.QuadPart, Buffer->EndOfFile.QuadPart));
#endif
            Status =  TRUE;

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            IoStatus->Status = GetExceptionCode();
        }

    } __finally {

        if (FcbMainResourceAcquired) {
            ExReleaseResourceLite(&Fcb->MainResource);
        }

        FsRtlExitFileSystem();
    }

#if EXT2_DEBUG
    if (Status == FALSE) {
        DEBUG(DL_INF, (
                  "Ext2FastIoQueryStandardInfo: %s %s Status: FALSE ***\n",
                  Ext2GetCurrentProcessName(),
                  "FASTIO_QUERY_STANDARD_INFO"            ));
    } else if (IoStatus->Status != STATUS_SUCCESS) {
        DEBUG(DL_INF, (
                  "Ext2FastIoQueryStandardInfo: %s %s Status: %#x ***\n",
                  Ext2GetCurrentProcessName(),
                  "FASTIO_QUERY_STANDARD_INFO",
                  IoStatus->Status            ));
    }
#endif

    return Status;
}

BOOLEAN
Ext2FastIoLock (
    IN PFILE_OBJECT         FileObject,
    IN PLARGE_INTEGER       FileOffset,
    IN PLARGE_INTEGER       Length,
    IN PEPROCESS            Process,
    IN ULONG                Key,
    IN BOOLEAN              FailImmediately,
    IN BOOLEAN              ExclusiveLock,
    OUT PIO_STATUS_BLOCK    IoStatus,
    IN PDEVICE_OBJECT       DeviceObject
)
{
    BOOLEAN     Status = FALSE;
    PEXT2_FCB   Fcb;

    __try {

        FsRtlEnterFileSystem();

        __try {

            if (IsExt2FsDevice(DeviceObject)) {
                IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
                __leave;
            }

            Fcb = (PEXT2_FCB) FileObject->FsContext;
            if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }

            ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                   (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

            if (IsDirectory(Fcb)) {
                DbgBreak();
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }
#if EXT2_DEBUG
            DEBUG(DL_INF, (
                      "Ext2FastIoLock: %s %s %wZ\n",
                      Ext2GetCurrentProcessName(),
                      "FASTIO_LOCK",
                      &Fcb->Mcb->FullName        ));

            DEBUG(DL_INF, (
                      "Ext2FastIoLock: Offset: %I64xh Length: %I64xh Key: %u %s%s\n",
                      FileOffset->QuadPart,
                      Length->QuadPart,
                      Key,
                      (FailImmediately ? "FailImmediately " : ""),
                      (ExclusiveLock ? "ExclusiveLock " : "") ));
#endif

            if (!FsRtlOplockIsFastIoPossible(&Fcb->Oplock)) {
                __leave;
            }

            Status = FsRtlFastLock(
                         &Fcb->FileLockAnchor,
                         FileObject,
                         FileOffset,
                         Length,
                         Process,
                         Key,
                         FailImmediately,
                         ExclusiveLock,
                         IoStatus,
                         NULL,
                         FALSE);

            if (Status) {
                Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
            }

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            IoStatus->Status = GetExceptionCode();
        }

    } __finally {

        FsRtlExitFileSystem();
    }

#if EXT2_DEBUG
    if (Status == FALSE) {
        DEBUG(DL_ERR, (
                  "Ext2FastIoLock: %s %s *** Status: FALSE ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_LOCK"
              ));
    } else if (IoStatus->Status != STATUS_SUCCESS) {
        DEBUG(DL_ERR, (
                  "Ext2FastIoLock: %s %s *** Status: %s (%#x) ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_LOCK",
                  Ext2NtStatusToString(IoStatus->Status),
                  IoStatus->Status
              ));
    }
#endif

    return Status;
}

BOOLEAN
Ext2FastIoUnlockSingle (
    IN PFILE_OBJECT         FileObject,
    IN PLARGE_INTEGER       FileOffset,
    IN PLARGE_INTEGER       Length,
    IN PEPROCESS            Process,
    IN ULONG                Key,
    OUT PIO_STATUS_BLOCK    IoStatus,
    IN PDEVICE_OBJECT       DeviceObject
)
{
    BOOLEAN     Status = FALSE;
    PEXT2_FCB   Fcb;

    __try {

        FsRtlEnterFileSystem();

        __try {

            if (IsExt2FsDevice(DeviceObject)) {
                IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
                __leave;
            }

            Fcb = (PEXT2_FCB) FileObject->FsContext;
            if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
                DbgBreak();
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }

            ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                   (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

            if (IsDirectory(Fcb)) {
                DbgBreak();
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }

#if EXT2_DEBUG
            DEBUG(DL_INF, (
                      "Ext2FastIoUnlockSingle: %s %s %wZ\n",
                      (PUCHAR) Process + ProcessNameOffset,
                      "FASTIO_UNLOCK_SINGLE",
                      &Fcb->Mcb->FullName        ));

            DEBUG(DL_INF, (
                      "Ext2FastIoUnlockSingle: Offset: %I64xh Length: %I64xh Key: %u\n",
                      FileOffset->QuadPart,
                      Length->QuadPart,
                      Key     ));
#endif

            if (!FsRtlOplockIsFastIoPossible(&Fcb->Oplock)) {
                __leave;
            }

            IoStatus->Status = FsRtlFastUnlockSingle(
                                   &Fcb->FileLockAnchor,
                                   FileObject,
                                   FileOffset,
                                   Length,
                                   Process,
                                   Key,
                                   NULL,
                                   FALSE);

            IoStatus->Information = 0;
            Status =  TRUE;

            Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            IoStatus->Status = GetExceptionCode();
        }

    } __finally {

        FsRtlExitFileSystem();
    }

#if EXT2_DEBUG
    if (Status == FALSE) {

        DEBUG(DL_ERR, (
                  "Ext2FastIoUnlockSingle: %s %s *** Status: FALSE ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_UNLOCK_SINGLE"          ));
    } else if (IoStatus->Status != STATUS_SUCCESS) {
        DEBUG(DL_ERR, (
                  "Ext2FastIoUnlockSingle: %s %s *** Status: %s (%#x) ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_UNLOCK_SINGLE",
                  Ext2NtStatusToString(IoStatus->Status),
                  IoStatus->Status            ));
    }
#endif

    return Status;
}

BOOLEAN
Ext2FastIoUnlockAll (
    IN PFILE_OBJECT         FileObject,
    IN PEPROCESS            Process,
    OUT PIO_STATUS_BLOCK    IoStatus,
    IN PDEVICE_OBJECT       DeviceObject)
{
    BOOLEAN     Status = FALSE;
    PEXT2_FCB   Fcb;

    __try {

        FsRtlEnterFileSystem();

        __try {

            if (IsExt2FsDevice(DeviceObject)) {
                IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
                __leave;
            }

            Fcb = (PEXT2_FCB) FileObject->FsContext;
            if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
                DbgBreak();
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }

            ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                   (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

            if (IsDirectory(Fcb)) {
                DbgBreak();
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }
#if EXT2_DEBUG
            DEBUG(DL_INF, (
                      "Ext2FastIoUnlockSingle: %s %s %wZ\n",
                      (PUCHAR) Process + ProcessNameOffset,
                      "FASTIO_UNLOCK_ALL",
                      &Fcb->Mcb->FullName
                  ));
#endif

            if (!FsRtlOplockIsFastIoPossible(&Fcb->Oplock)) {
                __leave;
            }

            IoStatus->Status = FsRtlFastUnlockAll(
                                   &Fcb->FileLockAnchor,
                                   FileObject,
                                   Process,
                                   NULL        );

            IoStatus->Information = 0;
            Status =  TRUE;

            Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            IoStatus->Status = GetExceptionCode();
        }

    } __finally {

        FsRtlExitFileSystem();
    }

#if EXT2_DEBUG
    if (Status == FALSE) {

        DEBUG(DL_ERR, (
                  "Ext2FastIoUnlockSingle: %s %s *** Status: FALSE ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_UNLOCK_ALL"
              ));
    } else if (IoStatus->Status != STATUS_SUCCESS) {
        DEBUG(DL_ERR, (
                  "Ext2FastIoUnlockSingle: %s %s *** Status: %s (%#x) ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_UNLOCK_ALL",
                  Ext2NtStatusToString(IoStatus->Status),
                  IoStatus->Status
              ));
    }
#endif

    return Status;
}

BOOLEAN
Ext2FastIoUnlockAllByKey (
    IN PFILE_OBJECT         FileObject,
    IN PEPROCESS            Process,
    IN ULONG                Key,
    OUT PIO_STATUS_BLOCK    IoStatus,
    IN PDEVICE_OBJECT       DeviceObject
)
{
    BOOLEAN     Status = FALSE;
    PEXT2_FCB   Fcb;

    __try {

        FsRtlEnterFileSystem();

        __try {

            if (IsExt2FsDevice(DeviceObject)) {
                IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
                __leave;
            }

            Fcb = (PEXT2_FCB) FileObject->FsContext;
            if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
                DbgBreak();
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }

            ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
                   (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

            if (IsDirectory(Fcb)) {
                DbgBreak();
                IoStatus->Status = STATUS_INVALID_PARAMETER;
                __leave;
            }

#if EXT2_DEBUG
            DEBUG(DL_INF, (
                      "Ext2FastIoUnlockAllByKey: %s %s %wZ\n",
                      (PUCHAR) Process + ProcessNameOffset,
                      "FASTIO_UNLOCK_ALL_BY_KEY",
                      &Fcb->Mcb->FullName
                  ));

            DEBUG(DL_INF, (
                      "Ext2FastIoUnlockAllByKey: Key: %u\n",
                      Key
                  ));
#endif

            if (!FsRtlOplockIsFastIoPossible(&Fcb->Oplock)) {
                __leave;
            }

            IoStatus->Status = FsRtlFastUnlockAllByKey(
                                   &Fcb->FileLockAnchor,
                                   FileObject,
                                   Process,
                                   Key,
                                   NULL
                               );

            IoStatus->Information = 0;
            Status =  TRUE;

            Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            IoStatus->Status = GetExceptionCode();
        }

    } __finally {

        FsRtlExitFileSystem();
    }

#if EXT2_DEBUG
    if (Status == FALSE) {

        DEBUG(DL_ERR, (
                  "Ext2FastIoUnlockAllByKey: %s %s *** Status: FALSE ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_UNLOCK_ALL_BY_KEY"
              ));
    } else if (IoStatus->Status != STATUS_SUCCESS) {

        DEBUG(DL_ERR, (
                  "Ext2FastIoUnlockAllByKey: %s %s *** Status: %s (%#x) ***\n",
                  (PUCHAR) Process + ProcessNameOffset,
                  "FASTIO_UNLOCK_ALL_BY_KEY",
                  Ext2NtStatusToString(IoStatus->Status),
                  IoStatus->Status
              ));
    }
#endif

    return Status;
}


BOOLEAN
Ext2FastIoQueryNetworkOpenInfo (
    IN PFILE_OBJECT         FileObject,
    IN BOOLEAN              Wait,
    IN OUT PFILE_NETWORK_OPEN_INFORMATION PFNOI,
    OUT PIO_STATUS_BLOCK    IoStatus,
    IN PDEVICE_OBJECT       DeviceObject
)
{
    PEXT2_FCB   Fcb = NULL;
    PEXT2_CCB   Ccb = NULL;
    PEXT2_MCB   Mcb = NULL;

    BOOLEAN     bResult = FALSE;
    BOOLEAN FcbResourceAcquired = FALSE;

    __try {

        FsRtlEnterFileSystem();

        if (IsExt2FsDevice(DeviceObject)) {
            IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
            __leave;
        }

        Fcb = (PEXT2_FCB) FileObject->FsContext;
        if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
            DbgBreak();
            IoStatus->Status = STATUS_INVALID_PARAMETER;
            __leave;
        }

        ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
               (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
        Ccb = (PEXT2_CCB) FileObject->FsContext2;
        Mcb = Fcb->Mcb;

#if EXT2_DEBUG
        DEBUG(DL_INF, (
                  "%-31s %wZ\n",
                  "FASTIO_QUERY_NETWORK_OPEN_INFO",
                  &Fcb->Mcb->FullName
              ));
#endif

        if (!Ccb) {
            __leave;
        }

        if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE)) {

            if (!ExAcquireResourceSharedLite(
                        &Fcb->MainResource,
                        Wait
                    )) {
                __leave;
            }

            FcbResourceAcquired = TRUE;
        }

        if (IsDirectory(Fcb)) {
            PFNOI->AllocationSize.QuadPart = 0;
            PFNOI->EndOfFile.QuadPart = 0;
        } else {
            PFNOI->AllocationSize = Fcb->Header.AllocationSize;
            PFNOI->EndOfFile      = Fcb->Header.FileSize;
        }

        PFNOI->FileAttributes = Mcb->FileAttr;
        if (PFNOI->FileAttributes == 0) {
            PFNOI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
        }

        PFNOI->CreationTime   = Mcb->CreationTime;
        PFNOI->LastAccessTime = Mcb->LastAccessTime;
        PFNOI->LastWriteTime  = Mcb->LastWriteTime;
        PFNOI->ChangeTime     = Mcb->ChangeTime;

        bResult = TRUE;

        IoStatus->Status = STATUS_SUCCESS;
        IoStatus->Information = sizeof(FILE_NETWORK_OPEN_INFORMATION);

    } __finally {

        if (FcbResourceAcquired) {
            ExReleaseResourceLite(&Fcb->MainResource);
        }

        FsRtlExitFileSystem();
    }

    return bResult;
}


VOID
Ext2AcquireForCreateSection (
    IN PFILE_OBJECT FileObject
)

{
    PEXT2_FCB Fcb = FileObject->FsContext;

    if (Fcb->Header.Resource != NULL) {
        ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
    }

    DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireForCreateSection:  Fcb=%p\n", Fcb));
}

VOID
Ext2ReleaseForCreateSection (
    IN PFILE_OBJECT FileObject
)
{
    PEXT2_FCB Fcb = FileObject->FsContext;

    DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseForCreateSection:  Fcb=%p\n", Fcb));

    if (Fcb->Header.Resource != NULL) {
        ExReleaseResourceLite(Fcb->Header.Resource);
    }
}


NTSTATUS
Ext2AcquireFileForModWrite (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER EndingOffset,
    OUT PERESOURCE *ResourceToRelease,
    IN PDEVICE_OBJECT DeviceObject
)

{
    BOOLEAN ResourceAcquired = FALSE;

    PEXT2_FCB Fcb = FileObject->FsContext;

    *ResourceToRelease = Fcb->Header.Resource;
    ResourceAcquired = ExAcquireResourceExclusiveLite(*ResourceToRelease, FALSE);
    if (!ResourceAcquired) {
        *ResourceToRelease = NULL;
    }

    DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireFileForModWrite:  Fcb=%p Acquired=%d\n",
                             Fcb, ResourceAcquired));

    return (ResourceAcquired ? STATUS_SUCCESS : STATUS_CANT_WAIT);
}

NTSTATUS
Ext2ReleaseFileForModWrite (
    IN PFILE_OBJECT FileObject,
    IN PERESOURCE ResourceToRelease,
    IN PDEVICE_OBJECT DeviceObject
)
{
    PEXT2_FCB Fcb = FileObject->FsContext;

    DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseFileForModWrite: Fcb=%p\n", Fcb));

    if (ResourceToRelease != NULL) {
        ASSERT(ResourceToRelease == Fcb->Header.Resource);
        ExReleaseResourceLite(ResourceToRelease);
    } else {
        DbgBreak();
    }

    return STATUS_SUCCESS;
}

NTSTATUS
Ext2AcquireFileForCcFlush (
    IN PFILE_OBJECT FileObject,
    IN PDEVICE_OBJECT DeviceObject
)
{
    PEXT2_FCB Fcb = FileObject->FsContext;

    if (Fcb->Header.Resource != NULL) {
        ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
    }

    DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireFileForCcFlush: Fcb=%p\n", Fcb));

    return STATUS_SUCCESS;
}

NTSTATUS
Ext2ReleaseFileForCcFlush (
    IN PFILE_OBJECT FileObject,
    IN PDEVICE_OBJECT DeviceObject
)
{
    PEXT2_FCB Fcb = FileObject->FsContext;

    DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseFileForCcFlush: Fcb=%p\n", Fcb));

    if (Fcb->Header.Resource != NULL) {
        ExReleaseResourceLite(Fcb->Header.Resource);
    }

    return STATUS_SUCCESS;
}


NTSTATUS
Ext2PreAcquireForCreateSection(
    IN PFS_FILTER_CALLBACK_DATA cd,
    OUT PVOID *cc
    )
{
    PEXT2_FCB Fcb = (PEXT2_FCB)cd->FileObject->FsContext;
    NTSTATUS        status;

    ASSERT(cd->Operation == FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION);
    ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
    if (cd->Parameters.AcquireForSectionSynchronization.SyncType != SyncTypeCreateSection) {
        status = STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY;
    } else if (Fcb->ShareAccess.Writers == 0) {
        status = STATUS_FILE_LOCKED_WITH_ONLY_READERS;
    } else {
        status = STATUS_FILE_LOCKED_WITH_WRITERS;
    }

    return status;
}
