Example #1
0
// node returns an fs.Node corresponding to the given key. It distinguishes
// between files and directories and correctly translates etcd errors into
// appropriate syscall errors.
func (f *etcdFS) node(ctx context.Context, key string) (fs.Node, error) {
	resp, err := f.etcd.Get(ctx, key, &client.GetOptions{
		Sort:   true,
		Quorum: true,
	})
	if err != nil {
		log.Printf("Error fetching node %q: %v", key, err)
		if _, ok := err.(client.Error); !ok {
			return nil, err
		}

		e := err.(client.Error)
		switch e.Code {
		case client.ErrorCodeKeyNotFound:
			return nil, fuse.Errno(syscall.ENOENT)
		case client.ErrorCodeNotDir:
			return nil, fuse.Errno(syscall.ENOTDIR)
		case client.ErrorCodeUnauthorized:
			return nil, fuse.Errno(syscall.EPERM)
		default:
			return nil, err
		}
	}

	n := resp.Node
	if n.Dir {
		return &etcdDir{f, n}, nil
	}
	return &etcdFile{f, n}, nil
}
Example #2
0
func (file *File) ReadAll(intr fs.Intr) ([]byte, fuse.Error) {
	bytes, err := ioutil.ReadFile(file.Path)
	if err != nil {
		return nil, fuse.Errno(syscall.ENOSYS)
	}
	return bytes, nil
}
Example #3
0
func (e fuseFile) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fusefs.Handle, error) {
	if !req.Flags.IsReadOnly() {
		return nil, fuse.Errno(syscall.EACCES)
	}

	return e, nil
}
Example #4
0
func (e fuseFile) Open(req *fuse.OpenRequest, resp *fuse.OpenResponse, intr fusefs.Intr) (fusefs.Handle, fuse.Error) {
	if req.Flags&syscall.O_ACCMODE != syscall.O_RDONLY {
		return nil, fuse.Errno(syscall.EACCES)
	}

	return e, nil
}
Example #5
0
func (e fuseFile) Open(req *fuse.OpenRequest, resp *fuse.OpenResponse, intr fusefs.Intr) (fusefs.Handle, fuse.Error) {
	if !req.Flags.IsReadOnly() {
		return nil, fuse.Errno(syscall.EACCES)
	}

	return e, nil
}
Example #6
0
func (h *handle) Read(ctx context.Context, request *fuse.ReadRequest, response *fuse.ReadResponse) (retErr error) {
	defer func() {
		if retErr == nil {
			protolion.Debug(&FileRead{&h.f.Node, string(response.Data), errorToString(retErr)})
		} else {
			protolion.Error(&FileRead{&h.f.Node, string(response.Data), errorToString(retErr)})
		}
	}()
	var buffer bytes.Buffer
	if err := h.f.fs.apiClient.GetFileUnsafe(
		h.f.File.Commit.Repo.Name,
		h.f.File.Commit.ID,
		h.f.File.Path,
		request.Offset,
		int64(request.Size),
		h.f.fs.getFromCommitID(h.f.getRepoOrAliasName()),
		h.f.Shard,
		h.f.fs.handleID,
		&buffer,
	); err != nil {
		if grpc.Code(err) == codes.NotFound {
			// ENOENT from read(2) is weird, let's call this EINVAL
			// instead.
			return fuse.Errno(syscall.EINVAL)
		}
		return err
	}
	response.Data = buffer.Bytes()
	return nil
}
Example #7
0
File: dir.go Project: jgluck/bazil
func (d *dir) Mkdir(req *fuse.MkdirRequest, intr fs.Intr) (fs.Node, fuse.Error) {
	d.mu.Lock()
	defer d.mu.Unlock()

	// TODO handle req.Mode

	var child node
	err := d.fs.db.Update(func(tx *bolt.Tx) error {
		bucket := d.fs.bucket(tx).Bucket(bucketInode)
		if bucket == nil {
			return errors.New("inode bucket is missing")
		}
		inode, err := inodes.Allocate(bucket)
		if err != nil {
			return err
		}
		child = &dir{
			inode:  inode,
			name:   req.Name,
			parent: d,
			fs:     d.fs,
			active: make(map[string]node),
		}
		d.active[req.Name] = child
		return d.saveInternal(tx, req.Name, child)
		// TODO clean up active on error
	})
	if err != nil {
		if err == inodes.OutOfInodes {
			return nil, fuse.Errno(syscall.ENOSPC)
		}
		return nil, err
	}
	return child, nil
}
Example #8
0
func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
	if !req.Flags.IsReadOnly() {
		return nil, fuse.Errno(syscall.EACCES)
	}
	resp.Flags |= fuse.OpenKeepCache
	return f, nil
}
Example #9
0
func (file *UpperCaseFile) ReadAll(intr fs.Intr) ([]byte, fuse.Error) {
	bytes, err := ioutil.ReadFile(file.Path)
	if err != nil {
		return nil, fuse.Errno(syscall.ENOSYS)
	}

	return []byte(strings.ToUpper(string(bytes))), nil
}
Example #10
0
// Rename implements the fs.NodeRenamer interface for Dir.
func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest,
	newDir fs.Node) (err error) {
	d.folder.fs.log.CDebugf(ctx, "Dir Rename %s -> %s",
		req.OldName, req.NewName)
	defer func() { d.folder.reportErr(ctx, libkbfs.WriteMode, err) }()

	var realNewDir *Dir
	switch newDir := newDir.(type) {
	case *Dir:
		realNewDir = newDir
	case *TLF:
		var err error
		realNewDir, err = newDir.loadDir(ctx)
		if err != nil {
			return err
		}
	default:
		// The destination is not a TLF instance, probably
		// because it's Root (or some other node type added
		// later). The kernel won't let a rename newDir point
		// to a non-directory.
		//
		// We have no cheap atomic rename across folders, so
		// we can't serve this. EXDEV makes `mv` do a
		// copy+delete, and the Lookup on the destination path
		// will decide whether it's legal.
		return fuse.Errno(syscall.EXDEV)
	}

	if d.folder != realNewDir.folder {
		// Check this explicitly, not just trusting KBFSOps.Rename to
		// return an error, because we rely on it for locking
		// correctness.
		return fuse.Errno(syscall.EXDEV)
	}

	// overwritten node, if any, will be removed from Folder.nodes, if
	// it is there in the first place, by its Forget

	if err := d.folder.fs.config.KBFSOps().Rename(
		ctx, d.node, req.OldName, realNewDir.node, req.NewName); err != nil {
		return err
	}

	return nil
}
Example #11
0
func (n *Node) Access(ctx context.Context, req *fuse.AccessRequest) error {
	isDir, err := isDir(n.path)
	defer trace(NewAccessOp(req, n.path, isDir))
	if err != nil {
		return err
	}
	if access(n.path, req.Mask) {
		return nil
	}
	return fuse.Errno(syscall.EACCES)
}
Example #12
0
// checkIsEmpty returns nil if 'id' has no children.
func checkIsEmpty(e sqlExecutor, id uint64) error {
	var count uint64
	const countSQL = `
SELECT COUNT(parentID) FROM fs.namespace WHERE parentID = $1`
	if err := e.QueryRow(countSQL, id).Scan(&count); err != nil {
		return err
	}
	if count != 0 {
		return fuse.Errno(syscall.ENOTEMPTY)
	}
	return nil
}
Example #13
0
func (f *file) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
	// allow kernel to use buffer cache
	resp.Flags &^= fuse.OpenDirectIO
	f.mu.Lock()
	defer f.mu.Unlock()
	tmp := f.handles + 1
	if tmp == 0 {
		return nil, fuse.Errno(syscall.ENFILE)
	}
	f.handles = tmp
	return f, nil
}
Example #14
0
// validateRename takes a source and destination node and verifies that
// a rename can be performed from source to destination.
// source must not be nil. destination can be.
func validateRename(tx *sql.Tx, source, destination *Node) error {
	if destination == nil {
		// No object at destination: good.
		return nil
	}

	if source.Mode.IsDir() {
		if destination.Mode.IsDir() {
			// Both are directories: destination must be empty
			return checkIsEmpty(tx, destination.ID)
		}
		// directory -> file: not allowed.
		return fuse.Errno(syscall.ENOTDIR)
	}

	// Source is a file.
	if destination.Mode.IsDir() {
		// file -> directory: not allowed.
		return fuse.Errno(syscall.EISDIR)
	}
	return nil
}
Example #15
0
// Readlink implements the fs.NodeReadlinker interface for Symlink
func (s *Symlink) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (link string, err error) {
	s.parent.folder.fs.log.CDebugf(ctx, "Symlink Readlink")
	defer func() { s.parent.folder.reportErr(ctx, libkbfs.ReadMode, err) }()

	_, de, err := s.parent.folder.fs.config.KBFSOps().Lookup(ctx, s.parent.node, s.name)
	if err != nil {
		return "", err
	}

	if de.Type != libkbfs.Sym {
		return "", fuse.Errno(syscall.EINVAL)
	}
	return de.SymPath, nil
}
Example #16
0
// osErrorToFuseError converts an os.PathError, os.LinkError or
// syscall.Errno into an error
func osErrorToFuseError(err error) error {
	if err == nil {
		return nil
	}
	errno := syscall.EIO
	if patherr, ok := err.(*os.PathError); ok {
		errno = patherr.Err.(syscall.Errno)
	} else if linkerr, ok := err.(*os.LinkError); ok {
		errno = linkerr.Err.(syscall.Errno)
	} else if _, ok := err.(*syscall.Errno); ok {
		errno = err.(syscall.Errno)
	}
	return fuse.Errno(errno)
}
Example #17
0
// Rename implements the fs.NodeRenamer interface for Dir.
func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest,
	newDir fs.Node) (err error) {
	ctx = NewContextWithOpID(ctx, d.folder.fs.log)
	d.folder.fs.log.CDebugf(ctx, "Dir Rename %s -> %s",
		req.OldName, req.NewName)
	defer func() { d.folder.fs.reportErr(ctx, err) }()

	newDir2, ok := newDir.(*Dir)
	if !ok {
		// The destination is not a Dir instance, probably because
		// it's Root (or some other node type added later). The kernel
		// won't let a rename newDir point to a non-directory.
		//
		// We have no cheap atomic rename across folders, so we can't
		// serve this. EXDEV makes `mv` do a copy+delete, and the
		// Lookup on the destination path will decide whether it's
		// legal.
		return fuse.Errno(syscall.EXDEV)
	}
	if d.folder != newDir2.folder {
		// Check this explicitly, not just trusting KBFSOps.Rename to
		// return an error, because we rely on it for locking
		// correctness.
		return fuse.Errno(syscall.EXDEV)
	}

	// overwritten node, if any, will be removed from Folder.nodes, if
	// it is there in the first place, by its Forget

	if err := d.folder.fs.config.KBFSOps().Rename(
		ctx, d.node, req.OldName, newDir2.node, req.NewName); err != nil {
		return err
	}

	return nil
}
Example #18
0
// HandleWriter
func (f *File) Write(req *fuse.WriteRequest, resp *fuse.WriteResponse, intr fs.Intr) fuse.Error {
	f.mu.Lock()
	defer f.mu.Unlock()

	newLen := req.Offset + int64(len(req.Data))
	if newLen > int64(maxInt) {
		return fuse.Errno(syscall.EFBIG)
	}

	n := copy(f.data[req.Offset:], req.Data)
	if n < len(req.Data) {
		f.data = append(f.data, req.Data[n:]...)
	}

	resp.Size = len(req.Data)
	return nil
}
Example #19
0
func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
	f.mu.Lock()
	defer f.mu.Unlock()

	// expand the buffer if necessary
	newLen := req.Offset + int64(len(req.Data))
	if newLen > int64(maxInt) {
		return fuse.Errno(syscall.EFBIG)
	}
	if newLen := int(newLen); newLen > len(f.data) {
		f.data = append(f.data, make([]byte, newLen-len(f.data))...)
	}

	n := copy(f.data[req.Offset:], req.Data)
	resp.Size = n
	return nil
}
Example #20
0
func (v *Volume) SyncReceive(ctx context.Context, dirPath string, peers map[uint32][]byte, dirClockBuf []byte, recv func() ([]*wirepeer.Dirent, error)) error {
	n, drop, err := v.lookupPath(dirPath)
	if err != nil {
		return err
	}
	defer drop()

	d, ok := n.(*dir)
	if !ok {
		return fuse.Errno(syscall.ENOTDIR)
	}

	if err := d.syncReceive(ctx, peers, dirClockBuf, recv); err != nil {
		return err
	}

	return nil
}
Example #21
0
func (file *File) Getxattr(req *fuse.GetxattrRequest, res *fuse.GetxattrResponse, intr fs.Intr) fuse.Error {
	// return fuse.EPERM
	// fmt.Printf("Get attr: %s\n", req.Name)

	buf := make([]byte, 8192)
	size, err := syscallx.Getxattr(file.Path, req.Name, buf)

	if err != nil {
		// fmt.Printf("Get xattr error: %s - %s: \n", file.Path, req.Name, err)
		// return err
		// On osx, we need to return NOATTR, but this isn't built into go or bazil.org/fuse, so we need to do this:
		return fuse.Errno(93)
	}

	res.Xattr = buf[:size]

	return nil
}
Example #22
0
func (f *File) Setattr(c context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error {
	log.Debugln("file_setattr:", f.dir.path, f.name, req)

	f.mu.Lock()
	defer f.mu.Unlock()

	if req.Valid.Size() {
		if req.Size > uint64(maxInt) {
			return fuse.Errno(syscall.EFBIG)
		}
		newLen := int(req.Size)
		switch {
		case newLen > len(f.data):
			f.data = append(f.data, make([]byte, newLen-len(f.data))...)
		case newLen < len(f.data):
			f.data = f.data[:newLen]
		}
	}
	return nil
}
Example #23
0
func (d Dir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
	var out []fuse.Dirent
	files, err := ioutil.ReadDir(d.Path)
	if err != nil {
		log.Print(err)
		return nil, fuse.Errno(err.(syscall.Errno))
	}
	for _, node := range files {
		de := fuse.Dirent{Name: node.Name()}
		if node.IsDir() {
			de.Type = fuse.DT_Dir
		}
		if node.Mode().IsRegular() {
			de.Type = fuse.DT_File
		}
		out = append(out, de)
	}

	return out, nil
}
// Moves a file from dir to newDir (potentially the same as dir) and changes its name from req.OldName
// to req.NewName
func (dir *Directory) Rename(req *fuse.RenameRequest, newDir fs.Node, intr fs.Intr) fuse.Error {
	filesystem.Lock(dir)
	defer filesystem.Unlock(dir)
	util.P_out(req.String())
	if d, newDirOk := newDir.(*Directory); newDirOk {
		if v, oldNameInDir := dir.children[req.OldName]; oldNameInDir {
			v.setName(req.NewName)
			d.setChild(v)
			if file, ok := v.(*File); ok {
				file.dirty = true
				file.parent = d
			}
			dir.removeChild(req.OldName)
			d.dirty = true
			dir.dirty = true
			return nil
		}
		return fuse.ENOENT
	}
	return fuse.Errno(syscall.ENOTDIR)
}
Example #25
0
func (d Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	lock.Lock()
	defer lock.Unlock()
	log.Debug("Remove(%s,%s)", d.GetPath(), req.Name)
	p := path.Join(d.GetPath(), req.Name)
	iter := d.Fs.Session.Query("SELECT entry FROM fuse.filesystem WHERE filename=? AND block=0 AND entry > '!';", p).Iter()
	var entry string
	for iter.Scan(&entry) {
		return fuse.Errno(syscall.ENOTEMPTY)
	}
	if err := d.Fs.Session.Query("DELETE FROM fuse.filesystem WHERE filename=? AND entry=? AND block=0;", d.GetPath(), req.Name).Exec(); err != nil {
		log.Error(err.Error())
		return err
	}
	if err := d.Fs.Session.Query("DELETE FROM fuse.filesystem WHERE filename=?;", p).Exec(); err != nil {
		log.Error(err.Error())
		return err
	}
	d.Fs.DropPath(p)
	return nil
}
Example #26
0
// RemoveDir is called to remove a directory
func (dir *consulDir) RemoveDir(ctx context.Context, req *fuse.RemoveRequest) error {
	// Look in the cache to find the child directory being removed.
	dir.mux.Lock()
	childDir, ok := dir.dirs[req.Name]
	if !ok {
		dir.mux.Unlock()
		return fuse.ENOENT
	}
	dir.mux.Unlock()

	// Don't delete a directory with files in it. To do that, we have to refresh the
	// file listing of the directory.
	err := childDir.refresh(ctx)
	if err != nil {
		return err
	}
	dir.mux.Lock()
	defer dir.mux.Unlock()
	childDir.mux.Lock()
	defer childDir.mux.Unlock()

	// State could have changed while the refresh was happening
	childDir2, ok := dir.dirs[req.Name]
	if !ok {
		return fuse.ENOENT
	}
	if childDir != childDir2 {
		// Many concurrent removes? Just give up.
		return fuse.EIO
	}

	// Only delete an empty directory
	if len(childDir.dirs) > 0 || len(childDir.files) > 0 {
		return fuse.Errno(syscall.ENOTEMPTY)
	}
	delete(dir.dirs, req.Name)
	return nil
}
Example #27
0
func (createrDir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
	// pick a really distinct error, to identify it later
	return nil, nil, fuse.Errno(syscall.ENAMETOOLONG)
}
Example #28
0
// Errno implements the fuse.ErrorNumber interface for NoCurrentSessionError.
func (e NoCurrentSessionError) Errno() fuse.Errno {
	return fuse.Errno(syscall.EACCES)
}
Example #29
0
// Errno implements the fuse.ErrorNumber interface for DirTooBigError.
func (e DirTooBigError) Errno() fuse.Errno {
	return fuse.Errno(syscall.EFBIG)
}
Example #30
0
// Errno implements the fuse.ErrorNumber interface for NameTooLongError.
func (e NameTooLongError) Errno() fuse.Errno {
	return fuse.Errno(syscall.ENAMETOOLONG)
}