1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
13 type siteFileSystem struct {
16 staleThreshold time.Time
20 // SiteFileSystem returns a FileSystem that maps collections and other
21 // Arvados objects onto a filesystem layout.
23 // This is experimental: the filesystem layout is not stable, and
24 // there are significant known bugs and shortcomings. For example,
25 // writes are not persisted until Sync() is called.
26 func (c *Client) SiteFileSystem(kc keepClient) FileSystem {
28 fs := &siteFileSystem{
29 fileSystem: fileSystem{
30 fsBackend: keepBackend{apiClient: c, keepClient: kc},
34 root.inode = &treenode{
39 mode: os.ModeDir | 0755,
42 inodes: make(map[string]inode),
44 root.inode.Child("by_id", func(inode) (inode, error) {
49 inodes: make(map[string]inode),
53 mode: 0755 | os.ModeDir,
56 create: fs.mountCollection,
59 root.inode.Child("home", func(inode) (inode, error) {
60 return fs.newProjectNode(fs.root, "home", ""), nil
65 func (fs *siteFileSystem) Sync() error {
67 defer fs.staleLock.Unlock()
68 fs.staleThreshold = time.Now()
72 // Stale returns true if information obtained at time t should be
74 func (fs *siteFileSystem) Stale(t time.Time) bool {
76 defer fs.staleLock.Unlock()
77 return !fs.staleThreshold.Before(t)
80 func (fs *siteFileSystem) newNode(name string, perm os.FileMode, modTime time.Time) (node inode, err error) {
81 return nil, ErrInvalidOperation
84 func (fs *siteFileSystem) mountCollection(parent inode, id string) inode {
86 err := fs.RequestAndDecode(&coll, "GET", "arvados/v1/collections/"+id, nil, nil)
90 cfs, err := coll.FileSystem(fs, fs)
94 root := cfs.rootnode()
95 root.SetParent(parent, id)
99 func (fs *siteFileSystem) newProjectNode(root inode, name, uuid string) inode {
105 inodes: make(map[string]inode),
109 mode: 0755 | os.ModeDir,
115 // vdirnode wraps an inode by ignoring any requests to add/replace
116 // children, and calling a create() func when a non-existing child is
119 // create() can return either a new node, which will be added to the
120 // treenode, or nil for ENOENT.
121 type vdirnode struct {
123 create func(parent inode, name string) inode
126 func (vn *vdirnode) Child(name string, replace func(inode) (inode, error)) (inode, error) {
127 return vn.inode.Child(name, func(existing inode) (inode, error) {
128 if existing == nil && vn.create != nil {
129 existing = vn.create(vn, name)
131 existing.SetParent(vn, name)
132 vn.inode.(*treenode).fileinfo.modTime = time.Now()
137 } else if tryRepl, err := replace(existing); err != nil {
139 } else if tryRepl != existing {
140 return existing, ErrInvalidArgument