// fillReply empties the unionFs and hashes files as needed. It will // return the FS back the pool as soon as possible. func (t *Mirror) fillReply(state *workerFSState) (*attr.FileSet, []string) { fsResult := state.fs.reap() t.returnFS(state) files := make([]*attr.FileAttr, 0, len(fsResult.files)) wrRoot := strings.TrimLeft(state.fs.fuseFS.writableRoot, "/") reapedHashes := map[string]string{} for path, v := range fsResult.files { f := &attr.FileAttr{ Path: fastpath.Join(wrRoot, path), } if v.Attr != nil { f.Attr = v.Attr } f.Link = v.Link if !f.Deletion() && f.IsRegular() { contentPath := fastpath.Join(wrRoot, v.Original) if v.Original != "" && v.Original != contentPath { fa := t.rpcFs.attr.Get(contentPath) if fa.Hash == "" { log.Panicf("Contents for %q disappeared.", contentPath) } f.Hash = fa.Hash } if v.Backing != "" { h, ok := reapedHashes[v.Backing] if !ok { var err error h, err = t.worker.content.DestructiveSavePath(v.Backing) if err != nil || h == "" { log.Fatalf("DestructiveSavePath fail %v, %q", err, h) } reapedHashes[v.Backing] = h } f.Hash = h } } files = append(files, f) } fset := attr.FileSet{Files: files} fset.Sort() err := os.Remove(fsResult.dir) if err != nil { log.Fatalf("fillReply: Remove failed: %v", err) } return &fset, fsResult.reads }
func ReadHexDatabase(d string) map[string]bool { hexRe := regexp.MustCompile("^([0-9a-fA-F][0-9a-fA-F])+$") db := map[string]bool{} entries, err := ioutil.ReadDir(d) if err != nil { return db } for _, e := range entries { if !hexRe.MatchString(e.Name()) || !e.IsDir() { continue } sub, _ := ioutil.ReadDir(fastpath.Join(d, e.Name())) for _, s := range sub { if !hexRe.MatchString(s.Name()) || s.IsDir() { continue } hex := e.Name() + s.Name() bin := make([]byte, len(hex)/2) n, err := fmt.Sscanf(hex, "%x", &bin) if n != 1 { log.Panic("sscanf %d %v", n, err) } db[string(bin)] = true } } return db }
func (me *memNode) reset(path string) (entryNotify bool) { for n, ch := range me.Inode().FsChildren() { p := fastpath.Join(path, n) mn := ch.Node().(*memNode) if mn.reset(p) { me.Inode().RmChild(n) me.fs.connector.EntryNotify(me.Inode(), n) } } if me.backing != "" || me.original != path { return true } if me.changed { info, code := me.fs.readonly.GetAttr(me.original, nil) if !code.Ok() { return true } me.info = *info me.fs.connector.FileNotify(me.Inode(), -1, 0) if me.Inode().IsDir() { me.fs.connector.FileNotify(me.Inode(), 0, 0) } } return false }
func (me *memNode) OpenDir(context *fuse.Context) (stream []fuse.DirEntry, code fuse.Status) { me.mutex.RLock() defer me.mutex.RUnlock() ch := map[string]uint32{} if me.original != "" || me == me.fs.root { stream, code = me.fs.readonly.OpenDir(me.original, context) for _, e := range stream { fn := fastpath.Join(me.original, e.Name) if !me.fs.deleted[fn] { ch[e.Name] = e.Mode } } } for k, n := range me.Inode().FsChildren() { ch[k] = n.Node().(*memNode).info.Mode } stream = make([]fuse.DirEntry, 0, len(ch)) for k, v := range ch { stream = append(stream, fuse.DirEntry{Name: k, Mode: v}) } return stream, fuse.OK }
// Must run with mutex held. func (me *memNode) lookup(out *fuse.Attr, name string, context *fuse.Context) (*nodefs.Inode, fuse.Status) { if me.original == "" && me != me.fs.root { return nil, fuse.ENOENT } fn := fastpath.Join(me.original, name) if _, del := me.fs.deleted[fn]; del { return nil, fuse.ENOENT } fi, code := me.fs.readonly.GetAttr(fn, context) if !code.Ok() { return nil, code } *out = *fi isDir := fi.Mode&fuse.S_IFDIR != 0 child := me.fs.newNode(isDir) child.info = *fi child.original = fn if child.info.Mode&fuse.S_IFLNK != 0 { child.link, _ = me.fs.readonly.Readlink(fn, context) } return me.Inode().NewChild(name, isDir, child), fuse.OK }
func (me *MemUnionFs) clearBackingStore() { f, err := os.Open(me.backingStore) if err != nil { return } defer f.Close() names, err := f.Readdirnames(-1) if err != nil { return } for _, n := range names { os.Remove(fastpath.Join(me.backingStore, n)) } }
func (me *memNode) Unlink(name string, context *fuse.Context) (code fuse.Status) { me.mutex.Lock() defer me.mutex.Unlock() if me.original != "" || me == me.fs.root { me.fs.deleted[fastpath.Join(me.original, name)] = true } ch := me.Inode().RmChild(name) if ch == nil { return fuse.ENOENT } me.touch() return fuse.OK }
func (me *memNode) reap(path string, results map[string]*Result) { if me.changed { info := me.info results[path] = &Result{ Attr: &info, Link: me.link, Backing: me.backing, Original: me.original, } } for n, ch := range me.Inode().FsChildren() { p := fastpath.Join(path, n) ch.Node().(*memNode).reap(p, results) } }
func (me *MemUnionFs) Reap() map[string]*Result { me.mutex.Lock() defer me.mutex.Unlock() for me.openWritable > 0 { me.cond.Wait() } m := map[string]*Result{} for name := range me.deleted { fi, code := me.readonly.GetAttr(name, nil) if !code.Ok() { continue } m[name] = &Result{} if !fi.IsDir() { continue } todo := []string{name} for len(todo) > 0 { l := len(todo) - 1 n := todo[l] todo = todo[:l] s, _ := me.readonly.OpenDir(n, nil) for _, e := range s { full := fastpath.Join(n, e.Name) m[full] = &Result{} if e.Mode&fuse.S_IFDIR != 0 { todo = append(todo, full) } } } } me.root.reap("", m) return m }
func (me *memNode) Rename(oldName string, newParent nodefs.Node, newName string, context *fuse.Context) (code fuse.Status) { me.mutex.Lock() defer me.mutex.Unlock() ch := me.Inode().RmChild(oldName) if ch == nil { return fuse.ENOENT } if me.original != "" || me == me.fs.root { me.fs.deleted[fastpath.Join(me.original, oldName)] = true } childNode := ch.Node().(*memNode) if childNode.original != "" || childNode == me.fs.root { childNode.materialize() childNode.markChanged() } newParent.Inode().RmChild(newName) newParent.Inode().AddChild(newName, ch) me.touch() return fuse.OK }