summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/rsc/appfs/appmount/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/rsc/appfs/appmount/main.go')
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/appmount/main.go287
1 files changed, 287 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/rsc/appfs/appmount/main.go b/vendor/github.com/mattermost/rsc/appfs/appmount/main.go
new file mode 100644
index 000000000..2c9f867d3
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/appmount/main.go
@@ -0,0 +1,287 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// appmount mounts an appfs file system.
+package main
+
+import (
+ "bytes"
+ "encoding/gob"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "strings"
+ "syscall"
+ "time"
+ "sync"
+ "runtime"
+
+ "github.com/mattermost/rsc/appfs/client"
+ "github.com/mattermost/rsc/appfs/proto"
+ "github.com/mattermost/rsc/fuse"
+ "github.com/mattermost/rsc/keychain"
+)
+
+var usageMessage = `usage: appmount [-h host] [-u user] [-p password] /mnt
+
+Appmount mounts the appfs file system on the named mount point.
+
+The default host is localhost:8080.
+`
+
+// Shared between master and slave.
+var z struct {
+ Client client.Client
+ Debug *bool
+ Mtpt string
+}
+
+var fc *fuse.Conn
+var cl = &z.Client
+
+func init() {
+ flag.StringVar(&cl.Host, "h", "localhost:8080", "app serving host")
+ flag.StringVar(&cl.User, "u", "", "user name")
+ flag.StringVar(&cl.Password, "p", "", "password")
+ z.Debug = flag.Bool("debug", false, "")
+}
+
+func usage() {
+ fmt.Fprint(os.Stderr, usageMessage)
+ os.Exit(2)
+}
+
+func main() {
+ log.SetFlags(0)
+
+ if len(os.Args) == 2 && os.Args[1] == "MOUNTSLAVE" {
+ mountslave()
+ return
+ }
+
+ flag.Usage = usage
+ flag.Parse()
+ args := flag.Args()
+ if len(args) == 0 {
+ usage()
+ }
+ z.Mtpt = args[0]
+
+ if cl.Password == "" {
+ var err error
+ cl.User, cl.Password, err = keychain.UserPasswd(cl.Host, "")
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "unable to obtain user and password: %s\n", err)
+ os.Exit(2)
+ }
+ }
+
+ if _, err := cl.Stat("/"); err != nil {
+ log.Fatal(err)
+ }
+
+ // Run in child so that we can exit once child is running.
+ r, w, err := os.Pipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var buf bytes.Buffer
+ enc := gob.NewEncoder(&buf)
+ enc.Encode(&z)
+
+ cmd := exec.Command(os.Args[0], "MOUNTSLAVE")
+ cmd.Stdin = &buf
+ cmd.Stdout = w
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ log.Fatalf("mount process: %v", err)
+ }
+ w.Close()
+
+ ok := make([]byte, 10)
+ n, _ := r.Read(ok)
+ if n != 2 || string(ok[0:2]) != "OK" {
+ os.Exit(1)
+ }
+
+ fmt.Fprintf(os.Stderr, "mounted on %s\n", z.Mtpt)
+}
+
+func mountslave() {
+ stdout, _ := syscall.Dup(1)
+ syscall.Dup2(2, 1)
+
+ r := gob.NewDecoder(os.Stdin)
+ if err := r.Decode(&z); err != nil {
+ log.Fatalf("gob decode: %v", err)
+ }
+
+ fc, err := fuse.Mount(z.Mtpt)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer exec.Command("umount", z.Mtpt).Run()
+
+ if *z.Debug {
+ fuse.Debugf = log.Printf
+ }
+
+ syscall.Write(stdout, []byte("OK"))
+ syscall.Close(stdout)
+ fc.Serve(FS{})
+}
+
+type FS struct{}
+
+func (FS) Root() (fuse.Node, fuse.Error) {
+ return file("/")
+}
+
+type File struct {
+ Name string
+ FileInfo *proto.FileInfo
+ Data []byte
+}
+
+type statEntry struct {
+ fi *proto.FileInfo
+ err error
+ t time.Time
+}
+
+var statCache struct {
+ mu sync.Mutex
+ m map[string] statEntry
+}
+
+func stat(name string) (*proto.FileInfo, error) {
+ if runtime.GOOS == "darwin" && strings.Contains(name, "/._") {
+ // Mac resource forks
+ return nil, fmt.Errorf("file not found")
+ }
+ statCache.mu.Lock()
+ e, ok := statCache.m[name]
+ statCache.mu.Unlock()
+ if ok && time.Since(e.t) < 2*time.Minute {
+ return e.fi, e.err
+ }
+ fi, err := cl.Stat(name)
+ saveStat(name, fi, err)
+ return fi, err
+}
+
+func saveStat(name string, fi *proto.FileInfo, err error) {
+ if *z.Debug {
+if fi != nil {
+ fmt.Fprintf(os.Stderr, "savestat %s %+v\n", name, *fi)
+} else {
+ fmt.Fprintf(os.Stderr, "savestat %s %v\n", name, err)
+}
+ }
+ statCache.mu.Lock()
+ if statCache.m == nil {
+ statCache.m = make(map[string]statEntry)
+ }
+ statCache.m[name] = statEntry{fi, err, time.Now()}
+ statCache.mu.Unlock()
+}
+
+func delStat(name string) {
+ statCache.mu.Lock()
+ if statCache.m != nil {
+ delete(statCache.m, name)
+ }
+ statCache.mu.Unlock()
+}
+
+func file(name string) (fuse.Node, fuse.Error) {
+ fi, err := stat(name)
+ if err != nil {
+ if strings.Contains(err.Error(), "no such entity") {
+ return nil, fuse.ENOENT
+ }
+ if *z.Debug {
+ log.Printf("stat %s: %v", name, err)
+ }
+ return nil, fuse.EIO
+ }
+ return &File{name, fi, nil}, nil
+}
+
+func (f *File) Attr() (attr fuse.Attr) {
+ fi := f.FileInfo
+ attr.Mode = 0666
+ if fi.IsDir {
+ attr.Mode |= 0111 | os.ModeDir
+ }
+ attr.Mtime = fi.ModTime
+ attr.Size = uint64(fi.Size)
+ return
+}
+
+func (f *File) Lookup(name string, intr fuse.Intr) (fuse.Node, fuse.Error) {
+ return file(path.Join(f.Name, name))
+}
+
+func (f *File) ReadAll(intr fuse.Intr) ([]byte, fuse.Error) {
+ data, err := cl.Read(f.Name)
+ if err != nil {
+ log.Printf("read %s: %v", f.Name, err)
+ return nil, fuse.EIO
+ }
+ return data, nil
+}
+
+func (f *File) ReadDir(intr fuse.Intr) ([]fuse.Dirent, fuse.Error) {
+ fis, err := cl.ReadDir(f.Name)
+ if err != nil {
+ log.Printf("read %s: %v", f.Name, err)
+ return nil, fuse.EIO
+ }
+ var dirs []fuse.Dirent
+ for _, fi := range fis {
+ saveStat(path.Join(f.Name, fi.Name), fi, nil)
+ dirs = append(dirs, fuse.Dirent{Name: fi.Name})
+ }
+ return dirs, nil
+}
+
+func (f *File) WriteAll(data []byte, intr fuse.Intr) fuse.Error {
+ defer delStat(f.Name)
+ if err := cl.Write(f.Name[1:], data); err != nil {
+ log.Printf("write %s: %v", f.Name, err)
+ return fuse.EIO
+ }
+ return nil
+}
+
+func (f *File) Mkdir(req *fuse.MkdirRequest, intr fuse.Intr) (fuse.Node, fuse.Error) {
+ defer delStat(f.Name)
+ p := path.Join(f.Name, req.Name)
+ if err := cl.Create(p[1:], true); err != nil {
+ log.Printf("mkdir %s: %v", p, err)
+ return nil, fuse.EIO
+ }
+ delStat(p)
+ return file(p)
+}
+
+func (f *File) Create(req *fuse.CreateRequest, resp *fuse.CreateResponse, intr fuse.Intr) (fuse.Node, fuse.Handle, fuse.Error) {
+ defer delStat(f.Name)
+ p := path.Join(f.Name, req.Name)
+ if err := cl.Create(p[1:], false); err != nil {
+ log.Printf("create %s: %v", p, err)
+ return nil, nil, fuse.EIO
+ }
+ delStat(p)
+ n, err := file(p)
+ if err != nil {
+ return nil, nil, err
+ }
+ return n, n, nil
+}