Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# File.Replace protecting against a crash

Tags:

c#

.net

Does File.Replace do an atomic/transactional operation such that if there is a crash or power failure the destination file will never be missing nor a partial file (i.e. will be the original or the new file)?

If not, is there another method that would protect against this scenario?

Note: This would be on an NTFS drive with Windows 7 or later, which I understand supports transactions.

Note: I am asking about saving in an atomic manor and not concerned about a separate process also having the file open like this question.

like image 282
webwake Avatar asked Jan 08 '16 00:01

webwake


1 Answers

File.Replace uses the WinAPI function ReplaceFile internally (on Windows, of course). However, atomicity isn't a documented behaviour even in that function, and the documentation is somewhat ambiguous.

First, if you want consistency, you must use the backup file. As per documentation:

[When moving the file fails...] If lpBackupFileName was specified, the replaced and replacement files retain their original file names. Otherwise, the replaced file no longer exists and the replacement file exists under its original name.

Another failure mode results in

[When moving the file fails... ]The replacement file still exists under its original name; however, it has inherited the file streams and attributes from the file it is replacing. The file to be replaced still exists with a different name. If lpBackupFileName is specified, it will be the name of the replaced file.

This is the worst of the document behaviours - you still have both files, but the file to be "copied" already has its security attributes changed. If you're using a service with limited privileges to write the file, this might pose a problem.

Finally, when the delete fails, nothing happens.

So, is the whole operation atomic? Even though it's not officially documented, we have a few pointers. For one, the replacement operation is ultimately a swap of file IDs (and a one-way update of all the file attributes), as long as you use the backup file option; that's an operation that's transactional on NTFS, so my expectation would be that this part is effectively atomic, as long as you don't have to worry about the file attributes, ACLs and alternate data streams.

However, this behaviour is not contractual, neither for File.Replace nor ReplaceFile. If you need a contractual way of implementing transcational operations, you need to use TxF. The two main problems are that one, TxF is only supported from Vista on, and two, it wasn't used much in practice and is being deprecated. Bummer :) The official Microsoft-recommended-way of replacing TxF is documented in https://msdn.microsoft.com/en-us/library/windows/desktop/hh802690%28v=vs.85%29.aspx - and includes the use of ReplaceFile (exposed in .NET as File.Replace).

like image 76
Luaan Avatar answered Nov 03 '22 01:11

Luaan