/* ANY-LICENSE V1.0 ---------------- You can use these files under any license approved by the Open Source Initiative, preferrably one of the popular licenses, as long as the license you choose is compatible to the dependencies of these files. See http://www.opensource.org/licenses/ for a list of approved licenses. Author: Martin Furter Project: borgnet, borg.ch C# classes and examples. Modified: 2019 Support for atomically replacing an existing file. */ using System; using System.IO; using System.Runtime.InteropServices; namespace BorgCh.Hacks { /// @cond DEV interface ReplaceImpl { void replace( string newfile, string existing ); } /// @endcond public class Replace { private static ReplaceImpl impl = create_impl(); private static ReplaceImpl create_impl() { OperatingSystem os = Environment.OSVersion; PlatformID pid = os.Platform; switch( pid ) { case PlatformID.Win32NT: case PlatformID.Win32S: case PlatformID.Win32Windows: case PlatformID.WinCE: // Console.WriteLine( "windos" ); return new ReplaceWindows(); case PlatformID.Unix: // Console.WriteLine( "unix" ); return new ReplaceUnix(); default: Console.WriteLine( "unknown OS" ); throw new NotSupportedException( "Unknown platform ID." ); } } /** * Atomically replace the existing file by the new file. * * This is the same as deleting the existing file and renaming * the new file to the name of the existing file. * * @param newfile Name of the new file. * @param existing Name of the existing file. */ public static void replace( string newfile, string existing ) { impl.replace( newfile, existing ); } } /// @cond DEV /// Windows implementation of the replace function. class ReplaceWindows : ReplaceImpl { public ReplaceWindows() { } public void replace( string newfile, string existing ) { MoveFile( newfile, existing, MoveFileFlags.ReplaceExisting ); } [Flags] public enum MoveFileFlags { None = 0, ReplaceExisting = 1, CopyAllowed = 2, DelayUntilReboot = 4, WriteThrough = 8, CreateHardlink = 16, FailIfNotTrackable = 32, } public static void MoveFile( string existingFileName, string newFileName, MoveFileFlags flags ) { bool rc = NativeMethods.MoveFileEx( existingFileName, newFileName, flags ); if( !rc ) { Marshal.ThrowExceptionForHR( Marshal.GetLastWin32Error() ); } } private static class NativeMethods { [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool MoveFileEx( [In] string lpExistingFileName, [In] string lpNewFileName, [In] MoveFileFlags dwFlags); } } /// Unix implementation of the replace function. class ReplaceUnix : ReplaceImpl { public ReplaceUnix() { } public void replace( string newfile, string existing ) { int error = NativeMethods.rename( newfile, existing ); if( error != 0 ) { throw new IOException( string.Format( "Error replacing file '{0}' by '{1}'", existing, newfile ) ); } } private static class NativeMethods { [DllImport("libc.so.6")] public static extern int rename( [In] string oldpath, [In] string newpath ); } } /// @endcond } // namespace borg_ch.hacks