You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

282 lines
7.1 KiB

2 months ago
more solid weed mount (#4089) * compare chunks by timestamp * fix slab clearing error * fix test compilation * move oldest chunk to sealed, instead of by fullness * lock on fh.entryViewCache * remove verbose logs * revert slat clearing * less logs * less logs * track write and read by timestamp * remove useless logic * add entry lock on file handle release * use mem chunk only, swap file chunk has problems * comment out code that maybe used later * add debug mode to compare data read and write * more efficient readResolvedChunks with linked list * small optimization * fix test compilation * minor fix on writer * add SeparateGarbageChunks * group chunks into sections * turn off debug mode * fix tests * fix tests * tmp enable swap file chunk * Revert "tmp enable swap file chunk" This reverts commit 985137ec472924e4815f258189f6ca9f2168a0a7. * simple refactoring * simple refactoring * do not re-use swap file chunk. Sealed chunks should not be re-used. * comment out debugging facilities * either mem chunk or swap file chunk is fine now * remove orderedMutex as *semaphore.Weighted not found impactful * optimize size calculation for changing large files * optimize performance to avoid going through the long list of chunks * still problems with swap file chunk * rename * tiny optimization * swap file chunk save only successfully read data * fix * enable both mem and swap file chunk * resolve chunks with range * rename * fix chunk interval list * also change file handle chunk group when adding chunks * pick in-active chunk with time-decayed counter * fix compilation * avoid nil with empty fh.entry * refactoring * rename * rename * refactor visible intervals to *list.List * refactor chunkViews to *list.List * add IntervalList for generic interval list * change visible interval to use IntervalList in generics * cahnge chunkViews to *IntervalList[*ChunkView] * use NewFileChunkSection to create * rename variables * refactor * fix renaming leftover * renaming * renaming * add insert interval * interval list adds lock * incrementally add chunks to readers Fixes: 1. set start and stop offset for the value object 2. clone the value object 3. use pointer instead of copy-by-value when passing to interval.Value 4. use insert interval since adding chunk could be out of order * fix tests compilation * fix tests compilation
2 years ago
4 months ago
more solid weed mount (#4089) * compare chunks by timestamp * fix slab clearing error * fix test compilation * move oldest chunk to sealed, instead of by fullness * lock on fh.entryViewCache * remove verbose logs * revert slat clearing * less logs * less logs * track write and read by timestamp * remove useless logic * add entry lock on file handle release * use mem chunk only, swap file chunk has problems * comment out code that maybe used later * add debug mode to compare data read and write * more efficient readResolvedChunks with linked list * small optimization * fix test compilation * minor fix on writer * add SeparateGarbageChunks * group chunks into sections * turn off debug mode * fix tests * fix tests * tmp enable swap file chunk * Revert "tmp enable swap file chunk" This reverts commit 985137ec472924e4815f258189f6ca9f2168a0a7. * simple refactoring * simple refactoring * do not re-use swap file chunk. Sealed chunks should not be re-used. * comment out debugging facilities * either mem chunk or swap file chunk is fine now * remove orderedMutex as *semaphore.Weighted not found impactful * optimize size calculation for changing large files * optimize performance to avoid going through the long list of chunks * still problems with swap file chunk * rename * tiny optimization * swap file chunk save only successfully read data * fix * enable both mem and swap file chunk * resolve chunks with range * rename * fix chunk interval list * also change file handle chunk group when adding chunks * pick in-active chunk with time-decayed counter * fix compilation * avoid nil with empty fh.entry * refactoring * rename * rename * refactor visible intervals to *list.List * refactor chunkViews to *list.List * add IntervalList for generic interval list * change visible interval to use IntervalList in generics * cahnge chunkViews to *IntervalList[*ChunkView] * use NewFileChunkSection to create * rename variables * refactor * fix renaming leftover * renaming * renaming * add insert interval * interval list adds lock * incrementally add chunks to readers Fixes: 1. set start and stop offset for the value object 2. clone the value object 3. use pointer instead of copy-by-value when passing to interval.Value 4. use insert interval since adding chunk could be out of order * fix tests compilation * fix tests compilation
2 years ago
more solid weed mount (#4089) * compare chunks by timestamp * fix slab clearing error * fix test compilation * move oldest chunk to sealed, instead of by fullness * lock on fh.entryViewCache * remove verbose logs * revert slat clearing * less logs * less logs * track write and read by timestamp * remove useless logic * add entry lock on file handle release * use mem chunk only, swap file chunk has problems * comment out code that maybe used later * add debug mode to compare data read and write * more efficient readResolvedChunks with linked list * small optimization * fix test compilation * minor fix on writer * add SeparateGarbageChunks * group chunks into sections * turn off debug mode * fix tests * fix tests * tmp enable swap file chunk * Revert "tmp enable swap file chunk" This reverts commit 985137ec472924e4815f258189f6ca9f2168a0a7. * simple refactoring * simple refactoring * do not re-use swap file chunk. Sealed chunks should not be re-used. * comment out debugging facilities * either mem chunk or swap file chunk is fine now * remove orderedMutex as *semaphore.Weighted not found impactful * optimize size calculation for changing large files * optimize performance to avoid going through the long list of chunks * still problems with swap file chunk * rename * tiny optimization * swap file chunk save only successfully read data * fix * enable both mem and swap file chunk * resolve chunks with range * rename * fix chunk interval list * also change file handle chunk group when adding chunks * pick in-active chunk with time-decayed counter * fix compilation * avoid nil with empty fh.entry * refactoring * rename * rename * refactor visible intervals to *list.List * refactor chunkViews to *list.List * add IntervalList for generic interval list * change visible interval to use IntervalList in generics * cahnge chunkViews to *IntervalList[*ChunkView] * use NewFileChunkSection to create * rename variables * refactor * fix renaming leftover * renaming * renaming * add insert interval * interval list adds lock * incrementally add chunks to readers Fixes: 1. set start and stop offset for the value object 2. clone the value object 3. use pointer instead of copy-by-value when passing to interval.Value 4. use insert interval since adding chunk could be out of order * fix tests compilation * fix tests compilation
2 years ago
more solid weed mount (#4089) * compare chunks by timestamp * fix slab clearing error * fix test compilation * move oldest chunk to sealed, instead of by fullness * lock on fh.entryViewCache * remove verbose logs * revert slat clearing * less logs * less logs * track write and read by timestamp * remove useless logic * add entry lock on file handle release * use mem chunk only, swap file chunk has problems * comment out code that maybe used later * add debug mode to compare data read and write * more efficient readResolvedChunks with linked list * small optimization * fix test compilation * minor fix on writer * add SeparateGarbageChunks * group chunks into sections * turn off debug mode * fix tests * fix tests * tmp enable swap file chunk * Revert "tmp enable swap file chunk" This reverts commit 985137ec472924e4815f258189f6ca9f2168a0a7. * simple refactoring * simple refactoring * do not re-use swap file chunk. Sealed chunks should not be re-used. * comment out debugging facilities * either mem chunk or swap file chunk is fine now * remove orderedMutex as *semaphore.Weighted not found impactful * optimize size calculation for changing large files * optimize performance to avoid going through the long list of chunks * still problems with swap file chunk * rename * tiny optimization * swap file chunk save only successfully read data * fix * enable both mem and swap file chunk * resolve chunks with range * rename * fix chunk interval list * also change file handle chunk group when adding chunks * pick in-active chunk with time-decayed counter * fix compilation * avoid nil with empty fh.entry * refactoring * rename * rename * refactor visible intervals to *list.List * refactor chunkViews to *list.List * add IntervalList for generic interval list * change visible interval to use IntervalList in generics * cahnge chunkViews to *IntervalList[*ChunkView] * use NewFileChunkSection to create * rename variables * refactor * fix renaming leftover * renaming * renaming * add insert interval * interval list adds lock * incrementally add chunks to readers Fixes: 1. set start and stop offset for the value object 2. clone the value object 3. use pointer instead of copy-by-value when passing to interval.Value 4. use insert interval since adding chunk could be out of order * fix tests compilation * fix tests compilation
2 years ago
3 years ago
3 years ago
more solid weed mount (#4089) * compare chunks by timestamp * fix slab clearing error * fix test compilation * move oldest chunk to sealed, instead of by fullness * lock on fh.entryViewCache * remove verbose logs * revert slat clearing * less logs * less logs * track write and read by timestamp * remove useless logic * add entry lock on file handle release * use mem chunk only, swap file chunk has problems * comment out code that maybe used later * add debug mode to compare data read and write * more efficient readResolvedChunks with linked list * small optimization * fix test compilation * minor fix on writer * add SeparateGarbageChunks * group chunks into sections * turn off debug mode * fix tests * fix tests * tmp enable swap file chunk * Revert "tmp enable swap file chunk" This reverts commit 985137ec472924e4815f258189f6ca9f2168a0a7. * simple refactoring * simple refactoring * do not re-use swap file chunk. Sealed chunks should not be re-used. * comment out debugging facilities * either mem chunk or swap file chunk is fine now * remove orderedMutex as *semaphore.Weighted not found impactful * optimize size calculation for changing large files * optimize performance to avoid going through the long list of chunks * still problems with swap file chunk * rename * tiny optimization * swap file chunk save only successfully read data * fix * enable both mem and swap file chunk * resolve chunks with range * rename * fix chunk interval list * also change file handle chunk group when adding chunks * pick in-active chunk with time-decayed counter * fix compilation * avoid nil with empty fh.entry * refactoring * rename * rename * refactor visible intervals to *list.List * refactor chunkViews to *list.List * add IntervalList for generic interval list * change visible interval to use IntervalList in generics * cahnge chunkViews to *IntervalList[*ChunkView] * use NewFileChunkSection to create * rename variables * refactor * fix renaming leftover * renaming * renaming * add insert interval * interval list adds lock * incrementally add chunks to readers Fixes: 1. set start and stop offset for the value object 2. clone the value object 3. use pointer instead of copy-by-value when passing to interval.Value 4. use insert interval since adding chunk could be out of order * fix tests compilation * fix tests compilation
2 years ago
more solid weed mount (#4089) * compare chunks by timestamp * fix slab clearing error * fix test compilation * move oldest chunk to sealed, instead of by fullness * lock on fh.entryViewCache * remove verbose logs * revert slat clearing * less logs * less logs * track write and read by timestamp * remove useless logic * add entry lock on file handle release * use mem chunk only, swap file chunk has problems * comment out code that maybe used later * add debug mode to compare data read and write * more efficient readResolvedChunks with linked list * small optimization * fix test compilation * minor fix on writer * add SeparateGarbageChunks * group chunks into sections * turn off debug mode * fix tests * fix tests * tmp enable swap file chunk * Revert "tmp enable swap file chunk" This reverts commit 985137ec472924e4815f258189f6ca9f2168a0a7. * simple refactoring * simple refactoring * do not re-use swap file chunk. Sealed chunks should not be re-used. * comment out debugging facilities * either mem chunk or swap file chunk is fine now * remove orderedMutex as *semaphore.Weighted not found impactful * optimize size calculation for changing large files * optimize performance to avoid going through the long list of chunks * still problems with swap file chunk * rename * tiny optimization * swap file chunk save only successfully read data * fix * enable both mem and swap file chunk * resolve chunks with range * rename * fix chunk interval list * also change file handle chunk group when adding chunks * pick in-active chunk with time-decayed counter * fix compilation * avoid nil with empty fh.entry * refactoring * rename * rename * refactor visible intervals to *list.List * refactor chunkViews to *list.List * add IntervalList for generic interval list * change visible interval to use IntervalList in generics * cahnge chunkViews to *IntervalList[*ChunkView] * use NewFileChunkSection to create * rename variables * refactor * fix renaming leftover * renaming * renaming * add insert interval * interval list adds lock * incrementally add chunks to readers Fixes: 1. set start and stop offset for the value object 2. clone the value object 3. use pointer instead of copy-by-value when passing to interval.Value 4. use insert interval since adding chunk could be out of order * fix tests compilation * fix tests compilation
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
more solid weed mount (#4089) * compare chunks by timestamp * fix slab clearing error * fix test compilation * move oldest chunk to sealed, instead of by fullness * lock on fh.entryViewCache * remove verbose logs * revert slat clearing * less logs * less logs * track write and read by timestamp * remove useless logic * add entry lock on file handle release * use mem chunk only, swap file chunk has problems * comment out code that maybe used later * add debug mode to compare data read and write * more efficient readResolvedChunks with linked list * small optimization * fix test compilation * minor fix on writer * add SeparateGarbageChunks * group chunks into sections * turn off debug mode * fix tests * fix tests * tmp enable swap file chunk * Revert "tmp enable swap file chunk" This reverts commit 985137ec472924e4815f258189f6ca9f2168a0a7. * simple refactoring * simple refactoring * do not re-use swap file chunk. Sealed chunks should not be re-used. * comment out debugging facilities * either mem chunk or swap file chunk is fine now * remove orderedMutex as *semaphore.Weighted not found impactful * optimize size calculation for changing large files * optimize performance to avoid going through the long list of chunks * still problems with swap file chunk * rename * tiny optimization * swap file chunk save only successfully read data * fix * enable both mem and swap file chunk * resolve chunks with range * rename * fix chunk interval list * also change file handle chunk group when adding chunks * pick in-active chunk with time-decayed counter * fix compilation * avoid nil with empty fh.entry * refactoring * rename * rename * refactor visible intervals to *list.List * refactor chunkViews to *list.List * add IntervalList for generic interval list * change visible interval to use IntervalList in generics * cahnge chunkViews to *IntervalList[*ChunkView] * use NewFileChunkSection to create * rename variables * refactor * fix renaming leftover * renaming * renaming * add insert interval * interval list adds lock * incrementally add chunks to readers Fixes: 1. set start and stop offset for the value object 2. clone the value object 3. use pointer instead of copy-by-value when passing to interval.Value 4. use insert interval since adding chunk could be out of order * fix tests compilation * fix tests compilation
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  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. )
  11. func (wfs *WFS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
  12. glog.V(4).Infof("GetAttr %v", input.NodeId)
  13. if input.NodeId == 1 {
  14. wfs.setRootAttr(out)
  15. return fuse.OK
  16. }
  17. inode := input.NodeId
  18. _, _, entry, status := wfs.maybeReadEntry(inode)
  19. if status == fuse.OK {
  20. out.AttrValid = 1
  21. wfs.setAttrByPbEntry(&out.Attr, inode, entry, true)
  22. return status
  23. } else {
  24. if fh, found := wfs.fhMap.FindFileHandle(inode); found {
  25. out.AttrValid = 1
  26. wfs.setAttrByPbEntry(&out.Attr, inode, fh.entry.GetEntry(), true)
  27. out.Nlink = 0
  28. return fuse.OK
  29. }
  30. }
  31. return status
  32. }
  33. func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
  34. if wfs.IsOverQuota {
  35. return fuse.Status(syscall.ENOSPC)
  36. }
  37. path, fh, entry, status := wfs.maybeReadEntry(input.NodeId)
  38. if status != fuse.OK || entry == nil {
  39. return status
  40. }
  41. if fh != nil {
  42. fh.entryLock.Lock()
  43. defer fh.entryLock.Unlock()
  44. }
  45. wormEnforced, wormEnabled := wfs.wormEnforcedForEntry(path, entry)
  46. if wormEnforced {
  47. return fuse.EPERM
  48. }
  49. if size, ok := input.GetSize(); ok {
  50. glog.V(4).Infof("%v setattr set size=%v chunks=%d", path, size, len(entry.GetChunks()))
  51. if size < filer.FileSize(entry) {
  52. // fmt.Printf("truncate %v \n", fullPath)
  53. var chunks []*filer_pb.FileChunk
  54. var truncatedChunks []*filer_pb.FileChunk
  55. for _, chunk := range entry.GetChunks() {
  56. int64Size := int64(chunk.Size)
  57. if chunk.Offset+int64Size > int64(size) {
  58. // this chunk is truncated
  59. int64Size = int64(size) - chunk.Offset
  60. if int64Size > 0 {
  61. chunks = append(chunks, chunk)
  62. glog.V(4).Infof("truncated chunk %+v from %d to %d\n", chunk.GetFileIdString(), chunk.Size, int64Size)
  63. chunk.Size = uint64(int64Size)
  64. } else {
  65. glog.V(4).Infof("truncated whole chunk %+v\n", chunk.GetFileIdString())
  66. truncatedChunks = append(truncatedChunks, chunk)
  67. }
  68. } else {
  69. chunks = append(chunks, chunk)
  70. }
  71. }
  72. // set the new chunks and reset entry cache
  73. entry.Chunks = chunks
  74. if fh != nil {
  75. fh.entryChunkGroup.SetChunks(chunks)
  76. }
  77. }
  78. entry.Attributes.Mtime = time.Now().Unix()
  79. entry.Attributes.FileSize = size
  80. }
  81. if mode, ok := input.GetMode(); ok {
  82. // commit the file to worm when it is set to readonly at the first time
  83. if entry.WormEnforcedAtTsNs == 0 && wormEnabled && !hasWritePermission(mode) {
  84. entry.WormEnforcedAtTsNs = time.Now().UnixNano()
  85. }
  86. // glog.V(4).Infof("setAttr mode %o", mode)
  87. entry.Attributes.FileMode = chmod(entry.Attributes.FileMode, mode)
  88. if input.NodeId == 1 {
  89. wfs.option.MountMode = os.FileMode(chmod(uint32(wfs.option.MountMode), mode))
  90. }
  91. }
  92. if uid, ok := input.GetUID(); ok {
  93. entry.Attributes.Uid = uid
  94. if input.NodeId == 1 {
  95. wfs.option.MountUid = uid
  96. }
  97. }
  98. if gid, ok := input.GetGID(); ok {
  99. entry.Attributes.Gid = gid
  100. if input.NodeId == 1 {
  101. wfs.option.MountGid = gid
  102. }
  103. }
  104. if atime, ok := input.GetATime(); ok {
  105. entry.Attributes.Mtime = atime.Unix()
  106. }
  107. if mtime, ok := input.GetMTime(); ok {
  108. entry.Attributes.Mtime = mtime.Unix()
  109. }
  110. out.AttrValid = 1
  111. size, includeSize := input.GetSize()
  112. if includeSize {
  113. out.Attr.Size = size
  114. }
  115. wfs.setAttrByPbEntry(&out.Attr, input.NodeId, entry, !includeSize)
  116. if fh != nil {
  117. fh.dirtyMetadata = true
  118. return fuse.OK
  119. }
  120. return wfs.saveEntry(path, entry)
  121. }
  122. func (wfs *WFS) setRootAttr(out *fuse.AttrOut) {
  123. now := uint64(time.Now().Unix())
  124. out.AttrValid = 119
  125. out.Ino = 1
  126. setBlksize(&out.Attr, blockSize)
  127. out.Uid = wfs.option.MountUid
  128. out.Gid = wfs.option.MountGid
  129. out.Mtime = now
  130. out.Ctime = now
  131. out.Atime = now
  132. out.Mode = toSyscallType(os.ModeDir) | uint32(wfs.option.MountMode)
  133. out.Nlink = 1
  134. }
  135. func (wfs *WFS) setAttrByPbEntry(out *fuse.Attr, inode uint64, entry *filer_pb.Entry, calculateSize bool) {
  136. out.Ino = inode
  137. setBlksize(out, blockSize)
  138. if entry == nil {
  139. return
  140. }
  141. if entry.Attributes != nil && entry.Attributes.Inode != 0 {
  142. out.Ino = entry.Attributes.Inode
  143. }
  144. if calculateSize {
  145. out.Size = filer.FileSize(entry)
  146. }
  147. if entry.FileMode()&os.ModeSymlink != 0 {
  148. out.Size = uint64(len(entry.Attributes.SymlinkTarget))
  149. }
  150. out.Blocks = (out.Size + blockSize - 1) / blockSize
  151. out.Mtime = uint64(entry.Attributes.Mtime)
  152. out.Ctime = uint64(entry.Attributes.Mtime)
  153. out.Atime = uint64(entry.Attributes.Mtime)
  154. out.Mode = toSyscallMode(os.FileMode(entry.Attributes.FileMode))
  155. if entry.HardLinkCounter > 0 {
  156. out.Nlink = uint32(entry.HardLinkCounter)
  157. } else {
  158. out.Nlink = 1
  159. }
  160. out.Uid = entry.Attributes.Uid
  161. out.Gid = entry.Attributes.Gid
  162. out.Rdev = entry.Attributes.Rdev
  163. }
  164. func (wfs *WFS) setAttrByFilerEntry(out *fuse.Attr, inode uint64, entry *filer.Entry) {
  165. out.Ino = inode
  166. out.Size = entry.FileSize
  167. if entry.Mode&os.ModeSymlink != 0 {
  168. out.Size = uint64(len(entry.SymlinkTarget))
  169. }
  170. out.Blocks = (out.Size + blockSize - 1) / blockSize
  171. setBlksize(out, blockSize)
  172. out.Atime = uint64(entry.Attr.Mtime.Unix())
  173. out.Mtime = uint64(entry.Attr.Mtime.Unix())
  174. out.Ctime = uint64(entry.Attr.Mtime.Unix())
  175. out.Mode = toSyscallMode(entry.Attr.Mode)
  176. if entry.HardLinkCounter > 0 {
  177. out.Nlink = uint32(entry.HardLinkCounter)
  178. } else {
  179. out.Nlink = 1
  180. }
  181. out.Uid = entry.Attr.Uid
  182. out.Gid = entry.Attr.Gid
  183. out.Rdev = entry.Attr.Rdev
  184. }
  185. func (wfs *WFS) outputPbEntry(out *fuse.EntryOut, inode uint64, entry *filer_pb.Entry) {
  186. out.NodeId = inode
  187. out.Generation = 1
  188. out.EntryValid = 1
  189. out.AttrValid = 1
  190. wfs.setAttrByPbEntry(&out.Attr, inode, entry, true)
  191. }
  192. func (wfs *WFS) outputFilerEntry(out *fuse.EntryOut, inode uint64, entry *filer.Entry) {
  193. out.NodeId = inode
  194. out.Generation = 1
  195. out.EntryValid = 1
  196. out.AttrValid = 1
  197. wfs.setAttrByFilerEntry(&out.Attr, inode, entry)
  198. }
  199. func chmod(existing uint32, mode uint32) uint32 {
  200. return existing&^07777 | mode&07777
  201. }
  202. const ownerWrite = 0o200
  203. const groupWrite = 0o020
  204. const otherWrite = 0o002
  205. func hasWritePermission(mode uint32) bool {
  206. return (mode&ownerWrite != 0) || (mode&groupWrite != 0) || (mode&otherWrite != 0)
  207. }
  208. func toSyscallMode(mode os.FileMode) uint32 {
  209. return toSyscallType(mode) | uint32(mode)
  210. }
  211. func toSyscallType(mode os.FileMode) uint32 {
  212. switch mode & os.ModeType {
  213. case os.ModeDir:
  214. return syscall.S_IFDIR
  215. case os.ModeSymlink:
  216. return syscall.S_IFLNK
  217. case os.ModeNamedPipe:
  218. return syscall.S_IFIFO
  219. case os.ModeSocket:
  220. return syscall.S_IFSOCK
  221. case os.ModeDevice:
  222. return syscall.S_IFBLK
  223. case os.ModeCharDevice:
  224. return syscall.S_IFCHR
  225. default:
  226. return syscall.S_IFREG
  227. }
  228. }
  229. func toOsFileType(mode uint32) os.FileMode {
  230. switch mode & (syscall.S_IFMT & 0xffff) {
  231. case syscall.S_IFDIR:
  232. return os.ModeDir
  233. case syscall.S_IFLNK:
  234. return os.ModeSymlink
  235. case syscall.S_IFIFO:
  236. return os.ModeNamedPipe
  237. case syscall.S_IFSOCK:
  238. return os.ModeSocket
  239. case syscall.S_IFBLK:
  240. return os.ModeDevice
  241. case syscall.S_IFCHR:
  242. return os.ModeCharDevice
  243. default:
  244. return 0
  245. }
  246. }
  247. func toOsFileMode(mode uint32) os.FileMode {
  248. return toOsFileType(mode) | os.FileMode(mode&07777)
  249. }