aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base.py73
-rwxr-xr-xc4groupfs.py75
-rwxr-xr-xlcmodfs.py127
3 files changed, 275 insertions, 0 deletions
diff --git a/base.py b/base.py
new file mode 100644
index 0000000..80d1990
--- /dev/null
+++ b/base.py
@@ -0,0 +1,73 @@
+# Copyright (c) 2018, George Tokmaji
+
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import os, llfuse, errno, stat
+class LCOperations(llfuse.Operations):
+ _inode_list = None
+ def __init__(self):
+ super().__init__()
+ self._inode_list = [None, None]
+
+ def _add_entry(self, parent_inode, entry, is_dir=False):
+ entry["parent_inode"] = parent_inode
+ entry["inode"] = len(self._inode_list)
+ entry["stat"] = stat.S_IFDIR if is_dir else stat.S_IFREG
+ self._inode_list.append(entry)
+
+ def _get_inode_by_parent(self, inode_p):
+ return [i["inode"] for i in self._inode_list if i and i["parent_inode"] == inode_p][0]
+
+ def _is_dir(self, inode):
+ return inode == llfuse.ROOT_INODE
+
+ def lookup(self, inode_p, name, ctx=None):
+ if name == ".":
+ inode = inode_p
+ elif name == "..":
+ inode = [i["inode"] for i in self._inode_list if i and i["inode"] == inode_p][0]
+ else:
+ for i in filter(None, self._inode_list):
+ if i["title"] == os.fsdecode(name) and i["parent_inode"] == inode_p:
+ inode = i["inode"]
+ break
+ else:
+ raise llfuse.FUSEError(errno.ENOENT)
+ return self.getattr(inode, ctx)
+
+ def getattr(self, inode, ctx=None):
+ attr = llfuse.EntryAttributes()
+ attr.st_ino = inode
+ attr.st_mode = stat.S_IFDIR if self._is_dir(inode) else stat.S_IFREG
+ attr.st_nlink = 1
+ attr.st_uid = os.getuid()
+ attr.st_gid = os.getgid()
+ attr.st_rdev = 0
+ attr.st_size = 0
+ attr.st_blksize = 1
+ attr.st_blocks = 1
+ attr.generation = 0
+ attr.attr_timeout = 1
+ attr.entry_timeout = 1
+ attr.st_atime_ns = 0
+ attr.st_ctime_ns = 0
+ attr.st_mtime_ns = 0
+ return attr
+
+ def readdir(self, inode, off):
+ entries = [i for i in self._inode_list if i and i["parent_inode"] == inode]
+ for i in range(off, len(entries)):
+ yield (os.fsencode(entries[i]["title"]), self.getattr(entries[i]["inode"]), i + 1)
+
+ def opendir(self, inode, ctx=None):
+ return inode
diff --git a/c4groupfs.py b/c4groupfs.py
new file mode 100755
index 0000000..9f701b8
--- /dev/null
+++ b/c4groupfs.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018, George Tokmaji
+
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+from base import *
+import sys
+sys.path.append("../c4group")
+import c4group
+
+class C4GroupOperations(LCOperations):
+ def __init__(self, path):
+ super().__init__()
+ self._grp = c4group.C4GroupDirectory(path)
+ self._grp.load(recursive=False)
+ self._add_grp_content(llfuse.ROOT_INODE, self._grp)
+
+ def _add_grp_content(self, inode, grp):
+ for i in grp.content:
+ i["title"] = os.fsdecode(i.filename)
+ self._add_entry(inode, i, isinstance(i, c4group.C4GroupDirectory))
+
+ def _is_dir(self, inode):
+ return isinstance(self._inode_list[inode], c4group.C4GroupDirectory) or super()._is_dir(inode)
+
+ def getattr(self, inode, ctx=None):
+ entry = self._inode_list[inode]
+ attr = super().getattr(inode, ctx)
+ if entry:
+ attr.st_size = entry.size
+ return attr
+
+ def opendir(self, inode, ctx=None):
+ if self._is_dir(inode):
+ try:
+ self._get_inode_by_parent(inode)
+ except IndexError:
+ grp = self._inode_list[inode]
+ grp.load(recursive=False)
+ self._add_grp_content(inode, grp)
+ return inode
+
+ def open(self, inode, flags, ctx=None):
+ entry = self._inode_list[inode]
+ if self._is_dir(inode):
+ raise llfuse.FUSEError(errno.EISDIR)
+ if flags & os.O_APPEND:
+ raise llfuse.FUSEError(errno.EROFS)
+ return inode
+
+ def read(self, inode, off, size):
+ entry = self._inode_list[inode]
+ return entry.content[off:off+size]
+
+if __name__ == "__main__":
+ # Usage: ./c4groupfs.py <file> <mountpoint>
+ fuse_options = set(llfuse.default_options)
+ fuse_options.add("fsname=c4groupfs")
+ fuse_options.add("debug")
+ fuse_options.discard("default_permissions")
+ op = C4GroupOperations(sys.argv[1])
+ llfuse.init(op, sys.argv[2], fuse_options)
+ try:
+ llfuse.main()
+ finally:
+ llfuse.close(unmount=True)
diff --git a/lcmodfs.py b/lcmodfs.py
new file mode 100755
index 0000000..e25c27a
--- /dev/null
+++ b/lcmodfs.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python3
+# Copyright (c) 2018, George Tokmaji
+
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+import os
+import sys, pdb
+import llfuse, errno, stat
+import faulthandler
+import requests, threading
+sys.path.append("../larryviewer") #FIXME
+sys.path.append("../lc/src") #FIXME
+from larryviewer import *
+from base import *
+faulthandler.enable()
+
+class LCModOperations(LCOperations):
+ _inode_list = None
+ _viewer = None
+
+ def __init__(self, v : LarryViewer):
+ super().__init__()
+ self._viewer = v
+ for i in range(v.ui.lsEntries.count()):
+ self._add_entry(llfuse.ROOT_INODE, v.ui.lsEntries.item(i).larry, True)
+
+ def _is_dir(self, inode):
+ return isinstance(self._inode_list[inode], Entry) or super()._is_dir(inode)
+
+ def opendir(self, inode, ctx=None):
+ if inode != llfuse.ROOT_INODE:
+ print(inode)
+ try:
+ self._get_inode_by_parent(inode)
+ except IndexError:
+ for f in self._inode_list[inode].files():
+ self._add_entry(inode, {"title" : f, "address" : self._inode_list[inode].filePath(f)})
+ return inode
+
+ def getattr(self, inode, ctx=None):
+ attr = super().getattr(inode, ctx)
+ if inode != llfuse.ROOT_INODE:
+ entry = self._inode_list[inode]
+ if attr.st_mode & stat.S_IFREG:
+ attr.st_size = self._inode_list[entry["parent_inode"]].size()
+ return attr
+
+ def open(self, inode, flags, ctx=None):
+ entry = self._inode_list[inode]
+ if self.getattr(inode).st_mode & stat.S_IFDIR:
+ raise llfuse.FUSEError(errno.EISDIR)
+
+ print("checking flags")
+ if flags & os.O_APPEND:
+ raise llfuse.FUSEError(errno.EROFS)
+ print("returning")
+ return inode
+
+ def read(self, inode, off, size):
+ entry = self._inode_list[inode]
+ try:
+ r = requests.get(entry["address"], headers={"Range" : f"bytes={off}-{off+size}"}, stream=True)
+ except Exception as e:
+ print(e)
+ raise llfuse.FUSEError(errno.EREMOTEIO) from e
+ print(r, off, size)
+ if not r:
+ raise llfuse.FUSEError(errno.EREMOTEIO)
+
+ elif r.status_code == 206:
+ print("partial content", r.headers["Content-Length"])
+ b = r.raw.read(size)
+ return b
+
+ else:
+ buf = BytesIO()
+ i = 0
+ for chunk in r.iter_content(1024):
+ if off <= i:
+ buf.write(chunk)
+ if off + i >= size:
+ break
+ else:
+ raise llfuse.FUSEError(errno.EREMOTEIO)
+
+ buf.seek(i - off)
+ return buf.read(size)
+ #def flush(self, inode):
+ #pass
+
+ #def close(self, inode):
+ #pass
+
+ #def release(self, inode):
+ #pass
+
+if __name__ == "__main__":
+ # Usage: ./lcfs.py <mountpoint>
+ app = QApplication(sys.argv)
+ cwd = os.getcwd()
+ os.chdir("../larryviewer") #FIXME
+ v = LarryViewer()
+ os.chdir(cwd)
+ for t in threading.enumerate():
+ if t.name in "ccanlistlarrylist":
+ t.join()
+ fuse_options = set(llfuse.default_options)
+ fuse_options.add("fsname=lcmodfs")
+ fuse_options.add("debug")
+ fuse_options.discard("default_permissions")
+ op = LCModOperations(v)
+ llfuse.init(op, sys.argv[1], fuse_options)
+ try:
+ llfuse.main(workers=1)
+ except:
+ llfuse.close(unmount=True)
+ raise
+ llfuse.close()