This commit is contained in:
ed 2020-08-07 20:00:30 +00:00
parent 9405597c15
commit ec29b59d1e
2 changed files with 68 additions and 46 deletions

View file

@ -47,21 +47,23 @@ dependencies (windows):
""" """
WINDOWS = sys.platform == 'win32' WINDOWS = sys.platform == "win32"
def print(*args, **kwargs): def print(*args, **kwargs):
try: try:
builtins.print(*list(args), **kwargs) builtins.print(*list(args), **kwargs)
except: except:
builtins.print(termsafe(' '.join(str(x) for x in args)), **kwargs) builtins.print(termsafe(" ".join(str(x) for x in args)), **kwargs)
def termsafe(txt): def termsafe(txt):
try: try:
return txt.encode(sys.stdout.encoding, 'backslashreplace').decode(sys.stdout.encoding) return txt.encode(sys.stdout.encoding, "backslashreplace").decode(
sys.stdout.encoding
)
except: except:
return txt.encode(sys.stdout.encoding, 'replace').decode(sys.stdout.encoding) return txt.encode(sys.stdout.encoding, "replace").decode(sys.stdout.encoding)
def threadless_log(msg): def threadless_log(msg):
@ -100,7 +102,12 @@ def get_tid():
def html_dec(txt): def html_dec(txt):
return txt.replace('&lt;', '<').replace('&gt;', '>').replace('&quot;', '"').replace('&amp;', '&') return (
txt.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&quot;", '"')
.replace("&amp;", "&")
)
class CacheNode(object): class CacheNode(object):
@ -553,71 +560,71 @@ class CPPF(Operations):
release = None release = None
releasedir = None releasedir = None
statfs = None statfs = None
if False: if False:
# incorrect semantics but good for debugging stuff like samba and msys2 # incorrect semantics but good for debugging stuff like samba and msys2
def access(self, path, mode): def access(self, path, mode):
log("@@ access [{}] [{}]".format(path, mode)) log("@@ access [{}] [{}]".format(path, mode))
return 1 if self.getattr(path) else 0 return 1 if self.getattr(path) else 0
def flush(self, path, fh): def flush(self, path, fh):
log("@@ flush [{}] [{}]".format(path, fh)) log("@@ flush [{}] [{}]".format(path, fh))
return True return True
def getxattr(self, *args): def getxattr(self, *args):
log("@@ getxattr [{}]".format('] ['.join(str(x) for x in args))) log("@@ getxattr [{}]".format("] [".join(str(x) for x in args)))
return False return False
def listxattr(self, *args): def listxattr(self, *args):
log("@@ listxattr [{}]".format('] ['.join(str(x) for x in args))) log("@@ listxattr [{}]".format("] [".join(str(x) for x in args)))
return False return False
def open(self, path, flags): def open(self, path, flags):
log("@@ open [{}] [{}]".format(path, flags)) log("@@ open [{}] [{}]".format(path, flags))
return 42 return 42
def opendir(self, fh): def opendir(self, fh):
log("@@ opendir [{}]".format(fh)) log("@@ opendir [{}]".format(fh))
return 69 return 69
def release(self, ino, fi): def release(self, ino, fi):
log("@@ release [{}] [{}]".format(ino, fi)) log("@@ release [{}] [{}]".format(ino, fi))
return True return True
def releasedir(self, ino, fi): def releasedir(self, ino, fi):
log("@@ releasedir [{}] [{}]".format(ino, fi)) log("@@ releasedir [{}] [{}]".format(ino, fi))
return True return True
def statfs(self, path): def statfs(self, path):
log("@@ statfs [{}]".format(path)) log("@@ statfs [{}]".format(path))
return {} return {}
if sys.platform == 'win32': if sys.platform == "win32":
# quick compat for /mingw64/bin/python3 (msys2) # quick compat for /mingw64/bin/python3 (msys2)
def _open(self, path): def _open(self, path):
try: try:
x = self.getattr(path) x = self.getattr(path)
if x["st_mode"] <= 0: if x["st_mode"] <= 0:
raise Exception() raise Exception()
self.junk_fh_ctr += 1 self.junk_fh_ctr += 1
if self.junk_fh_ctr > 32000: # TODO untested if self.junk_fh_ctr > 32000: # TODO untested
self.junk_fh_ctr = 4 self.junk_fh_ctr = 4
return self.junk_fh_ctr return self.junk_fh_ctr
except Exception as ex: except Exception as ex:
log("open ERR {}".format(repr(ex))) log("open ERR {}".format(repr(ex)))
raise FuseOSError(errno.ENOENT) raise FuseOSError(errno.ENOENT)
def open(self, path, flags): def open(self, path, flags):
log("open [{}] [{}]".format(path, flags)) log("open [{}] [{}]".format(path, flags))
return self._open(path) return self._open(path)
def opendir(self, path): def opendir(self, path):
log("opendir [{}]".format(path)) log("opendir [{}]".format(path))
return self._open(path) return self._open(path)
def flush(self, path, fh): def flush(self, path, fh):
log("flush [{}] [{}]".format(path, fh)) log("flush [{}] [{}]".format(path, fh))
@ -626,7 +633,7 @@ class CPPF(Operations):
def releasedir(self, ino, fi): def releasedir(self, ino, fi):
log("releasedir [{}] [{}]".format(ino, fi)) log("releasedir [{}] [{}]".format(ino, fi))
def access(self, path, mode): def access(self, path, mode):
log("access [{}] [{}]".format(path, mode)) log("access [{}] [{}]".format(path, mode))
try: try:
@ -644,7 +651,7 @@ def main():
where = "local directory" where = "local directory"
if WINDOWS: if WINDOWS:
where += " or DRIVE:" where += " or DRIVE:"
print("need arg 1: " + where) print("need arg 1: " + where)
print("need arg 2: root url") print("need arg 2: root url")
print() print()
@ -652,13 +659,20 @@ def main():
print(" copyparty-fuse.py ./music http://192.168.1.69:3923/music/") print(" copyparty-fuse.py ./music http://192.168.1.69:3923/music/")
if WINDOWS: if WINDOWS:
print(" copyparty-fuse.py M: http://192.168.1.69:3923/music/") print(" copyparty-fuse.py M: http://192.168.1.69:3923/music/")
return return
if WINDOWS: if WINDOWS:
os.system("") os.system("")
FUSE(CPPF(remote), local, foreground=True, nothreads=True, allow_other=True, nonempty=True) FUSE(
CPPF(remote),
local,
foreground=True,
nothreads=True,
allow_other=True,
nonempty=True,
)
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -23,9 +23,10 @@ from urllib.parse import quote_from_bytes as quote
try: try:
import fuse import fuse
from fuse import Fuse from fuse import Fuse
fuse.fuse_python_api = (0, 2) fuse.fuse_python_api = (0, 2)
if not hasattr(fuse, '__version__'): if not hasattr(fuse, "__version__"):
raise Exception('your fuse-python is way old') raise Exception("your fuse-python is way old")
except: except:
print( print(
"\n could not import fuse; these may help:\n python3 -m pip install --user fuse-python\n apt install libfuse\n modprobe fuse\n" "\n could not import fuse; these may help:\n python3 -m pip install --user fuse-python\n apt install libfuse\n modprobe fuse\n"
@ -84,7 +85,12 @@ def get_tid():
def html_dec(txt): def html_dec(txt):
return txt.replace('&lt;', '<').replace('&gt;', '>').replace('&quot;', '"').replace('&amp;', '&') return (
txt.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&quot;", '"')
.replace("&amp;", "&")
)
class CacheNode(object): class CacheNode(object):
@ -254,7 +260,7 @@ class Gateway(object):
class CPPF(Fuse): class CPPF(Fuse):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
Fuse.__init__(self, *args, **kwargs) Fuse.__init__(self, *args, **kwargs)
self.url = None self.url = None
self.dircache = [] self.dircache = []
@ -265,7 +271,7 @@ class CPPF(Fuse):
def init2(self): def init2(self):
# TODO figure out how python-fuse wanted this to go # TODO figure out how python-fuse wanted this to go
self.gw = Gateway(self.url) #.decode('utf-8')) self.gw = Gateway(self.url) # .decode('utf-8'))
info("up") info("up")
def clean_dircache(self): def clean_dircache(self):
@ -484,28 +490,28 @@ class CPPF(Fuse):
self.clean_dircache() self.clean_dircache()
return ret return ret
def readdir(self, path, offset): def readdir(self, path, offset):
for e in self._readdir(path)[offset:]: for e in self._readdir(path)[offset:]:
#log("yield [{}]".format(e[0])) # log("yield [{}]".format(e[0]))
yield fuse.Direntry(e[0]) yield fuse.Direntry(e[0])
def open(self, path, flags): def open(self, path, flags):
if (flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)) != os.O_RDONLY: if (flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)) != os.O_RDONLY:
return -errno.EACCES return -errno.EACCES
st = self.getattr(path) st = self.getattr(path)
try: try:
if st.st_nlink > 0: if st.st_nlink > 0:
return st return st
except: except:
return st # -int(os.errcode) return st # -int(os.errcode)
def read(self, path, length, offset, fh=None, *args): def read(self, path, length, offset, fh=None, *args):
if args: if args:
log("unexpected args [" + "] [".join(repr(x) for x in args) + "]") log("unexpected args [" + "] [".join(repr(x) for x in args) + "]")
raise Exception() raise Exception()
path = path.strip("/") path = path.strip("/")
ofs2 = offset + length ofs2 = offset + length
@ -516,7 +522,7 @@ class CPPF(Fuse):
file_sz = st.st_size file_sz = st.st_size
except: except:
return st # -int(os.errcode) return st # -int(os.errcode)
if ofs2 > file_sz: if ofs2 > file_sz:
ofs2 = file_sz ofs2 = file_sz
log("truncate to len {} end {}".format(ofs2 - offset, ofs2)) log("truncate to len {} end {}".format(ofs2 - offset, ofs2))
@ -564,14 +570,16 @@ def main():
server = CPPF() server = CPPF()
server.parser.add_option(mountopt="url", metavar="BASE_URL", default=None) server.parser.add_option(mountopt="url", metavar="BASE_URL", default=None)
server.parse(values=server, errex=1) server.parse(values=server, errex=1)
if not server.url or not str(server.url).startswith('http'): if not server.url or not str(server.url).startswith("http"):
print('\nerror:') print("\nerror:")
print(' need argument: -o url=<...>') print(" need argument: -o url=<...>")
print(' need argument: mount-path') print(" need argument: mount-path")
print('example:') print("example:")
print(' ./copyparty-fuseb.py -f -o allow_other,auto_unmount,nonempty,url=http://192.168.1.69:3923 /mnt/nas') print(
" ./copyparty-fuseb.py -f -o allow_other,auto_unmount,nonempty,url=http://192.168.1.69:3923 /mnt/nas"
)
sys.exit(1) sys.exit(1)
server.init2() server.init2()
threading.Thread(target=server.main, daemon=True).start() threading.Thread(target=server.main, daemon=True).start()
while True: while True: