WriteFileContext
using System.IO;
using System.IO.Internal;
using System.Threading;
namespace System.Configuration.Internal
{
internal sealed class WriteFileContext
{
private const int SavingTimeout = 10000;
private const int SavingRetryInterval = 100;
private readonly string _templateFilename;
private TempFileCollection _tempFiles;
internal string TempNewFilename { get; }
internal WriteFileContext(string filename, string templateFilename)
{
string directoryOrRootName = UrlPath.GetDirectoryOrRootName(filename);
_templateFilename = templateFilename;
_tempFiles = new TempFileCollection(directoryOrRootName);
try {
TempNewFilename = _tempFiles.AddExtension("newcfg");
} catch {
((IDisposable)_tempFiles).Dispose();
_tempFiles = null;
throw;
}
}
internal void Complete(string filename, bool success)
{
try {
if (success) {
if (File.Exists(filename)) {
ValidateWriteAccess(filename);
DuplicateFileAttributes(filename, TempNewFilename);
} else if (_templateFilename != null) {
DuplicateTemplateAttributes(_templateFilename, TempNewFilename);
}
ReplaceFile(TempNewFilename, filename);
_tempFiles.KeepFiles = true;
}
} finally {
((IDisposable)_tempFiles).Dispose();
_tempFiles = null;
}
}
private static void DuplicateFileAttributes(string source, string destination)
{
FileAttributes attributes = File.GetAttributes(source);
File.SetAttributes(destination, attributes);
DateTime creationTimeUtc = File.GetCreationTimeUtc(source);
File.SetCreationTimeUtc(destination, creationTimeUtc);
DuplicateTemplateAttributes(source, destination);
}
private static void DuplicateTemplateAttributes(string source, string destination)
{
FileAttributes attributes = File.GetAttributes(source);
File.SetAttributes(destination, attributes);
}
private static void ValidateWriteAccess(string filename)
{
FileStream fileStream = null;
try {
fileStream = new FileStream(filename, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
} catch (IOException) {
} finally {
fileStream?.Close();
}
}
private static void ReplaceFile(string source, string target)
{
int num = 0;
bool flag = AttemptMove(source, target);
while (!flag && num < 10000 && File.Exists(target) && !FileIsWriteLocked(target)) {
Thread.Sleep(100);
num += 100;
flag = AttemptMove(source, target);
}
if (!flag)
throw new ConfigurationErrorsException(System.SR.Format(System.SR.Config_write_failed, target));
}
private static bool AttemptMove(string source, string target)
{
try {
if (File.Exists(target))
File.Replace(source, target, null);
else
File.Move(source, target);
return true;
} catch {
return false;
}
}
private static bool FileIsWriteLocked(string fileName)
{
FileStream fileStream = null;
if (File.Exists(fileName))
try {
fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
return false;
} catch {
return true;
} finally {
fileStream?.Close();
}
return false;
}
}
}