Beispiel #1
0
// -----------------------------------------------------------------------------------------
NTSTATUS
Disk_GetGeometry(PDEVICE_OBJECT pDevice, PVOID pBuffer)
{
	NTSTATUS ntstatus;
	ULONG i;
	ntstatus = GetDiskGeometry(pDevice, (PDISK_GEOMETRY)pBuffer);

	if (STATUS_NOT_IMPLEMENTED == ntstatus)
	{
		PDISK_GEOMETRY pgeom = (PDISK_GEOMETRY) pBuffer;
		USHORT sector_size;

		Disk_GetSectorSize(pDevice, &sector_size);
		pgeom->BytesPerSector = sector_size;

		pgeom->Cylinders.QuadPart = 1;
		pgeom->MediaType = Unknown;
		pgeom->SectorsPerTrack = 1;
		pgeom->TracksPerCylinder = 1;

		ntstatus = STATUS_SUCCESS;

		return ntstatus;
	}

	if (ntstatus == STATUS_VERIFY_REQUIRED)
	{
		DbPrint(DC_LLDISKIO, DL_WARNING, ("Disk_GetGeometry: !!! Why??? Was overryded!!! (Podavlen!!!) Verify required (status = %#x)\n",ntstatus));
		DbgBreakPoint();
		
		ntstatus = IoVerifyVolume(pDevice, TRUE);
		
		DbPrint(DC_LLDISKIO, DL_WARNING, ("Disk_GetGeometry: Verify request result status = %#x\n",ntstatus));

//		if (ntstatus == STATUS_SUCCESS || STATUS_WRONG_VOLUME)
			ntstatus = GetDiskGeometry(pDevice, (PDISK_GEOMETRY)pBuffer);
	}

	for(i=0;i<3 && ntstatus == STATUS_IO_DEVICE_ERROR;i++) {
		LARGE_INTEGER Timeout;
		*(__int64*)&Timeout= -((__int64)5L*1000000L);// 0.5 sec
		KeDelayExecutionThread(KernelMode,TRUE,&Timeout);
		ntstatus = GetDiskGeometry(pDevice, (PDISK_GEOMETRY)pBuffer);
		DbPrint(DC_LLDISKIO, DL_WARNING, ("Disk_GetGeometry (try %d) status= %#x\n",i+1, ntstatus));
	}

	return ntstatus;
}
Beispiel #2
0
NTSTATUS
VfatReadDisk(
    IN PDEVICE_OBJECT pDeviceObject,
    IN PLARGE_INTEGER ReadOffset,
    IN ULONG ReadLength,
    IN OUT PUCHAR Buffer,
    IN BOOLEAN Override)
{
    PIO_STACK_LOCATION Stack;
    PIRP Irp;
    IO_STATUS_BLOCK IoStatus;
    KEVENT Event;
    NTSTATUS Status;

again:
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    DPRINT("VfatReadDisk(pDeviceObject %p, Offset %I64x, Length %u, Buffer %p)\n",
           pDeviceObject, ReadOffset->QuadPart, ReadLength, Buffer);

    DPRINT ("Building synchronous FSD Request...\n");
    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
                                       pDeviceObject,
                                       Buffer,
                                       ReadLength,
                                       ReadOffset,
                                       &Event,
                                       &IoStatus);
    if (Irp == NULL)
    {
        DPRINT("IoBuildSynchronousFsdRequest failed\n");
        return STATUS_UNSUCCESSFUL;
    }

    if (Override)
    {
        Stack = IoGetNextIrpStackLocation(Irp);
        Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
    }

    DPRINT("Calling IO Driver... with irp %p\n", Irp);
    Status = IoCallDriver (pDeviceObject, Irp);

    DPRINT("Waiting for IO Operation for %p\n", Irp);
    if (Status == STATUS_PENDING)
    {
        DPRINT("Operation pending\n");
        KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
        DPRINT("Getting IO Status... for %p\n", Irp);
        Status = IoStatus.Status;
    }

    if (Status == STATUS_VERIFY_REQUIRED)
    {
        PDEVICE_OBJECT DeviceToVerify;

        DPRINT1 ("Media change detected!\n");

        /* Find the device to verify and reset the thread field to empty value again. */
        DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread());
        IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
        Status = IoVerifyVolume(DeviceToVerify,
                                FALSE);
        if (NT_SUCCESS(Status))
        {
            DPRINT1("Volume verification successful; Reissuing read request\n");
            goto again;
        }
    }

    if (!NT_SUCCESS(Status))
    {
        DPRINT("IO failed!!! VfatReadDisk : Error code: %x\n", Status);
        DPRINT("(pDeviceObject %p, Offset %I64x, Size %u, Buffer %p\n",
               pDeviceObject, ReadOffset->QuadPart, ReadLength, Buffer);
        return Status;
    }
    DPRINT("Block request succeeded for %p\n", Irp);
    return STATUS_SUCCESS;
}
Beispiel #3
0
NTSTATUS
VfatBlockDeviceIoControl(
    IN PDEVICE_OBJECT DeviceObject,
    IN ULONG CtlCode,
    IN PVOID InputBuffer OPTIONAL,
    IN ULONG InputBufferSize,
    IN OUT PVOID OutputBuffer OPTIONAL,
    IN OUT PULONG OutputBufferSize,
    IN BOOLEAN Override)
{
    PIO_STACK_LOCATION Stack;
    KEVENT Event;
    PIRP Irp;
    IO_STATUS_BLOCK IoStatus;
    NTSTATUS Status;

    DPRINT("VfatBlockDeviceIoControl(DeviceObject %p, CtlCode %x, "
           "InputBuffer %p, InputBufferSize %x, OutputBuffer %p, "
           "OutputBufferSize %p (%x)\n", DeviceObject, CtlCode,
           InputBuffer, InputBufferSize, OutputBuffer, OutputBufferSize,
           OutputBufferSize ? *OutputBufferSize : 0);

again:
    KeInitializeEvent(&Event, NotificationEvent, FALSE);

    DPRINT("Building device I/O control request ...\n");
    Irp = IoBuildDeviceIoControlRequest(CtlCode,
                                        DeviceObject,
                                        InputBuffer,
                                        InputBufferSize,
                                        OutputBuffer,
                                        (OutputBufferSize) ? *OutputBufferSize : 0,
                                        FALSE,
                                        &Event,
                                        &IoStatus);
    if (Irp == NULL)
    {
        DPRINT("IoBuildDeviceIoControlRequest failed\n");
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    if (Override)
    {
        Stack = IoGetNextIrpStackLocation(Irp);
        Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
    }

    DPRINT("Calling IO Driver... with irp %p\n", Irp);
    Status = IoCallDriver(DeviceObject, Irp);

    DPRINT("Waiting for IO Operation for %p\n", Irp);
    if (Status == STATUS_PENDING)
    {
        DPRINT("Operation pending\n");
        KeWaitForSingleObject (&Event, Suspended, KernelMode, FALSE, NULL);
        DPRINT("Getting IO Status... for %p\n", Irp);

        Status = IoStatus.Status;
    }

    if (Status == STATUS_VERIFY_REQUIRED)
    {
        PDEVICE_OBJECT DeviceToVerify;

        DPRINT1("Media change detected!\n");

        /* Find the device to verify and reset the thread field to empty value again. */
        DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread());
        IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
        Status = IoVerifyVolume(DeviceToVerify,
                                FALSE);

        if (NT_SUCCESS(Status))
        {
            DPRINT1("Volume verification successful; Reissuing IOCTL request\n");
            goto again;
        }
    }

    if (OutputBufferSize)
    {
        *OutputBufferSize = IoStatus.Information;
    }

    DPRINT("Returning Status %x\n", Status);

    return Status;
}
Beispiel #4
0
NTSTATUS
VfatWriteDiskPartial(
    IN PVFAT_IRP_CONTEXT IrpContext,
    IN PLARGE_INTEGER WriteOffset,
    IN ULONG WriteLength,
    IN ULONG BufferOffset,
    IN BOOLEAN Wait)
{
    PIRP Irp;
    PIO_STACK_LOCATION StackPtr;
    NTSTATUS Status;
    PVOID Buffer;

    DPRINT("VfatWriteDiskPartial(IrpContext %p, WriteOffset %I64x, WriteLength %u, BufferOffset %x, Wait %u)\n",
           IrpContext, WriteOffset->QuadPart, WriteLength, BufferOffset, Wait);

    Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset;

again:
    DPRINT("Building asynchronous FSD Request...\n");
    Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE);
    if (Irp == NULL)
    {
        DPRINT("IoAllocateIrp failed\n");
        return STATUS_UNSUCCESSFUL;
    }

    Irp->UserIosb = NULL;
    Irp->Tail.Overlay.Thread = PsGetCurrentThread();

    StackPtr = IoGetNextIrpStackLocation(Irp);
    StackPtr->MajorFunction = IRP_MJ_WRITE;
    StackPtr->MinorFunction = 0;
    StackPtr->Flags = 0;
    StackPtr->Control = 0;
    StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice;
    StackPtr->FileObject = NULL;
    StackPtr->CompletionRoutine = NULL;
    StackPtr->Parameters.Read.Length = WriteLength;
    StackPtr->Parameters.Read.ByteOffset = *WriteOffset;

    if (!IoAllocateMdl(Buffer, WriteLength, FALSE, FALSE, Irp))
    {
        DPRINT("IoAllocateMdl failed\n");
        IoFreeIrp(Irp);
        return STATUS_UNSUCCESSFUL;
    }

    IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, WriteLength);

    IoSetCompletionRoutine(Irp,
                           VfatReadWritePartialCompletion,
                           IrpContext,
                           TRUE,
                           TRUE,
                           TRUE);

    if (Wait)
    {
        KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
        IrpContext->RefCount = 1;
    }
    else
    {
        InterlockedIncrement((PLONG)&IrpContext->RefCount);
    }

    DPRINT("Calling IO Driver...\n");
    Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, Irp);
    if (Wait && Status == STATUS_PENDING)
    {
        KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
        Status = IrpContext->Irp->IoStatus.Status;
    }

    if (Status == STATUS_VERIFY_REQUIRED)
    {
        PDEVICE_OBJECT DeviceToVerify;

        DPRINT1("Media change detected!\n");

        /* Find the device to verify and reset the thread field to empty value again. */
        DeviceToVerify = IoGetDeviceToVerify(PsGetCurrentThread());
        IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
        Status = IoVerifyVolume(DeviceToVerify,
                                 FALSE);
        if (NT_SUCCESS(Status))
        {
            DPRINT1("Volume verification successful; Reissuing write request\n");
            goto again;
        }
    }

    return Status;
}
Beispiel #5
0
NTSTATUS
CdPerformVerify (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp,
    IN PDEVICE_OBJECT DeviceToVerify
)

/*++

Routine Description:

    This routines performs an IoVerifyVolume operation and takes the
    appropriate action.  If the verify is successful then we send the originating
    Irp off to an Ex Worker Thread.  This routine is called from the exception handler.

    No file system resources are held when this routine is called.

Arguments:

    Irp - The irp to send off after all is well and done.

    Device - The real device needing verification.

Return Value:

    None.

--*/

{
    PVCB Vcb;
    NTSTATUS Status = STATUS_SUCCESS;
    PIO_STACK_LOCATION IrpSp;

    ASSERT_IRP_CONTEXT( IrpContext );
    ASSERT_IRP( Irp );

    //
    //  Check if this Irp has a status of Verify required and if it does
    //  then call the I/O system to do a verify.
    //
    //  Skip the IoVerifyVolume if this is a mount or verify request
    //  itself.  Trying a recursive mount will cause a deadlock with
    //  the DeviceObject->DeviceLock.
    //

    if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
            ((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) ||
             (IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME))) {

        return CdFsdPostRequest( IrpContext, Irp );
    }

    //
    //  Extract a pointer to the Vcb from the VolumeDeviceObject.
    //  Note that since we have specifically excluded mount,
    //  requests, we know that IrpSp->DeviceObject is indeed a
    //  volume device object.
    //

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    Vcb = &CONTAINING_RECORD( IrpSp->DeviceObject,
                              VOLUME_DEVICE_OBJECT,
                              DeviceObject )->Vcb;
    try {

        //
        //  Send down the verify FSCTL.  Note that this is sent to the
        //  currently mounted volume,  which may not be this one.
        //
        //  We will allow Raw to mount this volume if we were doing a
        //  an absolute DASD open.
        //

        Status = IoVerifyVolume( DeviceToVerify, CdOperationIsDasdOpen( IrpContext));

        //
        //  Acquire the Vcb so we're working with a stable VcbCondition.
        //

        CdAcquireVcbShared( IrpContext, Vcb, FALSE);

        //
        //  If the verify operation completed it will return
        //  either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly.
        //
        //  If CdVerifyVolume encountered an error during
        //  processing, it will return that error.  If we got
        //  STATUS_WRONG_VOLUME from the verify, and our volume
        //  is now mounted, commute the status to STATUS_SUCCESS.
        //

        if ((Status == STATUS_WRONG_VOLUME) &&
                (Vcb->VcbCondition == VcbMounted)) {

            Status = STATUS_SUCCESS;
        }
        else if ((STATUS_SUCCESS == Status) && (Vcb->VcbCondition != VcbMounted))  {

            //
            //  If the verify succeeded,  but our volume is not mounted,
            //  then some other volume is on the device.
            //

            Status = STATUS_WRONG_VOLUME;
        }

        //
        //  Do a quick unprotected check here.  The routine will do
        //  a safe check.  After here we can release the resource.
        //  Note that if the volume really went away, we will be taking
        //  the Reparse path.
        //

        //
        //  If the device might need to go away then call our dismount routine.
        //

        if (((Vcb->VcbCondition == VcbNotMounted) ||
                (Vcb->VcbCondition == VcbInvalid) ||
                (Vcb->VcbCondition == VcbDismountInProgress)) &&
                (Vcb->VcbReference <= CDFS_RESIDUAL_REFERENCE)) {

            CdReleaseVcb( IrpContext, Vcb);

            CdAcquireCdData( IrpContext );
            CdCheckForDismount( IrpContext, Vcb, FALSE );
            CdReleaseCdData( IrpContext );
        }
        else {

            CdReleaseVcb( IrpContext, Vcb);
        }

        //
        //  If this is a create and the verify succeeded then complete the
        //  request with a REPARSE status.
        //

        if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
                (IrpSp->FileObject->RelatedFileObject == NULL) &&
                ((Status == STATUS_SUCCESS) || (Status == STATUS_WRONG_VOLUME))) {

            Irp->IoStatus.Information = IO_REMOUNT;

            CdCompleteRequest( IrpContext, Irp, STATUS_REPARSE );
            Status = STATUS_REPARSE;
            Irp = NULL;
            IrpContext = NULL;

            //
            //  If there is still an error to process then call the Io system
            //  for a popup.
            //

        } else if ((Irp != NULL) && !NT_SUCCESS( Status )) {

            //
            //  Fill in the device object if required.
            //

            if (IoIsErrorUserInduced( Status ) ) {

                IoSetHardErrorOrVerifyDevice( Irp, DeviceToVerify );
            }

            CdNormalizeAndRaiseStatus( IrpContext, Status );
        }

        //
        //  If there is still an Irp, send it off to an Ex Worker thread.
        //

        if (IrpContext != NULL) {

            Status = CdFsdPostRequest( IrpContext, Irp );
        }

    }
    except(CdExceptionFilter( IrpContext, GetExceptionInformation() )) {

        //
        //  We had some trouble trying to perform the verify or raised
        //  an error ourselves.  So we'll abort the I/O request with
        //  the error status that we get back from the execption code.
        //

        Status = CdProcessException( IrpContext, Irp, GetExceptionCode() );
    }

    return Status;
}
Beispiel #6
0
/*
Routine Description:

    This routines performs an IoVerifyVolume operation and takes the
    appropriate action.  If the verify is successful then we send the originating
    Irp off to an Ex Worker Thread.  This routine is called from the exception handler.
    No file system resources are held when this routine is called.

Arguments:

    Irp - The irp to send off after all is well and done.
    Device - The real device needing verification.

*/
NTSTATUS
UDFPerformVerify(
    IN PtrUDFIrpContext IrpContext,
    IN PIRP Irp,
    IN PDEVICE_OBJECT DeviceToVerify
    )
{

    PVCB Vcb;
    NTSTATUS RC = STATUS_SUCCESS;
    PIO_STACK_LOCATION IrpSp;

    KdPrint(("UDFPerformVerify:\n"));
    if(!IrpContext) return STATUS_INVALID_PARAMETER;
    if(!Irp) return STATUS_INVALID_PARAMETER;

    //  Check if this Irp has a status of Verify required and if it does
    //  then call the I/O system to do a verify.
    //
    //  Skip the IoVerifyVolume if this is a mount or verify request
    //  itself.  Trying a recursive mount will cause a deadlock with
    //  the DeviceObject->DeviceLock.
    if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
       ((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) ||
        (IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME))) {

        return UDFPostRequest(IrpContext, Irp);
    }

    //  Extract a pointer to the Vcb from the VolumeDeviceObject.
    //  Note that since we have specifically excluded mount,
    //  requests, we know that IrpSp->DeviceObject is indeed a
    //  volume device object.

    IrpSp = IoGetCurrentIrpStackLocation(Irp);

    Vcb = (PVCB)IrpSp->DeviceObject->DeviceExtension;

    KdPrint(("UDFPerformVerify: check\n"));
    //  Check if the volume still thinks it needs to be verified,
    //  if it doesn't then we can skip doing a verify because someone
    //  else beat us to it.
    _SEH2_TRY {

        if (DeviceToVerify->Flags & DO_VERIFY_VOLUME) {

            //  If the IopMount in IoVerifyVolume did something, and
            //  this is an absolute open, force a reparse.
            RC = IoVerifyVolume( DeviceToVerify, FALSE );

            // Bug?
/*            if (UDFIsRawDevice(RC)) {
                RC = STATUS_WRONG_VOLUME;
            }*/

            //  If the verify operation completed it will return
            //  either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly.
            if (RC == STATUS_SUCCESS) {
                IrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_EXCEPTION;
            }
            //  If UDFVerifyVolume encountered an error during
            //  processing, it will return that error.  If we got
            //  STATUS_WRONG_VOLUME from the verify, and our volume
            //  is now mounted, commute the status to STATUS_SUCCESS.
            if ((RC == STATUS_WRONG_VOLUME) &&
                (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
                RC = STATUS_SUCCESS;
            }

            //  Do a quick unprotected check here.  The routine will do
            //  a safe check.  After here we can release the resource.
            //  Note that if the volume really went away, we will be taking
            //  the Reparse path.

            //  If the device might need to go away then call our dismount routine.
            if ( (!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) ||
                   (Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED)) &&
                   (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE) )
            {
                KdPrint(("UDFPerformVerify: UDFCheckForDismount\n"));
                UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
                UDFCheckForDismount( IrpContext, Vcb, FALSE );
                UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
            }

            //  If this is a create and the verify succeeded then complete the
            //  request with a REPARSE status.
            if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
                (IrpSp->FileObject->RelatedFileObject == NULL) &&
                ((RC == STATUS_SUCCESS) || (RC == STATUS_WRONG_VOLUME)) ) {

                KdPrint(("UDFPerformVerify: IO_REMOUNT\n"));

                Irp->IoStatus.Information = IO_REMOUNT;

                Irp->IoStatus.Status = STATUS_REPARSE;
                IoCompleteRequest(Irp,IO_DISK_INCREMENT);

                UDFReleaseIrpContext(IrpContext);

                RC = STATUS_REPARSE;
                Irp = NULL;
                IrpContext = NULL;

            //  If there is still an error to process then call the Io system
            //  for a popup.
            } else if ((Irp != NULL) && !NT_SUCCESS( RC )) {

                KdPrint(("UDFPerformVerify: check IoIsErrorUserInduced\n"));
                //  Fill in the device object if required.
                if (IoIsErrorUserInduced( RC ) ) {
                    IoSetHardErrorOrVerifyDevice( Irp, DeviceToVerify );
                }
                KdPrint(("UDFPerformVerify: UDFNormalizeAndRaiseStatus\n"));
                UDFNormalizeAndRaiseStatus( IrpContext, RC );
            }
        }

        //  If there is still an Irp, send it off to an Ex Worker thread.
        if (IrpContext != NULL) {

            RC = UDFPostRequest( IrpContext, Irp );
        }

    } _SEH2_EXCEPT(UDFExceptionFilter( IrpContext, _SEH2_GetExceptionInformation())) {
        //  We had some trouble trying to perform the verify or raised
        //  an error ourselves.  So we'll abort the I/O request with
        //  the error status that we get back from the execption code.
        RC = UDFExceptionHandler( IrpContext, Irp);
    } _SEH2_END;

    KdPrint(("UDFPerformVerify: RC = %x\n", RC));

    return RC;
    
} // end UDFPerformVerify()
Beispiel #7
0
// start event dispatching
NTSTATUS
DokanEventStart(__in PDEVICE_OBJECT DeviceObject, _Inout_ PIRP Irp) {
  ULONG outBufferLen;
  ULONG inBufferLen;
  PIO_STACK_LOCATION irpSp = NULL;
  PEVENT_START eventStart = NULL;
  PEVENT_DRIVER_INFO driverInfo = NULL;
  PDOKAN_GLOBAL dokanGlobal = NULL;
  PDokanDCB dcb = NULL;
  NTSTATUS status;
  DEVICE_TYPE deviceType;
  ULONG deviceCharacteristics = 0;
  WCHAR *baseGuidString;
  GUID baseGuid = DOKAN_BASE_GUID;
  UNICODE_STRING unicodeGuid;
  ULONG deviceNamePos;
  BOOLEAN useMountManager = FALSE;
  BOOLEAN mountGlobally = TRUE;
  BOOLEAN fileLockUserMode = FALSE;

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

  dokanGlobal = DeviceObject->DeviceExtension;
  if (GetIdentifierType(dokanGlobal) != DGL) {
    return STATUS_INVALID_PARAMETER;
  }

  irpSp = IoGetCurrentIrpStackLocation(Irp);

  outBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  inBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;

  eventStart = ExAllocatePool(sizeof(EVENT_START));
  baseGuidString = ExAllocatePool(64 * sizeof(WCHAR));

  if (outBufferLen != sizeof(EVENT_DRIVER_INFO) ||
      inBufferLen != sizeof(EVENT_START) || eventStart == NULL ||
      baseGuidString == NULL) {
    if (eventStart)
      ExFreePool(eventStart);
    if (baseGuidString)
      ExFreePool(baseGuidString);
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  RtlCopyMemory(eventStart, Irp->AssociatedIrp.SystemBuffer,
                sizeof(EVENT_START));
  driverInfo = Irp->AssociatedIrp.SystemBuffer;

  if (eventStart->UserVersion != DOKAN_DRIVER_VERSION) {
    driverInfo->DriverVersion = DOKAN_DRIVER_VERSION;
    driverInfo->Status = DOKAN_START_FAILED;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO);
    ExFreePool(eventStart);
    ExFreePool(baseGuidString);
    return STATUS_SUCCESS;
  }

  switch (eventStart->DeviceType) {
  case DOKAN_DISK_FILE_SYSTEM:
    deviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
    break;
  case DOKAN_NETWORK_FILE_SYSTEM:
    deviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
    deviceCharacteristics |= FILE_REMOTE_DEVICE;
    break;
  default:
    DDbgPrint("  Unknown device type: %d\n", eventStart->DeviceType);
    deviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
  }

  if (eventStart->Flags & DOKAN_EVENT_REMOVABLE) {
    DDbgPrint("  DeviceCharacteristics |= FILE_REMOVABLE_MEDIA\n");
    deviceCharacteristics |= FILE_REMOVABLE_MEDIA;
  }

  if (eventStart->Flags & DOKAN_EVENT_WRITE_PROTECT) {
    DDbgPrint("  DeviceCharacteristics |= FILE_READ_ONLY_DEVICE\n");
    deviceCharacteristics |= FILE_READ_ONLY_DEVICE;
  }

  if (eventStart->Flags & DOKAN_EVENT_MOUNT_MANAGER) {
    DDbgPrint("  Using Mount Manager\n");
    useMountManager = TRUE;
  }

  if (eventStart->Flags & DOKAN_EVENT_CURRENT_SESSION) {
    DDbgPrint("  Mounting on current session only\n");
    mountGlobally = FALSE;
  }

  if (eventStart->Flags & DOKAN_EVENT_FILELOCK_USER_MODE) {
    DDbgPrint("  FileLock in User Mode\n");
    fileLockUserMode = TRUE;
  }

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

  DOKAN_CONTROL dokanControl;
  RtlZeroMemory(&dokanControl, sizeof(dokanControl));
  RtlStringCchCopyW(dokanControl.MountPoint, MAXIMUM_FILENAME_LENGTH,
                    L"\\DosDevices\\");
  if (wcslen(eventStart->MountPoint) == 1) {
    dokanControl.MountPoint[12] = towupper(eventStart->MountPoint[0]);
    dokanControl.MountPoint[13] = L':';
    dokanControl.MountPoint[14] = L'\0';
  } else {
    RtlStringCchCatW(dokanControl.MountPoint, MAXIMUM_FILENAME_LENGTH,
                     eventStart->MountPoint);
  }

  DDbgPrint("  Checking for MountPoint %ls \n", dokanControl.MountPoint);
  PMOUNT_ENTRY foundEntry = FindMountEntry(dokanGlobal, &dokanControl, FALSE);
  if (foundEntry != NULL) {
    DDbgPrint("  MountPoint exists already %ls \n", dokanControl.MountPoint);
    driverInfo->DriverVersion = DOKAN_DRIVER_VERSION;
    driverInfo->Status = DOKAN_START_FAILED;
    Irp->IoStatus.Status = STATUS_SUCCESS;
    Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO);
    ExReleaseResourceLite(&dokanGlobal->Resource);
    KeLeaveCriticalRegion();
    ExFreePool(eventStart);
    ExFreePool(baseGuidString);
    return STATUS_SUCCESS;
  }

  baseGuid.Data2 = (USHORT)(dokanGlobal->MountId & 0xFFFF) ^ baseGuid.Data2;
  baseGuid.Data3 = (USHORT)(dokanGlobal->MountId >> 16) ^ baseGuid.Data3;

  status = RtlStringFromGUID(&baseGuid, &unicodeGuid);
  if (!NT_SUCCESS(status)) {
    ExReleaseResourceLite(&dokanGlobal->Resource);
    KeLeaveCriticalRegion();
    ExFreePool(eventStart);
    ExFreePool(baseGuidString);
    return status;
  }
  RtlZeroMemory(baseGuidString, 64 * sizeof(WCHAR));
  RtlStringCchCopyW(baseGuidString, 64,
                    unicodeGuid.Buffer);
  RtlFreeUnicodeString(&unicodeGuid);

  InterlockedIncrement((LONG *)&dokanGlobal->MountId);

  status = DokanCreateDiskDevice(
      DeviceObject->DriverObject, dokanGlobal->MountId, eventStart->MountPoint,
      eventStart->UNCName, baseGuidString, dokanGlobal, deviceType,
      deviceCharacteristics, mountGlobally, useMountManager, &dcb);

  if (!NT_SUCCESS(status)) {
    ExReleaseResourceLite(&dokanGlobal->Resource);
    KeLeaveCriticalRegion();
    ExFreePool(eventStart);
    ExFreePool(baseGuidString);
    return status;
  }

  dcb->FileLockInUserMode = fileLockUserMode;

  DDbgPrint("  MountId:%d\n", dcb->MountId);
  driverInfo->DeviceNumber = dokanGlobal->MountId;
  driverInfo->MountId = dokanGlobal->MountId;
  driverInfo->Status = DOKAN_MOUNTED;
  driverInfo->DriverVersion = DOKAN_DRIVER_VERSION;

  // SymbolicName is
  // \\DosDevices\\Global\\Volume{D6CC17C5-1734-4085-BCE7-964F1E9F5DE9}
  // Finds the last '\' and copy into DeviceName.
  // DeviceName is \Volume{D6CC17C5-1734-4085-BCE7-964F1E9F5DE9}
  deviceNamePos = dcb->SymbolicLinkName->Length / sizeof(WCHAR) - 1;
  for (; dcb->SymbolicLinkName->Buffer[deviceNamePos] != L'\\'; --deviceNamePos)
    ;
  RtlStringCchCopyW(driverInfo->DeviceName,
                    sizeof(driverInfo->DeviceName) / sizeof(WCHAR),
                    &(dcb->SymbolicLinkName->Buffer[deviceNamePos]));

  // Set the irp timeout in milliseconds
  // If the IrpTimeout is 0, we assume that the value was not changed
  dcb->IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT;
  if (eventStart->IrpTimeout > 0) {
    if (eventStart->IrpTimeout > DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX) {
      eventStart->IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX;
    }

    if (eventStart->IrpTimeout < DOKAN_IRP_PENDING_TIMEOUT) {
      eventStart->IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT;
    }
    dcb->IrpTimeout = eventStart->IrpTimeout;
  }

  DDbgPrint("  DeviceName:%ws\n", driverInfo->DeviceName);

  dcb->UseAltStream = 0;
  if (eventStart->Flags & DOKAN_EVENT_ALTERNATIVE_STREAM_ON) {
    DDbgPrint("  ALT_STREAM_ON\n");
    dcb->UseAltStream = 1;
  }

  DokanStartEventNotificationThread(dcb);

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

  IoVerifyVolume(dcb->DeviceObject, FALSE);

  Irp->IoStatus.Status = STATUS_SUCCESS;
  Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO);

  ExFreePool(eventStart);
  ExFreePool(baseGuidString);

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

  return Irp->IoStatus.Status;
}