// Copyright (C) Stichting Deltares 2016. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.IO; using Application.Ringtoets.Storage.Exceptions; using Application.Ringtoets.Storage.Properties; using Core.Common.Utils; namespace Application.Ringtoets.Storage { /// /// Class for providing a safe way of writing files by creating a temporary backup file of targeted files. /// public class BackedUpFileWriter { private const string temporarySuffix = "~"; private readonly string temporaryFilePath; private readonly string targetFilePath; private bool isTemporaryFileCreated; /// /// Creates an instance of . /// /// The path of the file which will be overwritten. /// is not a valid path. public BackedUpFileWriter(string targetFilePath) { FileUtils.ValidateFilePath(targetFilePath); this.targetFilePath = targetFilePath; temporaryFilePath = targetFilePath + temporarySuffix; } /// /// Performs the in a safe way by backing up the targeted file provided when /// constructing the . It is expected that the /// will throw an exception when the operation fails, so that the backed up target file can be restored. /// /// The action to perform after backing up the targeted file. /// Thrown when: /// /// The temporary file already exists and cannot be deleted. /// The temporary file cannot be created from the target file. /// When reverting, the original file cannot be restored. /// /// /// When cleaning up, the temporary file cannot be removed. /// Any thrown by will be rethrown. public void Perform(Action writeAction) { CreateTemporaryFile(); try { writeAction(); } catch { Revert(); throw; } Finish(); } /// /// Removes the temporary file if it was created. /// /// The temporary file cannot be removed. private void Finish() { if (isTemporaryFileCreated) { DeleteTemporaryFile(); } } /// /// Reverts the target file to the temporary file if it was created. If the operation fails, /// the temporary file will remain in the directory of the target file. /// /// The original file cannot be restored. private void Revert() { if (isTemporaryFileCreated) { RestoreOriginalFile(); } } /// /// Creates a temporary file from the target file, if there is any. Creates a new file at the target /// file path. /// /// Thrown when either: /// /// The temporary file already exists and cannot be deleted. /// The temporary file cannot be created from the target file. /// /// private void CreateTemporaryFile() { isTemporaryFileCreated = false; if (File.Exists(targetFilePath)) { RemoveAlreadyExistingTemporaryFile(); CreateNewTemporaryFile(); isTemporaryFileCreated = true; } } /// /// Removes the temporary file for the target file if it already exists. /// /// The temporary file already exists and cannot be deleted. private void RemoveAlreadyExistingTemporaryFile() { if (File.Exists(temporaryFilePath)) { try { File.Delete(temporaryFilePath); } catch (Exception e) { if (e is ArgumentException || e is IOException || e is NotSupportedException || e is UnauthorizedAccessException) { var message = string.Format( Resources.SafeOverwriteFileHelper_RemoveAlreadyExistingTemporaryFile_Already_existing_temporary_file_at_FilePath_0_could_not_be_removed, temporaryFilePath); throw new IOException(message, e); } throw; } } } /// /// Creates a temporary file from the target file. /// /// The temporary file cannot be created from the target file. private void CreateNewTemporaryFile() { try { File.Move(targetFilePath, temporaryFilePath); } catch (Exception e) { if (e is ArgumentException || e is IOException || e is UnauthorizedAccessException || e is NotSupportedException) { var message = string.Format( Resources.SafeOverwriteFileHelper_CreateNewTemporaryFile_Cannot_create_temporary_FilePath_0_Try_change_save_location, targetFilePath); throw new IOException(message, e); } throw; } } /// /// Moves the temporary file back to the original path. If the operation fails, the temporary file /// will remain. /// /// Thrown when either: /// /// The new file could not be deleted. /// The temporary file could not be moved to its original place. /// private void RestoreOriginalFile() { try { File.Delete(targetFilePath); File.Move(temporaryFilePath, targetFilePath); } catch (Exception e) { if (e is ArgumentException || e is IOException || e is NotSupportedException || e is UnauthorizedAccessException) { var message = string.Format( Resources.SafeOverwriteFileHelper_RestoreOriginalFile_Cannot_revert_to_original_FilePath_0_Try_reverting_manually, targetFilePath); throw new IOException(message, e); } throw; } } /// /// Deletes the created temporary file. /// /// The temporary file cannot be removed. private void DeleteTemporaryFile() { try { File.Delete(temporaryFilePath); } catch (Exception e) { if (e is ArgumentException || e is IOException || e is NotSupportedException || e is UnauthorizedAccessException) { var message = string.Format( Resources.SafeOverwriteFileHelper_DeleteTemporaryFile_Cannot_remove_temporary_FilePath_0_Try_removing_manually, temporaryFilePath); throw new CannotDeleteBackupFileException(message, e); } throw; } } } }