Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mirror sample bug about Info.IsDirectory #274

Open
blackeyed7 opened this issue Aug 2, 2021 · 6 comments
Open

Mirror sample bug about Info.IsDirectory #274

blackeyed7 opened this issue Aug 2, 2021 · 6 comments

Comments

@blackeyed7
Copy link

in CreateFile method
info.IsDirectory not working (not sure if its 100% fail)
I see the C mirror code has a check there, so I added check code on mine too

        var filePath = GetPath(fileName);
        FileAttributes attr = File.GetAttributes(filePath);
        if ((attr & FileAttributes.Directory) == FileAttributes.Directory) info.IsDirectory = true;
@Liryna
Copy link
Member

Liryna commented Aug 2, 2021

Yes, you do need to set this field if the directory exist.
This is expected and documented.

Could you explain a little more where you added this code ?

@blackeyed7
Copy link
Author

I've read more code in C# mirror, and I thought its should not be fixed in this way, but
I found its more complex than I thought, I think I need more help for this

the key code in C mirror is this (line 273)
if (fileAttr != INVALID_FILE_ATTRIBUTES &&
fileAttr & FILE_ATTRIBUTE_DIRECTORY) {
if (CreateOptions & FILE_NON_DIRECTORY_FILE) {
DbgPrint(L"\tCannot open a dir as a file\n");
return STATUS_FILE_IS_A_DIRECTORY;

it seems that user software tring to open a directory as a file, so then here it tells that this FILE IS A DIRECTORY, then everything's fine.

But there is no STATUS_FILE_IS_A_DIRECTORY in Dokan.NET
I tried to add same long code, and edit the code in CreateFile

            switch (mode)
            {
                case FileMode.Open:

                    if (pathExists)
                    {
                        // check if driver only wants to read attributes, security info, or open directory
                        if (readWriteAttributes || pathIsDirectory)
                        {
                            if (pathIsDirectory && (access & FileAccess.Delete) == FileAccess.Delete
                                && (access & FileAccess.Synchronize) != FileAccess.Synchronize)
                                //It is a DeleteFile request on a directory
                                return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
                                    attributes, DokanResult.AccessDenied);

                            info.IsDirectory = pathIsDirectory;
                            info.Context = new object();
                            // must set it to something if you return DokanError.Success

                            return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
                                attributes, DokanResult.FILE_IS_A_DIRECTORY);
                        }
                    }

then I no longer able to open the any directory in my mounted driver, it says "denied"

@blackeyed7
Copy link
Author

Yes, you do need to set this field if the directory exist.
This is expected and documented.

Could you explain a little more where you added this code ?

I was adding that code at the very begining of the CreateFile method, it fixed the problem that my user software met when using mirror sample for Dokan.NET

but I am not able to use this fix code in my own code, it is a little complex the fix code
FileAttributes attr = File.GetAttributes(filePath);
this will throw exception reading "destkop.ini", even I use MountManger, it still happens (not suppose to happen with MountManger?)
and if I catch it, still the user software recognize the directory as a file (so my pre problem still there)

@blackeyed7
Copy link
Author

blackeyed7 commented Aug 2, 2021

found a workaround, not sure if any side effect so far

            switch (mode)
            {
                case FileMode.Open:

                    if (pathExists)
                    {
                        // check if driver only wants to read attributes, security info, or open directory
                        if (readWriteAttributes || pathIsDirectory)
                        {
                            if (pathIsDirectory && (access & FileAccess.Delete) == FileAccess.Delete
                                && (access & FileAccess.Synchronize) != FileAccess.Synchronize)
                                //It is a DeleteFile request on a directory
                                return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
                                    attributes, DokanResult.AccessDenied);

                            info.IsDirectory = pathIsDirectory;
                            info.Context = new object();
                            // must set it to something if you return DokanError.Success

                            if (pathIsDirectory)
                            {
                                if (access == FileAccess.GenericRead)
                                    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
                                        (NtStatus)0xC00000BAL);
                            }

                            return Trace(nameof(CreateFile), fileName, info, access, share, mode, options,
                                attributes, DokanResult.Success);
                        }
                    }

@Liryna
Copy link
Member

Liryna commented Aug 3, 2021

To properly handle this issue we need to support FILE_NON_DIRECTORY_FILE which is not part of the official FileOptions enum. So we would need to extend the current enum and the others present in NtCreateFile.

Also add STATUS_FILE_IS_A_DIRECTORY to the NtStatus:
https://github.com/dokan-dev/dokan-dotnet/blob/master/DokanNet/NtStatus.cs


if (pathIsDirectory)
{
  if (access == FileAccess.GenericRead) <=== createOptions & FileOptions.NonDirectoryFile
    return Trace(nameof(CreateFile), fileName, info, access, share, mode, options, attributes,
                                        (NtStatus)0xC00000BAL);
}

GenericRead is too wild and will create many issues.

@fiddyschmitt
Copy link

Thanks @blackeyed7,

I was experiencing the same issue when scanning my virtual drive with log4jscanner.

If I ran: log4jscanner.exe N:\

it would instantly return:

2022/01/20 11:37:59 log4jscanner.go:120: Error: scanning N:\: readdir N:\/.: The system cannot find the path specified.

So to scanner seems to enumerate the drive in an unusual way. Also, the scan would run fine on a virtual drive provided through mirror.exe. Those two facts suggested an issue with dokan-dotnet which led me to your post. Thanks!

Thanks @Liryna, I added that block of code to CreateFile() and now log4jscanner processes the drive fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants