Esempio n. 1
0
NTSTATUS
DokanDispatchRead(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp)

/*++

Routine Description:

        This device control dispatcher handles read IRPs.

Arguments:

        DeviceObject - Context for the activity.
        Irp          - The device control argument block.

Return Value:

        NTSTATUS

--*/
{
  PIO_STACK_LOCATION irpSp;
  PFILE_OBJECT fileObject;
  ULONG bufferLength;
  LARGE_INTEGER byteOffset;
  NTSTATUS status = STATUS_INVALID_PARAMETER;
  ULONG readLength = 0;
  PDokanCCB ccb;
  PDokanFCB fcb = NULL;
  PDokanVCB vcb;
  PVOID currentAddress = NULL;
  PEVENT_CONTEXT eventContext;
  ULONG eventLength;
  BOOLEAN fcbLocked = FALSE;
  BOOLEAN isPagingIo = FALSE;
  BOOLEAN isSynchronousIo = FALSE;
  BOOLEAN noCache = FALSE;

  __try {

    DDbgPrint("==> DokanRead\n");

    irpSp = IoGetCurrentIrpStackLocation(Irp);
    fileObject = irpSp->FileObject;

    //
    //  If this is a zero length read then return SUCCESS immediately.
    //
    if (irpSp->Parameters.Read.Length == 0) {
      DDbgPrint("  Parameters.Read.Length == 0 \n");
      Irp->IoStatus.Information = 0;
      status = STATUS_SUCCESS;
      __leave;
    }

    if (irpSp->MinorFunction == IRP_MN_COMPLETE) {
      Irp->MdlAddress = NULL;
      status = STATUS_SUCCESS;
      __leave;
    }

    if (fileObject == NULL && Irp->MdlAddress != NULL) {
      DDbgPrint("  Reads by File System Recognizers\n");

      currentAddress = MmGetSystemAddressForMdlNormalSafe(Irp->MdlAddress);
      if (currentAddress == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        __leave;
      }

      // here we could return the bootsector. If we don't have one
      // the requested read lenght must be returned as requested
      readLength = irpSp->Parameters.Read.Length;
      status = STATUS_SUCCESS;
      __leave;
    }

    if (fileObject == NULL) {
      DDbgPrint("  fileObject == NULL\n");
      status = STATUS_INVALID_DEVICE_REQUEST;
      __leave;
    }

    vcb = DeviceObject->DeviceExtension;
    if (GetIdentifierType(vcb) != VCB ||
        !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) {
      status = STATUS_INVALID_DEVICE_REQUEST;
      __leave;
    }

    bufferLength = irpSp->Parameters.Read.Length;
    if (irpSp->Parameters.Read.ByteOffset.LowPart ==
            FILE_USE_FILE_POINTER_POSITION &&
        irpSp->Parameters.Read.ByteOffset.HighPart == -1) {

      // irpSp->Parameters.Read.ByteOffset == NULL don't need check?

      DDbgPrint("use FileObject ByteOffset\n");

      byteOffset = fileObject->CurrentByteOffset;

    } else {
      byteOffset = irpSp->Parameters.Read.ByteOffset;
    }

    DDbgPrint("  ProcessId %lu\n", IoGetRequestorProcessId(Irp));
    DokanPrintFileName(fileObject);
    DDbgPrint("  ByteCount:%lu ByteOffset:%I64d\n", bufferLength,
              byteOffset.QuadPart);

    if (bufferLength == 0) {
      status = STATUS_SUCCESS;
      readLength = 0;
      __leave;
    }

    // make a MDL for UserBuffer that can be used later on another thread
    // context
    if (Irp->MdlAddress == NULL) {
      status = DokanAllocateMdl(Irp, irpSp->Parameters.Read.Length);
      if (!NT_SUCCESS(status)) {
        __leave;
      }
    }

    ccb = fileObject->FsContext2;
    ASSERT(ccb != NULL);

    fcb = ccb->Fcb;
    ASSERT(fcb != NULL);

    if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
      DDbgPrint("   DOKAN_FILE_DIRECTORY %p\n", fcb);
      status = STATUS_INVALID_PARAMETER;
      __leave;
    }

    if (Irp->Flags & IRP_PAGING_IO) {
      isPagingIo = TRUE;
    }
    if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
      isSynchronousIo = TRUE;
    }

    if (Irp->Flags & IRP_NOCACHE) {
      noCache = TRUE;
    }

    if (!isPagingIo && (fileObject->SectionObjectPointer != NULL) &&
        (fileObject->SectionObjectPointer->DataSectionObject != NULL)) {
      ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE);
      CcFlushCache(&fcb->SectionObjectPointers,
                   &irpSp->Parameters.Read.ByteOffset,
                   irpSp->Parameters.Read.Length, NULL);
      ExReleaseResourceLite(&fcb->PagingIoResource);
    }

    DokanFCBLockRO(fcb);
    fcbLocked = TRUE;
    // length of EventContext is sum of file name length and itself
    eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length;

    eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb);
    if (eventContext == NULL) {
      status = STATUS_INSUFFICIENT_RESOURCES;
      __leave;
    }

    eventContext->Context = ccb->UserContext;
    // DDbgPrint("   get Context %X\n", (ULONG)ccb->UserContext);

    if (isPagingIo) {
      DDbgPrint("  Paging IO\n");
      eventContext->FileFlags |= DOKAN_PAGING_IO;
    }
    if (isSynchronousIo) {
      DDbgPrint("  Synchronous IO\n");
      eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO;
    }

    if (noCache) {
      DDbgPrint("  Nocache\n");
      eventContext->FileFlags |= DOKAN_NOCACHE;
    }

    // offset of file to read
    eventContext->Operation.Read.ByteOffset = byteOffset;

    // buffer size for read
    // user-mode file system application can return this size
    eventContext->Operation.Read.BufferLength = irpSp->Parameters.Read.Length;

    // copy the accessed file name
    eventContext->Operation.Read.FileNameLength = fcb->FileName.Length;
    RtlCopyMemory(eventContext->Operation.Read.FileName, fcb->FileName.Buffer,
                  fcb->FileName.Length);

    //
    //  We now check whether we can proceed based on the state of
    //  the file oplocks.
    //
    if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
      // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking.
      status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext,
                                DokanOplockComplete, DokanPrePostIrp);

      //
      //  if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
      //  to service an oplock break and we need to leave now.
      //
      if (status != STATUS_SUCCESS) {
        if (status == STATUS_PENDING) {
          DDbgPrint("   FsRtlCheckOplock returned STATUS_PENDING\n");
        } else {
          DokanFreeEventContext(eventContext);
        }
        __leave;
      }

      //
      // We have to check for read access according to the current
      // state of the file locks, and set FileSize from the Fcb.
      //
      // FsRtlCheckLockForReadAccess does not block.
      if (!FsRtlCheckLockForReadAccess(&fcb->FileLock, Irp)) {
        status = STATUS_FILE_LOCK_CONFLICT;
        __leave;
      }
    }

    // register this IRP to pending IPR list and make it pending status
    status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0);
  } __finally {
    if(fcbLocked)
      DokanFCBUnlock(fcb);

    DokanCompleteIrpRequest(Irp, status, readLength);

    DDbgPrint("<== DokanRead\n");
  }

  return status;
}
Esempio n. 2
0
NTSTATUS
DokanDispatchSetInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) {

  NTSTATUS status = STATUS_NOT_IMPLEMENTED;
  PIO_STACK_LOCATION irpSp;
  PVOID buffer;
  PFILE_OBJECT fileObject;
  PDokanCCB ccb;
  PDokanFCB fcb = NULL;
  PDokanVCB vcb;
  ULONG eventLength;
  PFILE_OBJECT targetFileObject;
  PEVENT_CONTEXT eventContext;
  BOOLEAN isPagingIo = FALSE;
  BOOLEAN fcbLocked = FALSE;
  PFILE_END_OF_FILE_INFORMATION pInfoEoF = NULL;

  vcb = DeviceObject->DeviceExtension;

  __try {
    DDbgPrint("==> DokanSetInformationn\n");

    irpSp = IoGetCurrentIrpStackLocation(Irp);
    fileObject = irpSp->FileObject;

    if (fileObject == NULL) {
      DDbgPrint("  fileObject == NULL\n");
      status = STATUS_INVALID_PARAMETER;
      __leave;
    }

    if (GetIdentifierType(vcb) != VCB ||
        !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) {
      status = STATUS_INVALID_PARAMETER;
      __leave;
    }

    ccb = (PDokanCCB)fileObject->FsContext2;
    ASSERT(ccb != NULL);

    DDbgPrint("  ProcessId %lu\n", IoGetRequestorProcessId(Irp));
    DokanPrintFileName(fileObject);

    buffer = Irp->AssociatedIrp.SystemBuffer;

    if (Irp->Flags & IRP_PAGING_IO) {
      isPagingIo = TRUE;
    }

    fcb = ccb->Fcb;
    ASSERT(fcb != NULL);

    switch (irpSp->Parameters.SetFile.FileInformationClass) {
    case FileAllocationInformation:
      DDbgPrint(
          "  FileAllocationInformation %lld\n",
          ((PFILE_ALLOCATION_INFORMATION)buffer)->AllocationSize.QuadPart);
      break;
    case FileBasicInformation:
      DDbgPrint("  FileBasicInformation\n");
      break;
    case FileDispositionInformation:
      DDbgPrint("  FileDispositionInformation\n");
      break;
    case FileEndOfFileInformation:
      if ((fileObject->SectionObjectPointer != NULL) &&
          (fileObject->SectionObjectPointer->DataSectionObject != NULL)) {

        pInfoEoF = (PFILE_END_OF_FILE_INFORMATION)buffer;

        if (!MmCanFileBeTruncated(fileObject->SectionObjectPointer,
                                  &pInfoEoF->EndOfFile)) {
          status = STATUS_USER_MAPPED_FILE;
          __leave;
        }

        if (!isPagingIo) {
          ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE);
          CcFlushCache(&fcb->SectionObjectPointers, NULL, 0, NULL);
          CcPurgeCacheSection(&fcb->SectionObjectPointers, NULL, 0, FALSE);
          ExReleaseResourceLite(&fcb->PagingIoResource);
        }
      }
      DDbgPrint("  FileEndOfFileInformation %lld\n",
                ((PFILE_END_OF_FILE_INFORMATION)buffer)->EndOfFile.QuadPart);
      break;
    case FileLinkInformation:
      DDbgPrint("  FileLinkInformation\n");
      break;
    case FilePositionInformation: {
      PFILE_POSITION_INFORMATION posInfo;

      posInfo = (PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
      ASSERT(posInfo != NULL);

      DDbgPrint("  FilePositionInformation %lld\n",
                posInfo->CurrentByteOffset.QuadPart);
      fileObject->CurrentByteOffset = posInfo->CurrentByteOffset;

      status = STATUS_SUCCESS;

      __leave;
    } break;
    case FileRenameInformation:
      DDbgPrint("  FileRenameInformation\n");
      break;
    case FileValidDataLengthInformation:
      DDbgPrint("  FileValidDataLengthInformation\n");
      break;
    default:
      DDbgPrint("  unknown type:%d\n",
                irpSp->Parameters.SetFile.FileInformationClass);
      break;
    }

    //
    // when this IRP is not handled in swich case
    //

    // calcurate the size of EVENT_CONTEXT
    // it is sum of file name length and size of FileInformation
    DokanFCBLockRW(fcb);
    fcbLocked = TRUE;
    eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length +
                  irpSp->Parameters.SetFile.Length;

    targetFileObject = irpSp->Parameters.SetFile.FileObject;

    if (targetFileObject) {
      DDbgPrint("  FileObject Specified %wZ\n", &(targetFileObject->FileName));
      eventLength += targetFileObject->FileName.Length;
    }

    eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb);

    if (eventContext == NULL) {
      status = STATUS_INSUFFICIENT_RESOURCES;
      __leave;
    }

    eventContext->Context = ccb->UserContext;

    eventContext->Operation.SetFile.FileInformationClass =
        irpSp->Parameters.SetFile.FileInformationClass;

    // the size of FileInformation
    eventContext->Operation.SetFile.BufferLength =
        irpSp->Parameters.SetFile.Length;

    // the offset from begining of structure to fill FileInfo
    eventContext->Operation.SetFile.BufferOffset =
        FIELD_OFFSET(EVENT_CONTEXT, Operation.SetFile.FileName[0]) +
        fcb->FileName.Length + sizeof(WCHAR); // the last null char

    BOOLEAN isRenameOrLink = irpSp->Parameters.SetFile.FileInformationClass ==
        FileRenameInformation ||
        irpSp->Parameters.SetFile.FileInformationClass == FileLinkInformation;

    if (!isRenameOrLink) {
        // copy FileInformation
        RtlCopyMemory(
            (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset,
            Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.SetFile.Length);
    }

    if (isRenameOrLink) {
      // We need to hanle FileRenameInformation separetly because the structure
      // of FILE_RENAME_INFORMATION
      // has HANDLE type field, which size is different in 32 bit and 64 bit
      // environment.
      // This cases problems when driver is 64 bit and user mode library is 32
      // bit.
      PFILE_RENAME_INFORMATION renameInfo =
          (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
      PDOKAN_RENAME_INFORMATION renameContext = (PDOKAN_RENAME_INFORMATION)(
          (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset);

      // This code assumes FILE_RENAME_INFORMATION and FILE_LINK_INFORMATION
      // have
      // the same typse and fields.
      ASSERT(sizeof(FILE_RENAME_INFORMATION) == sizeof(FILE_LINK_INFORMATION));

      renameContext->ReplaceIfExists = renameInfo->ReplaceIfExists;
      renameContext->FileNameLength = renameInfo->FileNameLength;
      RtlCopyMemory(renameContext->FileName, renameInfo->FileName,
                    renameInfo->FileNameLength);

      if (targetFileObject != NULL) {
        // if Parameters.SetFile.FileObject is specified, replase
        // FILE_RENAME_INFO's file name by
        // FileObject's file name. The buffer size is already adjusted.

        DDbgPrint("  renameContext->FileNameLength %d\n",
            renameContext->FileNameLength);
        DDbgPrint("  renameContext->FileName %ws\n", renameContext->FileName);
        RtlZeroMemory(renameContext->FileName, renameContext->FileNameLength);

        PFILE_OBJECT parentFileObject = targetFileObject->RelatedFileObject;
        if (parentFileObject != NULL) {
            RtlCopyMemory(renameContext->FileName,
                parentFileObject->FileName.Buffer,
                parentFileObject->FileName.Length);

            RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, L"\\");
            RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, targetFileObject->FileName.Buffer);
            renameContext->FileNameLength = targetFileObject->FileName.Length + 
                parentFileObject->FileName.Length + sizeof(WCHAR);
        } else {
            RtlCopyMemory(renameContext->FileName,
                targetFileObject->FileName.Buffer,
                targetFileObject->FileName.Length);
            renameContext->FileNameLength = targetFileObject->FileName.Length;
        }
      }

      if (irpSp->Parameters.SetFile.FileInformationClass ==
          FileRenameInformation) {
        DDbgPrint("   rename: %wZ => %ls, FileCount = %u\n", fcb->FileName,
                  renameContext->FileName, (ULONG)fcb->FileCount);
      }
    }

    // copy the file name
    eventContext->Operation.SetFile.FileNameLength = fcb->FileName.Length;
    RtlCopyMemory(eventContext->Operation.SetFile.FileName,
                  fcb->FileName.Buffer, fcb->FileName.Length);

    // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking.
    status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext,
                              DokanOplockComplete, DokanPrePostIrp);

    //
    //  if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
    //  to service an oplock break and we need to leave now.
    //
    if (status != STATUS_SUCCESS) {
      if (status == STATUS_PENDING) {
        DDbgPrint("   FsRtlCheckOplock returned STATUS_PENDING\n");
      } else {
        DokanFreeEventContext(eventContext);
      }
      __leave;
    }

    // register this IRP to waiting IRP list and make it pending status
    status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0);

  } __finally {
    if(fcbLocked)
      DokanFCBUnlock(fcb);

    DokanCompleteIrpRequest(Irp, status, 0);

    DDbgPrint("<== DokanSetInformation\n");
  }

  return status;
}
Esempio n. 3
0
NTSTATUS
CdCommonLockControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for Lock Control called by both the fsd and fsp
    threads.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );

    TYPE_OF_OPEN TypeOfOpen;
    PFCB Fcb;
    PCCB Ccb;

    PAGED_CODE();

    //
    //  Extract and decode the type of file object we're being asked to process
    //

    TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );

    //
    //  If the file is not a user file open then we reject the request
    //  as an invalid parameter
    //

    if (TypeOfOpen != UserFileOpen) {

        CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  We check whether we can proceed based on the state of the file oplocks.
    //  This call might post the irp for us.
    //

    Status = FsRtlCheckOplock( &Fcb->Oplock,
                               Irp,
                               IrpContext,
                               CdOplockComplete,
                               NULL );

    //
    //  If we don't get success then the oplock package completed the request.
    //

    if (Status != STATUS_SUCCESS) {

        return Status;
    }

    //
    //  Verify the Fcb.
    //

    CdVerifyFcbOperation( IrpContext, Fcb );

    //
    //  If we don't have a file lock, then get one now.
    //

    if (Fcb->FileLock == NULL) { CdCreateFileLock( IrpContext, Fcb, TRUE ); }

    //
    //  Now call the FsRtl routine to do the actual processing of the
    //  Lock request
    //

    Status = FsRtlProcessFileLock( Fcb->FileLock, Irp, NULL );

    //
    //  Set the flag indicating if Fast I/O is possible
    //

    CdLockFcb( IrpContext, Fcb );
    Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
    CdUnlockFcb( IrpContext, Fcb );

    //
    //  Complete the request.
    //

    CdCompleteRequest( IrpContext, NULL, Status );
    return Status;
}
Esempio n. 4
0
File: read.c Progetto: jrfl/ext2fsd
NTSTATUS
Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
{
    NTSTATUS            Status = STATUS_UNSUCCESSFUL;

    PEXT2_VCB           Vcb = NULL;
    PEXT2_FCB           Fcb = NULL;
    PEXT2_CCB           Ccb = NULL;
    PFILE_OBJECT        FileObject = NULL;

    PDEVICE_OBJECT      DeviceObject = NULL;

    PIRP                Irp = NULL;
    PIO_STACK_LOCATION  IoStackLocation = NULL;

    ULONG               Length;
    ULONG               ReturnedLength = 0;
    LARGE_INTEGER       ByteOffset;

    BOOLEAN             OpPostIrp = FALSE;
    BOOLEAN             PagingIo;
    BOOLEAN             Nocache;
    BOOLEAN             SynchronousIo;
    BOOLEAN             MainResourceAcquired = FALSE;
    BOOLEAN             PagingIoResourceAcquired = FALSE;

    PUCHAR              Buffer;

    __try {

        ASSERT(IrpContext);
        ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
               (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));

        DeviceObject = IrpContext->DeviceObject;
        Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
        ASSERT(Vcb != NULL);
        ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
               (Vcb->Identifier.Size == sizeof(EXT2_VCB)));

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

        Ccb = (PEXT2_CCB) FileObject->FsContext2;

        Irp = IrpContext->Irp;
        IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

        Length = IoStackLocation->Parameters.Read.Length;
        ByteOffset = IoStackLocation->Parameters.Read.ByteOffset;

        PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO);
        Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE);
        SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);

        if (PagingIo) {
            ASSERT(Nocache);
        }

        DEBUG(DL_INF, ("Ext2ReadFile: reading %wZ Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
                       &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));

        if ((IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ||
            IsFileDeleted(Fcb->Mcb)) {
            Status = STATUS_FILE_DELETED;
            __leave;
        }

        if (Length == 0) {
            Irp->IoStatus.Information = 0;
            Status = STATUS_SUCCESS;
            __leave;
        }

        if (Nocache &&
                (ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
                 Length & (SECTOR_SIZE - 1))) {
            Status = STATUS_INVALID_PARAMETER;
            DbgBreak();
            __leave;
        }

        if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
            ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
            Status = STATUS_PENDING;
            DbgBreak();
            __leave;
        }

        if (!PagingIo && Nocache && (FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
            CcFlushCache( FileObject->SectionObjectPointer,
                          &ByteOffset,
                          Length,
                          &Irp->IoStatus );

            if (!NT_SUCCESS(Irp->IoStatus.Status)) {
                __leave;
            }
        }

        ReturnedLength = Length;

        if (PagingIo) {

            if (!ExAcquireResourceSharedLite(
                        &Fcb->PagingIoResource,
                        IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
                Status = STATUS_PENDING;
                __leave;
            }
            PagingIoResourceAcquired = TRUE;

        } else {

            if (Nocache) {

                if (!ExAcquireResourceExclusiveLite(
                            &Fcb->MainResource,
                            IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
                    Status = STATUS_PENDING;
                    __leave;
                }
                MainResourceAcquired = TRUE;

            } else {

                if (!ExAcquireResourceSharedLite(
                            &Fcb->MainResource,
                            IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
                    Status = STATUS_PENDING;
                    __leave;
                }
                MainResourceAcquired = TRUE;
            }

            if (!FsRtlCheckLockForReadAccess(
                        &Fcb->FileLockAnchor,
                        Irp         )) {
                Status = STATUS_FILE_LOCK_CONFLICT;
                __leave;
            }
        }

        if ((ByteOffset.QuadPart + (LONGLONG)Length) > Fcb->Header.FileSize.QuadPart) {
            if (ByteOffset.QuadPart >= Fcb->Header.FileSize.QuadPart) {
                Irp->IoStatus.Information = 0;
                Status = STATUS_END_OF_FILE;
                __leave;
            }
            ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
        }


        if (!IsDirectory(Fcb) && Ccb != NULL) {

            Status = FsRtlCheckOplock( &Fcb->Oplock,
                                       Irp,
                                       IrpContext,
                                       Ext2OplockComplete,
                                       Ext2LockIrp );

            if (Status != STATUS_SUCCESS) {
                OpPostIrp = TRUE;
                __leave;
            }

            //
            //  Set the flag indicating if Fast I/O is possible
            //

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

        if (!Nocache) {

            if (IsDirectory(Fcb)) {
                __leave;
            }

            if (FileObject->PrivateCacheMap == NULL) {
                CcInitializeCacheMap(
                        FileObject,
                        (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
                        FALSE,
                        &Ext2Global->CacheManagerCallbacks,
                        Fcb );
                CcSetReadAheadGranularity(
                        FileObject,
                        READ_AHEAD_GRANULARITY );
            }

            if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {
                CcMdlRead(
                    FileObject,
                    (&ByteOffset),
                    ReturnedLength,
                    &Irp->MdlAddress,
                    &Irp->IoStatus );

                Status = Irp->IoStatus.Status;

            } else {

                Buffer = Ext2GetUserBuffer(Irp);
                if (Buffer == NULL) {
                    Status = STATUS_INVALID_USER_BUFFER;
                    DbgBreak();
                    __leave;
                }

                if (!CcCopyRead(FileObject, &ByteOffset, ReturnedLength,
                                Ext2CanIWait(), Buffer, &Irp->IoStatus)) {

                    if (Ext2CanIWait() || !CcCopyRead(FileObject, &ByteOffset,
                                                      ReturnedLength, TRUE,
                                                      Buffer, &Irp->IoStatus)) {
                        Status = STATUS_PENDING;
                        DbgBreak();
                        __leave;
                    }
                }
                Status = Irp->IoStatus.Status;
            }

        } else {

            ULONG   BytesRead = ReturnedLength;
            PUCHAR  SystemVA  = Ext2GetUserBuffer(IrpContext->Irp);

            if (ByteOffset.QuadPart + BytesRead > Fcb->Header.ValidDataLength.QuadPart) {

                if (ByteOffset.QuadPart >= Fcb->Header.ValidDataLength.QuadPart) {
                    if (SystemVA) {
                        SafeZeroMemory(SystemVA, Length);
                    }
                    Irp->IoStatus.Information = ReturnedLength;
                    Status = STATUS_SUCCESS;
                    __leave;
                } else {
                    BytesRead = (ULONG)(Fcb->Header.ValidDataLength.QuadPart - ByteOffset.QuadPart);
                    if (SystemVA) {
                        SafeZeroMemory(SystemVA + BytesRead, Length - BytesRead);
                    }
                }
            }

            Status = Ext2LockUserBuffer(
                         IrpContext->Irp,
                         BytesRead,
                         IoReadAccess );

            if (!NT_SUCCESS(Status)) {
                __leave;
            }

            Status = Ext2ReadInode(
                         IrpContext,
                         Vcb,
                         Fcb->Mcb,
                         ByteOffset.QuadPart,
                         NULL,
                         BytesRead,
                         TRUE,
                         NULL );

            /* we need re-queue this request in case STATUS_CANT_WAIT
               and fail it in other failure cases  */
            if (!NT_SUCCESS(Status)) {
                __leave;
            }

            /* pended by low level device */
            if (Status == STATUS_PENDING) {
                IrpContext->Irp = Irp = NULL;
                __leave;
            }

            Irp = IrpContext->Irp;
            ASSERT(Irp);
            Status = Irp->IoStatus.Status;

            if (!NT_SUCCESS(Status)) {
                Ext2NormalizeAndRaiseStatus(IrpContext, Status);
            }
        }

        Irp->IoStatus.Information = ReturnedLength;

    } __finally {

        if (Irp) {
            if (PagingIoResourceAcquired) {
                ExReleaseResourceLite(&Fcb->PagingIoResource);
            }

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

        if (!OpPostIrp && !IrpContext->ExceptionInProgress) {

            if (Irp) {
                if ( Status == STATUS_PENDING ||
                     Status == STATUS_CANT_WAIT) {

                    Status = Ext2LockUserBuffer(
                                 IrpContext->Irp,
                                 Length,
                                 IoWriteAccess );

                    if (NT_SUCCESS(Status)) {
                        Status = Ext2QueueRequest(IrpContext);
                    } else {
                        Ext2CompleteIrpContext(IrpContext, Status);
                    }
                } else {
                    if (NT_SUCCESS(Status)) {
                        if (!PagingIo) {
                            if (SynchronousIo) {
                                FileObject->CurrentByteOffset.QuadPart =
                                    ByteOffset.QuadPart + Irp->IoStatus.Information;
                            }
                            FileObject->Flags |= FO_FILE_FAST_IO_READ;
                        }
                    }

                    Ext2CompleteIrpContext(IrpContext, Status);
                }

            } else {

                Ext2FreeIrpContext(IrpContext);
            }
        }
    }

    DEBUG(DL_IO, ("Ext2ReadFile: %wZ fetch at Off=%I64xh Len=%xh Paging=%xh Nocache=%xh Returned=%xh Status=%xh\n",
                  &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache, ReturnedLength, Status));
    return Status;

}
Esempio n. 5
0
IO_STATUS_BLOCK
NTAPI
FatiOpenExistingFcb(IN PFAT_IRP_CONTEXT IrpContext,
                    IN PFILE_OBJECT FileObject,
                    IN PVCB Vcb,
                    IN PFCB Fcb,
                    IN PACCESS_MASK DesiredAccess,
                    IN USHORT ShareAccess,
                    IN ULONG AllocationSize,
                    IN PFILE_FULL_EA_INFORMATION EaBuffer,
                    IN ULONG EaLength,
                    IN UCHAR FileAttributes,
                    IN ULONG CreateDisposition,
                    IN BOOLEAN NoEaKnowledge,
                    IN BOOLEAN DeleteOnClose,
                    IN BOOLEAN OpenedAsDos,
                    OUT PBOOLEAN OplockPostIrp)
{
    IO_STATUS_BLOCK Iosb = {{0}};
    ACCESS_MASK AddedAccess = 0;
    BOOLEAN Hidden;
    BOOLEAN System;
    PCCB Ccb = NULL;
    NTSTATUS Status, StatusPrev;

    /* Acquire exclusive FCB lock */
    (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);

    *OplockPostIrp = FALSE;

    /* Check if there is a batch oplock */
    if (FsRtlCurrentBatchOplock(&Fcb->Fcb.Oplock))
    {
        /* Return with a special information field */
        Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY;

        /* Check the oplock */
        Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
                                       IrpContext->Irp,
                                       IrpContext,
                                       FatOplockComplete,
                                       FatPrePostIrp);

        if (Iosb.Status != STATUS_SUCCESS &&
            Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)
        {
            /* The Irp needs to be queued */
            *OplockPostIrp = TRUE;

            /* Release the FCB and return */
            FatReleaseFcb(IrpContext, Fcb);
            return Iosb;
        }
    }

    /* Validate parameters and modify access */
    if (CreateDisposition == FILE_CREATE)
    {
        Iosb.Status = STATUS_OBJECT_NAME_COLLISION;

        /* Release the FCB and return */
        FatReleaseFcb(IrpContext, Fcb);
        return Iosb;
    }
    else if (CreateDisposition == FILE_SUPERSEDE)
    {
        SetFlag(AddedAccess, DELETE & ~(*DesiredAccess));
        *DesiredAccess |= DELETE;
    }
    else if ((CreateDisposition == FILE_OVERWRITE) ||
             (CreateDisposition == FILE_OVERWRITE_IF))
    {
        SetFlag(AddedAccess,
                (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES)
                & ~(*DesiredAccess) );

        *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
    }

    // TODO: Check desired access

    // TODO: Check if this file is readonly and DeleteOnClose is set

    /* Validate disposition information */
    if ((CreateDisposition == FILE_SUPERSEDE) ||
        (CreateDisposition == FILE_OVERWRITE) ||
        (CreateDisposition == FILE_OVERWRITE_IF))
    {
        // TODO: Get this attributes from the dirent
        Hidden = FALSE;
        System = FALSE;

        if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
            (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM)))
        {
            DPRINT1("Hidden/system attributes don't match\n");

            Iosb.Status = STATUS_ACCESS_DENIED;

            /* Release the FCB and return */
            FatReleaseFcb(IrpContext, Fcb);
            return Iosb;
        }

        // TODO: Check for write protected volume
    }

    /* Check share access */
    Iosb.Status = IoCheckShareAccess(*DesiredAccess,
                                     ShareAccess,
                                     FileObject,
                                     &Fcb->ShareAccess,
                                     FALSE);
    if (!NT_SUCCESS(Iosb.Status))
    {
        /* Release the FCB and return */
        FatReleaseFcb(IrpContext, Fcb);
        return Iosb;
    }

    /* Check the oplock status after checking for share access */
    Iosb.Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
                                   IrpContext->Irp,
                                   IrpContext,
                                   FatOplockComplete,
                                   FatPrePostIrp );

    if (Iosb.Status != STATUS_SUCCESS &&
        Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)
    {
        /* The Irp needs to be queued */
        *OplockPostIrp = TRUE;

        /* Release the FCB and return */
        FatReleaseFcb(IrpContext, Fcb);
        return Iosb;
    }

    /* Set Fast I/O flag */
    Fcb->Header.IsFastIoPossible = FALSE; //FatiIsFastIoPossible(Fcb);

    /* Make sure image is not mapped */
    if (DeleteOnClose || FlagOn(*DesiredAccess, FILE_WRITE_DATA))
    {
        /* Try to flush the image section */
        if (!MmFlushImageSection(&Fcb->SectionObjectPointers, MmFlushForWrite))
        {
            /* Yes, image section exists, set correct status code */
            if (DeleteOnClose)
                Iosb.Status = STATUS_CANNOT_DELETE;
            else
                Iosb.Status = STATUS_SHARING_VIOLATION;

            /* Release the FCB and return */
            FatReleaseFcb(IrpContext, Fcb);
            return Iosb;
        }
    }

    /* Flush the cache if it's non-cached non-pagefile access */
    if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING) &&
        Fcb->SectionObjectPointers.DataSectionObject &&
        !FlagOn(Fcb->State, FCB_STATE_PAGEFILE))
    {
        /* Set the flag that create is in progress */
        SetFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS);

        /* Flush the cache */
        CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);

        /* Acquire and release Paging I/O resource before purging the cache section
           to let lazy writer finish */
        ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
        ExReleaseResourceLite( Fcb->Header.PagingIoResource );

        /* Delete the cache section */
        CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE);

        /* Clear the flag */
        ClearFlag(Fcb->Vcb->State, VCB_STATE_CREATE_IN_PROGRESS);
    }

    /* Check create disposition flags and branch accordingly */
    if (CreateDisposition == FILE_OPEN ||
        CreateDisposition == FILE_OPEN_IF)
    {
        DPRINT("Opening a file\n");

        /* Check if we need to bother with EA */
        if (NoEaKnowledge && FALSE /* FatIsFat32(Vcb)*/)
        {
            UNIMPLEMENTED;
        }

        /* Set up file object */
        Ccb = FatCreateCcb();
        FatSetFileObject(FileObject,
                         UserFileOpen,
                         Fcb,
                         Ccb);

        FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;

        /* The file is opened */
        Iosb.Information = FILE_OPENED;
        goto SuccComplete;
    }
    else if ((CreateDisposition == FILE_SUPERSEDE) ||
             (CreateDisposition == FILE_OVERWRITE) ||
             (CreateDisposition == FILE_OVERWRITE_IF))
    {
        /* Remember previous status */
        StatusPrev = Iosb.Status;

        // TODO: Check system security access

        /* Perform overwrite operation */
        Iosb = FatiOverwriteFile(IrpContext,
                                 FileObject,
                                 Fcb,
                                 AllocationSize,
                                 EaBuffer,
                                 EaLength,
                                 FileAttributes,
                                 CreateDisposition,
                                 NoEaKnowledge);

        /* Restore previous status in case of success */
        if (Iosb.Status == STATUS_SUCCESS)
            Iosb.Status = StatusPrev;

        /* Fall down to completion */
    }
    else
    {
        /* We can't get here */
        KeBugCheckEx(FAT_FILE_SYSTEM, CreateDisposition, 0, 0, 0);
    }


SuccComplete:
    /* If all is fine */
    if (Iosb.Status != STATUS_PENDING &&
        NT_SUCCESS(Iosb.Status))
    {
        /* Update access if needed */
        if (AddedAccess)
        {
            /* Remove added access flags from desired access */
            ClearFlag(*DesiredAccess, AddedAccess);

            /* Check share access */
            Status = IoCheckShareAccess(*DesiredAccess,
                                        ShareAccess,
                                        FileObject,
                                        &Fcb->ShareAccess,
                                        TRUE);

            /* Make sure it's success */
            ASSERT(Status == STATUS_SUCCESS);
        }
        else
        {
            /* Update the share access */
            IoUpdateShareAccess(FileObject, &Fcb->ShareAccess);
        }

        /* Clear the delay close */
        ClearFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);

        /* Increase counters */
        Fcb->UncleanCount++;
        Fcb->OpenCount++;
        Vcb->OpenFileCount++;
        if (IsFileObjectReadOnly(FileObject)) Vcb->ReadOnlyCount++;
        if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) Fcb->NonCachedUncleanCount++;

        // TODO: Handle DeleteOnClose and OpenedAsDos by storing those flags in CCB
    }

    return Iosb;
}
Esempio n. 6
0
NTSTATUS
XixFsdCommonLockControl(
	IN PXIFS_IRPCONTEXT pIrpContext
	)
{
	NTSTATUS			RC = STATUS_SUCCESS;
	PIRP					pIrp = NULL;
	PIO_STACK_LOCATION	pIrpSp = NULL;
	PFILE_OBJECT		pFileObject = NULL;
	PXIFS_FCB			pFCB = NULL;
	PXIFS_CCB			pCCB = NULL;
	PXIFS_VCB			pVCB = NULL;
	TYPE_OF_OPEN		TypeOfOpen = UnopenedFileObject;

	PAGED_CODE();

	DebugTrace(DEBUG_LEVEL_CRITICAL, DEBUG_TARGET_ALL, 
					("!!!!Enter XixFsdCommonLockControl \n"));

	DebugTrace(DEBUG_LEVEL_TRACE,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB),
		("Enter XixFsdCommonLockControl\n"));




	ASSERT(pIrpContext);

	pIrp = pIrpContext->Irp;
	ASSERT(pIrp);

	pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
	ASSERT(pIrpSp);

	pFileObject = pIrpSp->FileObject;
	ASSERT(pFileObject);

	TypeOfOpen = XixFsdDecodeFileObject(pFileObject, &pFCB, &pCCB);

	ASSERT_FCB(pFCB);


	if(TypeOfOpen != UserFileOpen){
		RC = STATUS_INVALID_PARAMETER;
		XixFsdCompleteRequest(pIrpContext, RC, 0);
		return RC;
	}

	if(pFCB->FCBType != FCB_TYPE_FILE) 
	{
		RC = STATUS_INVALID_PARAMETER;
		XixFsdCompleteRequest(pIrpContext, RC, 0);
		return RC;
	}

	if(pFCB->HasLock != FCB_FILE_LOCK_HAS){
		RC = STATUS_ACCESS_DENIED;
		XixFsdCompleteRequest(pIrpContext, RC, 0);
		return RC;
	}

	
	pVCB = pFCB->PtrVCB;
	ASSERT_VCB(pVCB);

	DebugTrace(DEBUG_LEVEL_TRACE|DEBUG_LEVEL_ALL,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB),
		("CALL FsRtlCheckOplock : XixFsdCommonLockControl\n"));

	RC = FsRtlCheckOplock(&pFCB->FCBOplock,
						pIrp,
						pIrpContext,
						XixFsdOplockComplete,
						NULL);

	if(!NT_SUCCESS(RC)){
		DebugTrace(DEBUG_LEVEL_TRACE|DEBUG_LEVEL_ALL,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB),
			("return PENDING FsRtlCheckOplock : XixFsdCommonLockControl\n"));
		return RC;
	}

	if(!XixFsdVerifyFcbOperation(pIrpContext, pFCB)){
		RC = STATUS_INVALID_PARAMETER;
		XixFsdCompleteRequest(pIrpContext, RC, 0);
		return RC;
	}


	try{


		if(pFCB->FCBFileLock == NULL){
			pFCB->FCBFileLock = FsRtlAllocateFileLock(NULL, NULL);

			if(!pFCB->FCBFileLock){
				RC = STATUS_INSUFFICIENT_RESOURCES;
				try_return(RC);
			}
		}


		RC = FsRtlProcessFileLock(pFCB->FCBFileLock, pIrp, NULL);

		XifsdLockFcb(pIrpContext, pFCB);
		pFCB->IsFastIoPossible = XixFsdCheckFastIoPossible(pFCB);
		XifsdUnlockFcb(pIrpContext, pFCB);
	
	}finally{
	}
	
	XixFsdCompleteRequest(pIrpContext, RC, 0);

	DebugTrace(DEBUG_LEVEL_TRACE|DEBUG_LEVEL_ALL,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB),
		("Exit XixFsdCommonLockControl\n"));
	
	return RC;
	
}
Esempio n. 7
0
NTSTATUS
NtfsCommonLockControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for Lock Control called by both the fsd and fsp
    threads.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;
    PFILE_OBJECT FileObject;

    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PSCB Scb;
    PCCB Ccb;
    BOOLEAN FcbAcquired = FALSE;

    BOOLEAN OplockPostIrp;

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_IRP( Irp );

    PAGED_CODE();

    //
    //  Get a pointer to the current Irp stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace( +1, Dbg, ("NtfsCommonLockControl\n") );
    DebugTrace( 0, Dbg, ("IrpContext    = %08lx\n", IrpContext) );
    DebugTrace( 0, Dbg, ("Irp           = %08lx\n", Irp) );
    DebugTrace( 0, Dbg, ("MinorFunction = %08lx\n", IrpSp->MinorFunction) );

    //
    //  Extract and decode the type of file object we're being asked to process
    //

    FileObject = IrpSp->FileObject;
    TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );

    //
    //  If the file is not a user file open then we reject the request
    //  as an invalid parameter
    //

    if (TypeOfOpen != UserFileOpen) {

        NtfsCompleteRequest( &IrpContext, &Irp, STATUS_INVALID_PARAMETER );

        DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> STATUS_INVALID_PARAMETER\n") );
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  Acquire exclusive access to the Fcb
    //

    if (Scb->ScbType.Data.FileLock == NULL) {

        NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, FALSE, FALSE );
        FcbAcquired = TRUE;

    } else {

        //NtfsAcquireSharedFcb( IrpContext, Fcb, Scb );
    }

    OplockPostIrp = FALSE;

    try {

        //
        //  We check whether we can proceed based on the state of the file oplocks.
        //  This call might post the irp for us.
        //

        Status = FsRtlCheckOplock( &Scb->ScbType.Data.Oplock,
                                   Irp,
                                   IrpContext,
                                   NtfsOplockComplete,
                                   NULL );

        if (Status != STATUS_SUCCESS) {

            OplockPostIrp = TRUE;
            try_return( NOTHING );
        }

        //
        //  If we don't have a file lock, then get one now.
        //

        if (Scb->ScbType.Data.FileLock == NULL) {

            NtfsCreateFileLock( Scb, TRUE );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request
        //

        Status = FsRtlProcessFileLock( Scb->ScbType.Data.FileLock, Irp, NULL );

        //
        //  Set the flag indicating if Fast I/O is possible
        //

        NtfsAcquireFsrtlHeader( Scb );
        Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb );
        NtfsReleaseFsrtlHeader( Scb );

    try_exit: NOTHING;
    } finally {

        DebugUnwind( NtfsCommonLockControl );

        //
        //  Release the Fcb, and return to our caller
        //

        if (FcbAcquired) {
            NtfsReleaseFcb( IrpContext, Fcb );
        }

        //
        //  Only if this is not an abnormal termination and we did not post the irp
        //  do we delete the irp context
        //

        if (!AbnormalTermination() && !OplockPostIrp) {

            NtfsCompleteRequest( &IrpContext, NULL, 0 );
        }

        DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> %08lx\n", Status) );
    }

    return Status;
}
Esempio n. 8
0
NTSTATUS
XixFsdCommonCleanUp(
	IN PXIFS_IRPCONTEXT pIrpContext
	)
{
	NTSTATUS		RC = STATUS_SUCCESS;
	PXIFS_FCB		pFCB = NULL;
	PXIFS_CCB		pCCB = NULL;
	PXIFS_VCB		pVCB = NULL;
	PFILE_OBJECT	pFileObject = NULL;	
	TYPE_OF_OPEN	TypeOfOpen = UnopenedFileObject;

	PIRP					pIrp = NULL;
	PIO_STACK_LOCATION		pIrpSp = NULL;
	KIRQL					SavedIrql;

	PXIFS_LCB	pLCB = NULL;
	PXIFS_FCB	pParentFCB = NULL;

	BOOLEAN					Wait = FALSE;
	BOOLEAN					VCBAcquired = FALSE;
	BOOLEAN					ParentFCBAcquired = FALSE;
	BOOLEAN					CanWait = FALSE;
	BOOLEAN					AttemptTeardown = FALSE;
	BOOLEAN					SendUnlockNotification = FALSE;

	PAGED_CODE();

	DebugTrace((DEBUG_LEVEL_TRACE), (DEBUG_TARGET_CLEANUP|DEBUG_TARGET_IRPCONTEXT), 
		("Enter XifsdCommonCleanUp pIrpContext(%p)\n", pIrpContext));


	ASSERT_IRPCONTEXT(pIrpContext);

	pIrp = pIrpContext->Irp;
	ASSERT(pIrp);

	// check if open request is releated to file system CDO
	{
		PDEVICE_OBJECT	DeviceObject = pIrpContext->TargetDeviceObject;
		ASSERT(DeviceObject);
		
		if (DeviceObject == XiGlobalData.XifsControlDeviceObject) {
			RC = STATUS_SUCCESS;

			DebugTrace(DEBUG_LEVEL_TRACE, (DEBUG_TARGET_CLEANUP), 
					("CDO Device TargetDevide(%p).\n", DeviceObject));
			XixFsdCompleteRequest(pIrpContext,RC,0);
			return(RC);
		}

	}	



	if(pIrpContext->VCB == NULL){

		DebugTrace(DEBUG_LEVEL_TRACE, DEBUG_TARGET_CLEANUP, 
					("pIrpContext->VCB == NULL.\n"));
		RC = STATUS_SUCCESS;
		XixFsdCompleteRequest(pIrpContext, RC, 0);
		return RC;
	}


	

	pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
	ASSERT(pIrpSp);

	pFileObject = pIrpSp->FileObject;
	ASSERT(pFileObject);

	TypeOfOpen = XixFsdDecodeFileObject(pFileObject, &pFCB, &pCCB);

	if(TypeOfOpen <= StreamFileOpen){
		DebugTrace((DEBUG_LEVEL_TRACE|DEBUG_LEVEL_INFO), DEBUG_TARGET_CLEANUP, 
					("TypeOfOpen <= StreamFileOpen.\n"));
		XixFsdCompleteRequest(pIrpContext, STATUS_SUCCESS, 0);
		return STATUS_SUCCESS;
	}


	CanWait = XifsdCheckFlagBoolean(pIrpContext->IrpContextFlags, XIFSD_IRP_CONTEXT_WAIT);

	
	if(CanWait == FALSE){
		DebugTrace((DEBUG_LEVEL_TRACE|DEBUG_LEVEL_INFO), (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_IRPCONTEXT), 
					("PostRequest IrpCxt(%p) Irp(%p)\n", pIrpContext, pIrp));
		RC = XixFsdPostRequest(pIrpContext, pIrp);
		return RC;
	}

	ASSERT_FCB(pFCB);
	pVCB = pFCB->PtrVCB;
	ASSERT_VCB(pVCB);




	DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_RESOURCE|DEBUG_TARGET_VCB), 
				("Acquire exclusive pVCB(%p) VCBResource(%p).\n", pVCB, &pVCB->VCBResource));	

	if((TypeOfOpen == UserVolumeOpen)
		&& XifsdCheckFlagBoolean(pFileObject->Flags, FO_FILE_MODIFIED))
	{
		XifsdAcquireVcbExclusive(CanWait, pVCB, FALSE);
		VCBAcquired = TRUE;		
	}


	XifsdAcquireFcbExclusive(CanWait, pFCB, FALSE);		


	DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_RESOURCE| DEBUG_TARGET_FCB), 
					("Acquire exclusive FCB(%p) FCBResource(%p).\n", pFCB, pFCB->FCBResource));

	
	XifsdSetFlag(pFileObject->Flags, FO_CLEANUP_COMPLETE);
	DebugTrace(DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_CLEANUP| DEBUG_TARGET_RESOURCE| DEBUG_TARGET_FCB), 
					("Set File Object Flags(0x%x)\n", pFileObject->Flags));	



	//IoRemoveShareAccess( pFileObject, &pFCB->FCBShareAccess );

	try{
		switch(TypeOfOpen){
		case UserDirectoryOpen:
			
			if(XifsdCheckFlagBoolean(pCCB->CCBFlags, XIFSD_CCB_FLAG_NOFITY_SET))
			{
				DebugTrace(DEBUG_LEVEL_CRITICAL, DEBUG_TARGET_ALL, 
					("CompletionFilter Notify CleanUp (%wZ) pCCB(%p)\n", &pFCB->FCBName, pCCB));

				FsRtlNotifyCleanup(pVCB->NotifyIRPSync, &pVCB->NextNotifyIRP, pCCB);

				//DbgPrint("Notify CleanUp (%wZ) pCCB(%p)\n", &pFCB->FCBName, pCCB);

			}


			//DbgPrint("CleanUp (%wZ) pCCB(%p) pCCB->CCBFlags(%x)\n", &pFCB->FCBName, pCCB, pCCB->CCBFlags);


			DebugTrace(DEBUG_LEVEL_CRITICAL, DEBUG_TARGET_ALL, 
					("!!!!CleanUp (%wZ) pCCB(%p)\n", &pFCB->FCBName, pCCB));


			IoRemoveShareAccess( pFileObject, &pFCB->FCBShareAccess );
			break;
			
		case UserFileOpen:
			//
			//  Coordinate the cleanup operation with the oplock state.
			//  Oplock cleanup operations can always cleanup immediately so no
			//  need to check for STATUS_PENDING.
			//

			FsRtlCheckOplock( &pFCB->FCBOplock,
							  pIrp,
							  pIrpContext,
							  NULL,
							  NULL );

			//
			//  Unlock all outstanding file locks.
			//

			if (pFCB->FCBFileLock != NULL) {

				FsRtlFastUnlockAll( pFCB->FCBFileLock,
									pFileObject,
									IoGetRequestorProcess( pIrp ),
									NULL );
			}



			//
			//  Check the fast io state.
			//

			XifsdLockFcb( pIrpContext, pFCB );
			pFCB->IsFastIoPossible = XixFsdCheckFastIoPossible( pFCB );
			XifsdUnlockFcb( pIrpContext, pFCB );


			/*
			if((pFCB->HasLock != FCB_FILE_LOCK_HAS)
				&& (!XifsdCheckFlagBoolean(pFCB->FCBFlags, XIFSD_FCB_OPEN_WRITE))
				&& XifsdCheckFlagBoolean(pFileObject->Flags, FO_CACHE_SUPPORTED) 
				&& (pFCB->FCBCleanup == 1)
			){
					if(pFCB->SectionObject.DataSectionObject != NULL) 
					{
						
						CcFlushCache(&(pFCB->SectionObject), NULL, 0, NULL);

						ExAcquireResourceSharedLite(pFCB->PagingIoResource, TRUE);
						ExReleaseResourceLite( pFCB->PagingIoResource );
						
						
						CcPurgeCacheSection( &(pFCB->SectionObject),
														NULL,
														0,
														FALSE 
														);	
														
					}			
			
			}
			*/


			
			if(
				XifsdCheckFlagBoolean(pFileObject->Flags, FO_CACHE_SUPPORTED) &&
				(pFCB->FcbNonCachedOpenCount > 1)	&&
				((pFCB->FcbNonCachedOpenCount + 1) ==  pFCB->FCBCleanup)
			)
			{
				if(pFCB->SectionObject.DataSectionObject != NULL) 
				{

					// changed by ILGU HONG for readonly 09052006
					if(!pFCB->PtrVCB->IsVolumeWriteProctected)
						CcFlushCache(&(pFCB->SectionObject), NULL, 0, NULL);
					// changed by ILGU HONG for readonly end
					
					//DbgPrint("CcFlush  1 File(%wZ)\n", &pFCB->FCBFullPath);
					ExAcquireResourceSharedLite(pFCB->PagingIoResource, TRUE);
					ExReleaseResourceLite( pFCB->PagingIoResource );


					CcPurgeCacheSection( &(pFCB->SectionObject),
														NULL,
														0,
														FALSE 
														);					
					

				}	
			}
			
			/*
			else if(pFCB->FCBCleanup == 1 ){
		
				if(XifsdCheckFlagBoolean(pFileObject->Flags, FO_CACHE_SUPPORTED)){
					if(pFCB->SectionObject.DataSectionObject != NULL) 
					{
						CcFlushCache(&(pFCB->SectionObject), NULL, 0, NULL);

						ExAcquireResourceSharedLite(pFCB->PagingIoResource, TRUE);
						ExReleaseResourceLite( pFCB->PagingIoResource );

						CcPurgeCacheSection( &(pFCB->SectionObject),
															NULL,
															0,
															FALSE 
															);					
						

					}
				}

				if(XifsdCheckFlagBoolean(pFCB->FCBFlags,XIFSD_FCB_MODIFIED_FILE)){
					XixFsdUpdateFCB(pFCB);
				}

			}
			*/

			IoRemoveShareAccess( pFileObject, &pFCB->FCBShareAccess );
			//
			//  Cleanup the cache map.
			//
			
			CcUninitializeCacheMap( pFileObject, NULL, NULL );
					
			

			break;
		case UserVolumeOpen:
			break;
		default:
			break;
		}

		


		if((TypeOfOpen == UserDirectoryOpen) || (TypeOfOpen == UserFileOpen)){

			if(pFCB->FCBCleanup == 1 ){
				if(XifsdCheckFlagBoolean(pFCB->FCBFlags,XIFSD_FCB_MODIFIED_FILE)){
					
					// changed by ILGU HONG for readonly 09052006
					if(!pFCB->PtrVCB->IsVolumeWriteProctected){

						XixFsdUpdateFCB(pFCB);

						if(pFCB->WriteStartOffset != -1){

							//DbgPrint("Set Update Information!!!\n");
							XixFsdSendFileChangeRC(
									TRUE,
									pVCB->HostMac, 
									pFCB->LotNumber, 
									pVCB->DiskId, 
									pVCB->PartitionId, 
									pFCB->FileSize.QuadPart, 
									pFCB->RealAllocationSize,
									pFCB->WriteStartOffset
							);
							
							pFCB->WriteStartOffset = -1;
						}
					}
					// changed by ILGU HONG for readonly end

				}


	


			}




			if(XifsdCheckFlagBoolean(pCCB->CCBFlags, XIFSD_CCB_FLAGS_DELETE_ON_CLOSE)){
				
				if(pFCB == pFCB->PtrVCB->RootDirFCB){
					XifsdClearFlag(pCCB->CCBFlags, XIFSD_CCB_FLAGS_DELETE_ON_CLOSE);
					XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
				}else{
					XifsdSetFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
				}
			}

	


			// changed by ILGU HONG for readonly 09082006
			if(XifsdCheckFlagBoolean(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE) && (!pFCB->PtrVCB->IsVolumeWriteProctected) ){
			// changed by ILGU HONG for readonly end
				if(pFCB->FCBCleanup == 1){
					
					//DbgPrint(" !!!Delete Entry From table (%wZ)  .\n", &pFCB->FCBFullPath);

					ASSERT_CCB(pCCB);
					pLCB = pCCB->PtrLCB;

					ASSERT_LCB(pLCB);

					pParentFCB = pLCB->ParentFcb;
					ASSERT_FCB(pParentFCB);					



  					pFCB->FileSize.QuadPart = 0;
					pFCB->ValidDataLength.QuadPart = 0;

					if(pFCB->FCBType == FCB_TYPE_FILE){
						
						XifsdReleaseFcb(TRUE, pFCB);
						XifsdAcquireFcbExclusive(TRUE, pParentFCB, FALSE);
						ParentFCBAcquired = TRUE;
						XifsdAcquireFcbExclusive(TRUE, pFCB, FALSE);
						RC = DeleteParentChild(pIrpContext, pParentFCB, &pLCB->FileName);
						
						if(!NT_SUCCESS(RC)){
							DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL,
								("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName));
							
							//XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
							RC = STATUS_SUCCESS;
							goto pass_through;
						}
						
						XifsdClearFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_DELETE_ON_CLOSE);
						XifsdSetFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_LINK_IS_GONE);
						
						XixFsdRemovePrefix(TRUE, pLCB);

						//
						//  Now Decrement the reference counts for the parent and drop the Vcb.
						//
						XifsdLockVcb(pIrpContext,pVCB);
						DebugTrace( DEBUG_LEVEL_INFO, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT),
									("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", 
									pParentFCB->LotNumber,
									 pVCB->VCBReference,
									 pVCB->VCBUserReference,
									 pParentFCB->FCBReference,
									 pParentFCB->FCBUserReference ));

						XifsdDecRefCount( pParentFCB, 1, 1 );

						DebugTrace( DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT),
									("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", 
									pParentFCB->LotNumber,
									 pVCB->VCBReference,
									 pVCB->VCBUserReference,
									 pParentFCB->FCBReference,
									 pParentFCB->FCBUserReference ));

						XifsdUnlockVcb( pIrpContext, pVCB );
						


						if(!NT_SUCCESS(RC)){
							DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL,
								("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName));
							
							XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
							RC = STATUS_SUCCESS;
							goto pass_through;
						}
						
						

					}else {
						
						RC = XixFsReLoadFileFromFcb(pFCB);
						
						if(!NT_SUCCESS(RC)){
							DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL,
								("Fail XixFsReLoadFileFromFcb (%wZ)\n", &pFCB->FCBName));
							
							XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
							RC = STATUS_SUCCESS;
							goto pass_through;
						}
						
						if(pFCB->ChildCount != 0){
							XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
							RC = STATUS_SUCCESS;
							goto pass_through;
						}

						XifsdReleaseFcb(TRUE, pFCB);
						XifsdAcquireFcbExclusive(TRUE, pParentFCB, FALSE);
						ParentFCBAcquired = TRUE;
						
						XifsdAcquireFcbExclusive(TRUE, pFCB, FALSE);

						RC = DeleteParentChild(pIrpContext, pParentFCB, &pLCB->FileName);

						if(!NT_SUCCESS(RC)){
							DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL,
								("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName));
							
							//ifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
							RC = STATUS_SUCCESS;
							goto pass_through;
						}
						

						XifsdClearFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_DELETE_ON_CLOSE);
						XifsdSetFlag(pLCB->LCBFlags, XIFSD_LCB_STATE_LINK_IS_GONE);
						
						
						XixFsdRemovePrefix(TRUE, pLCB);

						//
						//  Now Decrement the reference counts for the parent and drop the Vcb.
						//
						XifsdLockVcb(pIrpContext,pVCB);
						DebugTrace( DEBUG_LEVEL_INFO, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT),
									("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", 
									pParentFCB->LotNumber,
									 pVCB->VCBReference,
									 pVCB->VCBUserReference,
									 pParentFCB->FCBReference,
									 pParentFCB->FCBUserReference ));

						XifsdDecRefCount( pParentFCB, 1, 1 );

						DebugTrace( DEBUG_LEVEL_CRITICAL, (DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB|DEBUG_TARGET_REFCOUNT),
									("XifsdSetRenameInformation, PFcb (%I64d) Vcb %d/%d Fcb %d/%d\n", 
									pParentFCB->LotNumber,
									 pVCB->VCBReference,
									 pVCB->VCBUserReference,
									 pParentFCB->FCBReference,
									 pParentFCB->FCBUserReference ));

						XifsdUnlockVcb( pIrpContext, pVCB );

						
						if(!NT_SUCCESS(RC)){
							DebugTrace(DEBUG_LEVEL_ERROR, DEBUG_TARGET_ALL,
								("Fail DeleteParentChild (%wZ)\n", &pLCB->FileName));
							
							XifsdClearFlag(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE);
							RC = STATUS_SUCCESS;
							goto pass_through;
						}
						

						
					}


			
					//XixFsdDeleteUpdateFCB(pFCB);

					XixFsdSendRenameLinkBC(
						TRUE,
						XIFS_SUBTYPE_FILE_DEL,
						pVCB->HostMac,
						pFCB->LotNumber,
						pVCB->DiskId,
						pVCB->PartitionId,
						pFCB->ParentLotNumber,
						0
					);

				}
			}
			

		}


pass_through:

		XifsdLockVcb(pIrpContext, pVCB);
		
		if(XifsdCheckFlagBoolean(pFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
		{
			ASSERT(pFCB->FcbNonCachedOpenCount > 0);
			pFCB->FcbNonCachedOpenCount --;
		}

		XifsdDecrementClenupCount(pFCB);


		DebugTrace(DEBUG_LEVEL_ALL, DEBUG_TARGET_ALL,
			("Cleanup  Name(%wZ) FCBLotNumber(%I64d) FCBCleanUp(%ld) VCBCleanup(%ld) pCCB(%p) FileObject(%p)\n", 
			&pFCB->FCBName,
			pFCB->LotNumber, 
			pFCB->FCBCleanup, 
			pVCB->VCBCleanup,
			pCCB,
			pFileObject
			));
			
		XifsdUnlockVcb( pIrpContext, pVCB );

		AttemptTeardown = (pVCB->VCBCleanup == 0 && pVCB->VCBState == XIFSD_VCB_STATE_VOLUME_DISMOUNTED );
		
		if(pFileObject == pVCB->LockVolumeFileObject){
			ASSERT(XifsdCheckFlagBoolean(pVCB->VCBFlags, XIFSD_VCB_FLAGS_VOLUME_LOCKED));
			
			IoAcquireVpbSpinLock(&SavedIrql);
			XifsdClearFlag(pVCB->PtrVPB->Flags, VPB_LOCKED);
			IoReleaseVpbSpinLock( SavedIrql );
			
			XifsdClearFlag(pVCB->VCBFlags, XIFSD_VCB_FLAGS_VOLUME_LOCKED);
			pVCB->LockVolumeFileObject = NULL;
			SendUnlockNotification = TRUE;
			
		}

		

		/*
		if( (pFCB->FCBCleanup == 0) 
				&& (!XifsdCheckFlagBoolean(pFCB->FCBFlags, XIFSD_FCB_DELETE_ON_CLOSE)) ){

			DebugTrace(DEBUG_LEVEL_INFO, (DEBUG_TARGET_CLEANUP|DEBUG_TARGET_IRPCONTEXT| DEBUG_TARGET_ALL), 
				("CleanUp Release Lot Lock LotNumber(%ld)\n", pFCB->LotNumber));

			XifsdLotUnLock(pVCB, pVCB->TargetDeviceObject, pFCB->LotNumber);
			pFCB->HasLock = FCB_FILE_LOCK_INVALID;
		}
		*/

		//
		//  We must clean up the share access at this time, since we may not
		//  get a Close call for awhile if the file was mapped through this
		//  File Object.
		//

		


	}finally{

		XifsdReleaseFcb(pIrpContext, pFCB);

		if(ParentFCBAcquired) {
			XifsdReleaseFcb(TRUE,pParentFCB);
		}
		

        if (SendUnlockNotification) {

            FsRtlNotifyVolumeEvent( pFileObject, FSRTL_VOLUME_UNLOCK );
        }

  		if (VCBAcquired)  {

			XifsdReleaseVcb( pIrpContext, pVCB);
		}


	}



    if (AttemptTeardown) {
        XifsdAcquireVcbExclusive( CanWait, pVCB, FALSE );

        try {
            
            XixFsdPurgeVolume( pIrpContext, pVCB, FALSE );

        } finally {

            XifsdReleaseVcb( pIrpContext, pVCB );
        }
    }


    //
    //  If this is a normal termination then complete the request
    //

	DebugTrace((DEBUG_LEVEL_TRACE), (DEBUG_TARGET_CLEANUP|DEBUG_TARGET_IRPCONTEXT), 
		("Exit XifsdCommonCleanUp pIrpContext(%p)\n", pIrpContext));

    XixFsdCompleteRequest( pIrpContext, STATUS_SUCCESS, 0 );

    return STATUS_SUCCESS;
}
Esempio n. 9
0
NTSTATUS
FatCommonLockControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for doing Lock control operations called
    by both the fsd and fsp threads

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status = STATUS_SUCCESS;
    PIO_STACK_LOCATION IrpSp;

    TYPE_OF_OPEN TypeOfOpen;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    BOOLEAN OplockPostIrp = FALSE;

    PAGED_CODE();

    //
    //  Get a pointer to the current Irp stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonLockControl\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %08lx\n", Irp);
    DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);

    //
    //  Decode the type of file object we're being asked to process
    //

    TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );

    //
    //  If the file is not a user file open then we reject the request
    //  as an invalid parameter
    //

    if (TypeOfOpen != UserFileOpen) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );

        DebugTrace(-1, Dbg, "FatCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0);
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  Acquire exclusive access to the Fcb and enqueue the Irp if we didn't
    //  get access
    //

    if (!FatAcquireSharedFcb( IrpContext, Fcb )) {

        Status = FatFsdPostRequest( IrpContext, Irp );

        DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status);
        return Status;
    }

    try {

        //
        //  We check whether we can proceed
        //  based on the state of the file oplocks.
        //

#if (NTDDI_VERSION >= NTDDI_WIN8)

        if (((IRP_MN_LOCK == IrpSp->MinorFunction) &&
             ((ULONGLONG)IrpSp->Parameters.LockControl.ByteOffset.QuadPart <
              (ULONGLONG)Fcb->Header.AllocationSize.QuadPart)) ||
            ((IRP_MN_LOCK != IrpSp->MinorFunction) &&
             FsRtlAreThereWaitingFileLocks( &Fcb->Specific.Fcb.FileLock ))) {

            //
            //  Check whether we can proceed based on the state of file oplocks if doing
            //  an operation that interferes with oplocks. Those operations are:
            //
            //      1. Lock a range within the file's AllocationSize.
            //      2. Unlock a range when there are waiting locks on the file. This one
            //         is not guaranteed to interfere with oplocks, but it could, as
            //         unlocking this range might cause a waiting lock to be granted
            //         within AllocationSize!
            //

#endif
            Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb),
                                       Irp,
                                       IrpContext,
                                       FatOplockComplete,
                                       NULL );

#if (NTDDI_VERSION >= NTDDI_WIN8)
        }
#endif

        if (Status != STATUS_SUCCESS) {

            OplockPostIrp = TRUE;
            try_return( NOTHING );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request
        //

        Status = FsRtlProcessFileLock( &Fcb->Specific.Fcb.FileLock, Irp, NULL );

        //
        //  Set the flag indicating if Fast I/O is possible
        //

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

    try_exit:  NOTHING;
    } finally {

        DebugUnwind( FatCommonLockControl );

        //
        //  Only if this is not an abnormal termination do we delete the
        //  irp context
        //

        if (!AbnormalTermination() && !OplockPostIrp) {

            FatCompleteRequest( IrpContext, FatNull, 0 );
        }

        //
        //  Release the Fcb, and return to our caller
        //

        FatReleaseFcb( IrpContext, Fcb );

        DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status);
    }

    return Status;
}
Esempio n. 10
0
NTSTATUS
DokanDispatchCleanup(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp)

/*++

Routine Description:

        This device control dispatcher handles Cleanup IRP.

Arguments:

        DeviceObject - Context for the activity.
        Irp          - The device control argument block.

Return Value:

        NTSTATUS

--*/
{
  PDokanVCB vcb;
  PIO_STACK_LOCATION irpSp;
  NTSTATUS status = STATUS_INVALID_PARAMETER;
  PFILE_OBJECT fileObject;
  PDokanCCB ccb = NULL;
  PDokanFCB fcb = NULL;
  PEVENT_CONTEXT eventContext;
  ULONG eventLength;
  DOKAN_INIT_LOGGER(logger, DeviceObject->DriverObject, IRP_MJ_CLEANUP);

  __try {

    DDbgPrint("==> DokanCleanup\n");

    irpSp = IoGetCurrentIrpStackLocation(Irp);
    fileObject = irpSp->FileObject;

    DDbgPrint("  ProcessId %lu\n", IoGetRequestorProcessId(Irp));
    DokanPrintFileName(fileObject);

    // Cleanup must be success in any case
    if (fileObject == NULL) {
      DDbgPrint("  fileObject == NULL\n");
      status = STATUS_SUCCESS;
      __leave;
    }

    vcb = DeviceObject->DeviceExtension;
    if (vcb == NULL) {
      DDbgPrint("  No device extension\n");
      status = STATUS_SUCCESS;
      __leave;
    }

    if (GetIdentifierType(vcb) != VCB ||
        !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) {
      status = STATUS_SUCCESS;
      __leave;
    }

    ccb = fileObject->FsContext2;
    ASSERT(ccb != NULL);

    fcb = ccb->Fcb;
    ASSERT(fcb != NULL);

    if (fcb->IsKeepalive) {
      DokanFCBLockRW(fcb);
      BOOLEAN shouldUnmount = ccb->IsKeepaliveActive;
      if (shouldUnmount) {
        // Here we intentionally let the VCB-level flag stay set, because
        // there's no sense in having an opportunity for an "operation timeout
        // unmount" in this case.
        ccb->IsKeepaliveActive = FALSE;
      }
      DokanFCBUnlock(fcb);
      if (shouldUnmount) {
        if (IsUnmountPendingVcb(vcb)) {
          DokanLogInfo(&logger,
                       L"Ignoring keepalive close because unmount is already in"
                       L" progress.");
        } else {
          DokanLogInfo(&logger, L"Unmounting due to keepalive close.");
          DokanUnmount(vcb->Dcb);
        }
      }
    }
    if (fcb->BlockUserModeDispatch) {
      status = STATUS_SUCCESS;
      __leave;
    }

    FlushFcb(fcb, fileObject);

    DokanFCBLockRW(fcb);

    eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length;
    eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb);

    if (eventContext == NULL) {
      status = STATUS_INSUFFICIENT_RESOURCES;
      DokanFCBUnlock(fcb);
      __leave;
    }

    fileObject->Flags |= FO_CLEANUP_COMPLETE;

    eventContext->Context = ccb->UserContext;
    eventContext->FileFlags |= DokanCCBFlagsGet(ccb);
    // DDbgPrint("   get Context %X\n", (ULONG)ccb->UserContext);

    // copy the filename to EventContext from ccb
    eventContext->Operation.Cleanup.FileNameLength = fcb->FileName.Length;
    RtlCopyMemory(eventContext->Operation.Cleanup.FileName,
                  fcb->FileName.Buffer, fcb->FileName.Length);

    // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking.
    status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext,
                              DokanOplockComplete, DokanPrePostIrp);
    DokanFCBUnlock(fcb);

    //
    //  if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
    //  to service an oplock break and we need to leave now.
    //
    if (status != STATUS_SUCCESS) {
      if (status == STATUS_PENDING) {
        DDbgPrint("   FsRtlCheckOplock returned STATUS_PENDING\n");
      } else {
        DokanFreeEventContext(eventContext);
      }
      __leave;
    }

    // register this IRP to pending IRP list
    status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0);

  } __finally {

    DokanCompleteIrpRequest(Irp, status, 0);

    DDbgPrint("<== DokanCleanup\n");
  }

  return status;
}
Esempio n. 11
0
NTSTATUS
NTAPI
FatiLockControl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
{
    PIO_STACK_LOCATION IrpSp;
    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;
    NTSTATUS Status;

    /* Get IRP stack location */
    IrpSp = IoGetCurrentIrpStackLocation(Irp);

    /* Determine type of open */
    TypeOfOpen = FatDecodeFileObject(IrpSp->FileObject, &Vcb, &Fcb, &Ccb);

    /* Only user file open is allowed */
    if (TypeOfOpen != UserFileOpen)
    {
        FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER);
        return STATUS_INVALID_PARAMETER;
    }

    /* Acquire shared FCB lock */
    if (!FatAcquireSharedFcb(IrpContext, Fcb))
    {
        UNIMPLEMENTED;
        //Status = FatFsdPostRequest(IrpContext, Irp);
        Status = STATUS_NOT_IMPLEMENTED;
        return Status;
    }

    /* Check oplock state */
    Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
                              Irp,
                              IrpContext,
                              FatOplockComplete,
                              NULL);

    if (Status != STATUS_SUCCESS)
    {
        /* Release FCB lock */
        FatReleaseFcb(IrpContext, Fcb);

        return Status;
    }

    /* Process the lock */
    Status = FsRtlProcessFileLock(&Fcb->Fcb.Lock, Irp, NULL);

    /* Update Fast I/O state */
    Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb);

    /* Complete the request */
    FatCompleteRequest(IrpContext, NULL, 0);

    /* Release FCB lock */
    FatReleaseFcb(IrpContext, Fcb);

    return Status;
}
Esempio n. 12
0
NTSTATUS
DokanDispatchCleanup(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp)

/*++

Routine Description:

        This device control dispatcher handles Cleanup IRP.

Arguments:

        DeviceObject - Context for the activity.
        Irp          - The device control argument block.

Return Value:

        NTSTATUS

--*/
{
  PDokanVCB vcb;
  PIO_STACK_LOCATION irpSp;
  NTSTATUS status = STATUS_INVALID_PARAMETER;
  PFILE_OBJECT fileObject;
  PDokanCCB ccb = NULL;
  PDokanFCB fcb = NULL;
  PEVENT_CONTEXT eventContext;
  ULONG eventLength;

  __try {

    DDbgPrint("==> DokanCleanup\n");

    irpSp = IoGetCurrentIrpStackLocation(Irp);
    fileObject = irpSp->FileObject;

    DDbgPrint("  ProcessId %lu\n", IoGetRequestorProcessId(Irp));
    DokanPrintFileName(fileObject);

    // Cleanup must be success in any case
    if (fileObject == NULL) {
      DDbgPrint("  fileObject == NULL\n");
      status = STATUS_SUCCESS;
      __leave;
    }

    vcb = DeviceObject->DeviceExtension;
    if (vcb == NULL) {
      DDbgPrint("  No device extension\n");
      status = STATUS_SUCCESS;
      __leave;
    }

    if (GetIdentifierType(vcb) != VCB ||
        !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) {
      status = STATUS_SUCCESS;
      __leave;
    }

    ccb = fileObject->FsContext2;
    ASSERT(ccb != NULL);

    fcb = ccb->Fcb;
    ASSERT(fcb != NULL);

    FlushFcb(fcb, fileObject);

    DokanFCBLockRW(fcb);

    eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length;
    eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb);

    if (eventContext == NULL) {
      status = STATUS_INSUFFICIENT_RESOURCES;
      DokanFCBUnlock(fcb);
      __leave;
    }

    fileObject->Flags |= FO_CLEANUP_COMPLETE;

    eventContext->Context = ccb->UserContext;
    eventContext->FileFlags |= DokanCCBFlagsGet(ccb);
    // DDbgPrint("   get Context %X\n", (ULONG)ccb->UserContext);

    // copy the filename to EventContext from ccb
    eventContext->Operation.Cleanup.FileNameLength = fcb->FileName.Length;
    RtlCopyMemory(eventContext->Operation.Cleanup.FileName,
                  fcb->FileName.Buffer, fcb->FileName.Length);

    // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking.
    status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext,
                              DokanOplockComplete, DokanPrePostIrp);
    DokanFCBUnlock(fcb);

    //
    //  if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
    //  to service an oplock break and we need to leave now.
    //
    if (status != STATUS_SUCCESS) {
      if (status == STATUS_PENDING) {
        DDbgPrint("   FsRtlCheckOplock returned STATUS_PENDING\n");
      } else {
        DokanFreeEventContext(eventContext);
      }
      __leave;
    }

    // register this IRP to pending IRP list
    status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0);

  } __finally {

    DokanCompleteIrpRequest(Irp, status, 0);

    DDbgPrint("<== DokanCleanup\n");
  }

  return status;
}
Esempio n. 13
0
NTSTATUS
DokanCommonLockControl(__in PIRP Irp) {
  NTSTATUS Status = STATUS_SUCCESS;

  PDokanFCB Fcb;
  PDokanCCB Ccb;
  PFILE_OBJECT fileObject;

  PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);

  DDbgPrint("==> DokanCommonLockControl\n");

  PAGED_CODE();

  fileObject = irpSp->FileObject;
  DokanPrintFileName(fileObject);

  Ccb = fileObject->FsContext2;
  if (Ccb == NULL || Ccb->Identifier.Type != CCB) {
    DDbgPrint("    DokanOplockRequest STATUS_INVALID_PARAMETER\n");
    return STATUS_INVALID_PARAMETER;
  }

  Fcb = Ccb->Fcb;
  if (Fcb == NULL || Fcb->Identifier.Type != FCB) {
    DDbgPrint("    DokanOplockRequest STATUS_INVALID_PARAMETER\n");
    return STATUS_INVALID_PARAMETER;
  }
  DokanFCBLockRW(Fcb);

  //
  //  If the file is not a user file open then we reject the request
  //  as an invalid parameter
  //
  if (FlagOn(Fcb->Flags, DOKAN_FILE_DIRECTORY)) {
    DDbgPrint("  DokanCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0);
    DokanFCBUnlock(Fcb);
    return STATUS_INVALID_PARAMETER;
  }

  try {

//
//  We check whether we can proceed
//  based on the state of the file oplocks.
//
#if (NTDDI_VERSION >= NTDDI_WIN8)

    if (((IRP_MN_LOCK == irpSp->MinorFunction) &&
         ((ULONGLONG)irpSp->Parameters.LockControl.ByteOffset.QuadPart <
          (ULONGLONG)Fcb->AdvancedFCBHeader.AllocationSize.QuadPart)) ||
        ((IRP_MN_LOCK != irpSp->MinorFunction) &&
         FsRtlAreThereWaitingFileLocks(&Fcb->FileLock))) {

//
//  Check whether we can proceed based on the state of file oplocks if doing
//  an operation that interferes with oplocks. Those operations are:
//
//      1. Lock a range within the file's AllocationSize.
//      2. Unlock a range when there are waiting locks on the file. This one
//         is not guaranteed to interfere with oplocks, but it could, as
//         unlocking this range might cause a waiting lock to be granted
//         within AllocationSize!
//
#endif
      // Dokan DokanOplockComplete sends the operation to user mode, which isn't
      // what we want to do
      // so now wait for the oplock to be broken (pass in NULL for the callback)
      Status =
          FsRtlCheckOplock(DokanGetFcbOplock(Fcb), Irp, NULL /* EventContext */,
                           NULL /*DokanOplockComplete*/, NULL);

#if (NTDDI_VERSION >= NTDDI_WIN8)
    }
#endif
    //  If we were waiting for the callback, then STATUS_PENDING would be ok too
    if (Status != STATUS_SUCCESS) {
      __leave;
    }

    //
    //  Now call the FsRtl routine to do the actual processing of the
    //  Lock request
    //
    Status = FsRtlProcessFileLock(&Fcb->FileLock, Irp, NULL);
  } finally {
    DokanFCBUnlock(Fcb);
  }

  DDbgPrint("<== DokanCommonLockControl\n");

  return Status;
}
Esempio n. 14
0
NTSTATUS
DokanDispatchWrite(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) {
  PIO_STACK_LOCATION irpSp;
  PFILE_OBJECT fileObject;
  NTSTATUS status = STATUS_INVALID_PARAMETER;
  PEVENT_CONTEXT eventContext;
  ULONG eventLength;
  PDokanCCB ccb;
  PDokanFCB fcb = NULL;
  PDokanVCB vcb;
  PVOID buffer;
  BOOLEAN writeToEoF = FALSE;
  BOOLEAN isPagingIo = FALSE;
  BOOLEAN isNonCached = FALSE;
  BOOLEAN isSynchronousIo = FALSE;
  BOOLEAN fcbLocked = FALSE;

  __try {

    DDbgPrint("==> DokanWrite\n");

    irpSp = IoGetCurrentIrpStackLocation(Irp);
    fileObject = irpSp->FileObject;

    //
    //  If this is a zero length write then return SUCCESS immediately.
    //

    if (irpSp->Parameters.Write.Length == 0) {
      DDbgPrint("  Parameters.Write.Length == 0\n");
      Irp->IoStatus.Information = 0;
      status = STATUS_SUCCESS;
      __leave;
    }

    if (fileObject == NULL) {
      DDbgPrint("  fileObject == NULL\n");
      status = STATUS_INVALID_DEVICE_REQUEST;
      __leave;
    }

    vcb = DeviceObject->DeviceExtension;

    if (GetIdentifierType(vcb) != VCB ||
        !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) {
      status = STATUS_INVALID_PARAMETER;
      __leave;
    }

    DDbgPrint("  ProcessId %lu\n", IoGetRequestorProcessId(Irp));
    DokanPrintFileName(fileObject);

    ccb = fileObject->FsContext2;
    ASSERT(ccb != NULL);

    fcb = ccb->Fcb;
    ASSERT(fcb != NULL);

    if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
      status = STATUS_INVALID_PARAMETER;
      __leave;
    }

    if (Irp->MdlAddress) {
      DDbgPrint("  use MdlAddress\n");
      buffer = MmGetSystemAddressForMdlNormalSafe(Irp->MdlAddress);
    } else {
      DDbgPrint("  use UserBuffer\n");
      buffer = Irp->UserBuffer;
    }

    if (buffer == NULL) {
      DDbgPrint("  buffer == NULL\n");
      status = STATUS_INVALID_PARAMETER;
      __leave;
    }

    if (irpSp->Parameters.Write.ByteOffset.LowPart ==
            FILE_WRITE_TO_END_OF_FILE &&
        irpSp->Parameters.Write.ByteOffset.HighPart == -1) {
      writeToEoF = TRUE;
    }

    if (Irp->Flags & IRP_PAGING_IO) {
      isPagingIo = TRUE;
    }

    if (Irp->Flags & IRP_NOCACHE) {
      isNonCached = TRUE;
    }

    if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
      isSynchronousIo = TRUE;
    }

    if (!isPagingIo && (fileObject->SectionObjectPointer != NULL) &&
        (fileObject->SectionObjectPointer->DataSectionObject != NULL)) {
      ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE);
      CcFlushCache(&fcb->SectionObjectPointers,
                   writeToEoF ? NULL : &irpSp->Parameters.Write.ByteOffset,
                   irpSp->Parameters.Write.Length, NULL);
      CcPurgeCacheSection(&fcb->SectionObjectPointers,
                          writeToEoF ? NULL
                                     : &irpSp->Parameters.Write.ByteOffset,
                          irpSp->Parameters.Write.Length, FALSE);
      ExReleaseResourceLite(&fcb->PagingIoResource);
    }

    // Cannot write at end of the file when using paging IO
    if (writeToEoF && isPagingIo) {
      DDbgPrint("  writeToEoF & isPagingIo\n");
      Irp->IoStatus.Information = 0;
      status = STATUS_SUCCESS;
      __leave;
    }

    // the length of EventContext is sum of length to write and length of file
    // name
    DokanFCBLockRO(fcb);
    fcbLocked = TRUE;
    eventLength = sizeof(EVENT_CONTEXT) + irpSp->Parameters.Write.Length +
                  fcb->FileName.Length;

    eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb);

    // no more memory!
    if (eventContext == NULL) {
      status = STATUS_INSUFFICIENT_RESOURCES;
      __leave;
    }

    eventContext->Context = ccb->UserContext;
    // DDbgPrint("   get Context %X\n", (ULONG)ccb->UserContext);

    // When the length is bigger than usual event notitfication buffer,
    // saves pointer in DiverContext to copy EventContext after allocating
    // more bigger memory.
    Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = eventContext;

    if (isPagingIo) {
      DDbgPrint("  Paging IO\n");
      eventContext->FileFlags |= DOKAN_PAGING_IO;
    }
    if (isSynchronousIo) {
      DDbgPrint("  Synchronous IO\n");
      eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO;
    }
    if (isNonCached) {
      DDbgPrint("  Nocache\n");
      eventContext->FileFlags |= DOKAN_NOCACHE;
    }

    // offset of file to write
    eventContext->Operation.Write.ByteOffset =
        irpSp->Parameters.Write.ByteOffset;

    if (writeToEoF) {
      eventContext->FileFlags |= DOKAN_WRITE_TO_END_OF_FILE;
      DDbgPrint("  WriteOffset = end of file\n");
    }

    if (isSynchronousIo &&
        ((irpSp->Parameters.Write.ByteOffset.LowPart ==
          FILE_USE_FILE_POINTER_POSITION) &&
         (irpSp->Parameters.Write.ByteOffset.HighPart == -1))) {
      // NOTE:
      // http://msdn.microsoft.com/en-us/library/ms795960.aspx
      // Do not check IrpSp->Parameters.Write.ByteOffset.QuadPart == 0
      // Probably the document is wrong.
      eventContext->Operation.Write.ByteOffset.QuadPart =
          fileObject->CurrentByteOffset.QuadPart;
    }

    // the size of buffer to write
    eventContext->Operation.Write.BufferLength = irpSp->Parameters.Write.Length;

    // the offset from the begining of structure
    // the contents to write will be copyed to this offset
    eventContext->Operation.Write.BufferOffset =
        FIELD_OFFSET(EVENT_CONTEXT, Operation.Write.FileName[0]) +
        fcb->FileName.Length + sizeof(WCHAR); // adds last null char

    // copies the content to write to EventContext
    RtlCopyMemory((PCHAR)eventContext +
                      eventContext->Operation.Write.BufferOffset,
                  buffer, irpSp->Parameters.Write.Length);

    // copies file name
    eventContext->Operation.Write.FileNameLength = fcb->FileName.Length;
    RtlCopyMemory(eventContext->Operation.Write.FileName, fcb->FileName.Buffer,
                  fcb->FileName.Length);

    // When eventlength is less than event notification buffer,
    // returns it to user-mode using pending event.
    if (eventLength <= EVENT_CONTEXT_MAX_SIZE) {

      DDbgPrint("   Offset %d:%d, Length %d\n",
                irpSp->Parameters.Write.ByteOffset.HighPart,
                irpSp->Parameters.Write.ByteOffset.LowPart,
                irpSp->Parameters.Write.Length);

      // EventContext is no longer needed, clear it
      Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0;

      //
      //  We now check whether we can proceed based on the state of
      //  the file oplocks.
      //
      // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking.
      if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
        status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext,
                                  DokanOplockComplete, DokanPrePostIrp);

        //
        //  if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
        //  to service an oplock break and we need to leave now.
        //
        if (status != STATUS_SUCCESS) {
          if (status == STATUS_PENDING) {
            DDbgPrint("   FsRtlCheckOplock returned STATUS_PENDING\n");
          } else {
            DokanFreeEventContext(eventContext);
          }
          __leave;
        }
      }

      // register this IRP to IRP waiting list and make it pending status
      status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0);

      // Resuests bigger memory
      // eventContext will be freed later using
      // Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT]
    } else {
      // the length at lest file name can be stored
      ULONG requestContextLength = max(
          sizeof(EVENT_CONTEXT), eventContext->Operation.Write.BufferOffset);
      PEVENT_CONTEXT requestContext =
          AllocateEventContext(vcb->Dcb, Irp, requestContextLength, ccb);

      // no more memory!
      if (requestContext == NULL) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0;
        DokanFreeEventContext(eventContext);
        __leave;
      }

      DDbgPrint("   Offset %d:%d, Length %d (request)\n",
                irpSp->Parameters.Write.ByteOffset.HighPart,
                irpSp->Parameters.Write.ByteOffset.LowPart,
                irpSp->Parameters.Write.Length);

      // copies from begining of EventContext to the end of file name
      RtlCopyMemory(requestContext, eventContext,
                    eventContext->Operation.Write.BufferOffset);
      // puts actual size of RequestContext
      requestContext->Length = requestContextLength;
      // requsts enough size to copy EventContext
      requestContext->Operation.Write.RequestLength = eventLength;

      //
      //  We now check whether we can proceed based on the state of
      //  the file oplocks.
      //
      // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking.
      if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) {
        status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, requestContext,
                                  DokanOplockComplete, DokanPrePostIrp);

        //
        //  if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
        //  to service an oplock break and we need to leave now.
        //
        if (status != STATUS_SUCCESS) {
          if (status == STATUS_PENDING) {
            DDbgPrint("   FsRtlCheckOplock returned STATUS_PENDING\n");
          } else {
            DokanFreeEventContext(requestContext);
            Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0;
            DokanFreeEventContext(eventContext);
          }
          __leave;
        }
      }

      // regiters this IRP to IRP wainting list and make it pending status
      status = DokanRegisterPendingIrp(DeviceObject, Irp, requestContext, 0);
    }

  } __finally {
    if(fcbLocked)
      DokanFCBUnlock(fcb);

    DokanCompleteIrpRequest(Irp, status, 0);

    DDbgPrint("<== DokanWrite\n");
  }

  return status;
}
Esempio n. 15
0
NTSTATUS
Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
{
    PDEVICE_OBJECT  DeviceObject;
    NTSTATUS        Status = STATUS_SUCCESS;
    PEXT2_VCB       Vcb;
    PFILE_OBJECT    FileObject;
    PEXT2_FCB       Fcb;
    PEXT2_CCB       Ccb;
    PIRP            Irp;
    PEXT2_MCB       Mcb;


    BOOLEAN         VcbResourceAcquired = FALSE;
    BOOLEAN         FcbResourceAcquired = FALSE;
    BOOLEAN         FcbPagingIoResourceAcquired = FALSE;

    __try {

        ASSERT(IrpContext != NULL);
        ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
               (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));

        DeviceObject = IrpContext->DeviceObject;
        if (IsExt2FsDevice(DeviceObject))  {
            Status = STATUS_SUCCESS;
            __leave;
        }

        Irp = IrpContext->Irp;
        Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
        ASSERT(Vcb != NULL);
        ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
               (Vcb->Identifier.Size == sizeof(EXT2_VCB)));

        if (!IsVcbInited(Vcb)) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        FileObject = IrpContext->FileObject;
        Fcb = (PEXT2_FCB) FileObject->FsContext;
        if (!Fcb || (Fcb->Identifier.Type != EXT2VCB &&
                     Fcb->Identifier.Type != EXT2FCB)) {
            Status = STATUS_SUCCESS;
            __leave;
        }
        Mcb = Fcb->Mcb;
        Ccb = (PEXT2_CCB) FileObject->FsContext2;

        if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        VcbResourceAcquired =
            ExAcquireResourceExclusiveLite(
                &Vcb->MainResource,
                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
            );

        if (Fcb->Identifier.Type == EXT2VCB) {

            if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
                    (Vcb->LockFile == FileObject) ) {

                ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
                Vcb->LockFile = NULL;
                Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
            }

            if (Ccb) {
                Ext2DerefXcb(&Vcb->OpenHandleCount);
                Ext2DerefXcb(&Vcb->OpenVolumeCount);
            }

            IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);

            Status = STATUS_SUCCESS;
            __leave;
        }

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

        if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
            if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
                    IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
                    !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) {
                Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
            }
            __leave;
        }

        if (Ccb == NULL) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        if (IsDirectory(Fcb)) {
            if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))  {
                SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);

                FsRtlNotifyFullChangeDirectory(
                    Vcb->NotifySync,
                    &Vcb->NotifyList,
                    Ccb,
                    NULL,
                    FALSE,
                    FALSE,
                    0,
                    NULL,
                    NULL,
                    NULL );
            }

            FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb);

        }

        ExReleaseResourceLite(&Vcb->MainResource);
        VcbResourceAcquired = FALSE;

        FcbResourceAcquired =
            ExAcquireResourceExclusiveLite(
                &Fcb->MainResource,
                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
            );

        ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
               (Ccb->Identifier.Size == sizeof(EXT2_CCB)));

        Ext2DerefXcb(&Vcb->OpenHandleCount);
        Ext2DerefXcb(&Fcb->OpenHandleCount);

        if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
            Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
        }

        if (IsDirectory(Fcb)) {

            ext3_release_dir(Fcb->Inode, &Ccb->filp);

        } else {

            if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
                    !IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {

                LARGE_INTEGER   SysTime;
                KeQuerySystemTime(&SysTime);

                Fcb->Inode->i_atime =
                    Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
                Fcb->Mcb->LastAccessTime =
                    Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime);

                Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);

                Ext2NotifyReportChange(
                    IrpContext,
                    Vcb,
                    Fcb->Mcb,
                    FILE_NOTIFY_CHANGE_ATTRIBUTES |
                    FILE_NOTIFY_CHANGE_LAST_WRITE |
                    FILE_NOTIFY_CHANGE_LAST_ACCESS,
                    FILE_ACTION_MODIFIED );
            }

            FsRtlCheckOplock( &Fcb->Oplock,
                              Irp,
                              IrpContext,
                              NULL,
                              NULL );

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

            if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) {
                Fcb->NonCachedOpenCount--;
            }

            if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))  {
                SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
            }

            //
            // Drop any byte range locks this process may have on the file.
            //

            FsRtlFastUnlockAll(
                &Fcb->FileLockAnchor,
                FileObject,
                IoGetRequestorProcess(Irp),
                NULL  );

            //
            // If there are no byte range locks owned by other processes on the
            // file the fast I/O read/write functions doesn't have to check for
            // locks so we set IsFastIoPossible to FastIoIsPossible again.
            //
            if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) {
                if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) {
#if EXT2_DEBUG
                    DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n",
                                   Ext2GetCurrentProcessName(),
                                   "FastIoIsPossible",
                                   &Fcb->Mcb->FullName
                                  ));
#endif

                    Fcb->Header.IsFastIoPossible = FastIoIsPossible;
                }
            }

            if (Fcb->OpenHandleCount == 0 &&
                    (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE) ||
                     IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) ) {

                LARGE_INTEGER Size;

                ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
                FcbPagingIoResourceAcquired = TRUE;

                Size.QuadPart = CEILING_ALIGNED(ULONGLONG,
                                                (ULONGLONG)Fcb->Mcb->Inode.i_size,
                                                (ULONGLONG)BLOCK_SIZE);
                if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {

                    Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
                    Fcb->Header.ValidDataLength.QuadPart =
                        Fcb->Header.FileSize.QuadPart = Fcb->Mcb->Inode.i_size;
                    Fcb->Header.AllocationSize = Size;
                    if (CcIsFileCached(FileObject)) {
                        CcSetFileSizes(FileObject,
                                       (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    }
                }
                ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE);
                ExReleaseResourceLite(&Fcb->PagingIoResource);
                FcbPagingIoResourceAcquired = FALSE;
            }
        }

        if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {

            if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) {

                //
                // Ext2DeleteFile will acquire these lock inside
                //

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

                //
                //  this file is to be deleted ...
                //
                if (Ccb->SymLink) {
                    Mcb = Ccb->SymLink;
                    FileObject->DeletePending = FALSE;
                }

                Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);

                if (NT_SUCCESS(Status)) {
                    if (IsMcbDirectory(Mcb)) {
                        Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
                                                FILE_NOTIFY_CHANGE_DIR_NAME,
                                                FILE_ACTION_REMOVED );
                    } else {
                        Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
                                                FILE_NOTIFY_CHANGE_FILE_NAME,
                                                FILE_ACTION_REMOVED );
                    }
                }

                //
                // re-acquire the main resource lock
                //

                FcbResourceAcquired =
                    ExAcquireResourceExclusiveLite(
                        &Fcb->MainResource,
                        IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
                    );

                if (CcIsFileCached(FileObject)) {
                    CcSetFileSizes(FileObject,
                                   (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
                }
            }
        }

        if (!IsDirectory(Fcb)) {

            if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
                    (Fcb->NonCachedOpenCount + 1 == Fcb->ReferenceCount) &&
                    (Fcb->SectionObject.DataSectionObject != NULL)) {

                if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) &&
                        !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) {
                    CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
                }

                if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
                    ExReleaseResourceLite(&(Fcb->PagingIoResource));
                }

                CcPurgeCacheSection( &Fcb->SectionObject,
                                     NULL,
                                     0,
                                     FALSE );
            }

            CcUninitializeCacheMap(FileObject, NULL, NULL);
        }

        IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);

        DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n",
                        Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName));

        Status = STATUS_SUCCESS;

        if (FileObject) {
            SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
        }

    } __finally {

        if (FcbPagingIoResourceAcquired) {
            ExReleaseResourceLite(&Fcb->PagingIoResource);
        }

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

        if (VcbResourceAcquired) {
            ExReleaseResourceLite(&Vcb->MainResource);
        }

        if (!IrpContext->ExceptionInProgress) {
            if (Status == STATUS_PENDING) {
                Ext2QueueRequest(IrpContext);
            } else {
                IrpContext->Irp->IoStatus.Status = Status;
                Ext2CompleteIrpContext(IrpContext, Status);
            }
        }
    }

    return Status;
}
Esempio n. 16
0
NTSTATUS
FatCommonLockControl (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
)

/*++

Routine Description:

    This is the common routine for doing Lock control operations called
    by both the fsd and fsp threads

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;
    PIO_STACK_LOCATION IrpSp;

    TYPE_OF_OPEN TypeOfOpen;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    BOOLEAN OplockPostIrp = FALSE;

    //
    //  Get a pointer to the current Irp stack location
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonLockControl\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %08lx\n", Irp);
    DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction);

    //
    //  Decode the type of file object we're being asked to process
    //

    TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb );

    //
    //  If the file is not a user file open then we reject the request
    //  as an invalid parameter
    //

    if (TypeOfOpen != UserFileOpen) {

        FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );

        DebugTrace(-1, Dbg, "FatCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0);
        return STATUS_INVALID_PARAMETER;
    }

    //
    //  Acquire exclusive access to the Fcb and enqueue the Irp if we didn't
    //  get access
    //

    if (!FatAcquireSharedFcb( IrpContext, Fcb )) {

        Status = FatFsdPostRequest( IrpContext, Irp );

        DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status);
        return Status;
    }

    try {

        //
        //  We check whether we can proceed
        //  based on the state of the file oplocks.
        //

        Status = FsRtlCheckOplock( &Fcb->Specific.Fcb.Oplock,
                                   Irp,
                                   IrpContext,
                                   FatOplockComplete,
                                   NULL );

        if (Status != STATUS_SUCCESS) {

            OplockPostIrp = TRUE;
            try_return( NOTHING );
        }

        //
        //  Now call the FsRtl routine to do the actual processing of the
        //  Lock request
        //

        Status = FsRtlProcessFileLock( &Fcb->Specific.Fcb.FileLock, Irp, NULL );

        //
        //  Set the flag indicating if Fast I/O is possible
        //

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

try_exit:
        NOTHING;
    }
    finally {

        DebugUnwind( FatCommonLockControl );

        //
        //  Only if this is not an abnormal termination do we delete the
        //  irp context
        //

        if (!AbnormalTermination() && !OplockPostIrp) {

            FatCompleteRequest( IrpContext, FatNull, 0 );
        }

        //
        //  Release the Fcb, and return to our caller
        //

        FatReleaseFcb( IrpContext, Fcb );

        DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status);
    }

    return Status;
}
Esempio n. 17
0
NTSTATUS
Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
{
    PEXT2_VCB           Vcb = NULL;
    PEXT2_FCB           Fcb = NULL;
    PEXT2_CCB           Ccb = NULL;
    PFILE_OBJECT        FileObject = NULL;

    PDEVICE_OBJECT      DeviceObject = NULL;

    PIRP                Irp = NULL;
    PIO_STACK_LOCATION  IoStackLocation = NULL;
    PUCHAR              Buffer = NULL;

    LARGE_INTEGER       ByteOffset;
    ULONG               ReturnedLength = 0;
    ULONG               Length;

    NTSTATUS            Status = STATUS_UNSUCCESSFUL;

    BOOLEAN             OpPostIrp = FALSE;
    BOOLEAN             PagingIo = FALSE;
    BOOLEAN             Nocache = FALSE;
    BOOLEAN             SynchronousIo = FALSE;

    BOOLEAN             RecursiveWriteThrough = FALSE;
    BOOLEAN             MainResourceAcquired = FALSE;
    BOOLEAN             PagingIoResourceAcquired = FALSE;

    BOOLEAN             bDeferred = FALSE;
    BOOLEAN             UpdateFileValidSize = FALSE;
    BOOLEAN             FileSizesChanged = FALSE;
    BOOLEAN             rc;


    __try {

        ASSERT(IrpContext);
        ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
               (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));

        DeviceObject = IrpContext->DeviceObject;
        Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
        ASSERT(Vcb != NULL);
        ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
               (Vcb->Identifier.Size == sizeof(EXT2_VCB)));

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

        Irp = IrpContext->Irp;
        IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

        Length = IoStackLocation->Parameters.Write.Length;
        ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;

        PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO);
        Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE);
        SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);

        if (PagingIo) {
            ASSERT(Nocache);
        }

        DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
                       &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));

        if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
            Status = STATUS_INVALID_DEVICE_REQUEST;
            __leave;
        }

        if (IsFileDeleted(Fcb->Mcb) ||
            (IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ) {
            Status = STATUS_FILE_DELETED;
            __leave;
        }

        if (Length == 0) {
            Irp->IoStatus.Information = 0;
            Status = STATUS_SUCCESS;
            __leave;
        }

        if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
            ByteOffset.HighPart == -1) {
            ByteOffset = FileObject->CurrentByteOffset;
        } else if (IsWritingToEof(ByteOffset)) {
            ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
        }

        if (Nocache && !PagingIo &&
            ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
               (Length & (SECTOR_SIZE - 1))) ) {
            Status = STATUS_INVALID_PARAMETER;
            __leave;
        }

        if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
            ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
            Status = STATUS_PENDING;
            __leave;
        }

        if (!Nocache) {

            BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
            BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
            BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);

            if ( !CcCanIWrite(
                        FileObject,
                        Length,
                        (bWait && bQueue),
                        bAgain ) ) {

                Status = Ext2LockUserBuffer(
                             IrpContext->Irp,
                             Length,
                             IoReadAccess);

                if (NT_SUCCESS(Status)) {
                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
                    CcDeferWrite( FileObject,
                                  (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite,
                                  IrpContext,
                                  Irp,
                                  Length,
                                  bAgain );
                    bDeferred = TRUE;
                    Status = STATUS_PENDING;
                    __leave;
                }
            }
        }

        if (IsDirectory(Fcb) && !PagingIo) {
            Status = STATUS_INVALID_DEVICE_REQUEST;
            __leave;
        }

        if (IsFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) && !IrpContext->IsTopLevel) {

            PIRP TopIrp;

            TopIrp = IoGetTopLevelIrp();

            if ( (ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG &&
                    NodeType(TopIrp) == IO_TYPE_IRP) {

                PIO_STACK_LOCATION IrpStack;

                IrpStack = IoGetCurrentIrpStackLocation(TopIrp);

                if ((IrpStack->MajorFunction == IRP_MJ_WRITE) &&
                    (IrpStack->FileObject->FsContext == FileObject->FsContext) &&
                    !FlagOn(TopIrp->Flags, IRP_NOCACHE) ) {

                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
                    RecursiveWriteThrough = TRUE;
                }
            }
        }

        if (PagingIo) {

            if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, TRUE)) {
                Status = STATUS_PENDING;
                __leave;
            }
            PagingIoResourceAcquired = TRUE;

            if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {

                if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {

                    Status = STATUS_SUCCESS;
                    Irp->IoStatus.Information = 0;
                    __leave;

                } else {

                    ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
                    if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart)
                        Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
                }

            } else {

                ReturnedLength = Length;
            }

        } else {

            if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) {
                Status = STATUS_ACCESS_DENIED;
                __leave;
            }

            if (IsDirectory(Fcb)) {
                __leave;
            }

            if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE)) {
                Status = STATUS_PENDING;
                __leave;
            }
            MainResourceAcquired = TRUE;

            //
            //  Do flushing for such cases
            //
            if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject != NULL)  {

                ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE);
                ExReleaseResourceLite(&Fcb->PagingIoResource);

                CcFlushCache( &(Fcb->SectionObject),
                              &ByteOffset,
                              CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE),
                              &(Irp->IoStatus));
                ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);

                if (!NT_SUCCESS(Irp->IoStatus.Status)) {
                    Status = Irp->IoStatus.Status;
                    __leave;
                }

                ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE);
                ExReleaseResourceLite(&Fcb->PagingIoResource);

                CcPurgeCacheSection( &(Fcb->SectionObject),
                                     &(ByteOffset),
                                     CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE),
                                     FALSE );
            }

            if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLockAnchor, Irp)) {
                Status = STATUS_FILE_LOCK_CONFLICT;
                __leave;
            }

            if (Ccb != NULL) {

                Status = FsRtlCheckOplock( &Fcb->Oplock,
                                           Irp,
                                           IrpContext,
                                           Ext2OplockComplete,
                                           Ext2LockIrp );

                if (Status != STATUS_SUCCESS) {
                    OpPostIrp = TRUE;
                    __leave;
                }

                //
                //  Set the flag indicating if Fast I/O is possible
                //

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

            //
            //  Extend the inode size when the i/o is beyond the file end ?
            //

            if ((ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {

                LARGE_INTEGER AllocationSize, Last;

                if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE)) {
                    Status = STATUS_PENDING;
                    __leave;
                }
                PagingIoResourceAcquired = TRUE;

                /* let this irp wait, since it has to be synchronous */
                SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);

                Last.QuadPart = Fcb->Header.AllocationSize.QuadPart;
                AllocationSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);
                AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
                                          (ULONGLONG)AllocationSize.QuadPart,
                                          (ULONGLONG)BLOCK_SIZE);

                /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks
                   for indirect files, otherwise we might get gabage data in holes */
                IrpContext->MajorFunction += IRP_MJ_MAXIMUM_FUNCTION;
                Status = Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &AllocationSize);
                IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION;
                if (AllocationSize.QuadPart > Last.QuadPart) {
                    Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart;
                    SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_WRITE);
                }
                ExReleaseResourceLite(&Fcb->PagingIoResource);
                PagingIoResourceAcquired = FALSE;

                if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
                    if (NT_SUCCESS(Status)) {
                        DbgBreak();
                        Status = STATUS_UNSUCCESSFUL;
                    }
                    __leave;
                }

                if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) {
                    Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
                }

                Fcb->Header.FileSize.QuadPart = Fcb->Inode->i_size = ByteOffset.QuadPart + Length;
                Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);

                if (CcIsFileCached(FileObject)) {
                    CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                }

                FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED;
                FileSizesChanged = TRUE;

                if (Fcb->Header.FileSize.QuadPart >= 0x80000000 &&
                        !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
                    SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
                    Ext2SaveSuper(IrpContext, Vcb);
                }

                DEBUG(DL_IO, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n",
                              &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
                              Fcb->Header.AllocationSize.QuadPart));
            }

            ReturnedLength = Length;
        }

        if (!Nocache) {

            if (FileObject->PrivateCacheMap == NULL) {
                CcInitializeCacheMap(
                    FileObject,
                    (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
                    FALSE,
                    &Ext2Global->CacheManagerCallbacks,
                    Fcb );

                CcSetReadAheadGranularity(
                    FileObject,
                    READ_AHEAD_GRANULARITY );
            }

            if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {

                CcPrepareMdlWrite(
                    FileObject,
                    &ByteOffset,
                    Length,
                    &Irp->MdlAddress,
                    &Irp->IoStatus );

                Status = Irp->IoStatus.Status;

            } else {

                Buffer = Ext2GetUserBuffer(Irp);
                if (Buffer == NULL) {
                    DbgBreak();
                    Status = STATUS_INVALID_USER_BUFFER;
                    __leave;
                }

                if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {

                    /* let this irp wait, since it has to be synchronous */
                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);

                    rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
                                      &Fcb->Header.ValidDataLength, &ByteOffset);
                    if (!rc) {
                        Status = STATUS_PENDING;
                        DbgBreak();
                        __leave;
                    }
                }

                if (!CcCopyWrite(FileObject, &ByteOffset, Length, Ext2CanIWait(), Buffer)) {
                    if (Ext2CanIWait() || 
                        !CcCopyWrite(FileObject,  &ByteOffset, Length, TRUE, Buffer)) {
                        Status = STATUS_PENDING;
                        DbgBreak();
                        __leave;
                    }
                }

                if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {

                    if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
                        Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
                    } else {
                        if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
                            Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
                    }

                    CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    FileSizesChanged = TRUE;
                }

                Status = STATUS_SUCCESS;
            }

            if (NT_SUCCESS(Status)) {
                Irp->IoStatus.Information = Length;
                if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
                    DEBUG(DL_FLP, ("Ext2WriteFile is starting FlushingDpc...\n"));
                    Ext2StartFloppyFlushDpc(Vcb, Fcb, FileObject);
                }
            }

        } else {

            if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
                if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {

                    /* let this irp wait, since it has to be synchronous */
                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
                    rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
                                      &Fcb->Header.ValidDataLength,
                                      &ByteOffset);
                    if (!rc) {
                        Status = STATUS_PENDING;
                        DbgBreak();
                        __leave;
                    }
                }
            }

            Status = Ext2LockUserBuffer(
                         IrpContext->Irp,
                         Length,
                         IoReadAccess );

            if (!NT_SUCCESS(Status)) {
                __leave;
            }

            Irp->IoStatus.Status = STATUS_SUCCESS;
            Irp->IoStatus.Information = ReturnedLength;

            Status = Ext2WriteInode(
                         IrpContext,
                         Vcb,
                         Fcb->Mcb,
                         (ULONGLONG)(ByteOffset.QuadPart),
                         NULL,
                         ReturnedLength,
                         TRUE,
                         &Length
                     );

            Irp = IrpContext->Irp;

            if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {

                if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {

                    FileSizesChanged = TRUE;

                    if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
                        if (!PagingIo)
                            Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length;
                        Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
                    } else {
                        if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
                            Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
                    }

                    if (!PagingIo && CcIsFileCached(FileObject)) {
                        CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    }

                    DEBUG(DL_IO, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n",
                                  &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
                                   Fcb->Header.AllocationSize.QuadPart, ByteOffset.QuadPart, Length));
                }
            }
        }

        if (FileSizesChanged) {
            FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED;
            Ext2NotifyReportChange( IrpContext,  Vcb, Fcb->Mcb,
                                    FILE_NOTIFY_CHANGE_SIZE,
                                    FILE_ACTION_MODIFIED );
        }

    } __finally {

        /*
         *  in case we got excpetions, we need revert MajorFunction
         *  back to IRP_MJ_WRITE. The reason we do this, is to tell
         *  Ext2ExpandFile to allocate unwritten extent or don't add
         *  new blocks for indirect files.
         */
        if (IrpContext->MajorFunction > IRP_MJ_MAXIMUM_FUNCTION)
            IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION;

        if (Irp) {
            if (PagingIoResourceAcquired) {
                ExReleaseResourceLite(&Fcb->PagingIoResource);
            }

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

        if (!OpPostIrp && !IrpContext->ExceptionInProgress) {

            if (Irp) {

                if (Status == STATUS_PENDING ||
                        Status == STATUS_CANT_WAIT ) {

                    if (!bDeferred) {
                        Status = Ext2QueueRequest(IrpContext);
                    }

                } else {

                    if (NT_SUCCESS(Status) && !PagingIo) {

                        if (SynchronousIo) {
                            FileObject->CurrentByteOffset.QuadPart =
                                ByteOffset.QuadPart + Irp->IoStatus.Information;
                        }

                        SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
                        SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
                    }

                    Ext2CompleteIrpContext(IrpContext, Status);
                }
            } else {
                Ext2FreeIrpContext(IrpContext);
            }
        }
    }

    DEBUG(DL_IO, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d "
                  "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n",
                  &Fcb->Mcb->ShortName, ByteOffset, Length, PagingIo, Nocache, ReturnedLength,
                  Fcb->Header.ValidDataLength.QuadPart,Fcb->Header.FileSize.QuadPart,
                  Fcb->Inode->i_size, Status));

    return Status;
}
Esempio n. 18
0
NTSTATUS
CdCommonCleanup (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for cleanup of a file/directory called by both
    the fsd and fsp threads.

    Cleanup is invoked whenever the last handle to a file object is closed.
    This is different than the Close operation which is invoked when the last
    reference to a file object is deleted.

    The function of cleanup is to essentially "cleanup" the file/directory
    after a user is done with it.  The Fcb/Dcb remains around (because MM
    still has the file object referenced) but is now available for another
    user to open (i.e., as far as the user is concerned the is now closed).

    See close for a more complete description of what close does.

    We do no synchronization in this routine until we get to the point
    where we modify the counts, share access and volume lock field.

    We need to update the Fcb and Vcb to show that a user handle has been closed.
    The following structures and fields are affected.

    Vcb:

        VolumeLockFileObject - Did the user lock the volume with this file object.
        VcbState - Check if we are unlocking the volume here.
        VcbCleanup - Count of outstanding handles on the volume.
        DirNotifyQueue - If this file object has pending DirNotify Irps.

    Fcb:

        ShareAccess - If this is a user handle.
        FcbCleanup - Count of outstanding handles on this Fcb.
        Oplock - Any outstanding oplocks on this file object.
        FileLock - Any outstanding filelocks on this file object.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation.

--*/

{
    PFILE_OBJECT FileObject;
    TYPE_OF_OPEN TypeOfOpen;

    BOOLEAN SendUnlockNotification = FALSE;
    BOOLEAN AttemptTeardown;

    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    KIRQL SavedIrql;

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_IRP( Irp );

    //
    //  If we were called with our file system device object instead of a
    //  volume device object, just complete this request with STATUS_SUCCESS.
    //

    if (IrpContext->Vcb == NULL) {

        CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
        return STATUS_SUCCESS;
    }

    //
    //  Get the file object out of the Irp and decode the type of open.
    //

    FileObject = IoGetCurrentIrpStackLocation( Irp )->FileObject;

    TypeOfOpen = CdDecodeFileObject( IrpContext,
                                     FileObject,
                                     &Fcb,
                                     &Ccb );

    //
    //  No work here for either an UnopenedFile object or a StreamFileObject.
    //

    if (TypeOfOpen <= StreamFileOpen) {

        CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );

        return STATUS_SUCCESS;
    }

    //
    //  Keep a local pointer to the Vcb.
    //

    Vcb = Fcb->Vcb;
    
    //
    //  Synchronise with reads while we set the cleanup complete 
    //  flag on this fileobject.  Once this flag is set,  any further
    //  reads will be rejected (CdVerifyFcbOperation)
    //

    CdAcquireFileExclusive( IrpContext, Fcb);

    //
    //  Set the flag in the FileObject to indicate that cleanup is complete.
    //

    SetFlag( FileObject->Flags, FO_CLEANUP_COMPLETE );

    CdReleaseFile( IrpContext, Fcb);
    
    //
    //  Acquire the current file.
    //

    CdAcquireFcbExclusive( IrpContext, Fcb, FALSE );
    
    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {
    
        //
        //  Case on the type of open that we are trying to cleanup.
        //

        switch (TypeOfOpen) {

        case UserDirectoryOpen:

            //
            //  Check if we need to complete any dir notify Irps on this file object.
            //

            FsRtlNotifyCleanup( Vcb->NotifySync,
                                &Vcb->DirNotifyList,
                                Ccb );

            break;

        case UserFileOpen:

            //
            //  Coordinate the cleanup operation with the oplock state.
            //  Oplock cleanup operations can always cleanup immediately so no
            //  need to check for STATUS_PENDING.
            //

            FsRtlCheckOplock( &Fcb->Oplock,
                              Irp,
                              IrpContext,
                              NULL,
                              NULL );

            //
            //  Unlock all outstanding file locks.
            //

            if (Fcb->FileLock != NULL) {

                FsRtlFastUnlockAll( Fcb->FileLock,
                                    FileObject,
                                    IoGetRequestorProcess( Irp ),
                                    NULL );
            }

            //
            //  Cleanup the cache map.
            //

            CcUninitializeCacheMap( FileObject, NULL, NULL );

            //
            //  Check the fast io state.
            //

            CdLockFcb( IrpContext, Fcb );
            Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
            CdUnlockFcb( IrpContext, Fcb );

            break;

        case UserVolumeOpen :

            break;

        default :

            CdBugCheck( TypeOfOpen, 0, 0 );
        }

        //
        //  Now lock the Vcb in order to modify the fields in the in-memory
        //  structures.
        //

        CdLockVcb( IrpContext, Vcb );

        //
        //  Decrement the cleanup counts in the Vcb and Fcb.
        //

        CdDecrementCleanupCounts( IrpContext, Fcb );

        //
        //  If the cleanup count hit zero and the volume is not mounted, we
        //  will want to try to spark teardown.
        //

        AttemptTeardown = (Vcb->VcbCleanup == 0 && Vcb->VcbCondition == VcbNotMounted);

        //
        //  If this file object has locked the volume then perform the unlock operation.
        //  We do this regardless of explicit or implicit (no share DASD open) lock.
        //

        if (FileObject == Vcb->VolumeLockFileObject) {

            ASSERT( FlagOn( Vcb->VcbState, VCB_STATE_LOCKED));

            IoAcquireVpbSpinLock( &SavedIrql ); 

            ClearFlag( Vcb->Vpb->Flags, VPB_LOCKED);
            ClearFlag( Vcb->VcbState, VCB_STATE_LOCKED );
            Vcb->VolumeLockFileObject = NULL;
            SendUnlockNotification = TRUE;

            IoReleaseVpbSpinLock( SavedIrql );  
        }

        CdUnlockVcb( IrpContext, Vcb );

        //
        //  We must clean up the share access at this time, since we may not
        //  get a Close call for awhile if the file was mapped through this
        //  File Object.
        //

        IoRemoveShareAccess( FileObject, &Fcb->ShareAccess );

    } finally {

        CdReleaseFcb( IrpContext, Fcb );
        
        if (SendUnlockNotification) {
            
            FsRtlNotifyVolumeEvent( FileObject, FSRTL_VOLUME_UNLOCK );
        }
    }

    //
    //  If appropriate, try to spark teardown by purging the volume.  Should
    //  this very fileobject we were cleaning up be the last reason for the
    //  volume to remain, teardown will commence on completion of this Irp.
    //
    
    if (AttemptTeardown) {

        CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );

        try {
            
            CdPurgeVolume( IrpContext, Vcb, FALSE );

        } finally {

            CdReleaseVcb( IrpContext, Vcb );
        }
    }

    //
    //  If this is a normal termination then complete the request
    //

    CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );

    return STATUS_SUCCESS;
}
Esempio n. 19
0
/* Last handle to a file object is closed */
NTSTATUS
NTAPI
FatiCleanup(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
{
    PIO_STACK_LOCATION IrpSp;
    PFILE_OBJECT FileObject;
    TYPE_OF_OPEN TypeOfOpen;
    PSHARE_ACCESS ShareAccess;
    BOOLEAN SendUnlockNotification = FALSE;
    PLARGE_INTEGER TruncateSize = NULL;
    //LARGE_INTEGER LocalTruncateSize;
    BOOLEAN AcquiredVcb = FALSE, AcquiredFcb = FALSE;
    NTSTATUS Status;
    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DPRINT("FatiCleanup\n");
    DPRINT("\tIrp           = %p\n", Irp);
    DPRINT("\t->FileObject  = %p\n", IrpSp->FileObject);

    FileObject = IrpSp->FileObject;
    TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb);

    if (TypeOfOpen == UnopenedFileObject)
    {
        DPRINT1("Unopened File Object\n");

        FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
        return STATUS_SUCCESS;
    }

    if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ))
    {
        /* Just flush the file */

        if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
            FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
            !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED) &&
            (TypeOfOpen == UserFileOpen))
        {
            //Status = FatFlushFile(IrpContext, Fcb, Flush);
            //if (!NT_SUCCESS(Status)) FatNormalizeAndRaiseStatus(IrpContext, Status);
            UNIMPLEMENTED;
        }

        FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
        return STATUS_SUCCESS;
    }

    if (TypeOfOpen == UserFileOpen ||
        TypeOfOpen == UserDirectoryOpen)
    {
        ASSERT(Fcb != NULL);

        (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);

        AcquiredFcb = TRUE;

        /* Set FCB flags according to DELETE_ON_CLOSE */
        if (FlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))
        {
            ASSERT(FatNodeType(Fcb) != FAT_NTC_ROOT_DCB);

            SetFlag(Fcb->State, FCB_STATE_DELETE_ON_CLOSE);

            /* Issue a notification */
            if (TypeOfOpen == UserDirectoryOpen)
            {
                FsRtlNotifyFullChangeDirectory(Vcb->NotifySync,
                                               &Vcb->NotifyList,
                                               FileObject->FsContext,
                                               NULL,
                                               FALSE,
                                               FALSE,
                                               0,
                                               NULL,
                                               NULL,
                                               NULL);
            }
        }

        /* If file should be deleted, acquire locks */
        if ((Fcb->UncleanCount == 1) &&
            FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
            (Fcb->Condition != FcbBad) &&
            !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
        {
            FatReleaseFcb(IrpContext, Fcb);
            AcquiredFcb = FALSE;

            (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
            AcquiredVcb = TRUE;

            (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
            AcquiredFcb = TRUE;
        }
    }

    /* Acquire VCB lock if it was a volume open */
    if (TypeOfOpen == UserVolumeOpen)
    {
        (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
        AcquiredVcb = TRUE;
    }

    /* Cleanup all notifications */
    if (TypeOfOpen == UserDirectoryOpen)
    {
        FsRtlNotifyCleanup(Vcb->NotifySync,
                           &Vcb->NotifyList,
                           Ccb);
    }

    if (Fcb)
    {
        //TODO: FatVerifyFcb
    }

    switch (TypeOfOpen)
    {
    case DirectoryFile:
    case VirtualVolumeFile:
        DPRINT1("Cleanup VirtualVolumeFile/DirectoryFile\n");
        ShareAccess = NULL;
        break;

    case UserVolumeOpen:
        DPRINT("Cleanup UserVolumeOpen\n");

        if (FlagOn(Ccb->Flags, CCB_COMPLETE_DISMOUNT))
        {
            FatCheckForDismount( IrpContext, Vcb, TRUE );
        } else if (FileObject->WriteAccess &&
            FlagOn(FileObject->Flags, FO_FILE_MODIFIED))
        {
            UNIMPLEMENTED;
        }

        /* Release the volume and send notification */
        if (FlagOn(Vcb->State, VCB_STATE_FLAG_LOCKED) &&
            (Vcb->FileObjectWithVcbLocked == FileObject))
        {
            UNIMPLEMENTED;
            SendUnlockNotification = TRUE;
        }

        ShareAccess = &Vcb->ShareAccess;
        break;

    case EaFile:
        DPRINT1("Cleanup EaFileObject\n");
        ShareAccess = NULL;
        break;

    case UserDirectoryOpen:
        DPRINT("Cleanup UserDirectoryOpen\n");

        ShareAccess = &Fcb->ShareAccess;

        /* Should it be a delayed close? */
        if ((Fcb->UncleanCount == 1) &&
            (Fcb->OpenCount == 1) &&
            (Fcb->Dcb.DirectoryFileOpenCount == 0) &&
            !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
            Fcb->Condition == FcbGood)
        {
            /* Yes, a delayed one */
            SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
        }

        if (VcbGood == Vcb->Condition)
        {
            //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
            //TODO: Actually update dirent
        }

        if ((Fcb->UncleanCount == 1) &&
            (FatNodeType(Fcb) == FAT_NTC_DCB) &&
            (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) &&
            (Fcb->Condition != FcbBad) &&
            !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
        {
            UNIMPLEMENTED;
        }

        /*  Decrement unclean counter */
        ASSERT(Fcb->UncleanCount != 0);
        Fcb->UncleanCount--;
        break;

    case UserFileOpen:
        DPRINT("Cleanup UserFileOpen\n");

        ShareAccess = &Fcb->ShareAccess;

        /* Should it be a delayed close? */
        if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) &&
            (FileObject->SectionObjectPointer->ImageSectionObject == NULL) &&
            (Fcb->UncleanCount == 1) &&
            (Fcb->OpenCount == 1) &&
            !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
            Fcb->Condition == FcbGood)
        {
            /* Yes, a delayed one */
            //SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
            DPRINT1("Setting a delay on close for some reason for FCB %p, FF handle %p, file name '%wZ'\n", Fcb, Fcb->FatHandle, &Fcb->FullFileName);
        }

        /* Unlock all file locks */
        FsRtlFastUnlockAll(&Fcb->Fcb.Lock,
                           FileObject,
                           IoGetRequestorProcess(Irp),
                           NULL);

        if (Vcb->Condition == VcbGood)
        {
            if (Fcb->Condition != FcbBad)
            {
                //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
                // TODO: Update on-disk structures
            }

            if (Fcb->UncleanCount == 1 &&
                Fcb->Condition != FcbBad)
            {
                //DELETE_CONTEXT DeleteContext;

                /* Should this file be deleted on close? */
                if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
                    !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
                {
                    UNIMPLEMENTED;
                }
                else
                {
                    if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) &&
                        (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart))
                    {
#if 0
                        ULONG ValidDataLength;

                        ValidDataLength = Fcb->Header.ValidDataLength.LowPart;

                        if (ValidDataLength < Fcb->ValidDataToDisk) {
                            ValidDataLength = Fcb->ValidDataToDisk;
                        }

                        if (ValidDataLength < Fcb->Header.FileSize.LowPart)
                        {
                            FatZeroData( IrpContext,
                                Vcb,
                                FileObject,
                                ValidDataLength,
                                Fcb->Header.FileSize.LowPart -
                                ValidDataLength );

                            Fcb->ValidDataToDisk =
                                Fcb->Header.ValidDataLength.LowPart =
                                Fcb->Header.FileSize.LowPart;

                            if (CcIsFileCached(FileObject))
                            {
                                CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
                            }
                        }
#endif
                        DPRINT1("Zeroing out data is not implemented\n");
                    }
                }

                /* Should the file be truncated on close? */
                if (FlagOn(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE))
                {
                    if (Vcb->Condition == VcbGood)
                    {
                        // TODO: Actually truncate the file allocation
                        UNIMPLEMENTED;
                    }

                    /* Remove truncation flag */
                    Fcb->State &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
                }

                /* Check again if it should be deleted */
                if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
                    Fcb->Header.AllocationSize.LowPart == 0)
                {
                    FatNotifyReportChange(IrpContext,
                                          Vcb,
                                          Fcb,
                                          FILE_NOTIFY_CHANGE_FILE_NAME,
                                          FILE_ACTION_REMOVED);
                }

                /* Remove the entry from the splay table if the file was deleted */
                if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE))
                {
                    FatRemoveNames(IrpContext, Fcb);
                }
            }
        }

        ASSERT(Fcb->UncleanCount != 0);
        Fcb->UncleanCount--;
        if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
        {
            ASSERT(Fcb->NonCachedUncleanCount != 0);
            Fcb->NonCachedUncleanCount--;
        }

        if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
            (Fcb->NonCachedUncleanCount != 0) &&
            (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) &&
            (Fcb->SectionObjectPointers.DataSectionObject != NULL))
        {
            CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);

            /* Acquire and release PagingIo to get in sync with lazy writer */
            ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE);
            ExReleaseResourceLite(Fcb->Header.PagingIoResource);

            CcPurgeCacheSection(&Fcb->SectionObjectPointers,
                                NULL,
                                0,
                                FALSE);
        }

        if (Fcb->Condition == FcbBad)
        {
            //TruncateSize = &FatLargeZero;
            UNIMPLEMENTED;
        }

        /*  Cleanup the cache map */
        CcUninitializeCacheMap(FileObject, TruncateSize, NULL);
        break;

    default:
        KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0);
    }

    /* Cleanup the share access */

    if (ShareAccess)
    {
        DPRINT("Cleaning up the share access\n");
        IoRemoveShareAccess(FileObject, ShareAccess);
    }

    if (TypeOfOpen == UserFileOpen)
    {
        /* Update oplocks */
        FsRtlCheckOplock(&Fcb->Fcb.Oplock,
                         Irp,
                         IrpContext,
                         NULL,
                         NULL);

        Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb);
    }

    /* Set the FO_CLEANUP_COMPLETE flag */
    SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);

    Status = STATUS_SUCCESS;

    // TODO: Unpin repinned BCBs
    //FatUnpinRepinnedBcbs(IrpContext);

    /* Flush the volume if necessary */
    if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
        !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
    {
        UNIMPLEMENTED;
    }

    /* Cleanup */
    if (AcquiredFcb) FatReleaseFcb(IrpContext, Fcb);
    if (AcquiredVcb) FatReleaseVcb(IrpContext, Vcb);

    /* Send volume notification */
    if (SendUnlockNotification)
        FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK);

    return Status;
}