Exemple #1
0
func (me *UnionFs) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
	r := me.getBranch(path)
	if r.code != fuse.OK {
		return r.code
	}
	if !r.attr.IsDir() {
		return fuse.Status(syscall.ENOTDIR)
	}

	stream, code := me.OpenDir(path, context)
	found := false
	for _ = range stream {
		found = true
	}
	if found {
		return fuse.Status(syscall.ENOTEMPTY)
	}

	if r.branch > 0 {
		code = me.putDeletion(path)
		return code
	}
	code = me.fileSystems[0].Rmdir(path, context)
	if code != fuse.OK {
		return code
	}

	r = me.branchCache.GetFresh(path).(branchResult)
	if r.branch > 0 {
		code = me.putDeletion(path)
	}
	return code
}
Exemple #2
0
func (vfs FuseVfs) Rmdir(name string, context *fuse.Context) fuse.Status {
	log.Infof(2, "BEGIN Rmdir(%v)", name)
	defer log.Infof(2, "END Rmdir(%v)", name)

	path := vfs.splitPath(name)

	switch path[0] {
	case tagsDir:
		if len(path) != 2 {
			// can only remove top-level tag directories
			return fuse.EPERM
		}

		tagName := path[1]
		tag, err := vfs.store.TagByName(tagName)
		if err != nil {
			log.Fatalf("could not retrieve tag '%v': %v", tagName, err)
		}
		if tag == nil {
			return fuse.ENOENT
		}

		count, err := vfs.store.FileTagCountByTagId(tag.Id)
		if err != nil {
			log.Fatalf("could not retrieve file-tag count for tag '%v': %v", tagName, err)
		}
		if count > 0 {
			return fuse.Status(syscall.ENOTEMPTY)
		}

		if err := vfs.store.DeleteTag(tag.Id); err != nil {
			log.Fatalf("could not delete tag '%v': %v", tagName, err)
		}

		if err := vfs.store.Commit(); err != nil {
			log.Fatalf("could not commit transaction: %v", err)
		}

		return fuse.OK
	case queriesDir:
		if len(path) != 2 {
			// can only remove top-level queries directories
			return fuse.EPERM
		}

		text := path[1]

		if err := vfs.store.DeleteQuery(text); err != nil {
			log.Fatalf("could not remove tag '%v': %v", name, err)
		}

		if err := vfs.store.Commit(); err != nil {
			log.Fatalf("could not commit transaction: %v", err)
		}

		return fuse.OK
	}

	return fuse.ENOSYS
}
func (f *flipNode) GetAttr(out *fuse.Attr, file nodefs.File, c *fuse.Context) fuse.Status {
	select {
	case <-f.ok:
		// use a status that is easily recognizable.
		return fuse.Status(syscall.EXDEV)
	default:
	}
	return f.Node.GetAttr(out, file, c)
}
Exemple #4
0
func (node *inMemNode) Link(name string, existing nodefs.Node, context *fuse.Context) (newNode *nodefs.Inode, code fuse.Status) {
	if node.Inode().GetChild(name) != nil {
		return nil, fuse.Status(syscall.EEXIST)
	}
	node.Inode().AddChild(name, existing.Inode())
	if inMemChild, ok := existing.(*inMemNode); ok {
		inMemChild.incrementLinks()
	}
	return existing.Inode(), fuse.OK
}
Exemple #5
0
func (n *configNode) Symlink(name string, content string, context *fuse.Context) (*nodefs.Inode, fuse.Status) {
	dir := content
	components := strings.Split(content, ":")
	if len(components) > 2 || len(components) == 0 {
		return nil, fuse.Status(syscall.EINVAL)
	}

	var root nodefs.Node
	if len(components) == 2 {
		dir = components[0]
	}

	if fi, err := os.Lstat(dir); err != nil {
		return nil, fuse.ToStatus(err)
	} else if !fi.IsDir() {
		return nil, fuse.Status(syscall.ENOTDIR)
	}

	var opts *nodefs.Options
	if len(components) == 1 {
		root = pathfs.NewPathNodeFs(pathfs.NewLoopbackFileSystem(content), nil).Root()
	} else {
		var err error
		root, err = NewGitFSRoot(content, n.fs.opts)
		if err != nil {
			log.Printf("NewGitFSRoot(%q): %v", content, err)
			return nil, fuse.ENOENT
		}
		opts = &nodefs.Options{
			EntryTimeout:    time.Hour,
			NegativeTimeout: time.Hour,
			AttrTimeout:     time.Hour,
			PortableInodes:  true,
		}
	}

	if code := n.fs.fsConn.Mount(n.corresponding.Inode(), name, root, opts); !code.Ok() {
		return nil, code
	}

	linkNode := newGitConfigNode(content)
	return n.Inode().NewChild(name, false, linkNode), fuse.OK
}
// Allocate - FUSE call for fallocate(2)
//
// mode=FALLOC_FL_KEEP_SIZE is implemented directly.
//
// mode=FALLOC_DEFAULT is implemented as a two-step process:
//
//   (1) Allocate the space using FALLOC_FL_KEEP_SIZE
//   (2) Set the file size using ftruncate (via truncateGrowFile)
//
// This allows us to reuse the file grow mechanics from Truncate as they are
// complicated and hard to get right.
//
// Other modes (hole punching, zeroing) are not supported.
func (f *file) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
	if mode != FALLOC_DEFAULT && mode != FALLOC_FL_KEEP_SIZE {
		f := func() {
			tlog.Warn.Print("fallocate: only mode 0 (default) and 1 (keep size) are supported")
		}
		allocateWarnOnce.Do(f)
		return fuse.Status(syscall.EOPNOTSUPP)
	}

	f.fdLock.RLock()
	defer f.fdLock.RUnlock()
	if f.released {
		return fuse.EBADF
	}
	f.fileTableEntry.writeLock.Lock()
	defer f.fileTableEntry.writeLock.Unlock()

	blocks := f.contentEnc.ExplodePlainRange(off, sz)
	firstBlock := blocks[0]
	lastBlock := blocks[len(blocks)-1]

	// Step (1): Allocate the space the user wants using FALLOC_FL_KEEP_SIZE.
	// This will fill file holes and/or allocate additional space past the end of
	// the file.
	cipherOff := firstBlock.BlockCipherOff()
	cipherSz := lastBlock.BlockCipherOff() - cipherOff +
		f.contentEnc.PlainSizeToCipherSize(lastBlock.Skip+lastBlock.Length)
	err := syscallcompat.Fallocate(f.intFd(), FALLOC_FL_KEEP_SIZE, int64(cipherOff), int64(cipherSz))
	tlog.Debug.Printf("Allocate off=%d sz=%d mode=%x cipherOff=%d cipherSz=%d\n",
		off, sz, mode, cipherOff, cipherSz)
	if err != nil {
		return fuse.ToStatus(err)
	}
	if mode == FALLOC_FL_KEEP_SIZE {
		// The user did not want to change the apparent size. We are done.
		return fuse.OK
	}
	// Step (2): Grow the apparent file size
	// We need the old file size to determine if we are growing the file at all.
	newPlainSz := off + sz
	oldPlainSz, err := f.statPlainSize()
	if err != nil {
		return fuse.ToStatus(err)
	}
	if newPlainSz <= oldPlainSz {
		// The new size is smaller (or equal). Fallocate with mode = 0 never
		// truncates a file, so we are done.
		return fuse.OK
	}
	// The file grows. The space has already been allocated in (1), so what is
	// left to do is to pad the first and last block and call truncate.
	// truncateGrowFile does just that.
	return f.truncateGrowFile(oldPlainSz, newPlainSz)
}
Exemple #7
0
func (m *MNode) makeKnot(name string,isDir bool) (*nodefs.Inode,*MNode,fuse.Status) {
	m.obj.Lock()
	defer m.obj.Unlock()
	d,ok := m.obj.Obj.(*joinf.Directory)
	if !ok {
		return nil,nil,fuse.ENOTDIR
	}
	{
		c := m.Inode().GetChild(name)
		if c!=nil { return nil,nil,fuse.Status(syscall.EEXIST) }
		id,_ := d.Find(name)
		if id!="" { return nil,nil,fuse.Status(syscall.EEXIST) }
	}
	id := uuid.NewV4().String()
	if isDir {
		r := m.lm.Dirs(id)
		e := joinf.CreateDir(r)
		if e!=nil { return nil,nil,fuse.ToStatus(e) }
		e = d.Insert(name,id)
		if e!=nil {
			r.Delete()
			return nil,nil,fuse.ToStatus(e)
		}
		r.Dispose()
	}else{
		r := m.lm.Files(id)
		e := joinf.CreateFile(r)
		if e!=nil { return nil,nil,fuse.ToStatus(e) }
		e = d.Insert(name,id)
		if e!=nil {
			r.Delete()
			return nil,nil,fuse.ToStatus(e)
		}
		r.Dispose()
	}
	co := m.lm.Load(id)
	nin := &MNode{nodefs.NewDefaultNode(),m.lm,co}
	return m.Inode().NewChild(name,isDir,nin),nin,fuse.OK
}
Exemple #8
0
func (parent *inMemNode) Symlink(name string, content string, context *fuse.Context) (*nodefs.Inode, fuse.Status) {
	if parent.Inode().GetChild(name) != nil {
		return nil, fuse.Status(syscall.EEXIST)
	}
	node := parent.fs.createNode()
	node.attr.Mode = 0777 | fuse.S_IFLNK
	contentBytes := []byte(content)
	node.setSize(len(contentBytes))
	copy(node.contents, contentBytes)
	parent.Inode().NewChild(name, false, node)
	parent.incrementLinks()
	return node.Inode(), fuse.OK
}
Exemple #9
0
func (constor *Constor) Lookup(header *fuse.InHeader, name string, out *fuse.EntryOut) fuse.Status {
	var stat syscall.Stat_t
	if len(name) > 255 {
		constor.error("name too long : %s", name)
		return fuse.Status(syscall.ENAMETOOLONG)
	}
	li := -1
	parent := constor.inodemap.findInodePtr(header.NodeId)
	if parent == nil {
		constor.error("Unable to find parent inode : %d", header.NodeId)
		return fuse.ENOENT
	}
	constor.log("%s(%s)", parent.id, name)
	id, err := constor.getid(-1, parent.id, name)
	if err != nil {
		// logging this error will produce too many logs as there will be too many
		// lookps on non-existant files
		return fuse.ToStatus(err)
	}
	inode := constor.inodemap.findInodeId(id)
	if inode != nil {
		li = inode.layer
	} else {
		li = constor.getLayer(id)
	}
	if li == -1 {
		constor.error("Unable to find inode for %s(%s) id %s", parent.id, name, id)
		return fuse.ENOENT
	}
	err = constor.Lstat(li, id, &stat)
	if err != nil {
		constor.error("Unable to Lstat inode for %s(%s) id %s", parent.id, name, id)
		return fuse.ToStatus(err)
	}
	if inode == nil {
		inode = NewInode(constor, id)
		inode.layer = li
		constor.inodemap.hashInode(inode)
	} else {
		inode.lookup()
	}
	attr := (*fuse.Attr)(&out.Attr)
	attr.FromStat(&stat)
	out.NodeId = uint64(uintptr(unsafe.Pointer(inode)))
	out.Ino = attr.Ino
	out.EntryValid = 1000
	out.AttrValid = 1000
	constor.log("%s", id)
	return fuse.OK
}
Exemple #10
0
func (parent *inMemNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, child *nodefs.Inode, code fuse.Status) {
	if parent.Inode().GetChild(name) != nil {
		return nil, nil, fuse.Status(syscall.EEXIST)
	}
	node := parent.fs.createNode()
	node.attr.Mode = mode | fuse.S_IFREG
	parent.Inode().NewChild(name, false, node)
	parent.incrementLinks()
	f, openStatus := node.Open(flags, context)
	if openStatus != fuse.OK {
		return nil, nil, openStatus
	}
	return f, node.Inode(), fuse.OK
}
Exemple #11
0
func (me *UnionFs) createDeletionStore() (code fuse.Status) {
	writable := me.fileSystems[0]
	fi, code := writable.GetAttr(me.options.DeletionDirName, nil)
	if code == fuse.ENOENT {
		code = writable.Mkdir(me.options.DeletionDirName, 0755, nil)
		if code.Ok() {
			fi, code = writable.GetAttr(me.options.DeletionDirName, nil)
		}
	}

	if !code.Ok() || !fi.IsDir() {
		code = fuse.Status(syscall.EROFS)
	}

	return code
}
Exemple #12
0
func (fs *autoUnionFs) Symlink(pointedTo string, linkName string, context *fuse.Context) (code fuse.Status) {
	comps := strings.Split(linkName, "/")
	if len(comps) != 2 {
		return fuse.EPERM
	}

	if comps[0] == _CONFIG {
		roots := fs.getRoots(pointedTo)
		if roots == nil {
			return fuse.Status(syscall.ENOTDIR)
		}

		name := comps[1]
		return fs.addFs(name, roots)
	}
	return fuse.EPERM
}
Exemple #13
0
func (f *androidFile) Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status) {
	if off >= f.node.Size {
		// ENXIO = no such address.
		return nil, fuse.Status(int(syscall.ENXIO))
	}

	if off+int64(len(dest)) > f.node.Size {
		dest = dest[:f.node.Size-off]
	}
	b := bytes.NewBuffer(dest[:0])
	err := f.node.fs.dev.AndroidGetPartialObject64(f.node.Handle(), b, off, uint32(len(dest)))
	if err != nil {
		log.Println("AndroidGetPartialObject64 failed:", err)
		return nil, fuse.EIO
	}

	return &fuse.ReadResultData{dest[:b.Len()]}, fuse.OK
}
Exemple #14
0
func (parent *AppendFSNode) Mkdir(name string, mode uint32, context *fuse.Context) (newNode *nodefs.Inode, code fuse.Status) {
	if parent.Inode().GetChild(name) != nil {
		return nil, fuse.Status(syscall.EEXIST)
	}
	node := CreateNode(parent)
	node.attr.Mode = mode | fuse.S_IFDIR
	node.attr.Nlink = 2
	node.name = name
	inode := parent.inode.NewChild(name, true, node)
	parent.incrementLinks()

	err := node.fs.AppendMetadata(node.AsNodeMetadata())
	if err != nil {
		return nil, fuse.EIO
	}

	return inode, fuse.OK
}
Exemple #15
0
// The isDeleted() method tells us if a path has a marker in the deletion store.
// It may return an error code if the store could not be accessed.
func (me *UnionFs) isDeleted(name string) (deleted bool, code fuse.Status) {
	marker := me.deletionPath(name)
	haveCache, found := me.deletionCache.HasEntry(filepath.Base(marker))
	if haveCache {
		return found, fuse.OK
	}

	_, code = me.fileSystems[0].GetAttr(marker, nil)

	if code == fuse.OK {
		return true, code
	}
	if code == fuse.ENOENT {
		return false, fuse.OK
	}

	log.Println("error accessing deletion marker:", marker)
	return false, fuse.Status(syscall.EROFS)
}
Exemple #16
0
func (parent *AppendFSNode) Symlink(name string, content string, context *fuse.Context) (*nodefs.Inode, fuse.Status) {
	if parent.Inode().GetChild(name) != nil {
		return nil, fuse.Status(syscall.EEXIST)
	}
	node := CreateNode(parent)
	node.attr.Mode = 0777 | fuse.S_IFLNK
	contentBytes := []byte(content)
	node.setSize(uint64(len(contentBytes)))
	node.symlink = contentBytes
	node.name = name
	parent.Inode().NewChild(name, false, node)
	parent.incrementLinks()

	err := node.fs.AppendMetadata(node.AsNodeMetadata())
	if err != nil {
		return nil, fuse.EIO
	}

	return node.Inode(), fuse.OK
}
Exemple #17
0
func (fs *nomsFS) GetXAttr(path string, attribute string, context *fuse.Context) ([]byte, fuse.Status) {
	fs.mdLock.Lock()
	defer fs.mdLock.Unlock()
	np, code := fs.getPath(path)
	if code != fuse.OK {
		return nil, code
	}

	xattr := np.inode.Get("attr").(types.Struct).Get("xattr").(types.Map)

	v, found := xattr.MaybeGet(types.String(attribute))
	if !found {
		return nil, fuse.Status(93) // syscall.ENOATTR
	}

	blob := v.(types.Blob)

	data := make([]byte, blob.Len())
	blob.Reader().Read(data)

	return data, fuse.OK
}
Exemple #18
0
func (parent *AppendFSNode) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, child *nodefs.Inode, code fuse.Status) {
	if parent.Inode().GetChild(name) != nil {
		return nil, nil, fuse.Status(syscall.EEXIST)
	}
	node := CreateNode(parent)
	node.attr.Mode = mode | fuse.S_IFREG
	node.attr.Uid = context.Uid
	node.attr.Gid = context.Gid
	node.name = name
	parent.Inode().NewChild(name, false, node)
	parent.incrementLinks()

	err := node.fs.AppendMetadata(node.AsNodeMetadata())
	if err != nil {
		return nil, nil, fuse.EIO
	}

	f, openStatus := node.Open(flags, context)
	if openStatus != fuse.OK {
		return nil, nil, openStatus
	}
	return f, node.Inode(), fuse.OK
}
Exemple #19
0
func (me *UnionFs) Mkdir(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
	deleted, code := me.isDeleted(path)
	if !code.Ok() {
		return code
	}

	if !deleted {
		r := me.getBranch(path)
		if r.code != fuse.ENOENT {
			return fuse.Status(syscall.EEXIST)
		}
	}

	code = me.promoteDirsTo(path)
	if code.Ok() {
		code = me.fileSystems[0].Mkdir(path, mode, context)
	}
	if code.Ok() {
		me.removeDeletion(path)
		attr := &fuse.Attr{
			Mode: fuse.S_IFDIR | mode,
		}
		me.branchCache.Set(path, branchResult{attr, fuse.OK, 0})
	}

	var stream chan fuse.DirEntry
	stream, code = me.OpenDir(path, context)
	if code.Ok() {
		// This shouldn't happen, but let's be safe.
		for entry := range stream {
			me.putDeletion(filepath.Join(path, entry.Name))
		}
	}

	return code
}
Exemple #20
0
func (e errorReadResult) Bytes(buf []byte) ([]byte, fuse.Status) {
	return nil, fuse.Status(e)
}
Exemple #21
0
func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan fuse.DirEntry, status fuse.Status) {
	dirBranch := me.getBranch(directory)
	if dirBranch.branch < 0 {
		return nil, fuse.ENOENT
	}

	// We could try to use the cache, but we have a delay, so
	// might as well get the fresh results async.
	var wg sync.WaitGroup
	var deletions map[string]bool

	wg.Add(1)
	go func() {
		deletions = newDirnameMap(me.fileSystems[0], me.options.DeletionDirName)
		wg.Done()
	}()

	entries := make([]map[string]uint32, len(me.fileSystems))
	for i := range me.fileSystems {
		entries[i] = make(map[string]uint32)
	}

	statuses := make([]fuse.Status, len(me.fileSystems))
	for i, l := range me.fileSystems {
		if i >= dirBranch.branch {
			wg.Add(1)
			go func(j int, pfs fuse.FileSystem) {
				ch, s := pfs.OpenDir(directory, context)
				statuses[j] = s
				for s.Ok() {
					v, ok := <-ch
					if !ok {
						break
					}
					entries[j][v.Name] = v.Mode
				}
				wg.Done()
			}(i, l)
		}
	}

	wg.Wait()
	if deletions == nil {
		_, code := me.fileSystems[0].GetAttr(me.options.DeletionDirName, context)
		if code == fuse.ENOENT {
			deletions = map[string]bool{}
		} else {
			return nil, fuse.Status(syscall.EROFS)
		}
	}

	results := entries[0]

	// TODO(hanwen): should we do anything with the return
	// statuses?
	for i, m := range entries {
		if statuses[i] != fuse.OK {
			continue
		}
		if i == 0 {
			// We don't need to further process the first
			// branch: it has no deleted files.
			continue
		}
		for k, v := range m {
			_, ok := results[k]
			if ok {
				continue
			}

			deleted := deletions[filePathHash(filepath.Join(directory, k))]
			if !deleted {
				results[k] = v
			}
		}
	}
	if directory == "" {
		delete(results, me.options.DeletionDirName)
		for name, _ := range me.hiddenFiles {
			delete(results, name)
		}
	}

	stream = make(chan fuse.DirEntry, len(results))
	for k, v := range results {
		stream <- fuse.DirEntry{
			Name: k,
			Mode: v,
		}
	}
	close(stream)
	return stream, fuse.OK
}
Exemple #22
0
func (constor *Constor) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) {
	sendEntryNotify := false
	var inodedel *Inode
	oldParent := constor.inodemap.findInodePtr(input.NodeId)
	if oldParent == nil {
		constor.error("oldParent == nil")
		return fuse.ENOENT
	}
	newParent := constor.inodemap.findInodePtr(input.Newdir)
	if newParent == nil {
		constor.error("newParent == nil")
		return fuse.ENOENT
	}
	if err := constor.copyup(newParent); err != nil {
		constor.error("copyup failed for %s - %s", newParent.id, err)
		return fuse.EIO
	}
	newParentPath := constor.getPath(0, newParent.id)
	newentrypath := Path.Join(newParentPath, newName)
	constor.log("%s %s %s %s", oldParent.id, oldName, newParent.id, newName)
	// remove any entry that existed in the newName's place
	if iddel, err := constor.getid(-1, newParent.id, newName); err == nil {
		if inodedel = constor.inodemap.findInodeId(iddel); inodedel != nil {
			if inodedel.layer == 0 {
				linkcnt, err := constor.declinkscnt(inodedel.id)
				if err != nil {
					constor.error("declinkscnt %s : %s", inodedel.id, err)
					return fuse.ToStatus(err)
				}
				if linkcnt == 0 {
					path := constor.getPath(0, iddel)
					fi, err := os.Lstat(path)
					if err != nil {
						constor.error("Lstat failed on %s", path)
						return fuse.ToStatus(err)
					}
					if fi.IsDir() {
						// FIXME: take care of this situation
						constor.error("path is a directory")
						return fuse.Status(syscall.EEXIST)
					}
					if err := syscall.Unlink(path); err != nil {
						constor.error("Unable to remove %s", path)
						return fuse.ToStatus(err)
					}
					inodedel.layer = -1
				}
			}
			stat := syscall.Stat_t{}
			// FIXME do copyup and declinkscnt
			if err := syscall.Lstat(newentrypath, &stat); err == nil {
				fi, err := os.Lstat(newentrypath)
				if err != nil {
					constor.error("Lstat failed on %s", newentrypath)
					return fuse.ToStatus(err)
				}
				if fi.IsDir() {
					// FIXME: take care of this situation
					constor.error("path is a directory")
					return fuse.Status(syscall.EEXIST)
				}
				if err := syscall.Unlink(newentrypath); err != nil {
					constor.error("Unable to remove %s", newentrypath)
					return fuse.ToStatus(err)
				}
			}
			// inodedel.parentPtr = input.Newdir
			// inodedel.name = newName
			sendEntryNotify = true
			// constor.ms.DeleteNotify(input.Newdir, uint64(uintptr(unsafe.Pointer(inodedel))), newName)
			// constor.ms.EntryNotify(input.Newdir, newName)
		} else {
			constor.error("inodedel == nil for %s %s", newParent.id, newName)
			return fuse.EIO
		}
	}
	// remove any deleted placeholder
	if constor.isdeleted(newentrypath, nil) {
		if err := syscall.Unlink(newentrypath); err != nil {
			constor.error("Unlink %s : %s", newentrypath, err)
			return fuse.ToStatus(err)
		}
	}
	oldid, err := constor.getid(-1, oldParent.id, oldName)
	if err != nil {
		constor.error("getid error %s %s", oldParent.id, oldName)
		return fuse.ToStatus(err)
	}
	oldinode := constor.inodemap.findInodeId(oldid)
	if oldinode == nil {
		constor.error("oldinode == nil for %s", oldid)
		return fuse.ENOENT
	}
	path := constor.getPath(oldinode.layer, oldid)
	fi, err := os.Lstat(path)
	if err != nil {
		constor.error("Lstat %s", path)
		return fuse.ToStatus(err)
	}
	oldParentPath := constor.getPath(0, oldParent.id)
	oldentrypath := Path.Join(oldParentPath, oldName)
	oldstat := syscall.Stat_t{}
	if err := syscall.Lstat(oldentrypath, &oldstat); err == nil {
		if fi.IsDir() {
			if err := syscall.Rmdir(oldentrypath); err != nil {
				constor.error("Rmdir %s : %s", oldentrypath, err)
				return fuse.ToStatus(err)
			}
		} else {
			if err := syscall.Unlink(oldentrypath); err != nil {
				constor.error("Unlink %s : %s", oldentrypath, err)
				return fuse.ToStatus(err)
			}
		}
	}
	if _, err := constor.getid(-1, oldParent.id, oldName); err == nil {
		constor.setdeleted(oldentrypath)
	}
	if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
		err = os.Symlink("placeholder", newentrypath)
		if err != nil {
			constor.error("Symlink %s : %s", newentrypath, err)
			return fuse.ToStatus(err)
		}
	} else if fi.Mode()&os.ModeDir == os.ModeDir {
		err := os.Mkdir(newentrypath, fi.Mode())
		if err != nil {
			constor.error("Mkdir %s : %s", newentrypath, err)
			return fuse.ToStatus(err)
		}
	} else {
		fd, err := syscall.Creat(newentrypath, uint32(fi.Mode()))
		if err != nil {
			constor.error("create %s : %s", newentrypath, err)
			return fuse.ToStatus(err)
		}
		syscall.Close(fd)
	}
	id := constor.setid(newentrypath, oldid)
	if id == "" {
		constor.error("setid %s : %s", newentrypath, err)
		return fuse.EIO
	}
	if sendEntryNotify {
		go func() {
			// FIXME: is this needed?
			constor.ms.DeleteNotify(input.Newdir, uint64(uintptr(unsafe.Pointer(inodedel))), newName)
			constor.ms.DeleteNotify(input.NodeId, uint64(uintptr(unsafe.Pointer(oldinode))), oldName)
		}()
	}
	return fuse.OK
}
Exemple #23
0
package main

import (
	"github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	"github.com/hanwen/go-fuse/fuse/pathfs"
	"github.com/hashicorp/vault/api"
	"github.com/square/keywhiz-fs"
	"golang.org/x/sys/unix"
)

const (
	EISDIR = fuse.Status(unix.EISDIR)
)

type fs struct {
	pathfs.FileSystem
	client *api.Client
	owner  keywhizfs.Ownership
}

// NewKeywhizFs readies a KeywhizFs struct and its parent filesystem objects.
func NewFs(client *api.Client, owner keywhizfs.Ownership) (*fs, nodefs.Node) {
	defaultfs := pathfs.NewDefaultFileSystem()            // Returns ENOSYS by default
	readonlyfs := pathfs.NewReadonlyFileSystem(defaultfs) // R/W calls return EPERM

	kwfs := &fs{readonlyfs, client, owner}
	nfs := pathfs.NewPathNodeFs(kwfs, nil)
	nfs.SetDebug(true)
	return kwfs, nfs.Root()
}
Exemple #24
0
// toFuseStatusLog converts an Errno to a Status and logs it.
func toFuseStatusLog(err error, logEntry *LogEntry) fuse.Status {
	return fuse.Status(toErrnoLog(err, logEntry))
}
Exemple #25
0
func (constor *Constor) Rmdir(header *fuse.InHeader, name string) (code fuse.Status) {
	constor.log("%d %s", header.NodeId, name)
	var stat syscall.Stat_t
	parent := constor.inodemap.findInodePtr(header.NodeId)
	if parent == nil {
		constor.error("parent == nil")
		return fuse.ENOENT
	}
	constor.log("%s %s", parent.id, name)
	id, err := constor.getid(-1, parent.id, name)
	if err != nil {
		constor.error("getid failed %s %s", parent.id, name)
		return fuse.ToStatus(err)
	}
	inode := constor.inodemap.findInodeId(id)
	if inode == nil {
		constor.error("%s %s : inode == nil", parent.id, name)
		return fuse.ENOENT
	}

	entries := map[string]DirEntry{}
	for li, _ := range constor.layers {
		path := constor.getPath(li, inode.id)
		stat := syscall.Stat_t{}
		err := syscall.Lstat(path, &stat)
		if err != nil {
			// this means that the directory was created on the layer above this layer
			break
		}
		if (stat.Mode & syscall.S_IFMT) != syscall.S_IFDIR {
			constor.error("Not a dir: %s", path)
			break
		}

		f, err := os.Open(path)
		if err != nil {
			constor.error("Open failed on %s", path)
			break
		}
		infos, _ := f.Readdir(0)
		for i := range infos {
			// workaround forhttps://code.google.com/p/go/issues/detail?id=5960
			if infos[i] == nil {
				continue
			}
			name := infos[i].Name()
			if _, ok := entries[name]; ok {
				// skip if the file was in upper layer
				continue
			}
			d := DirEntry{
				Name: name,
				Mode: uint32(infos[i].Mode()),
			}
			if constor.isdeleted(Path.Join(path, name), infos[i].Sys().(*syscall.Stat_t)) {
				d.Deleted = true
			} else {
				id, err := constor.getid(li, inode.id, name)
				if err != nil {
					constor.error("getid failed on %d %s %s", li, inode.id, name)
					continue
				}
				d.Ino = idtoino(id)
			}
			entries[name] = d
		}
		f.Close()
	}
	output := make([]DirEntry, 0, 500)

	for _, d := range entries {
		if d.Deleted {
			continue
		}
		output = append(output, d)
	}

	if len(output) > 0 {
		constor.error("Directory not empty %s %s", parent.id, name)
		return fuse.Status(syscall.ENOTEMPTY)
	}

	if inode.layer == 0 {
		path := constor.getPath(0, inode.id)
		if err := os.RemoveAll(path); err != nil {
			constor.error("RemoveAll on %s : %s", path, err)
			return fuse.ToStatus(err)
		}
	}
	err = constor.copyup(parent)
	if err != nil {
		constor.error("copyup failed for %s - %s", parent.id, err)
		return fuse.ToStatus(err)
	}
	entrypath := Path.Join(constor.getPath(0, parent.id), name)
	if err := syscall.Lstat(entrypath, &stat); err == nil {
		if err := syscall.Rmdir(entrypath); err != nil {
			constor.error("Rmdir on %s : %s", entrypath, err)
			return fuse.ToStatus(err)
		}
	}
	// if the file is in a lower layer then create a deleted place holder file
	if _, err := constor.getid(-1, parent.id, name); err == nil {
		constor.setdeleted(entrypath)
	}
	inode.layer = -1
	return fuse.OK
}