dokan-dev / dokany

User mode file system library for windows with FUSE Wrapper
http://dokan-dev.github.io
5.2k stars 661 forks source link

Mounting an ISO image that exists on a drive mounted as a network drive. #1076

Open onexzero opened 2 years ago

onexzero commented 2 years ago

Feature request can skip this form. Bug report must complete it. Check List must be 100% match or it will be automatically closed without further discussion. Please remove this line.

Environment

Check List

Description

Is there a way to mount an iso image on a mounted drive with the /n switch? I have already read #855.

Logs

Please attach in separate files: mirror output, library logs and kernel logs. In case of BSOD, please attach minidump or dump analyze output.

Liryna commented 2 years ago

Is mounting an ISO from a network share possible by default on Windows ? What issue are you facing ?

onexzero commented 2 years ago

Yes It works well with network share. When i click iso image on my drive i got "Sorry, threre was a problem mounting the file.". On dokan mirror sample with /o switch it works well, but /o switch not work with /n switch. When i run mirror with /n same error poped up but image mounted and works but not on my drive. ImageMount

Liryna commented 2 years ago

Oh I see. It would be useful to use Procmon here and find out if there is a request that fails but should succeed that can explain the error.

Regarding mount manager and network manager, it is still a feature that would be nice to have indeed!

onexzero commented 2 years ago

I've already checked it on procmon, but I haven't found anything special. It's not an important problem right now, so I'll have to research it again when I have time. Thanks for reply.

Liryna commented 2 years ago

@onexzero were you able to get more information here ?

onexzero commented 2 years ago

I haven't had time to dig more yet.

onexzero commented 2 years ago

PS Z:\test> dir

Directory: Z:\test

Mode LastWriteTime Length Name


------ 3/21/2022 12:20 PM 375390208 android.iso

PS Z:\test> PS Z:\test> Mount-DiskImage -StorageType ISO -ImagePath "Z:\test\android.iso" Mount-DiskImage : The parameter is incorrect. At line:1 char:1

PS Z:\test>

As you can see, the ISO file exists in the path, but the mount fails. It also fails in windows explorer. However, in 3rd party utilities such as WinCDEmu, it mounts successfully.

Looking at the Procmon log, the PATH part is a bit strange.

\localhost\개인문서함\localhost\개인문서함\test\android.iso UNCName("\localhost\개인문서함") repeated twice. And we can see INVALID_PARAMETER (<-- this not returned from me). But It is uncertain that INVALID_PARAMETER caused above mount error - "The parameter is incorrect.".

When I try to mount with Powershell, I don't see any special user mode calls.

If I run my driver without the /n switch and mount it from powershell, it seems to work normally, so it seems to be related to the /n switch. Google doesn't have much information about this either.

mountlog.zip

Liryna commented 2 years ago

That looks to be the same issue as https://github.com/dokan-dev/dokany/issues/973. The UNC path is provided somewhere by the network provider or the driver when it should not and create this dup UNC path. It would be great if someone could take a look at it!

onexzero commented 2 years ago

I'm trying to figure it out, but I don't have much time.

onexzero commented 2 years ago

It has been confirmed that the issue of including UNCName twice in the path is not related to NP. This problem is probably driver related. From what I've figured out so far, ISO mount and abnormal path problems are seen as different problems.

onexzero commented 2 years ago

973 fix

replace FillNameInformation function of /sys/fileinfo.c

NTSTATUS FillNameInformation(__in PREQUEST_CONTEXT RequestContext,
                             __in PDokanFCB Fcb,
                             __in PFILE_NAME_INFORMATION NameInfo) {
  PUNICODE_STRING fileName = &Fcb->FileName;
  PCHAR dest = (PCHAR)&NameInfo->FileName;
  NameInfo->FileNameLength = fileName->Length;

  BOOLEAN isNetworkDevice = (RequestContext->Dcb->VolumeDeviceType ==
                             FILE_DEVICE_NETWORK_FILE_SYSTEM);
  if (isNetworkDevice) {
    PUNICODE_STRING devicePath = RequestContext->Dcb->UNCName->Length
                                     ? RequestContext->Dcb->UNCName
                                     : RequestContext->Dcb->DiskDeviceName;

    if (!(fileName->Length > 0 && wcsstr(fileName->Buffer, devicePath->Buffer) == fileName->Buffer)) {

        NameInfo->FileNameLength += devicePath->Length;

        if (!AppendVarSizeOutputString(RequestContext->Irp, dest, devicePath,
            /*UpdateInformationOnFailure=*/FALSE,
            /*FillSpaceWithPartialString=*/TRUE)) {
            return STATUS_BUFFER_OVERFLOW;
        }
        dest += devicePath->Length;
    }
  }

  if (!AppendVarSizeOutputString(RequestContext->Irp, dest, fileName,
                                 /*UpdateInformationOnFailure=*/FALSE,
                                 /*FillSpaceWithPartialString=*/TRUE)) {
    return STATUS_BUFFER_OVERFLOW;
  }
  return STATUS_SUCCESS;
}
onexzero commented 2 years ago

And to eliminate unnecessary calls
in /dokan/fileinfo.c

VOID DispatchQueryInformation(PDOKAN_IO_EVENT IoEvent) {
  BY_HANDLE_FILE_INFORMATION byHandleFileInfo;
  NTSTATUS status = STATUS_INVALID_PARAMETER;

  DbgPrint(
      "###GetFileInfo file handle = 0x%p, eventID = %04d, event Info = 0x%p\n",
      IoEvent->DokanOpenInfo,
      IoEvent->DokanOpenInfo != NULL ? IoEvent->DokanOpenInfo->EventId : -1,
      IoEvent);

  CheckFileName(IoEvent->EventContext->Operation.File.FileName);

  CreateDispatchCommon(IoEvent,
                       IoEvent->EventContext->Operation.File.BufferLength,
                       /*UseExtraMemoryPool=*/FALSE,
                       /*ClearNonPoolBuffer=*/TRUE);
  if (IoEvent->EventContext->Operation.File.FileInformationClass ==
      FileRemoteProtocolInformation)
      status = STATUS_NOT_IMPLEMENTED;
  else if (IoEvent->EventContext->Operation.File.FileInformationClass ==
      FileStreamInformation) {
    DbgPrint("FileStreamInformation\n");
    // https://msdn.microsoft.com/en-us/library/windows/hardware/ff540364(v=vs.85).aspx
    if (IoEvent->EventContext->Operation.File.BufferLength <
        sizeof(FILE_STREAM_INFORMATION)) {

      status = STATUS_BUFFER_TOO_SMALL;
    } else if (IoEvent->DokanInstance->DokanOperations->FindStreams) {

      status = IoEvent->DokanInstance->DokanOperations->FindStreams(
          IoEvent->EventContext->Operation.File.FileName,
          DokanFillFindStreamData, IoEvent, &IoEvent->DokanFileInfo);
      DokanEndDispatchFindStreams(IoEvent, status);
    } else {
      status = STATUS_NOT_IMPLEMENTED;
    }
  } else if (IoEvent->DokanInstance->DokanOperations->GetFileInformation) {

    ZeroMemory(&byHandleFileInfo, sizeof(BY_HANDLE_FILE_INFORMATION));
    status = IoEvent->DokanInstance->DokanOperations->GetFileInformation(
        IoEvent->EventContext->Operation.File.FileName, &byHandleFileInfo,
        &IoEvent->DokanFileInfo);
    DokanEndDispatchGetFileInformation(IoEvent, &byHandleFileInfo, status);
  } else {

    status = STATUS_NOT_IMPLEMENTED;
  }
}

But image mount still fails with "The requested operation could not be completed due to a file system limitation" For CIFS(SMB) drives this is well supported. But In dokan I don't know why..

Liryna commented 2 years ago

Thanks @onexzero for the patches. Regarding https://github.com/dokan-dev/dokany/issues/1076#issuecomment-1076095863 I actually believe we should NOT have the UNC in the Fcb->FileName from start. If we get a CreateFile with the UNC we should not copy it in our Fcb here https://github.com/dokan-dev/dokany/blob/master/sys/create.c#L608-L627 Would you agree ? Can you try see if it fix the issue here ?

https://github.com/dokan-dev/dokany/issues/1076#issuecomment-1076122348 The diff is skipping calls for FileRemoteProtocolInformation ? That might be a good idea! We should event just skip it from the Kernel. I don't see how we could support it at all.

onexzero commented 2 years ago

It will probably have the same effect. I haven't tested it, but it seems to be a more fundamental solution.

onexzero commented 2 years ago

I also tried to implement FileRemoteProtocolInformation, but it didn't seem like a generalizable part.

onexzero commented 2 years ago

Another thing I want to say about path notation is that it would be better to conform to the UNC notation. So it looks like we need one more leading "\" in unc-path.
ex) \Host\Share\PathToFile -> \\Host\Share\PathToFile

Liryna commented 2 years ago

Another thing I want to say about path notation is that it would be better to conform to the UNC notation. So it looks like we need one more leading "\" in unc-path. ex) \Host\Share\PathToFile -> \Host\Share\PathToFile

The single \ is made in purpose. It is the Windows kernel format we are using.

onexzero commented 2 years ago

All right. But usually use UNC format for network drives.

Liryna commented 2 years ago

Can confirm the iso is mount without issue on non network storage with mount manager option, with an error but still mount without the mount manager option and the same previous error without being mount on network storage.