예제 #1
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");
  }
}
예제 #2
0
파일: directory.c 프로젝트: 2asoft/dokany
NTSTATUS
DokanQueryDirectory(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) {
  PFILE_OBJECT fileObject;
  PIO_STACK_LOCATION irpSp;
  PDokanVCB vcb;
  PDokanCCB ccb;
  PDokanFCB fcb;
  NTSTATUS status;
  ULONG eventLength;
  PEVENT_CONTEXT eventContext;
  ULONG index;
  BOOLEAN initial;
  ULONG flags = 0;

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

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

  ccb = fileObject->FsContext2;
  if (ccb == NULL) {
    return STATUS_INVALID_PARAMETER;
  }
  ASSERT(ccb != NULL);

  if (irpSp->Flags & SL_INDEX_SPECIFIED) {
    DDbgPrint("  index specified %d\n",
              irpSp->Parameters.QueryDirectory.FileIndex);
  }
  if (irpSp->Flags & SL_RETURN_SINGLE_ENTRY) {
    DDbgPrint("  return single entry\n");
  }
  if (irpSp->Flags & SL_RESTART_SCAN) {
    DDbgPrint("  restart scan\n");
  }
  if (irpSp->Parameters.QueryDirectory.FileName) {
    DDbgPrint("  pattern:%wZ\n", irpSp->Parameters.QueryDirectory.FileName);
  }

  switch (irpSp->Parameters.QueryDirectory.FileInformationClass) {
  case FileDirectoryInformation:
    DDbgPrint("  FileDirectoryInformation\n");
    break;
  case FileIdFullDirectoryInformation:
    DDbgPrint("  FileIdFullDirectoryInformation\n");
    break;
  case FileFullDirectoryInformation:
    DDbgPrint("  FileFullDirectoryInformation\n");
    break;
  case FileNamesInformation:
    DDbgPrint("  FileNamesInformation\n");
    break;
  case FileBothDirectoryInformation:
    DDbgPrint("  FileBothDirectoryInformation\n");
    break;
  case FileIdBothDirectoryInformation:
    DDbgPrint("  FileIdBothDirectoryInformation\n");
    break;
  default:
    DDbgPrint("  unknown FileInfoClass %d\n",
              irpSp->Parameters.QueryDirectory.FileInformationClass);
    break;
  }

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

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

  // size of EVENT_CONTEXT is sum of its length and file name length
  eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length;

  initial = (BOOLEAN)(ccb->SearchPattern == NULL &&
                      !(DokanCCBFlagsIsSet(ccb, DOKAN_DIR_MATCH_ALL)));

  // this is an initial query
  if (initial) {
    DDbgPrint("    initial query\n");
    // and search pattern is provided
    if (irpSp->Parameters.QueryDirectory.FileName) {
      // free current search pattern stored in CCB
      if (ccb->SearchPattern)
        ExFreePool(ccb->SearchPattern);

      // the size of search pattern
      ccb->SearchPatternLength =
          irpSp->Parameters.QueryDirectory.FileName->Length;
      ccb->SearchPattern =
          ExAllocatePool(ccb->SearchPatternLength + sizeof(WCHAR));

      if (ccb->SearchPattern == NULL) {
        DokanFCBUnlock(fcb);
        return STATUS_INSUFFICIENT_RESOURCES;
      }

      RtlZeroMemory(ccb->SearchPattern,
                    ccb->SearchPatternLength + sizeof(WCHAR));

      // copy provided search pattern to CCB
      RtlCopyMemory(ccb->SearchPattern,
                    irpSp->Parameters.QueryDirectory.FileName->Buffer,
                    ccb->SearchPatternLength);

    } else {
      DokanCCBFlagsSetBit(ccb, DOKAN_DIR_MATCH_ALL);
    }
  }

  // if search pattern is provided, add the length of it to store pattern
  if (ccb->SearchPattern) {
    eventLength += ccb->SearchPatternLength;
  }

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

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

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

  // index which specified index-1 th directory entry has been returned
  // this time, 'index'th entry should be returned
  index = 0;

  if (irpSp->Flags & SL_INDEX_SPECIFIED) {
    index = irpSp->Parameters.QueryDirectory.FileIndex;
    DDbgPrint("    using FileIndex %d\n", index);

  } else if (FlagOn(irpSp->Flags, SL_RESTART_SCAN)) {
    DDbgPrint("    SL_RESTART_SCAN\n");
    index = 0;

  } else {
    index = (ULONG)ccb->Context;
    DDbgPrint("    ccb->Context %d\n", index);
  }

  eventContext->Operation.Directory.FileInformationClass =
      irpSp->Parameters.QueryDirectory.FileInformationClass;
  eventContext->Operation.Directory.BufferLength =
      irpSp->Parameters.QueryDirectory.Length; // length of buffer
  eventContext->Operation.Directory.FileIndex =
      index; // directory index which should be returned this time

  // copying file name(directory name)
  eventContext->Operation.Directory.DirectoryNameLength = fcb->FileName.Length;
  RtlCopyMemory(eventContext->Operation.Directory.DirectoryName,
                fcb->FileName.Buffer, fcb->FileName.Length);
  DokanFCBUnlock(fcb);

  // if search pattern is specified, copy it to EventContext
  if (ccb->SearchPatternLength && ccb->SearchPattern) {
    PVOID searchBuffer;

    eventContext->Operation.Directory.SearchPatternLength =
        ccb->SearchPatternLength;
    eventContext->Operation.Directory.SearchPatternOffset =
        eventContext->Operation.Directory.DirectoryNameLength;

    searchBuffer = (PVOID)(
        (SIZE_T)&eventContext->Operation.Directory.SearchPatternBase[0] +
        (SIZE_T)eventContext->Operation.Directory.SearchPatternOffset);

    RtlCopyMemory(searchBuffer, ccb->SearchPattern, ccb->SearchPatternLength);

    DDbgPrint("    ccb->SearchPattern %ws\n", ccb->SearchPattern);
  }

  status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, flags);

  return status;
}