fuse: be nicer to software which fails on truncated reads, such as Wimgapi.dll

This commit is contained in:
ed 2020-08-11 18:16:37 +00:00
parent b025c2f660
commit b6a3c52d67
2 changed files with 65 additions and 23 deletions

View file

@ -94,6 +94,7 @@ def null_log(msg):
class RecentLog(object): class RecentLog(object):
def __init__(self): def __init__(self):
self.mtx = threading.Lock() self.mtx = threading.Lock()
self.f = None # open("copyparty-fuse.log", "wb")
self.q = [] self.q = []
thr = threading.Thread(target=self.printer) thr = threading.Thread(target=self.printer)
@ -101,8 +102,13 @@ class RecentLog(object):
thr.start() thr.start()
def put(self, msg): def put(self, msg):
msg = "{} {}\n".format(rice_tid(), msg)
if self.f:
fmsg = " ".join([datetime.utcnow().strftime("%H%M%S.%f"), str(msg)])
self.f.write(fmsg.encode("utf-8"))
with self.mtx: with self.mtx:
self.q.append("{} {}\n".format(rice_tid(), msg)) self.q.append(msg)
if len(self.q) > 200: if len(self.q) > 200:
self.q = self.q[-50:] self.q = self.q[-50:]
@ -355,12 +361,13 @@ class CPPF(Operations):
def _describe(self): def _describe(self):
msg = "" msg = ""
for n, cn in enumerate(self.filecache): with self.filecache_mtx:
cache_path, cache1 = cn.tag for n, cn in enumerate(self.filecache):
cache2 = cache1 + len(cn.data) cache_path, cache1 = cn.tag
msg += "\n{:<2} {:>7} {:>10}:{:<9} {}".format( cache2 = cache1 + len(cn.data)
n, len(cn.data), cache1, cache2, cache_path msg += "\n{:<2} {:>7} {:>10}:{:<9} {}".format(
) n, len(cn.data), cache1, cache2, cache_path
)
return msg return msg
def clean_dircache(self): def clean_dircache(self):
@ -414,11 +421,8 @@ class CPPF(Operations):
car = None car = None
cdr = None cdr = None
ncn = -1 ncn = -1
dbg("cache request {}:{} |{}|".format(get1, get2, file_sz) + self._describe())
with self.filecache_mtx: with self.filecache_mtx:
dbg(
"cache request {}:{} |{}|".format(get1, get2, file_sz)
+ self._describe()
)
for cn in self.filecache: for cn in self.filecache:
ncn += 1 ncn += 1
@ -513,25 +517,33 @@ class CPPF(Operations):
elif cdr and (not car or len(car) < len(cdr)): elif cdr and (not car or len(car) < len(cdr)):
h_end = get1 + (get2 - get1) - len(cdr) h_end = get1 + (get2 - get1) - len(cdr)
h_ofs = h_end - 512 * 1024 h_ofs = min(get1, h_end - 512 * 1024)
if h_ofs < 0: if h_ofs < 0:
h_ofs = 0 h_ofs = 0
buf_ofs = (get2 - get1) - len(cdr) buf_ofs = get1 - h_ofs
dbg( dbg(
"<cache> cdr {}, car {}:{} |{}| [-{}:]".format( "<cache> cdr {}, car {}:{} |{}| [{}:]".format(
len(cdr), h_ofs, h_end, h_end - h_ofs, buf_ofs len(cdr), h_ofs, h_end, h_end - h_ofs, buf_ofs
) )
) )
buf = self.gw.download_file_range(path, h_ofs, h_end) buf = self.gw.download_file_range(path, h_ofs, h_end)
ret = buf[-buf_ofs:] + cdr if len(buf) == h_end - h_ofs:
ret = buf[buf_ofs:] + cdr
else:
ret = buf[get1 - h_ofs :]
info(
"remote truncated {}:{} to |{}|, will return |{}|".format(
h_ofs, h_end, len(buf), len(ret)
)
)
elif car: elif car:
h_ofs = get1 + len(car) h_ofs = get1 + len(car)
h_end = h_ofs + 1024 * 1024 h_end = max(get2, h_ofs + 1024 * 1024)
if h_end > file_sz: if h_end > file_sz:
h_end = file_sz h_end = file_sz
@ -548,8 +560,13 @@ class CPPF(Operations):
ret = car + buf[:buf_ofs] ret = car + buf[:buf_ofs]
else: else:
h_ofs = get1 - 256 * 1024 if get2 - get1 <= 1024 * 1024:
h_end = get2 + 1024 * 1024 h_ofs = get1 - 256 * 1024
h_end = get2 + 1024 * 1024
else:
# big enough, doesn't need pads
h_ofs = get1
h_end = get2
if h_ofs < 0: if h_ofs < 0:
h_ofs = 0 h_ofs = 0
@ -615,10 +632,35 @@ class CPPF(Operations):
if file_sz == 0 or offset >= ofs2: if file_sz == 0 or offset >= ofs2:
return b"" return b""
if not self.n_filecache or length > cache_max: if self.n_filecache and length <= cache_max:
return self.gw.download_file_range(path, offset, ofs2) ret = self.get_cached_file(path, offset, ofs2, file_sz)
else:
ret = self.gw.download_file_range(path, offset, ofs2)
return self.get_cached_file(path, offset, ofs2, file_sz) return ret
fn = "cppf-{}-{}-{}".format(time.time(), offset, length)
if False:
with open(fn, "wb", len(ret)) as f:
f.write(ret)
elif self.n_filecache:
ret2 = self.gw.download_file_range(path, offset, ofs2)
if ret != ret2:
info(fn)
for v in [ret, ret2]:
try:
info(len(v))
except:
info("uhh " + repr(v))
with open(fn + ".bad", "wb") as f:
f.write(ret)
with open(fn + ".good", "wb") as f:
f.write(ret2)
raise Exception("cache bork")
return ret
def getattr(self, path, fh=None): def getattr(self, path, fh=None):
log("getattr [{}]".format(path)) log("getattr [{}]".format(path))
@ -748,7 +790,7 @@ def main():
# filecache helps for reads that are ~64k or smaller; # filecache helps for reads that are ~64k or smaller;
# linux generally does 128k so the cache is a slowdown, # linux generally does 128k so the cache is a slowdown,
# windows likes to use 4k and 64k so cache is required, # windows likes to use 4k and 64k so cache is required,
# value is numChunks (~1M each) to keep in the cache # value is numChunks (1~3M each) to keep in the cache
nf = 24 if WINDOWS else 0 nf = 24 if WINDOWS else 0
# dircache is always a boost, # dircache is always a boost,

View file

@ -11,7 +11,7 @@ PYTHONPATH=.. python3 -m copyparty -v /dev/shm/fusefuzz/r::r -i 127.0.0.1
def main(): def main():
v = "virt" v = "v"
for n in range(5): for n in range(5):
with open(f"r/{n}", "wb") as f: with open(f"r/{n}", "wb") as f:
f.write(b"h" * n) f.write(b"h" * n)