blob: a9b0fb1dbec8a97cee44a1449b711fd73add08fd [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package node
import (
"sync"
"time"
"thinfs/fs"
)
type root struct {
metadata *Metadata
offsetStart int64 // Device offset at which the root starts.
maxSize int64 // The maximum size of the root node.
mu sync.RWMutex
children map[int]FileNode // Map of "direntIndex" --> "FileNode", if a child is open.
size int64 // The size of the node.
references int // The number of open files referencing this node.
}
// NewRoot makes a new root, specific for FAT-12 / FAT-16
func NewRoot(m *Metadata, offsetStart, maxSize int64) DirectoryNode {
r := &root{
metadata: m,
offsetStart: offsetStart,
maxSize: maxSize,
children: make(map[int]FileNode),
size: maxSize,
references: 1,
}
return r
}
func (r *root) Metadata() *Metadata {
return r.metadata
}
func (r *root) SetSize(size int64) {
if r.maxSize < size {
panic("Setting root size to something larger than max size")
}
r.size = size
}
func (r *root) MarkDeleted() {
panic("Cannot delete root")
}
func (r *root) IsDeleted() bool {
return false
}
func (r *root) RefUp() {
r.references++
}
func (r *root) RefCount() int {
return r.references
}
func (r *root) RefDown(numRefs int) error {
r.references -= numRefs
if r.references < 0 {
panic("Invalid internal refcounting")
}
return nil
}
func (r *root) readAt(buf []byte, off int64) (int, error) {
bytesToRead := len(buf)
if off < 0 || r.size <= off {
return 0, ErrBadArgument
} else if off+int64(bytesToRead) > r.size {
// Would the end of this read extend beyond the end of root? If so, read less.
bytesToRead = int(r.size - off)
}
bytesRead, err := r.metadata.Dev.ReadAt(buf[:bytesToRead], r.offsetStart+off)
if err != nil {
return 0, err
}
if bytesRead < len(buf) {
return bytesRead, fs.ErrEOF
}
return bytesRead, nil
}
func (r *root) writeAt(buf []byte, off int64) (int, error) {
if r.metadata.Readonly {
return 0, fs.ErrPermission
} else if off < 0 {
return 0, ErrBadArgument
} else if off >= r.maxSize || off+int64(len(buf)) > r.maxSize {
// Would the start/end of this write extend beyond the max size? If so, don't write.
return 0, ErrNoSpace
}
bytesWritten, err := r.metadata.Dev.WriteAt(buf, r.offsetStart+off)
// Adjust the size of the root if we have extended it.
if off+int64(bytesWritten) > r.size {
r.size = off + int64(bytesWritten)
}
return bytesWritten, err
}
func (r *root) IsDirectory() bool {
return true
}
// This root does not use clusters. However, for the sake of simplicity, we'll simply lie using a
// reserved cluster.
func (r *root) StartCluster() uint32 {
return r.metadata.ClusterMgr.ClusterEOF()
}
func (r *root) ID() uint32 {
return 0
}
func (r *root) NumClusters() int {
return 0
}
func (r *root) IsRoot() bool {
return true
}
func (r *root) MTime() time.Time {
return time.Time{}
}
func (r *root) SetMTime(mtime time.Time) {}
func (r *root) Size() int64 {
return r.size
}
func (r *root) Lock() {
r.mu.Lock()
}
func (r *root) Unlock() {
r.mu.Unlock()
}
func (r *root) RLock() {
r.mu.RLock()
}
func (r *root) RUnlock() {
r.mu.RUnlock()
}
func (r *root) ChildFiles() []FileNode {
children := make([]FileNode, len(r.children))
i := 0
for k := range r.children {
children[i] = r.children[k]
i++
}
return children
}
func (r *root) ChildFile(direntIndex int) (FileNode, bool) {
c, ok := r.children[direntIndex]
return c, ok
}
func (r *root) setChildFile(direntIndex int, child FileNode) {
if _, ok := r.children[direntIndex]; ok {
panic("setChildFile failed; a child already exists at this index")
}
r.children[direntIndex] = child
}
func (r *root) RemoveFile(direntIndex int) {
if _, ok := r.children[direntIndex]; !ok {
panic("Child does not exist in root16")
}
delete(r.children, direntIndex)
}