diff --git a/fs.py b/fs.py index a4cbd7e..7c7a279 100755 --- a/fs.py +++ b/fs.py @@ -2,28 +2,62 @@ import os, sys, shutil, pathlib from fuse import FUSE, FuseOSError, Operations +from collections import namedtuple + +Translator = namedtuple('Translator', ['mode', 'output_filename', 'command']) class FilterFS(Operations): def __init__(self, source, cache): self.source = source self.cache = cache - def _original(self, path): - print(path) + + def _mkparents(self, f): + pathlib.Path(os.path.dirname(f)).mkdir(parents = True, exist_ok = True) + def _parse(self, s): + if not s.startswith('/!/'): + return None + s = s[3:] + components = s.split('/') + return Translator( + mode = int(components[0], base=8), + output_filename = components[1], # TODO: forbid ../ attacks + command = '/'.join(components[2:]) + ) + def _peek(self, why, path): + print('peek', path) p = os.path.join(self.source, path.lstrip('/')) if os.path.islink(p): rl = os.readlink(p) if rl.startswith('/!/'): - cached_output = os.path.join(self.cache, path.lstrip('/')) + get = os.path.join(self.cache, 'get', path.lstrip('/')) + peek = os.path.join(self.cache, 'peek', path.lstrip('/')) + if os.path.exists(get): + p = get + else: + translator = self._parse(rl) + p = peek + self._mkparents(p) + pathlib.Path(p).touch() + os.chmod(p, translator.mode) + return p + + def _get(self, why, path): + print('get', why, path) + p = os.path.join(self.source, path.lstrip('/')) + if os.path.islink(p): + rl = os.readlink(p) + if rl.startswith('/!/'): + cached_output = os.path.join(self.cache, 'get', path.lstrip('/')) if not os.path.exists(cached_output): - rl = rl[3:] + translator = self._parse(rl) d = os.path.dirname(p) # begin hack old_cwd = os.getcwd() os.chdir(d) - os.system(rl) + os.system(translator.command) os.chdir(old_cwd) - pathlib.Path(os.path.dirname(cached_output)).mkdir(parents = True, exist_ok = True) - shutil.move(os.path.join(d, 'out'), cached_output) + self._mkparents(cached_output) + shutil.move(os.path.join(d, translator.output_filename), cached_output) # end hack p = cached_output return p @@ -32,13 +66,14 @@ class FilterFS(Operations): def readdir(self, path, fh): yield '.' yield '..' - if os.path.isdir(self._original(path)): - for d in os.listdir(self._original(path)): + orig = self._get("readdir", path) + if os.path.isdir(orig): + for d in os.listdir(orig): yield d # directory, file etc. def getattr(self, path, file_handle = None): - st = os.lstat(self._original(path)) + st = os.lstat(self._peek("getattr", path)) return { 'st_mode': st.st_mode, # 0o100775 file, 0o40775 dir #'st_ino': 42, @@ -46,7 +81,7 @@ class FilterFS(Operations): 'st_nlink': st.st_nlink, 'st_uid': st.st_uid, 'st_gid': st.st_gid, - 'st_size': st.st_size, + 'st_size': 999999999999999, #st.st_size, # TODO: max file size 'st_atime': st.st_atime, 'st_mtime': st.st_mtime, 'st_ctime': st.st_ctime, @@ -54,7 +89,7 @@ class FilterFS(Operations): # file def open(self, path, flags): - return os.open(self._original(path), flags) + return os.open(self._get("open", path), flags) def read(self, path, length, offset, file_handle): os.lseek(file_handle, offset, os.SEEK_SET) return os.read(file_handle, length) diff --git a/source/foo.mp3 b/source/foo.mp3 index f95e3b2..89a1ee0 120000 --- a/source/foo.mp3 +++ b/source/foo.mp3 @@ -1 +1 @@ -/!/lame -vbr -b 240 foo.ogg output.mp3; mv output.mp3 out \ No newline at end of file +/!/100644/out.mp3/ffmpeg -i foo.ogg -acodec libmp3lame -map_metadata 0:s:0 out.mp3 \ No newline at end of file diff --git a/source/foo.ogg b/source/foo.ogg index e69de29..a50c007 100644 Binary files a/source/foo.ogg and b/source/foo.ogg differ diff --git a/source/some_dir/bbb b/source/some_dir/bbb index 83012ab..c4f2bad 120000 --- a/source/some_dir/bbb +++ b/source/some_dir/bbb @@ -1 +1 @@ -/!/tr '[:lower:]' '[:upper:'] < aaa > out \ No newline at end of file +/!/10644/out/tr '[:lower:]' '[:upper:'] < aaa > out \ No newline at end of file