fileutil_linux.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Copyright (c) 2014 The fileutil 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 file.
  4. // +build !arm
  5. package fileutil
  6. import (
  7. "bytes"
  8. "io"
  9. "io/ioutil"
  10. "os"
  11. "strconv"
  12. "syscall"
  13. )
  14. func n(s []byte) byte {
  15. for i, c := range s {
  16. if c < '0' || c > '9' {
  17. s = s[:i]
  18. break
  19. }
  20. }
  21. v, _ := strconv.Atoi(string(s))
  22. return byte(v)
  23. }
  24. func init() {
  25. b, err := ioutil.ReadFile("/proc/sys/kernel/osrelease")
  26. if err != nil {
  27. panic(err)
  28. }
  29. tokens := bytes.Split(b, []byte("."))
  30. if len(tokens) > 3 {
  31. tokens = tokens[:3]
  32. }
  33. switch len(tokens) {
  34. case 3:
  35. // Supported since kernel 2.6.38
  36. if bytes.Compare([]byte{n(tokens[0]), n(tokens[1]), n(tokens[2])}, []byte{2, 6, 38}) < 0 {
  37. puncher = func(*os.File, int64, int64) error { return nil }
  38. }
  39. case 2:
  40. if bytes.Compare([]byte{n(tokens[0]), n(tokens[1])}, []byte{2, 7}) < 0 {
  41. puncher = func(*os.File, int64, int64) error { return nil }
  42. }
  43. default:
  44. puncher = func(*os.File, int64, int64) error { return nil }
  45. }
  46. }
  47. var puncher = func(f *os.File, off, len int64) error {
  48. const (
  49. /*
  50. /usr/include/linux$ grep FL_ falloc.h
  51. */
  52. _FALLOC_FL_KEEP_SIZE = 0x01 // default is extend size
  53. _FALLOC_FL_PUNCH_HOLE = 0x02 // de-allocates range
  54. )
  55. _, _, errno := syscall.Syscall6(
  56. syscall.SYS_FALLOCATE,
  57. uintptr(f.Fd()),
  58. uintptr(_FALLOC_FL_KEEP_SIZE|_FALLOC_FL_PUNCH_HOLE),
  59. uintptr(off),
  60. uintptr(len),
  61. 0, 0)
  62. if errno != 0 {
  63. return os.NewSyscallError("SYS_FALLOCATE", errno)
  64. }
  65. return nil
  66. }
  67. // PunchHole deallocates space inside a file in the byte range starting at
  68. // offset and continuing for len bytes. No-op for kernels < 2.6.38 (or < 2.7).
  69. func PunchHole(f *os.File, off, len int64) error {
  70. return puncher(f, off, len)
  71. }
  72. // Fadvise predeclares an access pattern for file data. See also 'man 2
  73. // posix_fadvise'.
  74. func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error {
  75. _, _, errno := syscall.Syscall6(
  76. syscall.SYS_FADVISE64,
  77. uintptr(f.Fd()),
  78. uintptr(off),
  79. uintptr(len),
  80. uintptr(advice),
  81. 0, 0)
  82. return os.NewSyscallError("SYS_FADVISE64", errno)
  83. }
  84. // IsEOF reports whether err is an EOF condition.
  85. func IsEOF(err error) bool { return err == io.EOF }