1// +build linux darwin 2 3/* 4Copyright 2012 The Perkeep Authors 5 6Licensed under the Apache License, Version 2.0 (the "License"); 7you may not use this file except in compliance with the License. 8You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12Unless required by applicable law or agreed to in writing, software 13distributed under the License is distributed on an "AS IS" BASIS, 14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15See the License for the specific language governing permissions and 16limitations under the License. 17*/ 18 19package fs 20 21import ( 22 "context" 23 "log" 24 "os" 25 "sync" 26 27 "bazil.org/fuse" 28 "bazil.org/fuse/fs" 29 "perkeep.org/pkg/blob" 30) 31 32// root implements fuse.Node and is the typical root of a 33// CamliFilesystem with a little hello message and the ability to 34// search and browse static snapshots, etc. 35type root struct { 36 fs *CamliFileSystem 37 38 mu sync.Mutex 39 recent *recentDir 40 roots *rootsDir 41 atDir *atDir 42 versionsDir *versionsDir 43} 44 45var ( 46 _ fs.Node = (*root)(nil) 47 _ fs.HandleReadDirAller = (*root)(nil) 48 _ fs.NodeStringLookuper = (*root)(nil) 49) 50 51func (n *root) Attr(ctx context.Context, a *fuse.Attr) error { 52 a.Mode = os.ModeDir | 0700 53 a.Uid = uint32(os.Getuid()) 54 a.Gid = uint32(os.Getgid()) 55 return nil 56} 57 58func (n *root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { 59 return []fuse.Dirent{ 60 {Name: "WELCOME.txt"}, 61 {Name: "tag"}, 62 {Name: "date"}, 63 {Name: "recent"}, 64 {Name: "roots"}, 65 {Name: "at"}, 66 {Name: "sha1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}, 67 {Name: "sha224-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}, 68 {Name: "versions"}, 69 }, nil 70} 71 72func (n *root) getRecentDir() *recentDir { 73 n.mu.Lock() 74 defer n.mu.Unlock() 75 if n.recent == nil { 76 n.recent = &recentDir{fs: n.fs} 77 } 78 return n.recent 79} 80 81func (n *root) getRootsDir() *rootsDir { 82 n.mu.Lock() 83 defer n.mu.Unlock() 84 if n.roots == nil { 85 n.roots = &rootsDir{fs: n.fs} 86 } 87 return n.roots 88} 89 90func (n *root) getAtDir() *atDir { 91 n.mu.Lock() 92 defer n.mu.Unlock() 93 if n.atDir == nil { 94 n.atDir = &atDir{fs: n.fs} 95 } 96 return n.atDir 97} 98 99func (n *root) getVersionsDir() *versionsDir { 100 n.mu.Lock() 101 defer n.mu.Unlock() 102 if n.versionsDir == nil { 103 n.versionsDir = &versionsDir{fs: n.fs} 104 } 105 return n.versionsDir 106} 107 108func (n *root) Lookup(ctx context.Context, name string) (fs.Node, error) { 109 Logger.Printf("root.Lookup(%s)", name) 110 switch name { 111 case ".quitquitquit": 112 log.Fatalf("Shutting down due to root .quitquitquit lookup.") 113 case "WELCOME.txt": 114 return staticFileNode("Welcome to PerkeepFS.\n\nMore information is available in the pk-mount documentation.\n\nSee https://perkeep.org/cmd/pk-mount/ , or run 'go doc perkeep.org/cmd/pk-mount'.\n"), nil 115 case "recent": 116 return n.getRecentDir(), nil 117 case "tag", "date": 118 return notImplementDirNode{}, nil 119 case "at": 120 return n.getAtDir(), nil 121 case "roots": 122 return n.getRootsDir(), nil 123 case "versions": 124 return n.getVersionsDir(), nil 125 case "sha1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx": 126 return notImplementDirNode{}, nil 127 case "sha224-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx": 128 return notImplementDirNode{}, nil 129 case ".camli_fs_stats": 130 return statsDir{}, nil 131 case "mach_kernel", ".hidden", "._.": 132 // Just quiet some log noise on OS X. 133 return nil, fuse.ENOENT 134 } 135 136 if br, ok := blob.Parse(name); ok { 137 Logger.Printf("Root lookup of blobref. %q => %v", name, br) 138 return &node{fs: n.fs, blobref: br}, nil 139 } 140 Logger.Printf("Bogus root lookup of %q", name) 141 return nil, fuse.ENOENT 142} 143