aboutsummaryrefslogtreecommitdiff
path: root/go/weed/mount.go
blob: 51b5e6919b491801f97835aa080dd9935e55b482 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package main

import (
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"code.google.com/p/weed-fs/go/filer"
	"code.google.com/p/weed-fs/go/glog"
	"code.google.com/p/weed-fs/go/storage"
	"code.google.com/p/weed-fs/go/util"
	"fmt"
	"os"
	"os/signal"
	"runtime"
)

type MountOptions struct {
	filer *string
	dir   *string
}

var (
	mountOptions MountOptions
)

func init() {
	cmdMount.Run = runMount // break init cycle
	cmdMount.IsDebug = cmdMount.Flag.Bool("debug", false, "verbose debug information")
	mountOptions.filer = cmdMount.Flag.String("filer", "localhost:8888", "weedfs filer location")
	mountOptions.dir = cmdMount.Flag.String("dir", "", "mount weed filer to this directory")
}

var cmdMount = &Command{
	UsageLine: "mount -filer=localhost:8888 -dir=/some/dir",
	Short:     "mount weed filer to a directory as file system in userspace(FUSE)",
	Long: `mount weed file system to userspace.
  
  Pre-requisites:
  1) have a weed file system running
  2) have a "weed filer" running
  These 2 requirements can be achieved with one command "weed server -filer=true"

  This uses bazil.org/fuse, whichenables writing FUSE file systems on
  FreeBSD, Linux, and OS X.

  On OS X, it requires OSXFUSE (http://osxfuse.github.com/).

  `,
}

func runMount(cmd *Command, args []string) bool {
	fmt.Printf("This is Weed File System version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH)
	if *mountOptions.dir == "" {
		fmt.Printf("Please specify the mount directory via \"-dir\"")
		return false
	}

	c, err := fuse.Mount(*mountOptions.dir)
	if err != nil {
		glog.Fatal(err)
		return false
	}

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, os.Interrupt)
	go func() {
		for _ = range signalChan {
			// sig is a ^C, handle it
			fuse.Unmount(*mountOptions.dir)
			c.Close()
			os.Exit(0)
		}
	}()

	err = fs.Serve(c, WFS{})
	if err != nil {
		fuse.Unmount(*mountOptions.dir)
	}

	// check if the mount process has an error to report
	<-c.Ready
	if err := c.MountError; err != nil {
		glog.Fatal(err)
	}

	return true
}

type File struct {
	FileId filer.FileId
	Name   string
}

func (File) Attr() fuse.Attr {
	return fuse.Attr{Mode: 0444}
}
func (File) ReadAll(intr fs.Intr) ([]byte, fuse.Error) {
	return []byte("hello, world\n"), nil
}

type Dir struct {
	DirectoryId filer.DirectoryId
	Name        string
}

func (dir Dir) Attr() fuse.Attr {
	return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0555}
}

func (dir Dir) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) {
	files_result, e := filer.ListFiles(*mountOptions.filer, dir.DirectoryId, name)
	if e != nil {
		return nil, fuse.ENOENT
	}
	if len(files_result.Files) > 0 {
		return File{files_result.Files[0].Id, files_result.Files[0].Name}, nil
	}
	return nil, fmt.Errorf("File Not Found for %s", name)
}

type WFS struct{}

func (WFS) Root() (fs.Node, fuse.Error) {
	return Dir{}, nil
}

func (dir *Dir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
	ret := make([]fuse.Dirent, 0)
	if dirs, e := filer.ListDirectories(*mountOptions.filer, dir.DirectoryId); e == nil {
		for _, d := range dirs.Directories {
			dirId := uint64(d.Id)
			ret = append(ret, fuse.Dirent{Inode: dirId, Name: d.Name, Type: fuse.DT_Dir})
		}
	}
	if files, e := filer.ListFiles(*mountOptions.filer, dir.DirectoryId, ""); e == nil {
		for _, f := range files.Files {
			if fileId, e := storage.ParseFileId(string(f.Id)); e == nil {
				fileInode := uint64(fileId.VolumeId)<<32 + fileId.Key
				ret = append(ret, fuse.Dirent{Inode: fileInode, Name: f.Name, Type: fuse.DT_File})
			}

		}
	}
	return ret, nil
}