weedfs_attr.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. package mount
  2. import (
  3. "os"
  4. "syscall"
  5. "time"
  6. "github.com/hanwen/go-fuse/v2/fuse"
  7. "github.com/seaweedfs/seaweedfs/weed/filer"
  8. "github.com/seaweedfs/seaweedfs/weed/glog"
  9. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  10. "github.com/seaweedfs/seaweedfs/weed/util"
  11. )
  12. func (wfs *WFS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
  13. glog.V(4).Infof("GetAttr %v", input.NodeId)
  14. if input.NodeId == 1 {
  15. wfs.setRootAttr(out)
  16. return fuse.OK
  17. }
  18. inode := input.NodeId
  19. _, _, entry, status := wfs.maybeReadEntry(inode)
  20. if status == fuse.OK {
  21. out.AttrValid = 1
  22. wfs.setAttrByPbEntry(&out.Attr, inode, entry, true)
  23. return status
  24. } else {
  25. if fh, found := wfs.fhMap.FindFileHandle(inode); found {
  26. out.AttrValid = 1
  27. // Use shared lock to prevent race with Write operations
  28. fhActiveLock := wfs.fhLockTable.AcquireLock("GetAttr", fh.fh, util.SharedLock)
  29. wfs.setAttrByPbEntry(&out.Attr, inode, fh.entry.GetEntry(), true)
  30. wfs.fhLockTable.ReleaseLock(fh.fh, fhActiveLock)
  31. out.Nlink = 0
  32. return fuse.OK
  33. }
  34. }
  35. return status
  36. }
  37. func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
  38. if wfs.IsOverQuota {
  39. return fuse.Status(syscall.ENOSPC)
  40. }
  41. path, fh, entry, status := wfs.maybeReadEntry(input.NodeId)
  42. if status != fuse.OK || entry == nil {
  43. return status
  44. }
  45. if fh != nil {
  46. fh.entryLock.Lock()
  47. defer fh.entryLock.Unlock()
  48. }
  49. wormEnforced, wormEnabled := wfs.wormEnforcedForEntry(path, entry)
  50. if wormEnforced {
  51. return fuse.EPERM
  52. }
  53. if size, ok := input.GetSize(); ok {
  54. glog.V(4).Infof("%v setattr set size=%v chunks=%d", path, size, len(entry.GetChunks()))
  55. if size < filer.FileSize(entry) {
  56. // fmt.Printf("truncate %v \n", fullPath)
  57. var chunks []*filer_pb.FileChunk
  58. var truncatedChunks []*filer_pb.FileChunk
  59. for _, chunk := range entry.GetChunks() {
  60. int64Size := int64(chunk.Size)
  61. if chunk.Offset+int64Size > int64(size) {
  62. // this chunk is truncated
  63. int64Size = int64(size) - chunk.Offset
  64. if int64Size > 0 {
  65. chunks = append(chunks, chunk)
  66. glog.V(4).Infof("truncated chunk %+v from %d to %d\n", chunk.GetFileIdString(), chunk.Size, int64Size)
  67. chunk.Size = uint64(int64Size)
  68. } else {
  69. glog.V(4).Infof("truncated whole chunk %+v\n", chunk.GetFileIdString())
  70. truncatedChunks = append(truncatedChunks, chunk)
  71. }
  72. } else {
  73. chunks = append(chunks, chunk)
  74. }
  75. }
  76. // set the new chunks and reset entry cache
  77. entry.Chunks = chunks
  78. if fh != nil {
  79. fh.entryChunkGroup.SetChunks(chunks)
  80. }
  81. }
  82. entry.Attributes.Mtime = time.Now().Unix()
  83. entry.Attributes.FileSize = size
  84. }
  85. if mode, ok := input.GetMode(); ok {
  86. // commit the file to worm when it is set to readonly at the first time
  87. if entry.WormEnforcedAtTsNs == 0 && wormEnabled && !hasWritePermission(mode) {
  88. entry.WormEnforcedAtTsNs = time.Now().UnixNano()
  89. }
  90. // glog.V(4).Infof("setAttr mode %o", mode)
  91. entry.Attributes.FileMode = chmod(entry.Attributes.FileMode, mode)
  92. if input.NodeId == 1 {
  93. wfs.option.MountMode = os.FileMode(chmod(uint32(wfs.option.MountMode), mode))
  94. }
  95. }
  96. if uid, ok := input.GetUID(); ok {
  97. entry.Attributes.Uid = uid
  98. if input.NodeId == 1 {
  99. wfs.option.MountUid = uid
  100. }
  101. }
  102. if gid, ok := input.GetGID(); ok {
  103. entry.Attributes.Gid = gid
  104. if input.NodeId == 1 {
  105. wfs.option.MountGid = gid
  106. }
  107. }
  108. if atime, ok := input.GetATime(); ok {
  109. entry.Attributes.Mtime = atime.Unix()
  110. }
  111. if mtime, ok := input.GetMTime(); ok {
  112. entry.Attributes.Mtime = mtime.Unix()
  113. }
  114. out.AttrValid = 1
  115. size, includeSize := input.GetSize()
  116. if includeSize {
  117. out.Attr.Size = size
  118. }
  119. wfs.setAttrByPbEntry(&out.Attr, input.NodeId, entry, !includeSize)
  120. if fh != nil {
  121. fh.dirtyMetadata = true
  122. return fuse.OK
  123. }
  124. return wfs.saveEntry(path, entry)
  125. }
  126. func (wfs *WFS) setRootAttr(out *fuse.AttrOut) {
  127. now := uint64(time.Now().Unix())
  128. out.AttrValid = 119
  129. out.Ino = 1
  130. setBlksize(&out.Attr, blockSize)
  131. out.Uid = wfs.option.MountUid
  132. out.Gid = wfs.option.MountGid
  133. out.Mtime = now
  134. out.Ctime = now
  135. out.Atime = now
  136. out.Mode = toSyscallType(os.ModeDir) | uint32(wfs.option.MountMode)
  137. out.Nlink = 1
  138. }
  139. func (wfs *WFS) setAttrByPbEntry(out *fuse.Attr, inode uint64, entry *filer_pb.Entry, calculateSize bool) {
  140. out.Ino = inode
  141. setBlksize(out, blockSize)
  142. if entry == nil {
  143. return
  144. }
  145. if entry.Attributes != nil && entry.Attributes.Inode != 0 {
  146. out.Ino = entry.Attributes.Inode
  147. }
  148. if calculateSize {
  149. out.Size = filer.FileSize(entry)
  150. }
  151. if entry.FileMode()&os.ModeSymlink != 0 {
  152. out.Size = uint64(len(entry.Attributes.SymlinkTarget))
  153. }
  154. out.Blocks = (out.Size + blockSize - 1) / blockSize
  155. out.Mtime = uint64(entry.Attributes.Mtime)
  156. out.Ctime = uint64(entry.Attributes.Mtime)
  157. out.Atime = uint64(entry.Attributes.Mtime)
  158. out.Mode = toSyscallMode(os.FileMode(entry.Attributes.FileMode))
  159. if entry.HardLinkCounter > 0 {
  160. out.Nlink = uint32(entry.HardLinkCounter)
  161. } else {
  162. out.Nlink = 1
  163. }
  164. out.Uid = entry.Attributes.Uid
  165. out.Gid = entry.Attributes.Gid
  166. out.Rdev = entry.Attributes.Rdev
  167. }
  168. func (wfs *WFS) setAttrByFilerEntry(out *fuse.Attr, inode uint64, entry *filer.Entry) {
  169. out.Ino = inode
  170. out.Size = entry.FileSize
  171. if entry.Mode&os.ModeSymlink != 0 {
  172. out.Size = uint64(len(entry.SymlinkTarget))
  173. }
  174. out.Blocks = (out.Size + blockSize - 1) / blockSize
  175. setBlksize(out, blockSize)
  176. out.Atime = uint64(entry.Attr.Mtime.Unix())
  177. out.Mtime = uint64(entry.Attr.Mtime.Unix())
  178. out.Ctime = uint64(entry.Attr.Mtime.Unix())
  179. out.Mode = toSyscallMode(entry.Attr.Mode)
  180. if entry.HardLinkCounter > 0 {
  181. out.Nlink = uint32(entry.HardLinkCounter)
  182. } else {
  183. out.Nlink = 1
  184. }
  185. out.Uid = entry.Attr.Uid
  186. out.Gid = entry.Attr.Gid
  187. out.Rdev = entry.Attr.Rdev
  188. }
  189. func (wfs *WFS) outputPbEntry(out *fuse.EntryOut, inode uint64, entry *filer_pb.Entry) {
  190. out.NodeId = inode
  191. out.Generation = 1
  192. out.EntryValid = 1
  193. out.AttrValid = 1
  194. wfs.setAttrByPbEntry(&out.Attr, inode, entry, true)
  195. }
  196. func (wfs *WFS) outputFilerEntry(out *fuse.EntryOut, inode uint64, entry *filer.Entry) {
  197. out.NodeId = inode
  198. out.Generation = 1
  199. out.EntryValid = 1
  200. out.AttrValid = 1
  201. wfs.setAttrByFilerEntry(&out.Attr, inode, entry)
  202. }
  203. func chmod(existing uint32, mode uint32) uint32 {
  204. return existing&^07777 | mode&07777
  205. }
  206. const ownerWrite = 0o200
  207. const groupWrite = 0o020
  208. const otherWrite = 0o002
  209. func hasWritePermission(mode uint32) bool {
  210. return (mode&ownerWrite != 0) || (mode&groupWrite != 0) || (mode&otherWrite != 0)
  211. }
  212. func toSyscallMode(mode os.FileMode) uint32 {
  213. return toSyscallType(mode) | uint32(mode)
  214. }
  215. func toSyscallType(mode os.FileMode) uint32 {
  216. switch mode & os.ModeType {
  217. case os.ModeDir:
  218. return syscall.S_IFDIR
  219. case os.ModeSymlink:
  220. return syscall.S_IFLNK
  221. case os.ModeNamedPipe:
  222. return syscall.S_IFIFO
  223. case os.ModeSocket:
  224. return syscall.S_IFSOCK
  225. case os.ModeDevice:
  226. return syscall.S_IFBLK
  227. case os.ModeCharDevice:
  228. return syscall.S_IFCHR
  229. default:
  230. return syscall.S_IFREG
  231. }
  232. }
  233. func toOsFileType(mode uint32) os.FileMode {
  234. switch mode & (syscall.S_IFMT & 0xffff) {
  235. case syscall.S_IFDIR:
  236. return os.ModeDir
  237. case syscall.S_IFLNK:
  238. return os.ModeSymlink
  239. case syscall.S_IFIFO:
  240. return os.ModeNamedPipe
  241. case syscall.S_IFSOCK:
  242. return os.ModeSocket
  243. case syscall.S_IFBLK:
  244. return os.ModeDevice
  245. case syscall.S_IFCHR:
  246. return os.ModeCharDevice
  247. default:
  248. return 0
  249. }
  250. }
  251. func toOsFileMode(mode uint32) os.FileMode {
  252. return toOsFileType(mode) | os.FileMode(mode&07777)
  253. }