tempfile.go 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. // Copyright (C) 2015 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package osutil
  7. import (
  8. "os"
  9. "path/filepath"
  10. "strconv"
  11. "sync"
  12. "time"
  13. "github.com/syncthing/syncthing/lib/fs"
  14. )
  15. var (
  16. rand uint32
  17. randmu sync.Mutex
  18. )
  19. func reseed() uint32 {
  20. return uint32(time.Now().UnixNano() + int64(os.Getpid()))
  21. }
  22. func nextSuffix() string {
  23. randmu.Lock()
  24. r := rand
  25. if r == 0 {
  26. r = reseed()
  27. }
  28. r = r*1664525 + 1013904223 // constants from Numerical Recipes
  29. rand = r
  30. randmu.Unlock()
  31. return strconv.Itoa(int(1e9 + r%1e9))[1:]
  32. }
  33. // TempFile creates a new temporary file in the directory dir
  34. // with a name beginning with prefix, opens the file for reading
  35. // and writing, and returns the resulting *os.File.
  36. // If dir is the empty string, TempFile uses the default directory
  37. // for temporary files (see os.TempDir).
  38. // Multiple programs calling TempFile simultaneously
  39. // will not choose the same file. The caller can use f.Name()
  40. // to find the pathname of the file. It is the caller's responsibility
  41. // to remove the file when no longer needed.
  42. func TempFile(filesystem fs.Filesystem, dir, prefix string) (f fs.File, err error) {
  43. nconflict := 0
  44. for i := 0; i < 10000; i++ {
  45. name := filepath.Join(dir, prefix+nextSuffix())
  46. f, err = filesystem.OpenFile(name, fs.OptReadWrite|fs.OptCreate|fs.OptExclusive, 0o600)
  47. if fs.IsExist(err) {
  48. if nconflict++; nconflict > 10 {
  49. randmu.Lock()
  50. rand = reseed()
  51. randmu.Unlock()
  52. }
  53. continue
  54. }
  55. break
  56. }
  57. return
  58. }