1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-09-09 17:22:21 +08:00
Files
kubo/mfs/ops.go
Jeromy 4b7e3282f1 introduce concept of filedescriptors to mfs, adjust fuse code to use them
License: MIT
Signed-off-by: Jeromy <jeromyj@gmail.com>
2016-02-08 14:45:44 -08:00

213 lines
3.9 KiB
Go

package mfs
import (
"errors"
"fmt"
"os"
gopath "path"
"strings"
dag "github.com/ipfs/go-ipfs/merkledag"
path "github.com/ipfs/go-ipfs/path"
)
// Mv moves the file or directory at 'src' to 'dst'
func Mv(r *Root, src, dst string) error {
srcDir, srcFname := gopath.Split(src)
var dstDirStr string
var filename string
if dst[len(dst)-1] == '/' {
dstDirStr = dst
filename = srcFname
} else {
dstDirStr, filename = gopath.Split(dst)
}
// get parent directories of both src and dest first
dstDir, err := lookupDir(r, dstDirStr)
if err != nil {
return err
}
srcDirObj, err := lookupDir(r, srcDir)
if err != nil {
return err
}
srcObj, err := srcDirObj.Child(srcFname)
if err != nil {
return err
}
nd, err := srcObj.GetNode()
if err != nil {
return err
}
fsn, err := dstDir.Child(filename)
if err == nil {
switch n := fsn.(type) {
case *File:
_ = dstDir.Unlink(filename)
case *Directory:
dstDir = n
default:
return fmt.Errorf("unexpected type at path: %s", dst)
}
} else if err != os.ErrNotExist {
return err
}
err = dstDir.AddChild(filename, nd)
if err != nil {
return err
}
err = srcDirObj.Unlink(srcFname)
if err != nil {
return err
}
return nil
}
func lookupDir(r *Root, path string) (*Directory, error) {
di, err := Lookup(r, path)
if err != nil {
return nil, err
}
d, ok := di.(*Directory)
if !ok {
return nil, fmt.Errorf("%s is not a directory", path)
}
return d, nil
}
// PutNode inserts 'nd' at 'path' in the given mfs
func PutNode(r *Root, path string, nd *dag.Node) error {
dirp, filename := gopath.Split(path)
pdir, err := lookupDir(r, dirp)
if err != nil {
return err
}
return pdir.AddChild(filename, nd)
}
// Mkdir creates a directory at 'path' under the directory 'd', creating
// intermediary directories as needed if 'mkparents' is set to true
func Mkdir(r *Root, pth string, mkparents bool, flush bool) error {
if pth == "" {
return nil
}
parts := path.SplitList(pth)
if parts[0] == "" {
parts = parts[1:]
}
// allow 'mkdir /a/b/c/' to create c
if parts[len(parts)-1] == "" {
parts = parts[:len(parts)-1]
}
if len(parts) == 0 {
// this will only happen on 'mkdir /'
if mkparents {
return nil
}
return fmt.Errorf("cannot create directory '/': Already exists")
}
cur := r.GetValue().(*Directory)
for i, d := range parts[:len(parts)-1] {
fsn, err := cur.Child(d)
if err == os.ErrNotExist && mkparents {
mkd, err := cur.Mkdir(d)
if err != nil {
return err
}
fsn = mkd
} else if err != nil {
return err
}
next, ok := fsn.(*Directory)
if !ok {
return fmt.Errorf("%s was not a directory", path.Join(parts[:i]))
}
cur = next
}
final, err := cur.Mkdir(parts[len(parts)-1])
if err != nil {
if !mkparents || err != os.ErrExist || final == nil {
return err
}
}
if flush {
err := final.Flush()
if err != nil {
return err
}
}
return nil
}
func Lookup(r *Root, path string) (FSNode, error) {
dir, ok := r.GetValue().(*Directory)
if !ok {
log.Error("root not a dir: %#v", r.GetValue())
return nil, errors.New("root was not a directory")
}
return DirLookup(dir, path)
}
// DirLookup will look up a file or directory at the given path
// under the directory 'd'
func DirLookup(d *Directory, pth string) (FSNode, error) {
pth = strings.Trim(pth, "/")
parts := path.SplitList(pth)
if len(parts) == 1 && parts[0] == "" {
return d, nil
}
var cur FSNode
cur = d
for i, p := range parts {
chdir, ok := cur.(*Directory)
if !ok {
return nil, fmt.Errorf("cannot access %s: Not a directory", path.Join(parts[:i+1]))
}
child, err := chdir.Child(p)
if err != nil {
return nil, err
}
cur = child
}
return cur, nil
}
func FlushPath(rt *Root, pth string) error {
nd, err := Lookup(rt, pth)
if err != nil {
return err
}
err = nd.Flush()
if err != nil {
return err
}
rt.repub.WaitPub()
return nil
}