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  }