Can using FileShare.Delete raise a UnauthorizedAccessException?

I open the file for reading, which I previously created in the user folder% TEMP%, using the following code:

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

On some user computers, this sometimes raises a UnauthorizedAccessException with the message "Access to path ... denied." I could not reproduce this. My initial guess is that the antivirus or indexing mechanism does something funky, but I also noticed that this code uses "FileShare.Delete", which I'm not sure should be there.

Is there a scenario in which using "FileShare.Delete" results in an UnauthorizedAccessException?

+6
source share
2 answers

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

FileShare.Delete allows another process to delete the file, even if the background process still has the file open and is reading it. This other process will not pay attention to the fact that the file has not actually disappeared, because it knows that the file is really deleted.

The problem starts when this other process depends on the actual removal of the file and does something else. Usually triggered by the creation of a new file with the same name. In particular, it is a very unreasonable way to save the file, as this will lead to complete data loss without backup, when the failure fails, but this error is very common.

This will not succeed because the directory entry for the file is still present, it will not disappear until the last process in which the file is open closes the handle. Any other process that tries to open the file again will be deleted with error 5, "access denied." Including this process, which deleted the file and tries to recreate it.

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

  • delete backup file, stop if failed
  • rename the old file to the backup file name, stop if failed
  • write a new file using the original file name, rename the backup if failed
  • delete backup file, ignore failure

Step 2 ensures that there will never be data loss, the original file will remain untouched if something goes wrong. Step 4 ensures that FileShare.Delete will work as planned, this backup file will disappear eventually when other processes close their descriptors.

+12
source

I found a script 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 the file C: \ temp.txt, then run this program. Try deleting the file using Explorer / TotalCommander, it will not complain, but it will not delete the file either. Then run the program again and it will throw a UnauthorizedAccessException. After you close both .exe, it looks like the file is permanently deleted.

Removing "FileShare.Delete" solves this problem because it simply will not allow you to try deleting the file during use.

+3
source

Source: https://habr.com/ru/post/957732/


All Articles