Przeglądaj źródła

Implement atomic file movement

NextTurn 5 lat temu
rodzic
commit
368b99d8a1

+ 4 - 5
src/Core/ServiceWrapper/Main.cs

@@ -106,7 +106,7 @@ namespace winsw
                         continue;
                     }
 
-                    CopyFile(tokens[0], tokens[1]);
+                    MoveFile(tokens[0], tokens[1]);
                 }
             }
             finally
@@ -118,16 +118,15 @@ namespace winsw
         /// <summary>
         /// File replacement.
         /// </summary>
-        private void CopyFile(string sourceFileName, string destFileName)
+        private void MoveFile(string sourceFileName, string destFileName)
         {
             try
             {
-                File.Delete(destFileName);
-                File.Move(sourceFileName, destFileName);
+                FileHelper.MoveOrReplaceFile(sourceFileName, destFileName);
             }
             catch (IOException e)
             {
-                LogEvent("Failed to copy :" + sourceFileName + " to " + destFileName + " because " + e.Message);
+                LogEvent("Failed to move :" + sourceFileName + " to " + destFileName + " because " + e.Message);
             }
         }
 

+ 1 - 8
src/Core/WinSWCore/Download.cs

@@ -181,14 +181,7 @@ namespace winsw
 #endif
             }
 
-#if NETCOREAPP
-            File.Move(tmpFilePath, To, true);
-#else
-            if (File.Exists(To))
-                File.Delete(To);
-
-            File.Move(tmpFilePath, To);
-#endif
+            FileHelper.MoveOrReplaceFile(To + ".tmp", To);
         }
 #if NET20
 

+ 6 - 6
src/Core/WinSWCore/LogAppenders.cs

@@ -8,6 +8,7 @@ using System.Threading;
 #if !VNEXT
 using ICSharpCode.SharpZipLib.Zip;
 #endif
+using winsw.Util;
 
 namespace winsw
 {
@@ -52,16 +53,15 @@ namespace winsw
         /// <summary>
         /// File replacement.
         /// </summary>
-        protected void CopyFile(string sourceFileName, string destFileName)
+        protected void MoveFile(string sourceFileName, string destFileName)
         {
             try
             {
-                File.Delete(destFileName);
-                File.Move(sourceFileName, destFileName);
+                FileHelper.MoveOrReplaceFile(sourceFileName, destFileName);
             }
             catch (IOException e)
             {
-                EventLogger.LogEvent("Failed to copy :" + sourceFileName + " to " + destFileName + " because " + e.Message);
+                EventLogger.LogEvent("Failed to move :" + sourceFileName + " to " + destFileName + " because " + e.Message);
             }
         }
     }
@@ -286,10 +286,10 @@ namespace winsw
         public override void log(StreamReader outputReader, StreamReader errorReader)
         {
             if (!OutFileDisabled)
-                CopyFile(OutputLogFileName, OutputLogFileName + ".old");
+                MoveFile(OutputLogFileName, OutputLogFileName + ".old");
 
             if (!ErrFileDisabled)
-                CopyFile(ErrorLogFileName, ErrorLogFileName + ".old");
+                MoveFile(ErrorLogFileName, ErrorLogFileName + ".old");
 
             base.log(outputReader, errorReader);
         }

+ 39 - 0
src/Core/WinSWCore/Util/FileHelper.cs

@@ -0,0 +1,39 @@
+#if !NETCOREAPP
+using System.ComponentModel;
+#endif
+using System.IO;
+#if !NETCOREAPP
+using System.Runtime.InteropServices;
+#endif
+
+namespace winsw.Util
+{
+    public static class FileHelper
+    {
+        public static void MoveOrReplaceFile(string sourceFileName, string destFileName)
+        {
+#if NETCOREAPP
+            File.Move(sourceFileName, destFileName, true);
+#else
+            string sourceFilePath = Path.GetFullPath(sourceFileName);
+            string destFilePath = Path.GetFullPath(destFileName);
+
+            if (!NativeMethods.MoveFileEx(sourceFilePath, destFilePath, NativeMethods.MOVEFILE_REPLACE_EXISTING | NativeMethods.MOVEFILE_COPY_ALLOWED))
+            {
+                throw new Win32Exception();
+            }
+#endif
+        }
+#if !NETCOREAPP
+
+        private static class NativeMethods
+        {
+            internal const uint MOVEFILE_REPLACE_EXISTING = 0x01;
+            internal const uint MOVEFILE_COPY_ALLOWED = 0x02;
+
+            [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "MoveFileExW")]
+            internal static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, uint dwFlags);
+        }
+#endif
+    }
+}