func getAttr(fs fuse.FileSystem, name string) *attrResponse { a, code := fs.GetAttr(name, nil) return &attrResponse{ Attr: a, Status: code, } }
func readLink(fs fuse.FileSystem, name string) *linkResponse { a, code := fs.Readlink(name, nil) return &linkResponse{ linkContent: a, Status: code, } }
func getXAttr(fs fuse.FileSystem, nameAttr string) *xattrResponse { ns := strings.SplitN(nameAttr, _XATTRSEP, 2) a, code := fs.GetXAttr(ns[0], ns[1], nil) return &xattrResponse{ data: a, Status: code, } }
func readDir(fs fuse.FileSystem, name string) *dirResponse { origStream, code := fs.OpenDir(name, nil) r := &dirResponse{nil, code} if !code.Ok() { return r } r.entries = origStream return r }
// newDirnameMap reads the contents of the given directory. On error, // returns a nil map. This forces reloads in the DirCache until we // succeed. func newDirnameMap(fs fuse.FileSystem, dir string) map[string]bool { stream, code := fs.OpenDir(dir) if !code.Ok() { log.Printf("newDirnameMap(): %v %v", dir, code) return nil } result := make(map[string]bool) for e := range stream { if e.Mode&fuse.S_IFREG != 0 { result[e.Name] = true } } return result }
func readDir(fs fuse.FileSystem, name string) *dirResponse { origStream, code := fs.OpenDir(name, nil) r := &dirResponse{nil, code} if code != fuse.OK { return r } for { d, ok := <-origStream if !ok { break } r.entries = append(r.entries, d) } return r }
// newDirnameMap reads the contents of the given directory. On error, // returns a nil map. This forces reloads in the DirCache until we // succeed. func newDirnameMap(fs fuse.FileSystem, dir string) map[string]bool { stream, code := fs.OpenDir(dir, nil) if code == fuse.ENOENT { // The directory not existing is not an error. return map[string]bool{} } if !code.Ok() { log.Printf("newDirnameMap(%v): %v %v", fs, dir, code) return nil } result := make(map[string]bool) for _, e := range stream { if e.Mode&fuse.S_IFREG != 0 { result[e.Name] = true } } return result }
func openFile(fs fuse.FileSystem, name string) (result *openResponse) { result = &openResponse{} flags := uint32(os.O_RDONLY) f, code := fs.Open(name, flags) if !code.Ok() { result.Status = code return } defer f.Release() defer f.Flush() buf := bytes.NewBuffer(nil) input := fuse.ReadIn{ Offset: 0, Size: 128 * (1 << 10), Flags: flags, } bp := fuse.NewGcBufferPool() for { data, status := f.Read(&input, bp) buf.Write(data) if !status.Ok() { result.Status = status return } if len(data) < int(input.Size) { break } input.Offset += uint64(len(data)) } result.File = fuse.NewReadOnlyFile(buf.Bytes()) return }
func IsDir(fs fuse.FileSystem, name string) bool { a, code := fs.GetAttr(name, nil) return code.Ok() && a.IsDir() }
func newWorkerFuseFs(tmpDir string, rpcFs fuse.FileSystem, writableRoot string, nobody *User) (*workerFuseFs, error) { tmpDir, err := ioutil.TempDir(tmpDir, "termite-task") if err != nil { return nil, err } me := &workerFuseFs{ tmpDir: tmpDir, writableRoot: strings.TrimLeft(writableRoot, "/"), tasks: map[*WorkerTask]bool{}, } type dirInit struct { dst *string val string } tmpBacking := "" for _, v := range []dirInit{ {&me.rwDir, "rw"}, {&me.mount, "mnt"}, {&tmpBacking, "tmp-backing"}, } { *v.dst = filepath.Join(me.tmpDir, v.val) err = os.Mkdir(*v.dst, 0700) if err != nil { return nil, err } } fuseOpts := fuse.MountOptions{} if os.Geteuid() == 0 { fuseOpts.AllowOther = true } me.rpcNodeFs = fuse.NewPathNodeFs(rpcFs, nil) ttl := 30 * time.Second mOpts := fuse.FileSystemOptions{ EntryTimeout: ttl, AttrTimeout: ttl, NegativeTimeout: ttl, // 32-bit programs have trouble with 64-bit inode // numbers. PortableInodes: true, } me.fsConnector = fuse.NewFileSystemConnector(me.rpcNodeFs, &mOpts) me.MountState = fuse.NewMountState(me.fsConnector) err = me.MountState.Mount(me.mount, &fuseOpts) if err != nil { return nil, err } go me.MountState.Loop() me.unionFs = fs.NewMemUnionFs( me.rwDir, &fuse.PrefixFileSystem{rpcFs, me.writableRoot}) me.procFs = fs.NewProcFs() me.procFs.StripPrefix = me.mount if nobody != nil { me.procFs.Uid = nobody.Uid } type submount struct { mountpoint string fs fuse.NodeFileSystem } mounts := []submount{ {"proc", fuse.NewPathNodeFs(me.procFs, nil)}, {"sys", fuse.NewPathNodeFs(&fuse.ReadonlyFileSystem{fuse.NewLoopbackFileSystem("/sys")}, nil)}, {"tmp", fuse.NewMemNodeFs(tmpBacking + "/tmp")}, {"dev", fs.NewDevNullFs()}, {"var/tmp", fuse.NewMemNodeFs(tmpBacking + "/vartmp")}, } for _, s := range mounts { subOpts := &mOpts if s.mountpoint == "proc" { subOpts = nil } code := me.rpcNodeFs.Mount(s.mountpoint, s.fs, subOpts) if !code.Ok() { if err := me.MountState.Unmount(); err != nil { log.Fatal("FUSE unmount error during cleanup:", err) } return nil, errors.New(fmt.Sprintf("submount error for %s: %v", s.mountpoint, code)) } } if strings.HasPrefix(me.writableRoot, "tmp/") { parent, _ := filepath.Split(me.writableRoot) err := os.MkdirAll(filepath.Join(me.mount, parent), 0755) if err != nil { if err := me.MountState.Unmount(); err != nil { log.Fatal("FUSE unmount error during cleanup:", err) } return nil, errors.New(fmt.Sprintf("Mkdir of %q in /tmp fail: %v", parent, err)) } // This is hackish, but we don't want rpcfs/fsserver // getting confused by asking for tmp/foo/bar // directly. rpcFs.GetAttr("tmp", nil) rpcFs.GetAttr(me.writableRoot, nil) } code := me.rpcNodeFs.Mount(me.writableRoot, me.unionFs, &mOpts) if !code.Ok() { if err := me.MountState.Unmount(); err != nil { log.Fatal("FUSE unmount error during cleanup:", err) } return nil, errors.New(fmt.Sprintf("submount error for %s: %v", me.writableRoot, code)) } return me, nil }