ops.go 3.42 KB
Newer Older
1 2 3 4 5
package mfs

import (
	"errors"
	"fmt"
Jeromy's avatar
Jeromy committed
6 7
	"os"
	gopath "path"
8
	"strings"
Jeromy's avatar
Jeromy committed
9 10

	dag "github.com/ipfs/go-ipfs/merkledag"
11
	path "github.com/ipfs/go-ipfs/path"
12 13
)

Jeromy's avatar
Jeromy committed
14 15 16 17 18 19 20 21 22 23 24 25 26
// 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)
	}

Jeromy's avatar
Jeromy committed
27 28
	// get parent directories of both src and dest first
	dstDir, err := lookupDir(r, dstDirStr)
Jeromy's avatar
Jeromy committed
29 30 31 32
	if err != nil {
		return err
	}

Jeromy's avatar
Jeromy committed
33
	srcDirObj, err := lookupDir(r, srcDir)
Jeromy's avatar
Jeromy committed
34 35 36 37
	if err != nil {
		return err
	}

Jeromy's avatar
Jeromy committed
38 39 40 41 42 43
	srcObj, err := srcDirObj.Child(srcFname)
	if err != nil {
		return err
	}

	nd, err := srcObj.GetNode()
Jeromy's avatar
Jeromy committed
44 45 46 47
	if err != nil {
		return err
	}

Jeromy's avatar
Jeromy committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
	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)
Jeromy's avatar
Jeromy committed
63 64 65 66 67 68 69 70 71 72 73 74
	if err != nil {
		return err
	}

	err = srcDirObj.Unlink(srcFname)
	if err != nil {
		return err
	}

	return nil
}

Jeromy's avatar
Jeromy committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88
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
}

Jeromy's avatar
Jeromy committed
89 90 91 92
// PutNode inserts 'nd' at 'path' in the given mfs
func PutNode(r *Root, path string, nd *dag.Node) error {
	dirp, filename := gopath.Split(path)

Jeromy's avatar
Jeromy committed
93
	pdir, err := lookupDir(r, dirp)
Jeromy's avatar
Jeromy committed
94
	if err != nil {
Jeromy's avatar
Jeromy committed
95
		return err
Jeromy's avatar
Jeromy committed
96 97 98 99 100 101 102
	}

	return pdir.AddChild(filename, nd)
}

// Mkdir creates a directory at 'path' under the directory 'd', creating
// intermediary directories as needed if 'parents' is set to true
103
func Mkdir(r *Root, pth string, parents bool) error {
rht's avatar
rht committed
104
	parts := path.SplitList(pth)
Jeromy's avatar
Jeromy committed
105 106 107 108
	if parts[0] == "" {
		parts = parts[1:]
	}

Jeromy's avatar
Jeromy committed
109 110 111 112 113 114 115
	// 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 /'
116
		return fmt.Errorf("cannot mkdir '%s'", pth)
Jeromy's avatar
Jeromy committed
117 118
	}

Jeromy's avatar
Jeromy committed
119 120 121
	cur := r.GetValue().(*Directory)
	for i, d := range parts[:len(parts)-1] {
		fsn, err := cur.Child(d)
Jeromy's avatar
Jeromy committed
122 123 124 125
		if err == os.ErrNotExist && parents {
			mkd, err := cur.Mkdir(d)
			if err != nil {
				return err
Jeromy's avatar
Jeromy committed
126
			}
Jeromy's avatar
Jeromy committed
127 128 129
			fsn = mkd
		} else if err != nil {
			return err
Jeromy's avatar
Jeromy committed
130 131 132 133
		}

		next, ok := fsn.(*Directory)
		if !ok {
134
			return fmt.Errorf("%s was not a directory", path.Join(parts[:i]))
Jeromy's avatar
Jeromy committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
		}
		cur = next
	}

	_, err := cur.Mkdir(parts[len(parts)-1])
	if err != nil {
		if !parents || err != os.ErrExist {
			return err
		}
	}

	return nil
}

func Lookup(r *Root, path string) (FSNode, error) {
150 151 152 153 154 155 156 157 158 159
	dir, ok := r.GetValue().(*Directory)
	if !ok {
		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'
160 161
func DirLookup(d *Directory, pth string) (FSNode, error) {
	pth = strings.Trim(pth, "/")
rht's avatar
rht committed
162
	parts := path.SplitList(pth)
163 164 165 166 167 168 169 170 171
	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 {
172
			return nil, fmt.Errorf("cannot access %s: Not a directory", path.Join(parts[:i+1]))
173 174 175 176 177 178 179 180 181 182 183
		}

		child, err := chdir.Child(p)
		if err != nil {
			return nil, err
		}

		cur = child
	}
	return cur, nil
}