dirent.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright 2015 Google Inc. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package fuseutil
  15. import (
  16. "syscall"
  17. "unsafe"
  18. "github.com/jacobsa/fuse/fuseops"
  19. )
  20. type DirentType uint32
  21. const (
  22. DT_Unknown DirentType = 0
  23. DT_Socket DirentType = syscall.DT_SOCK
  24. DT_Link DirentType = syscall.DT_LNK
  25. DT_File DirentType = syscall.DT_REG
  26. DT_Block DirentType = syscall.DT_BLK
  27. DT_Directory DirentType = syscall.DT_DIR
  28. DT_Char DirentType = syscall.DT_CHR
  29. DT_FIFO DirentType = syscall.DT_FIFO
  30. )
  31. // A struct representing an entry within a directory file, describing a child.
  32. // See notes on fuseops.ReadDirOp and on WriteDirent for details.
  33. type Dirent struct {
  34. // The (opaque) offset within the directory file of the entry following this
  35. // one. See notes on fuseops.ReadDirOp.Offset for details.
  36. Offset fuseops.DirOffset
  37. // The inode of the child file or directory, and its name within the parent.
  38. Inode fuseops.InodeID
  39. Name string
  40. // The type of the child. The zero value (DT_Unknown) is legal, but means
  41. // that the kernel will need to call GetAttr when the type is needed.
  42. Type DirentType
  43. }
  44. // Write the supplied directory entry intto the given buffer in the format
  45. // expected in fuseops.ReadFileOp.Data, returning the number of bytes written.
  46. // Return zero if the entry would not fit.
  47. func WriteDirent(buf []byte, d Dirent) (n int) {
  48. // We want to write bytes with the layout of fuse_dirent
  49. // (http://goo.gl/BmFxob) in host order. The struct must be aligned according
  50. // to FUSE_DIRENT_ALIGN (http://goo.gl/UziWvH), which dictates 8-byte
  51. // alignment.
  52. type fuse_dirent struct {
  53. ino uint64
  54. off uint64
  55. namelen uint32
  56. type_ uint32
  57. name [0]byte
  58. }
  59. const direntAlignment = 8
  60. const direntSize = 8 + 8 + 4 + 4
  61. // Compute the number of bytes of padding we'll need to maintain alignment
  62. // for the next entry.
  63. var padLen int
  64. if len(d.Name)%direntAlignment != 0 {
  65. padLen = direntAlignment - (len(d.Name) % direntAlignment)
  66. }
  67. // Do we have enough room?
  68. totalLen := direntSize + len(d.Name) + padLen
  69. if totalLen > len(buf) {
  70. return
  71. }
  72. // Write the header.
  73. de := fuse_dirent{
  74. ino: uint64(d.Inode),
  75. off: uint64(d.Offset),
  76. namelen: uint32(len(d.Name)),
  77. type_: uint32(d.Type),
  78. }
  79. n += copy(buf[n:], (*[direntSize]byte)(unsafe.Pointer(&de))[:])
  80. // Write the name afterward.
  81. n += copy(buf[n:], d.Name)
  82. // Add any necessary padding.
  83. if padLen != 0 {
  84. var padding [direntAlignment]byte
  85. n += copy(buf[n:], padding[:padLen])
  86. }
  87. return
  88. }