Beispiel #1
0
// 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
}
Beispiel #2
0
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
}
Beispiel #3
0
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
}
Beispiel #4
0
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
}
Beispiel #5
0
// 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
}
Beispiel #6
0
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))
	}
}
Beispiel #7
0
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
}
Beispiel #8
0
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)
	}
}
Beispiel #9
0
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
}
Beispiel #10
0
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
}