Can using FileShare.Delete cause a UnauthorizedAccessException?

那年仲夏 提交于 2019-12-19 06:04:08

问题


I'm opening a file with for reading that I had previously created in the user's %TEMP% folder, using the following code:

new FileStream(cacheFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);

On some user's computers, this sometimes throws an UnauthorizedAccessException with the message "Access to path ... is denied". I haven't been able to reproduce this. My initial guess is that an anti-virus or indexing engine is doing something funky, but I also noticed this code is using "FileShare.Delete", which I'm not sure should be there.

Is there a scenario where using "FileShare.Delete" leads to UnauthorizedAccessException ?


回答1:


Yes, FileShare.Delete tends to cause this problem. Used by any program that runs in the background and scans files, file indexers and virus scanners are the common examples.

FileShare.Delete allows another process to delete the file, even though the background process still has the file opened and is reading from it. That other process will be oblivious that the file didn't actually disappear, for all it knows the file actually got deleted.

The trouble starts when that other process relies on the file actually being removed and does something else. Commonly triggered by creating a new file with the same name. Notably a very unwise way to save a file since it will cause complete data loss without a backup when the save fails, but this mistake is very common.

This will fail because the directory entry for the file is still present, it won't disappear until the last process that has the file opened closes the handle. Any other process that tries to open the file again will be slapped with error 5, "access denied". Including that process that deleted the file and tries to re-create it.

The workaround is to always use "transactional" saves, renaming the file before trying to overwrite it. Available in .NET with File.Replace(), in the native winapi with ReplaceFile(). Also easily done by hand, the workflow is:

  1. delete the backup file, stop if failed
  2. rename the old file to the backup filename, stop if failed
  3. write the new file using the original filename, rename backup back if failed
  4. delete the backup file, ignore failure

Step 2 ensures that there will never be any data loss, the original file stays intact if anything goes wrong. Step 4 ensures that FileShare.Delete will work as intended, that backup file will disappear eventually when other processes close their handles.




回答2:


I found a scenario that reproduces this:

    static void Main(string[] args)
    {
        string cacheFileName = @"C:\temp.txt";
        using (var filestream = new FileStream(cacheFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete, 4096, FileOptions.SequentialScan))
        {
            filestream.Read(new byte[100], 1, 1);
            Console.ReadLine();
            GC.KeepAlive(filestream);
        }
        Console.WriteLine("Done!");
    }
}

Create a "C:\temp.txt" file, then run this program. Try to delete the file with Explorer/TotalCommander, it won't complain but it won't delete the file either. Then, run the program again and it will throw the UnauthorizedAccessException. After you close both .exes, it looks like the file is finally deleted.

Removing "FileShare.Delete" solves this problem, as it simply won't let you try to delete the file while it's in use.



来源:https://stackoverflow.com/questions/19875329/can-using-fileshare-delete-cause-a-unauthorizedaccessexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!