blob: d3827780b89edf6e6f1f2b4571ba7ac1c4bee418 [file] [log] [blame]
// Copyright 2018 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 pkgfs
import (
"log"
"os"
"path/filepath"
"strings"
"thinfs/fs"
"time"
)
type packagesRoot struct {
unsupportedDirectory
fs *Filesystem
}
func (d *packagesRoot) Dup() (fs.Directory, error) {
return d, nil
}
func (pr *packagesRoot) Close() error { return nil }
func (pr *packagesRoot) Open(name string, flags fs.OpenFlags) (fs.File, fs.Directory, *fs.Remote, error) {
name = clean(name)
debugLog("pkgfs:packagesroot:open %q", name)
if name == "" {
return nil, pr, nil, nil
}
parts := strings.Split(name, "/")
pld, err := newPackageListDir(parts[0], pr.fs)
if err != nil {
debugLog("pkgfs:packagesroot:open error reading package list dir for %q: %s", name, err)
return nil, nil, nil, err
}
if len(parts) > 1 {
debugLog("pkgfs:packagesroot:open forwarding %v to %q", parts[1:], name)
return pld.Open(filepath.Join(parts[1:]...), flags)
}
return nil, pld, nil, nil
}
func (pr *packagesRoot) Read() ([]fs.Dirent, error) {
debugLog("pkgfs:packagesroot:read")
var names = map[string]struct{}{}
if pr.fs.static != nil {
pkgs, err := pr.fs.static.List()
if err != nil {
return nil, err
}
for _, p := range pkgs {
names[p.Name] = struct{}{}
}
}
dnames, err := filepath.Glob(pr.fs.index.PackagePath("*"))
if err != nil {
return nil, goErrToFSErr(err)
}
for _, name := range dnames {
names[filepath.Base(name)] = struct{}{}
}
dirents := make([]fs.Dirent, 0, len(names))
for name := range names {
dirents = append(dirents, dirDirEnt(name))
}
return dirents, nil
}
func (pr *packagesRoot) Stat() (int64, time.Time, time.Time, error) {
debugLog("pkgfs:packagesRoot:stat")
// TODO(raggi): stat the index directory and pass on info
return 0, pr.fs.mountTime, pr.fs.mountTime, nil
}
// packageListDir is a directory in the pkgfs packages directory for an
// individual package that lists all versions of packages
type packageListDir struct {
unsupportedDirectory
fs *Filesystem
packageName string
}
func newPackageListDir(name string, f *Filesystem) (*packageListDir, error) {
debugLog("pkgfs:newPackageListDir: %q", name)
if !f.static.HasName(name) {
_, err := os.Stat(f.index.PackagePath(name))
if os.IsNotExist(err) {
debugLog("pkgfs:newPackageListDir: %q not found", name)
return nil, fs.ErrNotFound
}
if err != nil {
log.Printf("pkgfs: error opening package: %q: %s", name, err)
return nil, err
}
}
pld := packageListDir{
unsupportedDirectory: unsupportedDirectory(filepath.Join("/packages", name)),
fs: f,
packageName: name,
}
return &pld, nil
}
func (d *packageListDir) Dup() (fs.Directory, error) {
return d, nil
}
func (pld *packageListDir) Close() error {
debugLog("pkgfs:packageListDir:close %q", pld.packageName)
return nil
}
func (pld *packageListDir) Open(name string, flags fs.OpenFlags) (fs.File, fs.Directory, *fs.Remote, error) {
name = clean(name)
debugLog("pkgfs:packageListDir:open %q %s", pld.packageName, name)
if name == "" {
return nil, pld, nil, nil
}
parts := strings.Split(name, "/")
d, err := newPackageDir(pld.packageName, parts[0], pld.fs)
if err != nil {
return nil, nil, nil, err
}
if len(parts) > 1 {
return d.Open(filepath.Join(parts[1:]...), flags)
}
return nil, d, nil, nil
}
func (pld *packageListDir) Read() ([]fs.Dirent, error) {
debugLog("pkgfs:packageListdir:read %q", pld.packageName)
if pld.fs.static != nil && pld.fs.static.HasName(pld.packageName) {
versions := pld.fs.static.ListVersions(pld.packageName)
dirents := make([]fs.Dirent, len(versions))
for i := range versions {
dirents[i] = dirDirEnt(versions[i])
}
return dirents, nil
}
names, err := filepath.Glob(pld.fs.index.PackageVersionPath(pld.packageName, "*"))
if err != nil {
return nil, goErrToFSErr(err)
}
dirents := make([]fs.Dirent, len(names))
for i := range names {
dirents[i] = dirDirEnt(filepath.Base(names[i]))
}
return dirents, nil
}
func (pld *packageListDir) Stat() (int64, time.Time, time.Time, error) {
debugLog("pkgfs:packageListDir:stat %q", pld.packageName)
// TODO(raggi): stat the index directory and pass on info
return 0, pld.fs.mountTime, pld.fs.mountTime, nil
}