コード例 #1
0
ファイル: cleanup.c プロジェクト: bailey27/dokany
VOID DokanCompleteCleanup(__in PIRP_ENTRY IrpEntry,
                          __in PEVENT_INFORMATION EventInfo) {
  PIRP irp;
  PIO_STACK_LOCATION irpSp;
  NTSTATUS status = STATUS_SUCCESS;
  PDokanCCB ccb;
  PDokanFCB fcb;
  PDokanVCB vcb;
  PFILE_OBJECT fileObject;

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

  irp = IrpEntry->Irp;
  irpSp = IrpEntry->IrpSp;

  fileObject = IrpEntry->FileObject;
  ASSERT(fileObject != NULL);

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

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

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

  vcb = fcb->Vcb;

  status = EventInfo->Status;

  DokanFCBLockRO(fcb);
  if (DokanFCBFlagsIsSet(fcb, DOKAN_DELETE_ON_CLOSE)) {
    if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
      DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME,
                              FILE_ACTION_REMOVED);
    } else {
      DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME,
                              FILE_ACTION_REMOVED);
    }
  }
  DokanFCBUnlock(fcb);
  //
  //  Unlock all outstanding file locks.
  //
  (VOID) FsRtlFastUnlockAll(&fcb->FileLock, fileObject,
                            IoGetRequestorProcess(irp), NULL);

  if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
    FsRtlNotifyCleanup(vcb->NotifySync, &vcb->DirNotifyList, ccb);
  }

  IoRemoveShareAccess(irpSp->FileObject, &fcb->ShareAccess);

  DokanCompleteIrpRequest(irp, status, 0);

  DDbgPrint("<== DokanCompleteCleanup\n");
}
コード例 #2
0
ファイル: fileinfo.c プロジェクト: bailey27/dokany
VOID FlushAllCachedFcb(__in PDokanFCB fcbRelatedTo,
                       __in_opt PFILE_OBJECT fileObject) {
  PLIST_ENTRY thisEntry, nextEntry, listHead;
  PDokanFCB fcb = NULL;

  if (fcbRelatedTo == NULL) {
    return;
  }

  DDbgPrint("  FlushAllCachedFcb\n");

  if (!DokanFCBFlagsIsSet(fcbRelatedTo, DOKAN_FILE_DIRECTORY)) {
    DDbgPrint("  FlushAllCachedFcb file passed in. Flush only this file %wZ.\n", &fcbRelatedTo->FileName);
    FlushFcb(fcbRelatedTo, fileObject);
    return;
  }

  KeEnterCriticalRegion();
  ExAcquireResourceExclusiveLite(&fcbRelatedTo->Vcb->Resource, TRUE);

  listHead = &fcbRelatedTo->Vcb->NextFCB;

  for (thisEntry = listHead->Flink; thisEntry != listHead;
       thisEntry = nextEntry) {

    nextEntry = thisEntry->Flink;

    fcb = CONTAINING_RECORD(thisEntry, DokanFCB, NextFCB);

    if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
      DDbgPrint("  FlushAllCachedFcb %wZ is directory so skip it.\n",
                &fcb->FileName);
      continue;
    }

    DDbgPrint("  FlushAllCachedFcb check %wZ if is related to %wZ\n",
              &fcb->FileName, &fcbRelatedTo->FileName);

    if (StartsWith(&fcb->FileName, &fcbRelatedTo->FileName)) {
      DDbgPrint("  FlushAllCachedFcb flush %wZ if flush is possible.\n",
                &fcb->FileName);
      FlushFcb(fcb, NULL);
    }

    fcb = NULL;
  }

  ExReleaseResourceLite(&fcbRelatedTo->Vcb->Resource);
  KeLeaveCriticalRegion();

  DDbgPrint("  FlushAllCachedFcb finished\n");
}
コード例 #3
0
ファイル: directory.c プロジェクト: 2asoft/dokany
NTSTATUS
DokanNotifyChangeDirectory(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) {
  PDokanCCB ccb;
  PDokanFCB fcb;
  PFILE_OBJECT fileObject;
  PIO_STACK_LOCATION irpSp;
  PDokanVCB vcb;

  DDbgPrint("\tNotifyChangeDirectory\n");

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

  vcb = DeviceObject->DeviceExtension;
  if (GetIdentifierType(vcb) != VCB) {
    return STATUS_INVALID_PARAMETER;
  }

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

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

  if (!DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
    return STATUS_INVALID_PARAMETER;
  }

  DDbgPrint("\tFsRtlNotifyFullChangeDirectory FileName %wZ\n", &fcb->FileName);
  
  DokanFCBLockRO(fcb);
  FsRtlNotifyFullChangeDirectory(
      vcb->NotifySync, &vcb->DirNotifyList, ccb, (PSTRING)&fcb->FileName,
      (irpSp->Flags & SL_WATCH_TREE) ? TRUE : FALSE, FALSE,
      irpSp->Parameters.NotifyDirectory.CompletionFilter, Irp, NULL, NULL);
  DokanFCBUnlock(fcb);

  return STATUS_PENDING;
}
コード例 #4
0
ファイル: write.c プロジェクト: bailey27/dokany
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;
}
コード例 #5
0
ファイル: fileinfo.c プロジェクト: Corillian/dokany
VOID DokanCompleteSetInformation(__in PIRP_ENTRY IrpEntry,
                                 __in PEVENT_INFORMATION EventInfo) {
  PIRP irp;
  PIO_STACK_LOCATION irpSp;
  NTSTATUS status;
  ULONG info = 0;
  PDokanCCB ccb;
  PDokanFCB fcb = NULL;
  UNICODE_STRING oldFileName;

  FILE_INFORMATION_CLASS infoClass;
  irp = IrpEntry->Irp;
  status = EventInfo->Status;

  __try {

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

    irpSp = IrpEntry->IrpSp;

    ccb = IrpEntry->FileObject->FsContext2;
    ASSERT(ccb != NULL);

    KeEnterCriticalRegion();
    ExAcquireResourceExclusiveLite(&ccb->Resource, TRUE);

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

    ccb->UserContext = EventInfo->Context;

    info = EventInfo->BufferLength;

    infoClass = irpSp->Parameters.SetFile.FileInformationClass;

    RtlZeroMemory(&oldFileName, sizeof(UNICODE_STRING));

    if (NT_SUCCESS(status)) {

      if (infoClass == FileDispositionInformation) {

        if (EventInfo->Operation.Delete.DeleteOnClose) {

          if (!MmFlushImageSection(&fcb->SectionObjectPointers,
                                   MmFlushForDelete)) {
            DDbgPrint("  Cannot delete user mapped image\n");
            status = STATUS_CANNOT_DELETE;
          } else {
            DokanCCBFlagsSetBit(ccb, DOKAN_DELETE_ON_CLOSE);
            DokanFCBFlagsSetBit(fcb, DOKAN_DELETE_ON_CLOSE);
            DDbgPrint("   FileObject->DeletePending = TRUE\n");
            IrpEntry->FileObject->DeletePending = TRUE;
          }

        } else {
          DokanCCBFlagsClearBit(ccb, DOKAN_DELETE_ON_CLOSE);
          DokanFCBFlagsClearBit(fcb, DOKAN_DELETE_ON_CLOSE);
          DDbgPrint("   FileObject->DeletePending = FALSE\n");
          IrpEntry->FileObject->DeletePending = FALSE;
        }
      }

      // if rename is executed, reassign the file name
      if (infoClass == FileRenameInformation) {
        PVOID buffer = NULL;

        // this is used to inform rename in the bellow switch case
        oldFileName.Buffer = fcb->FileName.Buffer;
        oldFileName.Length = (USHORT)fcb->FileName.Length;
        oldFileName.MaximumLength = (USHORT)fcb->FileName.Length;

        // copy new file name
        buffer = ExAllocatePool(EventInfo->BufferLength + sizeof(WCHAR));

        if (buffer == NULL) {
          status = STATUS_INSUFFICIENT_RESOURCES;
          ExReleaseResourceLite(&ccb->Resource);
          KeLeaveCriticalRegion();
          __leave;
        }

        fcb->FileName.Buffer = buffer;

        ASSERT(fcb->FileName.Buffer != NULL);

        RtlZeroMemory(fcb->FileName.Buffer,
                      EventInfo->BufferLength + sizeof(WCHAR));
        RtlCopyMemory(fcb->FileName.Buffer, EventInfo->Buffer,
                      EventInfo->BufferLength);

        fcb->FileName.Length = (USHORT)EventInfo->BufferLength;
        fcb->FileName.MaximumLength = (USHORT)EventInfo->BufferLength;

      }
    }

    ExReleaseResourceLite(&ccb->Resource);
    KeLeaveCriticalRegion();

    if (NT_SUCCESS(status)) {
      switch (irpSp->Parameters.SetFile.FileInformationClass) {
      case FileAllocationInformation:
        DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE,
                                FILE_ACTION_MODIFIED);
        break;
      case FileBasicInformation:
        DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_ATTRIBUTES |
                                         FILE_NOTIFY_CHANGE_LAST_WRITE |
                                         FILE_NOTIFY_CHANGE_LAST_ACCESS |
                                         FILE_NOTIFY_CHANGE_CREATION,
                                FILE_ACTION_MODIFIED);
        break;
      case FileDispositionInformation:
        if (IrpEntry->FileObject->DeletePending) {
          if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) {
            DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME,
                                    FILE_ACTION_REMOVED);
          } else {
            DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME,
                                    FILE_ACTION_REMOVED);
          }
        }
        break;
      case FileEndOfFileInformation:
        DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE,
                                FILE_ACTION_MODIFIED);
        break;
      case FileLinkInformation:
        // TODO: should check whether this is a directory
        // TODO: should notify new link name
        // DokanNotifyReportChange(vcb, ccb, FILE_NOTIFY_CHANGE_FILE_NAME,
        // FILE_ACTION_ADDED);
        break;
      case FilePositionInformation:
        // this is never used
        break;
      case FileRenameInformation: {
        DokanNotifyReportChange0(fcb, &oldFileName,
                                 FILE_NOTIFY_CHANGE_FILE_NAME,
                                 FILE_ACTION_RENAMED_OLD_NAME);

        // free old file name
        ExFreePool(oldFileName.Buffer);

        DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME,
                                FILE_ACTION_RENAMED_NEW_NAME);
      } break;
      case FileValidDataLengthInformation:
        DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE,
                                FILE_ACTION_MODIFIED);
        break;
      default:
        DDbgPrint("  unknown type:%d\n",
                  irpSp->Parameters.SetFile.FileInformationClass);
        break;
      }
    }

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

    DokanCompleteIrpRequest(irp, status, info);

    DDbgPrint("<== DokanCompleteSetInformation\n");
  }
}
コード例 #6
0
ファイル: read.c プロジェクト: Corillian/dokany
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;
}
コード例 #7
0
ファイル: fscontrol.c プロジェクト: bailey27/dokany
NTSTATUS DokanOplockRequest(__in PIRP *pIrp) {
  NTSTATUS Status = STATUS_SUCCESS;
  ULONG FsControlCode;
  PDokanDCB Dcb;
  PDokanVCB Vcb;
  PDokanFCB Fcb = NULL;
  PDokanCCB Ccb;
  PFILE_OBJECT fileObject;
  PIRP Irp = *pIrp;

  ULONG OplockCount = 0;

  PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);

  BOOLEAN AcquiredVcb = FALSE;

#if (NTDDI_VERSION >= NTDDI_WIN7)
  PREQUEST_OPLOCK_INPUT_BUFFER InputBuffer = NULL;
  ULONG InputBufferLength;
  ULONG OutputBufferLength;
#endif

  PAGED_CODE();

  //
  //  Save some references to make our life a little easier
  //
  FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;

  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;
  }

  Vcb = Fcb->Vcb;
  if (Vcb == NULL || Vcb->Identifier.Type != VCB) {
    DDbgPrint("    DokanOplockRequest STATUS_INVALID_PARAMETER\n");
    return STATUS_INVALID_PARAMETER;
  }
  Dcb = Vcb->Dcb;

#if (NTDDI_VERSION >= NTDDI_WIN7)

  //
  //  Get the input & output buffer lengths and pointers.
  //
  if (FsControlCode == FSCTL_REQUEST_OPLOCK) {

    InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
    InputBuffer = (PREQUEST_OPLOCK_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer;

    OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;

    //
    //  Check for a minimum length on the input and ouput buffers.
    //
    if ((InputBufferLength < sizeof(REQUEST_OPLOCK_INPUT_BUFFER)) ||
        (OutputBufferLength < sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER))) {
      DDbgPrint("    DokanOplockRequest STATUS_BUFFER_TOO_SMALL\n");
      return STATUS_BUFFER_TOO_SMALL;
    }
  }

  //
  //  If the oplock request is on a directory it must be for a Read or
  //  Read-Handle
  //  oplock only.
  //
  if ((DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) &&
      ((FsControlCode != FSCTL_REQUEST_OPLOCK) ||
       !FsRtlOplockIsSharedRequest(Irp))) {

    DDbgPrint("    DokanOplockRequest STATUS_INVALID_PARAMETER\n");
    return STATUS_INVALID_PARAMETER;
  }

#endif

  //
  //  Use a try finally to free the Fcb/Vcb
  //
  try {

    //
    //  We grab the Fcb exclusively for oplock requests, shared for oplock
    //  break acknowledgement.
    //
    if ((FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1) ||
        (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) ||
        (FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) ||
        (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2)
#if (NTDDI_VERSION >= NTDDI_WIN7)
        || ((FsControlCode == FSCTL_REQUEST_OPLOCK) &&
            FlagOn(InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_REQUEST))
#endif
            ) {

      AcquiredVcb = ExAcquireResourceSharedLite(&(Fcb->Vcb->Resource), TRUE);

#if (NTDDI_VERSION >= NTDDI_WIN7)
      if (!Dcb->FileLockInUserMode && FsRtlOplockIsSharedRequest(Irp)) {
#else
      if (!Dcb->FileLockInUserMode &&
          FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
#endif
        //
        //  Byte-range locks are only valid on files.
        //
        if (!DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) {

//
//  Set OplockCount to nonzero if FsRtl denies access
//  based on current byte-range lock state.
//
#if (NTDDI_VERSION >= NTDDI_WIN8)
          OplockCount = (ULONG)!FsRtlCheckLockForOplockRequest(
              &Fcb->FileLock, &Fcb->AdvancedFCBHeader.AllocationSize);
#elif (NTDDI_VERSION >= NTDDI_WIN7)
          OplockCount =
              (ULONG)FsRtlAreThereCurrentOrInProgressFileLocks(&Fcb->FileLock);
#else
        OplockCount = (ULONG)FsRtlAreThereCurrentFileLocks(&Fcb->FileLock);
#endif
        }
      } else {
        // Shouldn't be something like UncleanCount counter and not FileCount
        // here?
        OplockCount = 0;//Fcb->FileCount;
      }
    } else if ((FsControlCode == FSCTL_OPLOCK_BREAK_ACKNOWLEDGE) ||
               (FsControlCode == FSCTL_OPBATCH_ACK_CLOSE_PENDING) ||
               (FsControlCode == FSCTL_OPLOCK_BREAK_NOTIFY) ||
               (FsControlCode == FSCTL_OPLOCK_BREAK_ACK_NO_2)
#if (NTDDI_VERSION >= NTDDI_WIN7)
               || ((FsControlCode == FSCTL_REQUEST_OPLOCK) &&
                   FlagOn(InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_ACK))
#endif
                   ) {

#if (NTDDI_VERSION >= NTDDI_WIN7)
    } else if (FsControlCode == FSCTL_REQUEST_OPLOCK) {
      //
      //  The caller didn't provide either REQUEST_OPLOCK_INPUT_FLAG_REQUEST or
      //  REQUEST_OPLOCK_INPUT_FLAG_ACK on the input buffer.
      //
      DDbgPrint("    DokanOplockRequest STATUS_INVALID_PARAMETER\n");
      Status = STATUS_INVALID_PARAMETER;
      __leave;
    } else {
#else
    } else {
#endif
      DDbgPrint("    DokanOplockRequest STATUS_INVALID_PARAMETER\n");
      Status = STATUS_INVALID_PARAMETER;
      __leave;
    }

    //
    //  Fail batch, filter, and handle oplock requests if the file is marked
    //  for delete.
    //
    if (((FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) ||
         (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK)
#if (NTDDI_VERSION >= NTDDI_WIN7)
         ||
         ((FsControlCode == FSCTL_REQUEST_OPLOCK) &&
          FlagOn(InputBuffer->RequestedOplockLevel, OPLOCK_LEVEL_CACHE_HANDLE))
#endif
             ) &&
        DokanFCBFlagsIsSet(Fcb, DOKAN_DELETE_ON_CLOSE)) {

      DDbgPrint("    DokanOplockRequest STATUS_DELETE_PENDING\n");
      Status = STATUS_DELETE_PENDING;
      __leave;
    }

    //
    //  Call the FsRtl routine to grant/acknowledge oplock.
    //
    Status = FsRtlOplockFsctrl(DokanGetFcbOplock(Fcb), Irp, OplockCount);

    //
    //  Once we call FsRtlOplockFsctrl, we no longer own the IRP and we should
    //  not complete it.
    //
    *pIrp = NULL;

  } finally {
コード例 #8
0
ファイル: lock.c プロジェクト: Corillian/dokany
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;
  }

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

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

    // Fcb's AllocationSize is constant after creation.
  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)
    // This may block and enter wait state.
    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) {
    //
    //  Now call the FsRtl routine to do the actual processing of the
    //  Lock request
    //
    Status = FsRtlProcessFileLock(&Fcb->FileLock, Irp, NULL);
  }

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

  return Status;
}