ioutil_linux.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE-GO file.
  4. // Modifications Copyright 2020 The Libc Authors. All rights reserved.
  5. // Use of this source code is governed by a BSD-style
  6. // license that can be found in the LICENSE file.
  7. package libc // import "modernc.org/libc"
  8. import (
  9. "fmt"
  10. "os"
  11. "sync"
  12. "time"
  13. "unsafe"
  14. "golang.org/x/sys/unix"
  15. "modernc.org/libc/errno"
  16. "modernc.org/libc/fcntl"
  17. )
  18. // Random number state.
  19. // We generate random temporary file names so that there's a good
  20. // chance the file doesn't exist yet - keeps the number of tries in
  21. // TempFile to a minimum.
  22. var randState uint32
  23. var randStateMu sync.Mutex
  24. func reseed() uint32 {
  25. return uint32(time.Now().UnixNano() + int64(os.Getpid()))
  26. }
  27. func nextRandom(x uintptr) {
  28. randStateMu.Lock()
  29. r := randState
  30. if r == 0 {
  31. r = reseed()
  32. }
  33. r = r*1664525 + 1013904223 // constants from Numerical Recipes
  34. randState = r
  35. randStateMu.Unlock()
  36. copy((*RawMem)(unsafe.Pointer(x))[:6:6], fmt.Sprintf("%06d", int(1e9+r%1e9)%1e6))
  37. }
  38. func tempFile(s, x uintptr, flags int32) (fd int, err error) {
  39. const maxTry = 10000
  40. nconflict := 0
  41. flags |= int32(os.O_RDWR | os.O_CREATE | os.O_EXCL | unix.O_LARGEFILE)
  42. for i := 0; i < maxTry; i++ {
  43. nextRandom(x)
  44. fdcwd := fcntl.AT_FDCWD
  45. n, _, err := unix.Syscall6(unix.SYS_OPENAT, uintptr(fdcwd), s, uintptr(flags), 0600, 0, 0)
  46. if err == 0 {
  47. return int(n), nil
  48. }
  49. if err != errno.EEXIST {
  50. return -1, err
  51. }
  52. if nconflict++; nconflict > 10 {
  53. randStateMu.Lock()
  54. randState = reseed()
  55. nconflict = 0
  56. randStateMu.Unlock()
  57. }
  58. }
  59. return -1, unix.Errno(errno.EEXIST)
  60. }