diff --git a/src/NAppUpdate.Framework/Tasks/FileUpdateTask.cs b/src/NAppUpdate.Framework/Tasks/FileUpdateTask.cs index 61278b5a..ba9f82da 100644 --- a/src/NAppUpdate.Framework/Tasks/FileUpdateTask.cs +++ b/src/NAppUpdate.Framework/Tasks/FileUpdateTask.cs @@ -76,15 +76,21 @@ public override TaskExecutionStatus Execute(bool coldRun) } var dirName = Path.GetDirectoryName(_destinationFile); + if (!Directory.Exists(dirName)) + { Utils.FileSystem.CreateDirectoryStructure(dirName, false); + } // Create a backup copy if target exists if (_backupFile == null && File.Exists(_destinationFile)) { if (!Directory.Exists(Path.GetDirectoryName(Path.Combine(UpdateManager.Instance.Config.BackupFolder, LocalPath)))) - Utils.FileSystem.CreateDirectoryStructure( - Path.GetDirectoryName(Path.Combine(UpdateManager.Instance.Config.BackupFolder, LocalPath)), false); + { + string backupPath = Path.GetDirectoryName(Path.Combine(UpdateManager.Instance.Config.BackupFolder, LocalPath)); + Utils.FileSystem.CreateDirectoryStructure(backupPath, false); + } + _backupFile = Path.Combine(UpdateManager.Instance.Config.BackupFolder, LocalPath); File.Copy(_destinationFile, _backupFile, true); } @@ -94,11 +100,7 @@ public override TaskExecutionStatus Execute(bool coldRun) { if (File.Exists(_destinationFile)) { - //if (FileSystem.IsExeRunning(_destinationFile)) - //{ - // UpdateManager.Instance.Logger.Log(Logger.SeverityLevel.Warning, "Process {0} is still running", _destinationFile); - // Thread.Sleep(1000); // TODO: retry a few times and throw after a while - //} + FileLockWait(); if (!PermissionsCheck.HaveWritePermissionsForFileOrFolder(_destinationFile)) { @@ -114,7 +116,10 @@ public override TaskExecutionStatus Execute(bool coldRun) try { if (File.Exists(_destinationFile)) + { File.Delete(_destinationFile); + } + File.Move(_tempFile, _destinationFile); _tempFile = null; } @@ -155,5 +160,23 @@ public override bool Rollback() return true; } + + /// + /// To mitigate problems with the files being locked even though the application mutex has been released. + /// https://github.com/synhershko/NAppUpdate/issues/35 + /// + private void FileLockWait() + { + int attempt = 0; + while (FileSystem.IsFileLocked(new FileInfo(_destinationFile))) + { + Thread.Sleep(500); + attempt++; + if (attempt == 10) + { + throw new UpdateProcessFailedException("Failed to update, the file is locked: " + _destinationFile); + } + } + } } } diff --git a/src/NAppUpdate.Framework/Utils/FileSystem.cs b/src/NAppUpdate.Framework/Utils/FileSystem.cs index 4e5ba459..3cfdde43 100644 --- a/src/NAppUpdate.Framework/Utils/FileSystem.cs +++ b/src/NAppUpdate.Framework/Utils/FileSystem.cs @@ -65,16 +65,36 @@ public static IEnumerable GetFiles(string path, string searchPattern, Se return files; } - public static bool IsExeRunning(string path) + /// + /// Returns true if read/write lock exists on the file, otherwise false + /// From http://stackoverflow.com/a/937558 + /// + /// The file to check for a lock + /// + public static bool IsFileLocked(FileInfo file) { - var processes = Process.GetProcesses(); - foreach (Process p in processes) + FileStream stream = null; + + try + { + stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None); + } + catch (IOException) { - if (p.MainModule.FileName.StartsWith(path, StringComparison.InvariantCultureIgnoreCase)) - return true; + //the file is unavailable because it is: + //still being written to + //or being processed by another thread + //or does not exist (has already been processed) + return true; } + finally + { + if (stream != null) + stream.Close(); + } + + //file is not locked return false; } - } }