osutil.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
  2. // All rights reserved. Use of this source code is governed by an MIT-style
  3. // license that can be found in the LICENSE file.
  4. // Package osutil implements utilities for native OS support.
  5. package osutil
  6. import (
  7. "os"
  8. "path/filepath"
  9. "runtime"
  10. "sync"
  11. )
  12. // Try to keep this entire operation atomic-like. We shouldn't be doing this
  13. // often enough that there is any contention on this lock.
  14. var renameLock sync.Mutex
  15. // Rename renames a file, while trying hard to succeed on various systems by
  16. // temporarily tweaking directory permissions and removing the destination
  17. // file when necessary. Will make sure to delete the from file if the
  18. // operation fails, so use only for situations like committing a temp file to
  19. // it's final location.
  20. func Rename(from, to string) error {
  21. renameLock.Lock()
  22. defer renameLock.Unlock()
  23. // Make sure the destination directory is writeable
  24. toDir := filepath.Dir(to)
  25. if info, err := os.Stat(toDir); err == nil {
  26. os.Chmod(toDir, 0777)
  27. defer os.Chmod(toDir, info.Mode())
  28. }
  29. // On Windows, make sure the destination file is writeable (or we can't delete it)
  30. if runtime.GOOS == "windows" {
  31. os.Chmod(to, 0666)
  32. err := os.Remove(to)
  33. if err != nil && !os.IsNotExist(err) {
  34. return err
  35. }
  36. }
  37. // Don't leave a dangling temp file in case of rename error
  38. defer os.Remove(from)
  39. return os.Rename(from, to)
  40. }