]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Support browsing torrents in the filesystem
authorMatt Joiner <anacrolix@gmail.com>
Sun, 6 Oct 2013 19:00:35 +0000 (06:00 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Sun, 6 Oct 2013 19:00:35 +0000 (06:00 +1100)
cmd/torrentfs/main.go

index d71a538b5a6fcf88e019a5310accab4f580a611e..e567aa29e6c65029e4aae7c6f468c614ae5960d4 100644 (file)
@@ -18,6 +18,10 @@ var (
        mountDir    string
 )
 
+const (
+       defaultMode = 0555
+)
+
 func init() {
        flag.StringVar(&downloadDir, "downloadDir", "", "location to save torrent data")
        flag.StringVar(&torrentPath, "torrentPath", func() string {
@@ -38,13 +42,130 @@ type rootNode struct {
        fs *TorrentFS
 }
 
+type node struct {
+       path     []string
+       metaInfo *metainfo.MetaInfo
+       client   *torrent.Client
+}
+
+type fileNode struct {
+       node
+       size uint64
+}
+
+func (fn fileNode) Attr() (attr fuse.Attr) {
+       attr.Size = fn.size
+       attr.Mode = defaultMode
+       return
+}
+
+type dirNode struct {
+       node
+}
+
+func isSubPath(parent, child []string) bool {
+       if len(child) <= len(parent) {
+               return false
+       }
+       for i := range parent {
+               if parent[i] != child[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+func (dn dirNode) ReadDir(intr fusefs.Intr) (des []fuse.Dirent, err fuse.Error) {
+       names := map[string]bool{}
+       for _, fi := range dn.metaInfo.Files {
+               if !isSubPath(dn.path, fi.Path) {
+                       continue
+               }
+               name := fi.Path[len(dn.path)]
+               if names[name] {
+                       continue
+               }
+               names[name] = true
+               de := fuse.Dirent{
+                       Name: name,
+               }
+               if len(fi.Path) == len(dn.path)+1 {
+                       de.Type = fuse.DT_File
+               } else {
+                       de.Type = fuse.DT_Dir
+               }
+               des = append(des, de)
+       }
+       return
+}
+
+func (dn dirNode) Lookup(name string, intr fusefs.Intr) (_node fusefs.Node, err fuse.Error) {
+       for _, fi := range dn.metaInfo.Files {
+               if !isSubPath(dn.path, fi.Path) {
+                       continue
+               }
+               if fi.Path[len(dn.path)] != name {
+                       continue
+               }
+               __node := node{
+                       path:     append(dn.path, name),
+                       metaInfo: dn.metaInfo,
+                       client:   dn.client,
+               }
+               if len(fi.Path) == len(dn.path)+1 {
+                       _node = fileNode{
+                               node: __node,
+                               size: uint64(fi.Length),
+                       }
+               } else {
+                       _node = dirNode{__node}
+               }
+               break
+       }
+       if _node == nil {
+               err = fuse.ENOENT
+       }
+       return
+}
+
+func (dn dirNode) Attr() (attr fuse.Attr) {
+       attr.Mode = os.ModeDir | defaultMode
+       return
+}
+
+func isSingleFileTorrent(mi *metainfo.MetaInfo) bool {
+       return len(mi.Files) == 1 && mi.Files[0].Path == nil
+}
+
+func (me rootNode) Lookup(name string, intr fusefs.Intr) (_node fusefs.Node, err fuse.Error) {
+       for _, _torrent := range me.fs.Client.Torrents() {
+               metaInfo := _torrent.MetaInfo
+               if metaInfo.Name == name {
+                       __node := node{
+                               metaInfo: metaInfo,
+                               client:   me.fs.Client,
+                       }
+                       if isSingleFileTorrent(metaInfo) {
+                               _node = fileNode{__node, uint64(metaInfo.Files[0].Length)}
+                       } else {
+                               _node = dirNode{__node}
+                       }
+                       break
+               }
+       }
+       if _node == nil {
+               err = fuse.ENOENT
+       }
+       return
+}
+
 func (me rootNode) ReadDir(intr fusefs.Intr) (dirents []fuse.Dirent, err fuse.Error) {
        for _, _torrent := range me.fs.Client.Torrents() {
                metaInfo := _torrent.MetaInfo
                dirents = append(dirents, fuse.Dirent{
                        Name: metaInfo.Name,
                        Type: func() fuse.DirentType {
-                               if len(metaInfo.Files) == 1 && metaInfo.Files[0].Path == nil {
+                               if isSingleFileTorrent(metaInfo) {
                                        return fuse.DT_File
                                } else {
                                        return fuse.DT_Dir
@@ -82,7 +203,10 @@ func main() {
                if err != nil {
                        log.Print(err)
                }
-               client.AddTorrent(metaInfo)
+               err = client.AddTorrent(metaInfo)
+               if err != nil {
+                       log.Print(err)
+               }
        }
        conn, err := fuse.Mount(mountDir)
        if err != nil {