Exemplo 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;
//	PVOID				buffer;
	NTSTATUS			status = STATUS_INVALID_PARAMETER;
	ULONG				readLength = 0;
	PDokanCCB			ccb;
	PDokanFCB			fcb;
	PDokanVCB			vcb;
	PEVENT_CONTEXT		eventContext;
	ULONG				eventLength;

	//PAGED_CODE();

	__try {

		FsRtlEnterFileSystem();

		DDbgPrint("==> DokanRead");

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

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

		vcb = DeviceObject->DeviceExtension;
		if (GetIdentifierType(vcb) != VCB ||
			!DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) {
			status = STATUS_INVALID_PARAMETER;
			__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");
			
			byteOffset = fileObject->CurrentByteOffset;
		
		} else {
			byteOffset	 = irpSp->Parameters.Read.ByteOffset;
		}

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

		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 (fcb->Flags & DOKAN_FILE_DIRECTORY) {
			DDbgPrint("   DOKAN_FILE_DIRECTORY %p\n", fcb);
			status = STATUS_INVALID_PARAMETER;
			__leave;
		}

		// 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 (Irp->Flags & IRP_PAGING_IO) {
			DDbgPrint("  Paging IO");
			eventContext->FileFlags |= DOKAN_PAGING_IO;
		}
		if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
			DDbgPrint("  Synchronous IO");
			eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO;
		}

		if (Irp->Flags & IRP_NOCACHE) {
			DDbgPrint("  Nocache");
			eventContext->FileFlags |= DOKAN_NOCACHE;
		}

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

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

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


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

		// if IRP status is not pending, must complete current IRP
		if (status != STATUS_PENDING) {
			Irp->IoStatus.Status = status;
			Irp->IoStatus.Information = readLength;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
			DokanPrintNTStatus(status);
		} else {
			DDbgPrint("  STATUS_PENDING");
		}

		DDbgPrint("<== DokanRead");
		
		FsRtlExitFileSystem();

	}

	return status;
}
Exemplo n.º 2
0
NTSTATUS
DokanDispatchQuerySecurity(
	__in PDEVICE_OBJECT DeviceObject,
	__in PIRP Irp
	)
{
	PIO_STACK_LOCATION	irpSp;
	NTSTATUS			status = STATUS_NOT_IMPLEMENTED;
	PFILE_OBJECT		fileObject;
	ULONG				info = 0;
	ULONG				bufferLength;
	SECURITY_DESCRIPTOR dummySecurityDesc;
	ULONG				descLength;
	PSECURITY_DESCRIPTOR securityDesc;
	PSECURITY_INFORMATION securityInfo;
	PDokanFCB			fcb;
	PDokanDCB			dcb;
	PDokanVCB			vcb;
	PDokanCCB			ccb;
	ULONG				eventLength;
	PEVENT_CONTEXT		eventContext;
	ULONG				flags = 0;

	__try {
		FsRtlEnterFileSystem();

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

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

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

		vcb = DeviceObject->DeviceExtension;
		if (GetIdentifierType(vcb) != VCB) {
			DbgPrint("    DeviceExtension != VCB\n");
			status = STATUS_INVALID_PARAMETER;
			__leave;
		}
		dcb = vcb->Dcb;

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

		ccb = fileObject->FsContext2;
		if (ccb == NULL) {
			DDbgPrint("    ccb == NULL\n");
			status = STATUS_INVALID_PARAMETER;
			__leave;
		}
		fcb = ccb->Fcb;

		bufferLength = irpSp->Parameters.QuerySecurity.Length;
		securityInfo = &irpSp->Parameters.QuerySecurity.SecurityInformation;

		if (*securityInfo & OWNER_SECURITY_INFORMATION) {
			DDbgPrint("    OWNER_SECURITY_INFORMATION\n");
		}
		if (*securityInfo & GROUP_SECURITY_INFORMATION) {
			DDbgPrint("    GROUP_SECURITY_INFORMATION\n");
		}
		if (*securityInfo & DACL_SECURITY_INFORMATION) {
			DDbgPrint("    DACL_SECURITY_INFORMATION\n");
		}
		if (*securityInfo & SACL_SECURITY_INFORMATION) {
			DDbgPrint("    SACL_SECURITY_INFORMATION\n");
		}
		if (*securityInfo & LABEL_SECURITY_INFORMATION) {
			DDbgPrint("    LABEL_SECURITY_INFORMATION\n");
		}

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

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

		if (Irp->UserBuffer != NULL && bufferLength > 0) {
			// make a MDL for UserBuffer that can be used later on another thread context	
			if (Irp->MdlAddress == NULL) {
				status = DokanAllocateMdl(Irp, bufferLength);
				if (!NT_SUCCESS(status)) {
					ExFreePool(eventContext);
					__leave;
				}
				flags = DOKAN_MDL_ALLOCATED;
			}
		}

		eventContext->Context = ccb->UserContext;
		eventContext->Security.SecurityInformation = *securityInfo;
		eventContext->Security.BufferLength = bufferLength;
	
		eventContext->Security.FileNameLength = fcb->FileName.Length;
		RtlCopyMemory(eventContext->Security.FileName,
				fcb->FileName.Buffer, fcb->FileName.Length);

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

	} __finally {

		if (status != STATUS_PENDING) {
			Irp->IoStatus.Status = status;
			Irp->IoStatus.Information = info;
			IoCompleteRequest(Irp, IO_NO_INCREMENT);
			DokanPrintNTStatus(status);
		}

		DDbgPrint("<== DokanQuerySecurity\n");
		FsRtlExitFileSystem();
	}

	return status;
}
Exemplo n.º 3
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;
}
Exemplo n.º 4
0
NTSTATUS
DokanQueryDirectory(
	__in PDEVICE_OBJECT DeviceObject,
	__in PIRP			Irp)
{
	PFILE_OBJECT		fileObject;
	PIO_STACK_LOCATION	irpSp;
	PDokanVCB			vcb;
	PDokanCCB			ccb;
	PDokanFCB			fcb;
	NTSTATUS			status;
	PUNICODE_STRING		searchPattern;
	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);

	fcb = ccb->Fcb;
	ASSERT(fcb != 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");
	}
	if (irpSp->Flags & SL_RESTART_SCAN) {
		DDbgPrint("  restart scan");
	}
	if (irpSp->Parameters.QueryDirectory.FileName) {
		DDbgPrint("  pattern:%wZ\n", irpSp->Parameters.QueryDirectory.FileName);
	}
	
	switch (irpSp->Parameters.QueryDirectory.FileInformationClass) {
	case FileDirectoryInformation:
		DDbgPrint("  FileDirectoryInformation");
		break;
	case FileFullDirectoryInformation:
		DDbgPrint("  FileFullDirectoryInformation");
		break;
	case FileNamesInformation:
		DDbgPrint("  FileNamesInformation");
		break;
	case FileBothDirectoryInformation:
		DDbgPrint("  FileBothDirectoryInformation");
		break;
	case FileIdBothDirectoryInformation:
		DDbgPrint("  FileIdBothDirectoryInformation");
		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;
	}

	
	// 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 && !(ccb->Flags & DOKAN_DIR_MATCH_ALL));

	// this is an initial query
	if (initial) {
		DDbgPrint("    initial query");
		// 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) {
				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 {
			ccb->Flags |= 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) {
		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");
		index = 0;
		
	} else {
		index = (ULONG)ccb->Context;
		DDbgPrint("    ccb->Context %d\n", index);
	}

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

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

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

		eventContext->Directory.SearchPatternLength = ccb->SearchPatternLength;
		eventContext->Directory.SearchPatternOffset = eventContext->Directory.DirectoryNameLength;
			
		searchBuffer = (PVOID)((SIZE_T)&eventContext->Directory.SearchPatternBase[0] +
							(SIZE_T)eventContext->Directory.SearchPatternOffset);
			
		RtlCopyMemory(searchBuffer, 
						ccb->SearchPattern,
						ccb->SearchPatternLength);

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


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

	return status;
}