func (n *Node) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
	newNode, ok := newDir.(*Node)
	if !ok {
		return fmt.Errorf("newDir is not a Node: %v", newDir)
	}
	if !n.isDir() || !newNode.isDir() {
		return fuse.Errno(syscall.ENOTDIR)
	}
	return n.cfs.rename(ctx, n.ID, newNode.ID, req.OldName, req.NewName)
}
Rename renames 'req.OldName' to 'req.NewName', optionally moving it to 'newDir'.
If req.NewName exists, it is deleted. It is assumed that it cannot be a directory.
NOTE: we do not keep track of opens, so we delete existing destinations right away.
This means that anyone holding an open file descriptor on the destination will fail
when trying to use it.
To properly handle this, we need to count references (including inode -> inode refs,
and open handles) and delete the inode only when it reaches zero.
package main
import (
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"os"
	"sync"
	"syscall"
	"github.com/cockroachdb/cockroach-go/crdb"
	"bazil.org/fuse"
	"bazil.org/fuse/fs"
	"golang.org/x/net/context"
)
var _ fs.Node = &Node{}                
var _ fs.NodeSetattrer = &Node{}       
var _ fs.NodeStringLookuper = &Node{}  
var _ fs.HandleReadDirAller = &Node{}  
var _ fs.NodeMkdirer = &Node{}         
var _ fs.NodeCreater = &Node{}         
var _ fs.NodeRemover = &Node{}         
var _ fs.HandleWriter = &Node{}        
var _ fs.HandleReader = &Node{}        
var _ fs.NodeFsyncer = &Node{}         
var _ fs.NodeRenamer = &Node{}         
var _ fs.NodeSymlinker = &Node{}       
var _ fs.NodeReadlinker = &Node{}      
const defaultPerms = 0755
const allPerms = 0777
const maxSize = math.MaxUint64
const maxSymlinkTargetLength = 4096
type Node struct {
	cfs CFS
	ID uint64
	Mode os.FileMode
	SymlinkTarget string
	mu   sync.RWMutex
	Size uint64
}
func (n *Node) isDir() bool {
	return n.Mode.IsDir()
}
func (n *Node) isRegular() bool {
	return n.Mode.IsRegular()
}
func (n *Node) isSymlink() bool {
	return n.Mode&os.ModeSymlink != 0
}
func (n *Node) toJSON() string {
	ret, err := json.Marshal(n)
	if err != nil {
		panic(err)
	}
	return string(ret)
}
func (n *Node) Attr(_ context.Context, a *fuse.Attr) error {
	a.Inode = n.ID
	a.Mode = n.Mode
	a.BlockSize = BlockSize
	if n.isRegular() {
		n.mu.RLock()
		defer n.mu.RUnlock()
		a.Size = n.Size
		a.Blocks = (n.Size + 511) / 512
	} else if n.isSymlink() {
		a.Size = uint64(len(n.SymlinkTarget))
	}
	return nil
}
func (n *Node) Setattr(
	ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse,
) error {
	if !req.Valid.Size() {
		return nil
	}
	if !n.isRegular() {
		return fuse.Errno(syscall.EINVAL)
	}
	if req.Size > maxSize {
		return fuse.Errno(syscall.EFBIG)
	}
	n.mu.Lock()
	defer n.mu.Unlock()
	if req.Size == n.Size {
		return nil
	}
	originalSize := n.Size
	err := crdb.ExecuteTx(ctx, n.cfs.db, nil  , func(tx *sql.Tx) error {
		if err := resizeBlocks(tx, n.ID, n.Size, req.Size); err != nil {
			return err
		}
		n.Size = req.Size
		return updateNode(tx, n)
	})
	if err != nil {
		log.Print(err)
		n.Size = originalSize
		return err
	}
	return nil
}
func (n *Node) Lookup(_ context.Context, name string) (fs.Node, error) {
	if !n.isDir() {
		return nil, fuse.Errno(syscall.ENOTDIR)
	}
	node, err := n.cfs.lookup(n.ID, name)
	if err != nil {
		if err == sql.ErrNoRows {
			return nil, fuse.ENOENT
		}
		return nil, err
	}
	node.cfs = n.cfs
	return node, nil
}
func (n *Node) ReadDirAll(_ context.Context) ([]fuse.Dirent, error) {
	if !n.isDir() {
		return nil, fuse.Errno(syscall.ENOTDIR)
	}
	return n.cfs.list(n.ID)
}
func (n *Node) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
	if !n.isDir() {
		return nil, fuse.Errno(syscall.ENOTDIR)
	}
	if !req.Mode.IsDir() {
		return nil, fuse.Errno(syscall.ENOTDIR)
	}
	node := n.cfs.newDirNode()
	err := n.cfs.create(ctx, n.ID, req.Name, node)
	if err != nil {
		return nil, err
	}
	return node, nil
}
func (n *Node) Create(
	ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse,
) (fs.Node, fs.Handle, error) {
	if !n.isDir() {
		return nil, nil, fuse.Errno(syscall.ENOTDIR)
	}
	if req.Mode.IsDir() {
		return nil, nil, fuse.Errno(syscall.EISDIR)
	} else if !req.Mode.IsRegular() {
		return nil, nil, fuse.Errno(syscall.EINVAL)
	}
	node := n.cfs.newFileNode()
	err := n.cfs.create(ctx, n.ID, req.Name, node)
	if err != nil {
		return nil, nil, err
	}
	return node, node, nil
}
func (n *Node) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
	if !n.isDir() {
		return fuse.Errno(syscall.ENOTDIR)
	}
	if req.Dir {
		return n.cfs.remove(ctx, n.ID, req.Name, true  )
	}
	return n.cfs.remove(ctx, n.ID, req.Name, false  )
}
func (n *Node) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
	if !n.isRegular() {
		return fuse.Errno(syscall.EINVAL)
	}
	if req.Offset < 0 {
		return fuse.Errno(syscall.EINVAL)
	}
	if len(req.Data) == 0 {
		return nil
	}
	n.mu.Lock()
	defer n.mu.Unlock()
	newSize := uint64(req.Offset) + uint64(len(req.Data))
	if newSize > maxSize {
		return fuse.Errno(syscall.EFBIG)
	}
	originalSize := n.Size
	err := crdb.ExecuteTx(ctx, n.cfs.db, nil  , func(tx *sql.Tx) error {
		if err := write(tx, n.ID, n.Size, uint64(req.Offset), req.Data); err != nil {
			return err
		}
		if newSize > originalSize {
			n.Size = newSize
			if err := updateNode(tx, n); err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		log.Print(err)
		n.Size = originalSize
		return err
	}
	resp.Size = len(req.Data)
	return nil
}
func (n *Node) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {
	if !n.isRegular() {
		return fuse.Errno(syscall.EINVAL)
	}
	if req.Offset < 0 {
		return fuse.Errno(syscall.EINVAL)
	}
	if req.Size == 0 {
		return nil
	}
	offset := uint64(req.Offset)
	n.mu.RLock()
	defer n.mu.RUnlock()
	if offset >= n.Size {
		return nil
	}
	to := min(n.Size, offset+uint64(req.Size))
	if offset == to {
		return nil
	}
	data, err := read(n.cfs.db, n.ID, offset, to)
	if err != nil {
		return err
	}
	resp.Data = data
	return nil
}
func (n *Node) Fsync(_ context.Context, _ *fuse.FsyncRequest) error {
	return nil
}