tags:

views:

1145

answers:

3

In my C# .NET 2.0 application I'm accessing network paths, and I'd like to be able to tell the difference between paths that don't exist, and paths which do exist but for which I don't have access rights. I tried doing the following:

try
{
    string[] contents = Directory.GetFileSystemEntries( path );
}
catch( Exception e )
{
    if( e is DirectoryNotFoundException )
        MessageBox.Show( "Path not found" );
    else
        MessageBox.Show( "Access denied" );
}

This works fine for local paths, but for network paths, the exception is always System.IO.IOException, regardless of the reason for the error. The exception Message field shows a different message depending on whether the path exists or not, so clearly the information is available at some point, but I can't get to it. Is there a way to differentiate between "path not found" and "access denied" for network paths?

Edit: So, in case anyone else wants the quick solution to this, as suggested by henrik, and incorporating peSHIr's advice, here is what you can do:

try
{
    // Issue this call just to find out whether the path exists
    // We don't care about the result

    string[] contents = Directory.GetFileSystemEntries( path );

    // If we get this far then the path exists.
}
catch( IOException e )
{
    uint error = (uint)Marshal.GetHRForException( e );

    if( error == (uint)0x80070041 )     // ERROR_NETWORK_ACCESS_DENIED
    {
        // The poor deluded user doesn't have access rights

        this.SuperProprietaryTechniqueForGettingAccessRights();
    }
    else
    {
        // Hah! The idiot user specified a path that doesn't exist!
        // Chastise them severely, like all good GUI should.

        MessageBox.Show( "NO! BAD USER!" );
    }
}
catch 
{
    // Swallow all other types of exception - we only made the call
    // to find out whether the path exists.
}
+4  A: 

First, I would not catch (Exception), but do something like this:

try {
  string[] contents = Directory.GetFileSystemEntries(path);
}
catch(DirectoryNotFoundException)
{
  MessageBox.Show("Path not found");
}
catch(IOException)
{
  MessageBox.Show("Could not access path");
}

But the real question is: why would you actually need to know the difference, if all you do is show a message box to the user with a generic error message?

peSHIr
Also, be sure to check http://stackoverflow.com/questions/434839/where-do-you-like-to-catch-exceptions-and-why/434903#434903: a catch statement that shows (G)UI to the user with error information is *always* wrong, except when in your global top-level unexpected exception handler (which should log the message as needed and then bomb the application).
peSHIr
Actually, the real question is: How can I tell the difference? Of course my real app is not going to just pop up a message box and do nothing else - that was for the purposes of illustration. The real app could do something like prompt for credentials if the error was "access denied" or display alternative paths if the error was "path not found".Thanks for the tip on multiple catch blocks though - I wasn't aware of that.
Sam Hopkins
A: 

You can call Marshal.GetHRForException to get more detailed information as in:

if (Marshal.GetHRForException(e) == unchecked((int)0x800704cf)) // ERROR_NETWORK_UNREACHABLE

See WinError.h for error codes.

Henrik
Great! Although this is rather too implementation-specific for my taste, it does work. I get an HRESULT of 0X80070041 for an access denied error, and other values for path not found. So that's how I'll handle it. Thanks.
Sam Hopkins
+1  A: 

Also, unfortunately, the path may exist and you don't have access, and the result is that the path appears non-existent to your account. Many companies modify the special privs on a folder to remove "intermediary" folders from visibility, but they are still present.

For example, consider the path \srv\test1\test2\test3\

If you modify the advanced security for the folder named "test2" above, you can prevent users from navigating into it. Attempts to open the folder will result in a not found exception, and viewing the parent folder "test1" will not show the folder as present. However, if you provide the full path above and have sufficient privileges on the folder named "test3" then the folder will open.

Just something to consider, for all intents and purposes the folder doesn't exist for the user, however, if you offer the ability for a user to specify a full path then you should keep the above in mind (e.g. allow users to reach paths by full name, because it's possible they lack privs to view/list/read/see an intermediary, and the error returned doesn't indicate that it's a security restriction, so preventing access to the full path because of an intermediary appeared non-existent coudl be considered bugged app logic.)

Hope that helps.

Shaun Wilson