diff options
| -rw-r--r-- | base.py | 73 | ||||
| -rwxr-xr-x | c4groupfs.py | 75 | ||||
| -rwxr-xr-x | lcmodfs.py | 127 |
3 files changed, 275 insertions, 0 deletions
@@ -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() |
