From 5d27fc48a8884dcda2b59e669cc523770081c6e0 Mon Sep 17 00:00:00 2001 From: Krasi Georgiev <8903888+krasi-georgiev@users.noreply.github.com> Date: Wed, 19 Jun 2019 12:10:51 +0300 Subject: [PATCH] fileutil.Replace - remove destination only when a directory. In cases where a rename fails the fileutil.Replace would delete the source files/folder. There is no easy way to make directory renaming atomic, but for files os.Rename is atomic and replaced the destination file so there is no need to remove the destination file explicitly. Signed-off-by: Krasi Georgiev <8903888+krasi-georgiev@users.noreply.github.com> --- fileutil/fileutil.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fileutil/fileutil.go b/fileutil/fileutil.go index c55a2b81d..25de316f8 100644 --- a/fileutil/fileutil.go +++ b/fileutil/fileutil.go @@ -128,9 +128,20 @@ func Rename(from, to string) error { // Replace moves a file or directory to a new location and deletes any previous data. // It is not atomic. func Replace(from, to string) error { - if err := os.RemoveAll(to); err != nil { - return err + // Remove destionation only if it is a dir. + // Otherwise os.Rename replaces the destination file and is atomic. + { + f, err := os.Stat(to) + if err != nil { + return err + } + if f.IsDir() { + if err := os.RemoveAll(to); err != nil { + return err + } + } } + if err := os.Rename(from, to); err != nil { return err }