fs,fuse: new 'welcome' root node, where you can navigate/search anywhere.

Change-Id: I66f076a85d8e474bb5d93ad8743fc8181de7502f
This commit is contained in:
Brad Fitzpatrick 2012-04-29 14:29:51 +10:00
parent add0f80721
commit 4b8df05859
4 changed files with 120 additions and 53 deletions

View File

@ -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)
}

View File

@ -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();

View File

@ -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)
}

63
pkg/fs/root.go Normal file
View File

@ -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
}