diff --git a/internal/osutil/osutil.go b/internal/osutil/osutil.go index 09323288..7b0fa43f 100644 --- a/internal/osutil/osutil.go +++ b/internal/osutil/osutil.go @@ -32,7 +32,7 @@ func TryRename(from, to string) error { renameLock.Lock() defer renameLock.Unlock() - return withPreparedTarget(to, func() error { + return withPreparedTarget(from, to, func() error { return os.Rename(from, to) }) } @@ -44,7 +44,9 @@ func TryRename(from, to string) error { // permissions and removing the destination file when necessary. func Rename(from, to string) error { // Don't leave a dangling temp file in case of rename error - defer os.Remove(from) + if !(runtime.GOOS == "windows" && strings.EqualFold(from, to)) { + defer os.Remove(from) + } return TryRename(from, to) } @@ -52,7 +54,7 @@ func Rename(from, to string) error { // Tries hard to succeed on various systems by temporarily tweaking directory // permissions and removing the destination file when necessary. func Copy(from, to string) (err error) { - return withPreparedTarget(to, func() error { + return withPreparedTarget(from, to, func() error { return copyFileContents(from, to) }) } @@ -143,7 +145,7 @@ func getHomeDir() (string, error) { // Tries hard to succeed on various systems by temporarily tweaking directory // permissions and removing the destination file when necessary. -func withPreparedTarget(to string, f func() error) error { +func withPreparedTarget(from, to string, f func() error) error { // Make sure the destination directory is writeable toDir := filepath.Dir(to) if info, err := os.Stat(toDir); err == nil && info.IsDir() && info.Mode()&0200 == 0 { @@ -154,9 +156,11 @@ func withPreparedTarget(to string, f func() error) error { // On Windows, make sure the destination file is writeable (or we can't delete it) if runtime.GOOS == "windows" { os.Chmod(to, 0666) - err := os.Remove(to) - if err != nil && !os.IsNotExist(err) { - return err + if !strings.EqualFold(from, to) { + err := os.Remove(to) + if err != nil && !os.IsNotExist(err) { + return err + } } } return f() diff --git a/test/util.go b/test/util.go index f941192e..7da4e0c7 100644 --- a/test/util.go +++ b/test/util.go @@ -23,6 +23,7 @@ import ( "sort" "strings" "time" + "unicode" "github.com/syncthing/syncthing/internal/osutil" "github.com/syncthing/syncthing/internal/symlinks" @@ -133,9 +134,7 @@ func alterFiles(dir string) error { case r == 0 && comps > 2: // Delete every tenth file or directory, except top levels err := removeAll(path) - if err != nil { - return err - } + return err case r == 1 && info.Mode().IsRegular(): if info.Mode()&0200 != 0200 { @@ -161,10 +160,22 @@ func alterFiles(dir string) error { return err } err = fd.Close() - if err != nil { - return err - } + return err + // Change capitalization + case r == 2 && comps > 3 && rand.Float64() < 0.2: + base := []rune(filepath.Base(path)) + for i, r := range base { + if rand.Float64() < 0.5 { + base[i] = unicode.ToLower(r) + } else { + base[i] = unicode.ToUpper(r) + } + } + err = osutil.TryRename(path, strings.Replace(path, filepath.Base(path), string(base), 1)) + return err + + // Switch between files and directories case r == 2 && comps > 3 && rand.Float64() < 0.2: if !info.Mode().IsRegular() { err = removeAll(path) @@ -177,7 +188,7 @@ func alterFiles(dir string) error { return err } } else { - err := os.Remove(path) + err := osutil.Remove(path) if err != nil { return err } @@ -187,6 +198,7 @@ func alterFiles(dir string) error { } generateFiles(path, 10, 20, "../LICENSE") } + return err case r == 3 && comps > 2 && (info.Mode().IsRegular() || rand.Float64() < 0.2): rpath := filepath.Dir(path) @@ -195,10 +207,8 @@ func alterFiles(dir string) error { rpath = filepath.Join(rpath, "..") } } - err = os.Rename(path, filepath.Join(rpath, randomName())) - if err != nil { - return err - } + err = osutil.TryRename(path, filepath.Join(rpath, randomName())) + return err } return nil })