func NewFileSystem(root string, hosts *HostSet) *PseudoFS {
	sectors := make(map[hostdb.HostPublicKey]*renter.SectorBuilder)
	for hostKey := range hosts.sessions {
		sectors[hostKey] = new(renter.SectorBuilder)
	}
	return &PseudoFS{
		root:           root,
		files:          make(map[int]*openMetaFile),
		dirs:           make(map[int]*os.File),
		hosts:          hosts,
		sectors:        sectors,
		lastCommitTime: time.Now(),
	}
}
NewFileSystem returns a new pseudo-filesystem rooted at root, which must be a
directory containing only metafiles and other directories.
package renterutil  
import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
	"go.sia.tech/siad/crypto"
	"lukechampine.com/us/hostdb"
	"lukechampine.com/us/renter"
)
const metafileExt = ".usa"
var ErrInvalidFileDescriptor = errors.New("invalid file descriptor")
type pseudoFileInfo struct {
	name string
	m    renter.MetaIndex
}
func (i pseudoFileInfo) Name() string       { return i.name }
func (i pseudoFileInfo) Size() int64        { return i.m.Filesize }
func (i pseudoFileInfo) Mode() os.FileMode  { return i.m.Mode }
func (i pseudoFileInfo) ModTime() time.Time { return i.m.ModTime }
func (i pseudoFileInfo) IsDir() bool        { return false }
func (i pseudoFileInfo) Sys() interface{}   { return i.m }
type PseudoFS struct {
	root           string
	curFD          int
	files          map[int]*openMetaFile
	dirs           map[int]*os.File
	hosts          *HostSet
	sectors        map[hostdb.HostPublicKey]*renter.SectorBuilder
	lastCommitTime time.Time
	mu             sync.RWMutex
}
func (fs *PseudoFS) path(name string) string {
	return filepath.Join(fs.root, name)
}
func isDir(path string) bool {
	stat, err := os.Stat(path)
	return err == nil && stat.IsDir()
}
func exists(path string) bool {
	_, err := os.Stat(path)
	return !os.IsNotExist(err)
}
func (fs *PseudoFS) Chmod(name string, mode os.FileMode) error {
	path := fs.path(name)
	if isDir(path) {
		return os.Chmod(path, mode)
	}
	path += metafileExt
	for _, of := range fs.files {
		if of.name == name {
			of.m.Mode = mode
			of.m.ModTime = time.Now()
			return nil
		}
	}
	m, err := renter.ReadMetaFile(path)
	if err != nil {
		return fmt.Errorf("chmod %v: %w", path, err)
	}
	m.Mode = mode
	m.ModTime = time.Now()
	if err := renter.WriteMetaFile(path, m); err != nil {
		return fmt.Errorf("chmod %v: %w", path, err)
	}
	return nil
}
func (fs *PseudoFS) Create(name string, minShards int) (*PseudoFile, error) {
	return fs.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o666, minShards)
}
func (fs *PseudoFS) Mkdir(name string, perm os.FileMode) error {
	return os.Mkdir(fs.path(name), perm)
}
func (fs *PseudoFS) MkdirAll(path string, perm os.FileMode) error {
	return os.MkdirAll(fs.path(path), perm)
}
func (fs *PseudoFS) Open(name string) (*PseudoFile, error) {
	return fs.OpenFile(name, os.O_RDONLY, 0, 0)
}
func (fs *PseudoFS) OpenFile(name string, flag int, perm os.FileMode, minShards int) (*PseudoFile, error) {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	path := fs.path(name)
	if isDir(path) {
		dir, err := os.OpenFile(path, flag, perm)
		if err != nil {
			return nil, err
		}
		fs.dirs[fs.curFD] = dir
		fs.curFD++
		return &PseudoFile{
			name: name,
			fd:   fs.curFD - 1,
			fs:   fs,
		}, nil
	}
	path += metafileExt
	for fd, of := range fs.files {
		if of.name == name {
			if flag&rwmask == os.O_WRONLY || flag&rwmask == os.O_RDWR {
				var missing []string
				for _, hostKey := range of.m.Hosts {
					if _, ok := fs.hosts.sessions[hostKey]; !ok {
						missing = append(missing, hostKey.ShortKey())
					}
				}
				if len(missing) > 0 {
					return nil, fmt.Errorf("insufficient contracts: need a contract from each of these hosts: %v",
						strings.Join(missing, " "))
				}
			}
			of.closed = false
			of.offset = 0
			if flag&os.O_APPEND == os.O_APPEND {
				of.offset = of.filesize()
			}
			return &PseudoFile{
				name:  name,
				flags: flag,
				fd:    fd,
				fs:    fs,
			}, nil
		}
	}
	var m *renter.MetaFile
	if flag&os.O_CREATE == os.O_CREATE {
		if len(fs.hosts.sessions) < minShards {
			return nil, errors.New("minShards cannot be greater than the number of hosts")
		}
		if flag&os.O_TRUNC == os.O_TRUNC {
			for fd, f := range fs.files {
				if f.name == name && f.closed {
					delete(fs.files, fd)
					break
				}
			}
		}
		hosts := make([]hostdb.HostPublicKey, 0, len(fs.hosts.sessions))
		for hostKey := range fs.hosts.sessions {
			hosts = append(hosts, hostKey)
		}
		m = renter.NewMetaFile(perm, 0, hosts, minShards)
	} else {
		var err error
		m, err = renter.ReadMetaFile(path)
		if err != nil {
			return nil, fmt.Errorf("open %v: %w", path, err)
		}
		var missing []string
		for _, hostKey := range m.Hosts {
			if _, ok := fs.hosts.sessions[hostKey]; !ok {
				missing = append(missing, hostKey.ShortKey())
			}
		}
		if flag&rwmask == os.O_RDONLY {
			if have := len(m.Hosts) - len(missing); have < m.MinShards {
				return nil, fmt.Errorf("insufficient contracts: need a contract from at least %v of these hosts: %v",
					m.MinShards-have, strings.Join(missing, " "))
			}
		} else {
			if len(missing) > 0 {
				return nil, fmt.Errorf("insufficient contracts: need a contract from each of these hosts: %v",
					strings.Join(missing, " "))
			}
		}
	}
	of := &openMetaFile{
		name: name,
		m:    m,
	}
	if flag&os.O_APPEND == os.O_APPEND {
		of.offset = m.Filesize
	}
	fs.files[fs.curFD] = of
	fs.curFD++
	return &PseudoFile{
		name:  name,
		flags: flag,
		fd:    fs.curFD - 1,
		fs:    fs,
	}, nil
}
func (fs *PseudoFS) Remove(name string) error {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	for fd, f := range fs.files {
		if f.name == name && f.closed {
			delete(fs.files, fd)
			break
		}
	}
	path := fs.path(name)
	if !isDir(path) {
		path += metafileExt
	}
	if !exists(path) {
		return nil
	}
	return os.Remove(path)
}
func (fs *PseudoFS) RemoveAll(path string) error {
	for fd, f := range fs.files {
		if strings.HasPrefix(f.name, path) && f.closed {
			delete(fs.files, fd)
		}
	}
	path = fs.path(path)
	if !isDir(path) {
		path += metafileExt
	}
	return os.RemoveAll(path)
}
func (fs *PseudoFS) GC() error {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	hostRoots := make(map[hostdb.HostPublicKey]map[crypto.Hash]struct{})
	for hostKey := range fs.hosts.sessions {
		err := func() error {
			h, err := fs.hosts.acquire(hostKey)
			if err != nil {
				return err
			}
			defer fs.hosts.release(hostKey)
			numRoots := h.Revision().NumSectors()
			rootMap := make(map[crypto.Hash]struct{}, numRoots)
			for offset := 0; offset < numRoots; {
				n := 130000  
				if offset+n > numRoots {
					n = numRoots - offset
				}
				roots, err := h.SectorRoots(offset, n)
				if err != nil {
					return err
				}
				for _, r := range roots {
					rootMap[r] = struct{}{}
				}
				offset += n
			}
			hostRoots[hostKey] = rootMap
			return nil
		}()
		if err != nil {
			return err
		}
	}
	err := filepath.Walk(fs.root, func(path string, info os.FileInfo, err error) error {
		if (info != nil && info.IsDir()) || !strings.HasSuffix(path, ".usa") {
			return nil
		} else if err != nil {
			return err
		}
		m, err := renter.ReadMetaFile(path)
		if err != nil {
			return err
		}
		for i, hostKey := range m.Hosts {
			if roots, ok := hostRoots[hostKey]; ok {
				for _, ss := range m.Shards[i] {
					delete(roots, ss.MerkleRoot)
				}
			}
		}
		return nil
	})
	if err != nil {
		return err
	}
	done := true
	for _, roots := range hostRoots {
		done = done && len(roots) == 0
	}
	if done {
		return nil
	}
	for hostKey, rootsMap := range hostRoots {
		err := func() error {
			h, err := fs.hosts.acquire(hostKey)
			if err != nil {
				return err
			}
			defer fs.hosts.release(hostKey)
			roots := make([]crypto.Hash, 0, len(rootsMap))
			for root := range rootsMap {
				roots = append(roots, root)
			}
			return h.DeleteSectors(roots)
		}()
		if err != nil {
			return err
		}
	}
	return nil
}
func (fs *PseudoFS) Rename(oldname, newname string) error {
	fs.mu.Lock()
	for _, f := range fs.files {
		if f.name == oldname && len(f.pendingWrites) > 0 {
			if err := fs.flushSectors(); err != nil {
				return err
			}
			break
		}
	}
	fs.mu.Unlock()
	oldpath, newpath := fs.path(oldname), fs.path(newname)
	if !isDir(oldpath) {
		oldpath += metafileExt
	}
	if !isDir(newpath) {
		newpath += metafileExt
	}
	return os.Rename(oldpath, newpath)
}
func (fs *PseudoFS) Stat(name string) (os.FileInfo, error) {
	fs.mu.RLock()
	for _, f := range fs.files {
		if f.name == name {
			info := pseudoFileInfo{name: f.name, m: f.m.MetaIndex}
			info.m.Filesize = f.filesize()
			fs.mu.RUnlock()
			return info, nil
		}
	}
	fs.mu.RUnlock()
	path := fs.path(name)
	if isDir(path) {
		return os.Stat(path)
	}
	path += metafileExt
	index, err := renter.ReadMetaIndex(path)
	if err != nil {
		return nil, fmt.Errorf("stat %v: %w", name, err)
	}
	return pseudoFileInfo{name, index}, nil
}
func (fs *PseudoFS) Close() error {
	fs.mu.Lock()
	defer fs.mu.Unlock()
	if err := fs.flushSectors(); err != nil {
		return err
	}
	for fd, f := range fs.files {
		if err := fs.commitChanges(f); err != nil {
			return err
		}
		delete(fs.files, fd)
	}
	for fd, d := range fs.dirs {
		d.Close()
		delete(fs.dirs, fd)
	}
	return fs.hosts.Close()
}