mirror of https://github.com/perkeep/perkeep.git
fs,fuse: new 'welcome' root node, where you can navigate/search anywhere.
Change-Id: I66f076a85d8e474bb5d93ad8743fc8181de7502f
This commit is contained in:
parent
add0f80721
commit
4b8df05859
|
@ -22,7 +22,6 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"camlistore.org/pkg/blobref"
|
||||
"camlistore.org/pkg/blobserver/localdisk" // used for the blob cache
|
||||
|
@ -33,20 +32,6 @@ import (
|
|||
"camlistore.org/third_party/code.google.com/p/rsc/fuse"
|
||||
)
|
||||
|
||||
func PrintMap(m map[string]float64) {
|
||||
keys := make([]string, len(m))
|
||||
for k, _ := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
if m[k] > 0 {
|
||||
fmt.Println(k, m[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Scans the arg list and sets up flags
|
||||
debug := flag.Bool("debug", false, "print debugging messages.")
|
||||
|
@ -58,14 +43,12 @@ func main() {
|
|||
os.Exit(2)
|
||||
}
|
||||
|
||||
if flag.NArg() < 2 {
|
||||
errorf("usage: cammount <blobref> <mountpoint>\n")
|
||||
if n := flag.NArg(); n < 1 || n > 2 {
|
||||
errorf("usage: cammount <mountpoint> [<root-blobref>]\n")
|
||||
}
|
||||
|
||||
root := blobref.Parse(flag.Arg(0))
|
||||
if root == nil {
|
||||
errorf("Error parsing root blobref: %q\n", root)
|
||||
}
|
||||
mountPoint := flag.Arg(0)
|
||||
|
||||
client := client.NewOrFail() // automatic from flags
|
||||
|
||||
cacheDir, err := ioutil.TempDir("", "camlicache")
|
||||
|
@ -79,18 +62,31 @@ func main() {
|
|||
}
|
||||
fetcher := cacher.NewCachingFetcher(diskcache, client)
|
||||
|
||||
fs := fs.NewCamliFileSystem(fetcher, root)
|
||||
var camfs *fs.CamliFileSystem
|
||||
if flag.NArg() == 2 {
|
||||
root := blobref.Parse(flag.Arg(1))
|
||||
if root == nil {
|
||||
errorf("Error parsing root blobref: %q\n", root)
|
||||
}
|
||||
var err error
|
||||
camfs, err = fs.NewRootedCamliFileSystem(fetcher, root)
|
||||
if err != nil {
|
||||
errorf("Error creating root with %v: %v", root, err)
|
||||
}
|
||||
} else {
|
||||
camfs = fs.NewCamliFileSystem(fetcher)
|
||||
log.Printf("starting with fs %#v", camfs)
|
||||
}
|
||||
|
||||
if *debug {
|
||||
// TODO: set fs's logger
|
||||
}
|
||||
|
||||
mountPoint := flag.Arg(1)
|
||||
|
||||
conn, err := fuse.Mount(mountPoint)
|
||||
if err != nil {
|
||||
log.Fatalf("Mount: %v", err)
|
||||
}
|
||||
err = conn.Serve(fs)
|
||||
err = conn.Serve(camfs)
|
||||
if err != nil {
|
||||
log.Fatalf("Serve: %v", err)
|
||||
}
|
||||
|
|
14
dev-cammount
14
dev-cammount
|
@ -5,10 +5,16 @@ use FindBin qw($Bin);
|
|||
use Getopt::Long;
|
||||
require "$Bin/misc/devlib.pl";
|
||||
|
||||
my $blobref = shift;
|
||||
unless ($blobref && $blobref =~ /^\w+-[0-9a-f]{10,}$/) {
|
||||
die "Usage: dev-cammount [blobref]\n";
|
||||
my @blobref_arg;
|
||||
|
||||
if (@ARGV) {
|
||||
my $blobref = shift;
|
||||
unless ($blobref && $blobref =~ /^\w+-[0-9a-f]{10,}$/) {
|
||||
die "Usage: dev-cammount [<blobref>]\n";
|
||||
}
|
||||
push @blobref_arg, $blobref;
|
||||
}
|
||||
|
||||
my $cammount = build_bin("./cmd/cammount");
|
||||
|
||||
my $dir = "/tmp/cammount-dir";
|
||||
|
@ -16,7 +22,7 @@ mkdir $dir, 0700 unless -d $dir;
|
|||
|
||||
try_unmount();
|
||||
print "Mounting on $dir ...\n";
|
||||
system("$cammount", "--blobserver=http://localhost:3179/bs", $blobref, $dir)
|
||||
system("$cammount", "--blobserver=http://localhost:3179/bs", $dir, @blobref_arg)
|
||||
and warn "cammount failure: $!\n";
|
||||
warn "Failed to unmount\n" unless try_unmount();
|
||||
|
||||
|
|
50
pkg/fs/fs.go
50
pkg/fs/fs.go
|
@ -41,7 +41,7 @@ var errNotDir = fuse.Errno(syscall.ENOTDIR)
|
|||
|
||||
type CamliFileSystem struct {
|
||||
fetcher blobref.SeekFetcher
|
||||
root *blobref.BlobRef
|
||||
root fuse.Node
|
||||
|
||||
// IgnoreOwners, if true, collapses all file ownership to the
|
||||
// uid/gid running the fuse filesystem, and sets all the
|
||||
|
@ -53,26 +53,40 @@ type CamliFileSystem struct {
|
|||
nameToAttr *lru.Cache // ~map[string]*fuse.Attr
|
||||
}
|
||||
|
||||
type CamliFile struct {
|
||||
fs *CamliFileSystem
|
||||
blob *blobref.BlobRef
|
||||
ss *schema.Superset
|
||||
|
||||
size uint64 // memoized
|
||||
}
|
||||
|
||||
var _ fuse.FS = (*CamliFileSystem)(nil)
|
||||
|
||||
func NewCamliFileSystem(fetcher blobref.SeekFetcher, root *blobref.BlobRef) *CamliFileSystem {
|
||||
func newCamliFileSystem(fetcher blobref.SeekFetcher) *CamliFileSystem {
|
||||
return &CamliFileSystem{
|
||||
fetcher: fetcher,
|
||||
blobToSchema: lru.New(1024), // arbitrary; TODO: tunable/smarter?
|
||||
root: root,
|
||||
nameToBlob: lru.New(1024), // arbitrary: TODO: tunable/smarter?
|
||||
nameToAttr: lru.New(1024), // arbitrary: TODO: tunable/smarter?
|
||||
}
|
||||
}
|
||||
|
||||
func NewCamliFileSystem(fetcher blobref.SeekFetcher) *CamliFileSystem {
|
||||
fs := newCamliFileSystem(fetcher)
|
||||
fs.root = &root{fs: fs} // root.go
|
||||
return fs
|
||||
}
|
||||
|
||||
// NewRootedCamliFileSystem returns a CamliFileSystem with root as its
|
||||
// base.
|
||||
func NewRootedCamliFileSystem(fetcher blobref.SeekFetcher, root *blobref.BlobRef) (*CamliFileSystem, error) {
|
||||
fs := newCamliFileSystem(fetcher)
|
||||
|
||||
ss, err := fs.fetchSchemaSuperset(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n := &node{fs: fs, blobref: root, ss: ss}
|
||||
n.populateAttr()
|
||||
fs.root = n
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
// node implements fuse.Node with a read-only Camli "file" or
|
||||
// "directory" blob.
|
||||
type node struct {
|
||||
fs *CamliFileSystem
|
||||
blobref *blobref.BlobRef
|
||||
|
@ -290,15 +304,7 @@ func (n *node) populateAttr() error {
|
|||
}
|
||||
|
||||
func (fs *CamliFileSystem) Root() (fuse.Node, fuse.Error) {
|
||||
ss, err := fs.fetchSchemaSuperset(fs.root)
|
||||
if err != nil {
|
||||
// TODO: map these to fuse.Error better
|
||||
log.Printf("Error fetching root: %v", err)
|
||||
return nil, fuse.EIO
|
||||
}
|
||||
n := &node{fs: fs, blobref: fs.root, ss: ss}
|
||||
n.populateAttr()
|
||||
return n, nil
|
||||
return fs.root, nil
|
||||
}
|
||||
|
||||
func (fs *CamliFileSystem) Statfs(req *fuse.StatfsRequest, res *fuse.StatfsResponse, intr fuse.Intr) fuse.Error {
|
||||
|
@ -342,7 +348,3 @@ func (fs *CamliFileSystem) fetchSchemaSuperset(br *blobref.BlobRef) (*schema.Sup
|
|||
fs.blobToSchema.Add(blobStr, ss)
|
||||
return ss, nil
|
||||
}
|
||||
|
||||
func (file *CamliFile) GetReader() (io.ReadCloser, error) {
|
||||
return file.ss.NewFileReader(file.fs.fetcher)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright 2012 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"camlistore.org/pkg/blobref"
|
||||
|
||||
"camlistore.org/third_party/code.google.com/p/rsc/fuse"
|
||||
)
|
||||
|
||||
// root implements fuse.Node and is the typical root of a
|
||||
// CamliFilesystem with a little hello message and the ability to
|
||||
// search and browse static snapshots, etc.
|
||||
type root struct {
|
||||
fs *CamliFileSystem
|
||||
}
|
||||
|
||||
func (n *root) Attr() fuse.Attr {
|
||||
return fuse.Attr{
|
||||
Mode: os.ModeDir | 0755,
|
||||
Uid: uint32(os.Getuid()),
|
||||
Gid: uint32(os.Getgid()),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *root) ReadDir(intr fuse.Intr) ([]fuse.Dirent, fuse.Error) {
|
||||
return []fuse.Dirent{
|
||||
{Name: "WELCOME.txt"},
|
||||
{Name: "tag"},
|
||||
{Name: "date"},
|
||||
{Name: "sha1-xxx...."},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (n *root) Lookup(name string, intr fuse.Intr) (fuse.Node, fuse.Error) {
|
||||
if name == ".quitquitquit" {
|
||||
log.Fatalf("Shutting down due to root .quitquitquit lookup.")
|
||||
}
|
||||
|
||||
br := blobref.Parse(name)
|
||||
log.Printf("Root lookup of %q = %v", name, br)
|
||||
if br != nil {
|
||||
return &node{fs: n.fs, blobref: br}, nil
|
||||
}
|
||||
return nil, fuse.ENOENT
|
||||
}
|
Loading…
Reference in New Issue