Browse Source

создание каталогов, удаление каталогов и файлов
сохранение ссылки на дерево в локальном конфиге

kpmy 9 năm trước cách đây
mục cha
commit
65116b88d6
3 tập tin đã thay đổi với 139 bổ sung13 xóa
  1. 91 8
      fs.go
  2. 16 0
      memo.go
  3. 32 5
      trav.go

+ 91 - 8
fs.go

@@ -6,9 +6,13 @@ import (
 
 	go_ipfs_api "github.com/ipfs/go-ipfs-api"
 
+	"fmt"
 	"github.com/kpmy/mipfs/ipfs_api"
 	. "github.com/kpmy/ypk/tc"
 	"golang.org/x/net/webdav"
+	"path/filepath"
+	"strings"
+	"sync"
 )
 
 type file struct {
@@ -162,9 +166,32 @@ type filesystem struct {
 	root string
 }
 
-func (f *filesystem) Mkdir(name string, perm os.FileMode) error {
+func (f *filesystem) Mkdir(name string, perm os.FileMode) (err error) {
 	Assert(name != "", 20)
-	panic(100)
+	ls := split(f.root, name)
+	ns := strings.Split(f.root+name, "/")
+	downHash := ""
+	downPath := ""
+	for i := len(ns) - 1; i >= 0; i-- {
+		newHash := ""
+		if i >= len(ls) {
+			newHash, _ = ipfs_api.Shell().NewObject("unixfs-dir")
+		} else {
+			newHash = ls[i].Hash
+		}
+		if downHash != "" {
+			newHash, _ = ipfs_api.Shell().PatchLink(newHash, downPath, downHash, false)
+		}
+		downHash = newHash
+		downPath = ns[i]
+		if i == 0 {
+			ipfs_api.Shell().Unpin(f.root)
+			f.root = newHash
+			ipfs_api.Shell().Pin(f.root)
+			memo.Write("root", []byte(f.root))
+		}
+	}
+	return
 }
 
 func (f *filesystem) OpenFile(name string, flag int, perm os.FileMode) (webdav.File, error) {
@@ -177,8 +204,36 @@ func (f *filesystem) OpenFile(name string, flag int, perm os.FileMode) (webdav.F
 	}
 }
 
-func (f *filesystem) RemoveAll(name string) error {
-	panic(100)
+func (f *filesystem) RemoveAll(name string) (err error) {
+	var ls []*loc
+	var ns []string
+	var newHash string
+	if li, fi := trav(f.root, name); fi != nil {
+		ls = split(f.root, filepath.Dir(name))
+		ns = strings.Split(f.root+filepath.Dir(name), "/")
+		_, fn := filepath.Split(name)
+		newHash, _ = ipfs_api.Shell().Patch(ls[len(ls)-1].Hash, "rm-link", fn)
+		if j := len(ls) - 2; j > 0 {
+			newHash, _ = ipfs_api.Shell().Patch(ls[len(ls)-2].Hash, "rm-link", ns[len(ns)-1])
+		}
+	} else if li != nil {
+		ls = split(f.root, name)
+		ns = strings.Split(f.root+name, "/")
+		newHash, _ = ipfs_api.Shell().Patch(ls[len(ls)-2].Hash, "rm-link", ns[len(ns)-1])
+		Assert(len(ls) > 1 && len(ns) > 1 && len(ls) == len(ns), 20)
+	} else {
+		panic(0)
+	}
+	if j := len(ls) - 2; j > 0 {
+		for i := j - 1; i >= 0; i-- {
+			newHash, _ = ipfs_api.Shell().PatchLink(ls[i].Hash, ns[i+1], newHash, false)
+		}
+	}
+	ipfs_api.Shell().Unpin(f.root)
+	f.root = newHash
+	ipfs_api.Shell().Pin(f.root)
+	memo.Write("root", []byte(f.root))
+	return
 }
 
 func (f *filesystem) Rename(oldName, newName string) error {
@@ -204,10 +259,18 @@ func init() {
 func NewFS() webdav.FileSystem {
 	//root, _ := ipfs.Shell().Resolve(nodeID.ID)
 	root := "QmbuSdtGUUfL7DSvvA9DmiGSRqAzkHEjWtsxZDRPBWcawg"
+	if r, err := memo.Read("root"); err == nil {
+		root = string(r)
+	} else {
+		memo.Write("root", []byte(root))
+	}
 	return &filesystem{node: nodeID.ID, root: root}
 }
 
 type locksystem struct {
+	sync.RWMutex
+	locks  map[string]string
+	tokens map[string]webdav.LockDetails
 }
 
 func (l *locksystem) Confirm(now time.Time, name0, name1 string, conditions ...webdav.Condition) (release func(), err error) {
@@ -215,17 +278,37 @@ func (l *locksystem) Confirm(now time.Time, name0, name1 string, conditions ...w
 }
 
 func (l *locksystem) Create(now time.Time, details webdav.LockDetails) (token string, err error) {
-	panic(100)
+	l.RLock()
+	if _, ok := l.locks[details.Root]; !ok {
+		l.RUnlock()
+		l.Lock()
+		token = fmt.Sprint(now.UnixNano())
+		l.locks[details.Root] = token
+		l.tokens[token] = details
+		l.RWMutex.Unlock()
+	} else {
+		l.RUnlock()
+		err = webdav.ErrLocked
+	}
+	return
 }
 
 func (l *locksystem) Refresh(now time.Time, token string, duration time.Duration) (webdav.LockDetails, error) {
 	panic(100)
 }
 
-func (l *locksystem) Unlock(now time.Time, token string) error {
-	panic(100)
+func (l *locksystem) Unlock(now time.Time, token string) (err error) {
+	l.Lock()
+	details := l.tokens[token]
+	delete(l.tokens, token)
+	delete(l.locks, details.Root)
+	l.RWMutex.Unlock()
+	return
 }
 
 func NewLS() webdav.LockSystem {
-	return &locksystem{}
+	ret := &locksystem{}
+	ret.locks = make(map[string]string)
+	ret.tokens = make(map[string]webdav.LockDetails)
+	return ret
 }

+ 16 - 0
memo.go

@@ -0,0 +1,16 @@
+package mipfs
+
+import (
+	"github.com/peterbourgon/diskv"
+)
+
+var memo *diskv.Diskv
+
+func init() {
+	memo = diskv.New(diskv.Options{
+		BasePath: ".memo",
+		Transform: func(s string) []string {
+			return []string{}
+		},
+	})
+}

+ 32 - 5
trav.go

@@ -6,7 +6,7 @@ import (
 	"path/filepath"
 )
 
-var root = string([]rune{os.PathSeparator})
+var rootName = string([]rune{os.PathSeparator})
 
 func find(li *loc, name string) (ret *loc) {
 	for _, i := range li.Links {
@@ -27,13 +27,13 @@ func find2(li *loc, name string) (ret *link) {
 	return
 }
 
-func trav(rootHash string, name string) (*loc, *link) {
-	if name == root {
-		ls, _ := ipfs_api.Shell().FileList(rootHash)
+func trav(root string, name string) (*loc, *link) {
+	if name == rootName {
+		ls, _ := ipfs_api.Shell().FileList(root)
 		return &loc{*ls}, nil
 	} else {
 		_, last := filepath.Split(name)
-		l, _ := trav(rootHash, filepath.Dir(name))
+		l, _ := trav(root, filepath.Dir(name))
 		if li := find(l, last); li != nil {
 			return li, nil
 		} else {
@@ -41,3 +41,30 @@ func trav(rootHash string, name string) (*loc, *link) {
 		}
 	}
 }
+
+func split(rootHash string, path string) (ret []*loc) {
+	var tr func(root string) *loc
+	tr = func(root string) *loc {
+		if root == rootName {
+			ls, _ := ipfs_api.Shell().FileList(rootHash)
+			l := &loc{*ls}
+			ret = append(ret, l)
+			return l
+		} else {
+			_, last := filepath.Split(root)
+			l := tr(filepath.Dir(root))
+			if l != nil {
+				if li := find(l, last); li != nil {
+					ret = append(ret, li)
+					return li
+				} else {
+					return nil
+				}
+			} else {
+				return nil
+			}
+		}
+	}
+	tr(path)
+	return
+}