Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UnauthorizedAccessException "Access to the path is denied" from File.ReadAllBytes in LOCALAPPDATA

This exception is occurring intermittently for the same user for the same machine, when reading files within %LOCALAPPDATA%.

Research

I have checked all the possible duplicates currently offered by this title (there are a lot). There is one relating to reading an AES encrypted file which has no answer; and I don't believe applies, since these files are not encrypted.

Most of them are to do with writing files (but I'm reading a file), or are the obvious causes as documented on MSDN for File.ReadAllBytes(string).

The three explanations for this exception on there are:

  1. "This operation is not supported on the current platform" - I don't know what that means; but given that this works sometimes for the same user on the same machine (I'll explain below), I think I can rule this out.
  2. "path specified a directory" - as you'll see from the code below, the call is made within a check of File.Exists, so I think I can rule this out.
  3. "The caller does not have the required permission." This is the usual explanation for this exception, and I suspect I'm getting some kind of "fringe case" of this.

Scenario

This is occurring when an application which is running as a domain user is reading a file inside a subfolder of %LOCALAPPDATA% of the same user (for which there should be no permission issues for that user to read files). The subfolders within that just follow the normal "CompanyName"\"ApplicationName" structure, and there are no additional permissions applied on the sub folders (we're just using the folder to keep our files away from other people's).

Exception

System.UnauthorizedAccessException: Access to the path '[redacted]' is denied. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.File.InternalReadAllBytes(String path, Boolean checkHost)
at the code below

Code

        // Note that filename is within %LOCALAPPDATA%
        if (File.Exists(fileName))
        {
            var readAllBytes = File.ReadAllBytes(fileName); // exception here
            // etc...
        }

Proof that it is intermittent

And I can prove from the combination of our error logs, and other information that this is working most of the time, and I can prove the following sequence of events for a particular combination of machine and user:

  • The application works, then
  • This exception occurs (maybe several times, with retry delays exponentially increasing each time: 1minute, 2minutes, 4minutes, etc), then
  • The application works again

I don't believe that any material change (e.g. permissions) will have occurred to the file system in order to fix it. I'm wondering whether this might be caused by a fringe permissions issue, for example, if their password is about to expire, or has recently been changed.

I have a specific example when I noticed this error happening, and I advised the user to reboot their machine, and the problem went away.

Question

Can anyone give me an authoritative explanation of the cause of this, above what I've already guessed, or to confirm what it is?

like image 973
Richardissimo Avatar asked Apr 27 '18 08:04

Richardissimo


1 Answers

The question is too broad, but I want to point out that there are other reasons for access denied exception besides you listed. For example, consider this simple program:

public class Program {
    static string _target = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "test", "test.txt");
    static void Main(string[] args) {
        File.Create(_target).Dispose();
        ProcessFile();

        // below throws access denied
        if (File.Exists(_target))
            Console.WriteLine(File.ReadAllText(_target));
        Console.ReadKey();
    }

    static void ProcessFile() {
        // open and abandon handle
        var fs = new FileStream(_target, FileMode.Open, FileAccess.Read, FileShare.Delete);
        // delete
        File.Delete(_target);
    }        
}  

Here we create new file under %LOCALAPPDATA%, and open it with FileShare.Delete, but not closing. FileShare.Delete allows subsequent deletion of the file, but file will not be actually deleted until all handles to it are closed.

Then we proceed with File.Delete, which does not actually delete file but marks it for deletion, because we still have open file handle to it.

Now, File.Exists returns true for such file, but trying to access it throws "Access denied" exception as you described.

Whether this specific situation is relevant to your case is hard to tell, but it might be.

My point mainly is: you should expect such exceptions (and also "file already in use" kind of exceptions) and handle them by retrying. They can happen for various reasons outside of your control.

like image 65
Evk Avatar answered Nov 17 '22 06:11

Evk