EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Determine whether a file exists and is a directory [Crash]

Also by EldoS: CallbackDisk
Create virtual disks backed by memory or custom location, expose disk images as disks and more.
#25265
Posted: 06/12/2013 20:16:04
by david bennett (Standard support level)
Joined: 03/29/2013
Posts: 50

Attached is the function I wrote to tell me whether a file existed and if it exists whether it is a directory. It seems to me that you should provide such a function because figuring out what things actually work inside the callback to do this is not obvious. For example, GetFileInformation doesn't work reliably within the filter when I call it for both the Callback file and Noncallback files. I find it odd that other people aren't trying to do the same thing and yet I found nothing in your forum that would help so I wrote the attached through trial and error (lots of error).

If you #define CRASH_THE_SYSTEM in this particular module and call it with "C:\" as the name of the file, for some reason the OpenFile() succeeds but the GetFileInformationByHandle() fails. Then, at some point in the future, the system will hang. If you don't #define CRASH_THE_SYSTEM, the function seems to work correctly and the system never hangs.

Can you tell me if I am doing something incorrectly? Is there a better way to accomplish what I'm trying to do? Does it make sense that passing the handle returned by OpenFile for "C:\" to GetFileInformationByHandle should subtly break things?

Thanks

Code
bool    ClassDerivedFromCallbackFilter::FileExists(CString Filename, bool NonFiltered, bool& IsDirectory)
{
//    Log("Checking for existence of %s", Filename);
    wchar_t lastchar = Filename[Filename.GetLength()-1];
    IsDirectory = (lastchar == ':' || lastchar == '\\');

    HANDLE h = NULL;
    if (NonFiltered)
        h = CreateNonCbFile( Filename, GENERIC_READ, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING );
    else
        h = OpenFile(Filename);

    DWORD e = GetLastError(); // Sadly, CreateNonCbFile will succeeed even if the file doesn't exist so must check error code.

    switch (e)
    {
    case ERROR_SUCCESS:
#ifdef CRASH_THE_SYSTEM
   if (h)
#else
        if (h && !IsDirectory)
#endif
        {
            BY_HANDLE_FILE_INFORMATION info;
            if (GetFileInformationByHandle(h, &info))
            {
                if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                    IsDirectory = true;
                else if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
                {
                    Log(">>> %s is a System File");
                    IsDirectory = true;
                }
                else if (info.dwFileAttributes & FILE_ATTRIBUTE_VIRTUAL)
                {
                    Log(">>> %s is Virtual");
                    IsDirectory = true;
                }
                else //if ((info.dwFileAttributes & ~FILE_ATTRIBUTE_ARCHIVE) != 0)
                   Log("Attributes (0x%x) for %s", (int)info.dwFileAttributes, Filename);
            }
            else
            {
                Log("%f : Unable to get file information by Handle", Filename);
                IsDirectory = true; // just continue.
            }
        }

        Log("File %s exists and %s a directory", Filename,
            IsDirectory ? L"is" : L"is NOT");
        break;
    case ERROR_FILE_NOT_FOUND:
        Log("File %s does not exist", Filename);
        break;
    case ERROR_PATH_NOT_FOUND:
        Log("Path %s not found", Filename);
        break;
    case ERROR_INVALID_PARAMETER:
        // Set the directory so we don't bother to go any further.
        Log("%s is invalid", Filename);
        IsDirectory = true;
        break;

    default:
        CString lastError;
        FormatMessage(  FORMAT_MESSAGE_FROM_SYSTEM |
                        FORMAT_MESSAGE_IGNORE_INSERTS,  
                        NULL,
                        e,
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                        (LPTSTR) lastError.GetBuffer(2048),  
                        2048,
                        NULL );
        lastError.ReleaseBuffer();
        Log("File %s: %s (0x%x)", Filename, lastError, (int)e);
        if (h)
        {
            BY_HANDLE_FILE_INFORMATION info;
            GetFileInformationByHandle(h, &info);
            Log("    attributes: 0x%x", (int)info.dwFileAttributes);
        }
        break;
    }
    if (h)
        CloseHandle(h);
    return (e == ERROR_SUCCESS);
}
#25266
Posted: 06/13/2013 01:24:37
by david bennett (Standard support level)
Joined: 03/29/2013
Posts: 50

Well it appears I spoke/wrote too soon. My "fix" doesn't completely fix the problem, but just makes it take longer to crash. What does fix the problem is to completely eliminate the call to GetFileInformationByHandle(), but then I don't know how to figure out whether the file is a directory or not.

Dave
#25267
Posted: 06/13/2013 01:41:42
by Vladimir Cherniga (EldoS Corp.)

You should check the HANDLE value against the 0xFFFFFFFF(INVALID_HANDLE_VALUE), not the NULL. This would be correctly. In addition, please specify where did you use this function exactly. If you could provide a kernel dump it would help to find the source of the problem. In this case we may move this question to helpdesk system for the detail analysis. Thank you.
#25268
Posted: 06/13/2013 01:43:20
by Eugene Mayevski (EldoS Corp.)

Also it would be nice if you explained what you were trying to accomplish. Not everything that can be called needs to be called and though the driver should not crash in such cases, GIGO principle still rules.


Sincerely yours
Eugene Mayevski
#25276
Posted: 06/13/2013 08:56:30
by david bennett (Standard support level)
Joined: 03/29/2013
Posts: 50

Quote
Vladimir Cherniga wrote:
You should check the HANDLE value against the 0xFFFFFFFF(INVALID_HANDLE_VALUE), not the NULL.


If you look at your documentation for OpenFile and CreateNonCbFile, both say:
"Handle of the file if the function succeeded or 0 / null / NULL if the function failed."

If this is incorrect, you should fix your documentation. I will try your suggestion and let you know.
#25277
Posted: 06/13/2013 09:01:10
by Vladimir Cherniga (EldoS Corp.)

Quote
If this is incorrect, you should fix your documentation. I will try your suggestion and let you know.

Yes for sure. We will fix it as soon as possible. Thank you for the information.
#25278
Posted: 06/13/2013 09:13:24
by david bennett (Standard support level)
Joined: 03/29/2013
Posts: 50

Quote
Vladimir Cherniga wrote:
please specify where did you use this function exactly


I am using it in the OnOpenFileC() callback. In fact, for debugging this is the *only* thing I am doing in the OnOpenFileC() callback and all of the other callbacks are disabled. I have set the property ReadWriteFileInPreCreatePath to true.

Quote
Vladimir Cherniga wrote:
If you could provide a kernel dump it would help


Perhaps the word "crash" was misleading. "Hang" is the correct word. It appears that the filter goes into an infinite loop because the machine is still up and running but anything that tries to access any file never returns.
#25279
Posted: 06/13/2013 09:15:15
by david bennett (Standard support level)
Joined: 03/29/2013
Posts: 50

Quote
Eugene Mayevski wrote:
Also it would be nice if you explained what you were trying to accomplish.


All I really want to do is determine whether a particular file exists and if it does exist, whether it is a regular file (as opposed to a directory). I saw no easy way to accomplish this inside the OpenFileC/CreateFileC functions.
#25280
Posted: 06/13/2013 09:21:03
by Eugene Mayevski (EldoS Corp.)

Quote
david bennett wrote:
All I really want to do is determine whether a particular file exists and if it does exist, whether it is a regular file (as opposed to a directory). I saw no easy way to accomplish this inside the OpenFileC/CreateFileC functions.


Thank you. This is usually done using FindFirstFile WinAPI function and passing it the filename. The function will either return 2 (file not found) or return the filename and all attributes. Remember to call FindClose after a call to FindFirstFile.

Also I'd like to thank you for pointing at the documentation - we've corrected it. I believe there was some confusion when writing it (or maybe copy/paste glitch) - in Windows API there's a mess with those invalid values - some functions return -1 (INVALID_HANDLE_VALUE) when they fail and others return 0.


Sincerely yours
Eugene Mayevski
#25281
Posted: 06/13/2013 09:21:33
by Vladimir Cherniga (EldoS Corp.)

Quote
All I really want to do is determine whether a particular file exists and if it does exist...

For this case trying to open file is enough. If the value returned equal to INVALID_HANDLE_VALUE, then file doesn't exist.
Also by EldoS: Callback File System
Create virtual file systems and disks, expose and manage remote data as if they were files on the local disk.

Reply

Statistics

Topic viewed 7629 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!