github.com/avfs/avfs@v0.33.1-0.20240303173310-c6ba67c33eb7/vfs/orefafs/orefafs_internal.go (about) 1 // 2 // Copyright 2020 The AVFS authors 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 package orefafs 18 19 import ( 20 "bytes" 21 "io/fs" 22 "sort" 23 "sync/atomic" 24 "time" 25 26 "github.com/avfs/avfs" 27 ) 28 29 // addChild adds a child to a node. 30 func (nd *node) addChild(name string, child *node) { 31 if nd.children == nil { 32 nd.children = make(children) 33 } 34 35 nd.children[name] = child 36 } 37 38 // createDir creates a new directory. 39 func (vfs *OrefaFS) createDir(parent *node, absPath, fileName string, perm fs.FileMode) *node { 40 mode := vfs.dirMode | (perm & avfs.FileModeMask &^ vfs.UMask()) 41 42 return vfs.createNode(parent, absPath, fileName, mode) 43 } 44 45 // createFile creates a new file. 46 func (vfs *OrefaFS) createFile(parent *node, absPath, fileName string, perm fs.FileMode) *node { 47 mode := vfs.fileMode | (perm & avfs.FileModeMask &^ vfs.UMask()) 48 49 return vfs.createNode(parent, absPath, fileName, mode) 50 } 51 52 // createNode creates a new node (directory or file). 53 func (vfs *OrefaFS) createNode(parent *node, absPath, fileName string, mode fs.FileMode) *node { 54 parent.mu.Lock() 55 defer parent.mu.Unlock() 56 57 nd := &node{ 58 id: atomic.AddUint64(vfs.lastId, 1), 59 mtime: time.Now().UnixNano(), 60 mode: mode, 61 uid: vfs.User().Uid(), 62 gid: vfs.User().Gid(), 63 nlink: 1, 64 } 65 66 parent.addChild(fileName, nd) 67 68 vfs.nodes[absPath] = nd 69 70 return nd 71 } 72 73 // fillStatFrom returns a OrefaInfo (implementation of fs.FileInfo) from a dirNode dn named name. 74 func (nd *node) fillStatFrom(name string) *OrefaInfo { 75 nd.mu.RLock() 76 77 fst := &OrefaInfo{ 78 id: nd.id, 79 name: name, 80 size: nd.size(), 81 mode: nd.mode, 82 mtime: nd.mtime, 83 uid: nd.uid, 84 gid: nd.gid, 85 nlink: nd.nlink, 86 } 87 88 nd.mu.RUnlock() 89 90 return fst 91 } 92 93 // dirEntries returns a slice of fs.DirEntry from a directory ordered by name. 94 func (nd *node) dirEntries() []fs.DirEntry { 95 l := len(nd.children) 96 if l == 0 { 97 return nil 98 } 99 100 entries := make([]fs.DirEntry, l) 101 i := 0 102 103 for name, node := range nd.children { 104 entries[i] = node.fillStatFrom(name) 105 i++ 106 } 107 108 sort.Slice(entries, func(i, j int) bool { return entries[i].Name() < entries[j].Name() }) 109 110 return entries 111 } 112 113 // dirNames returns a slice of file names from a directory ordered by name. 114 func (nd *node) dirNames() []string { 115 l := len(nd.children) 116 if l == 0 { 117 return nil 118 } 119 120 names := make([]string, l) 121 i := 0 122 123 for name := range nd.children { 124 names[i] = name 125 i++ 126 } 127 128 sort.Strings(names) 129 130 return names 131 } 132 133 // remove deletes the content of a node. 134 func (nd *node) remove() { 135 nd.children = nil 136 137 nd.nlink-- 138 if nd.nlink == 0 { 139 nd.data = nil 140 } 141 } 142 143 // setMode sets the permissions of the file node. 144 func (nd *node) setMode(mode fs.FileMode) { 145 nd.mode &^= avfs.FileModeMask 146 nd.mode |= mode & avfs.FileModeMask 147 } 148 149 // setModTime sets the modification time of the node. 150 func (nd *node) setModTime(mtime time.Time) { 151 nd.mtime = mtime.UnixNano() 152 } 153 154 // setOwner sets the user and group id. 155 func (nd *node) setOwner(uid, gid int) { 156 nd.uid = uid 157 nd.gid = gid 158 } 159 160 // size returns the size of the file. 161 func (nd *node) size() int64 { 162 if nd.mode.IsDir() { 163 return int64(len(nd.children)) 164 } 165 166 return int64(len(nd.data)) 167 } 168 169 // Size returns the size of the file. 170 func (nd *node) Size() int64 { 171 nd.mu.RLock() 172 s := nd.size() 173 nd.mu.RUnlock() 174 175 return s 176 } 177 178 // truncate truncates the file. 179 func (nd *node) truncate(size int64) { 180 if size == 0 { 181 nd.data = nil 182 183 return 184 } 185 186 diff := int(size) - len(nd.data) 187 if diff > 0 { 188 nd.data = append(nd.data, bytes.Repeat([]byte{0}, diff)...) 189 190 return 191 } 192 193 nd.data = nd.data[:size] 194 }