ioutil_linux.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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. //go:build !(linux && (amd64 || arm64 || loong64 || ppc64le || s390x || riscv64 || 386 || arm))
  8. package libc // import "modernc.org/libc"
  9. import (
  10. "fmt"
  11. "os"
  12. "sync"
  13. "time"
  14. "unsafe"
  15. "golang.org/x/sys/unix"
  16. "modernc.org/libc/errno"
  17. "modernc.org/libc/fcntl"
  18. )
  19. // Random number state.
  20. // We generate random temporary file names so that there's a good
  21. // chance the file doesn't exist yet - keeps the number of tries in
  22. // TempFile to a minimum.
  23. var randState uint32
  24. var randStateMu sync.Mutex
  25. func reseed() uint32 {
  26. return uint32(time.Now().UnixNano() + int64(os.Getpid()))
  27. }
  28. func nextRandom(x uintptr) {
  29. randStateMu.Lock()
  30. r := randState
  31. if r == 0 {
  32. r = reseed()
  33. }
  34. r = r*1664525 + 1013904223 // constants from Numerical Recipes
  35. randState = r
  36. randStateMu.Unlock()
  37. copy((*RawMem)(unsafe.Pointer(x))[:6:6], fmt.Sprintf("%06d", int(1e9+r%1e9)%1e6))
  38. }
  39. func tempFile(s, x uintptr, flags int32) (fd int, err error) {
  40. const maxTry = 10000
  41. nconflict := 0
  42. flags |= int32(os.O_RDWR | os.O_CREATE | os.O_EXCL | unix.O_LARGEFILE)
  43. for i := 0; i < maxTry; i++ {
  44. nextRandom(x)
  45. fdcwd := fcntl.AT_FDCWD
  46. n, _, err := unix.Syscall6(unix.SYS_OPENAT, uintptr(fdcwd), s, uintptr(flags), 0600, 0, 0)
  47. if err == 0 {
  48. return int(n), nil
  49. }
  50. if err != errno.EEXIST {
  51. return -1, err
  52. }
  53. if nconflict++; nconflict > 10 {
  54. randStateMu.Lock()
  55. randState = reseed()
  56. nconflict = 0
  57. randStateMu.Unlock()
  58. }
  59. }
  60. return -1, unix.Errno(errno.EEXIST)
  61. }