Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The morass of Exceptions related to opening a FileStream

Ok, so I have searched in many places for the answer to this question, but I'm open to any links if I missed something obvious.

I am interested in producing reasonable error messages to the user when they attempt to open a particular file, but for whatever reason the program cannot access that file. I would like to distinguish between the following cases:

  • The file was locked by another process such that this process cannot write to it.
  • The user does not have the appropriate access privileges to write to the file (as in, their user permissions, as seen in the Properties screen for a file in Windows explorer, do not give the user write permission)
  • The file requires "elevated" permission to access the file.

I am using a FileStream object. I have looked at the msdn documentation for instantiating a FileStream, and it is not at all clear to me which Exception does what for the above, and how to distinguish between them. I admit that my experience with Windows programming is limited, so I may be missing something obvious. My apologies if so.

like image 446
skybluecodeflier Avatar asked Feb 21 '12 00:02

skybluecodeflier


1 Answers

Here's what you could do:

1) You could test if you have rights to access to the file before trying to access to your file. From this SO thread, here is a method that should return true if user has Write rights (i.e. when right-clicking on a file -> property -> security). This covers your point (2) for unappropriated access privileges (do note that there is maybe something more robust/error-proof to get this information than the code below):

public static bool HasWritePermissionOnFile(string path)
{
    bool writeAllow = false;
    bool writeDeny = false;

    FileSecurity accessControlList = File.GetAccessControl(path);
    if (accessControlList == null)
    {
        return false;
    }

    var accessRules = accessControlList.GetAccessRules(true, true, typeof(SecurityIdentifier));
    if (accessRules == null)
    {
        return false;
    }

    foreach (FileSystemAccessRule rule in accessRules)
    {
        if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write)
        {
            continue;
        }

        if (rule.AccessControlType == AccessControlType.Allow)
        {
            writeAllow = true;
        }
        else if (rule.AccessControlType == AccessControlType.Deny)
        {
            writeDeny = true;
        }
    }

    return writeAllow && !writeDeny;
}

2) Do try to instantiate your FileStream, and catch exceptions:

try
{
    string file = "...";
    bool hasWritePermission = HasWritePermissionOnFile(file);
    using (FileStream fs = new FileStream(file, FileMode.Open))
    {
    }
}
catch (UnauthorizedAccessException ex)
{
    // Insert some logic here
}
catch (FileNotFoundException ex)
{
    // Insert some logic here
}
catch (IOException ex)
{
    // Insert some logic here
}

In your case (3) (file requires elevation), UnauthorizedAccessException is thrown.

In your case (1) (file is locked by another process), IOException is thrown. You can then check the HRESULT of the exception for more details:

catch (IOException ex)
{
    // Gets the HRESULT
    int hresult = Marshal.GetHRForException(ex);

    // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
    // for system error code
    switch (hresult & 0x0000FFFF)
    {
        case 32:    //ERROR_SHARING_VIOLATION
            Console.WriteLine("File is in use by another process");
            break;
    }
}

Now you should be able to distinguish your 3 use cases.

like image 158
ken2k Avatar answered Oct 20 '22 05:10

ken2k