From b791a1f734b6de5f63622483e2333468a8ebc810 Mon Sep 17 00:00:00 2001
From: mxmlnkn
Date: Wed, 2 Oct 2024 18:05:15 +0200
Subject: [PATCH 1/2] Implement io.IOBase.seekable method
---
sshfs/file.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sshfs/file.py b/sshfs/file.py
index 349f64d..5187d5b 100644
--- a/sshfs/file.py
+++ b/sshfs/file.py
@@ -81,6 +81,9 @@ async def _open_file(self):
def readable(self):
return "r" in self.mode
+ def seekable(self):
+ return "r" in self.mode or "w" in self.mode
+
def writable(self):
return not self.readable()
From f8443c3fea664d51520b0c7f44583b16819f05b7 Mon Sep 17 00:00:00 2001
From: mxmlnkn
Date: Thu, 3 Oct 2024 12:47:26 +0200
Subject: [PATCH 2/2] Use the block size determined by asyncssh if nothing is
specified
---
sshfs/file.py | 41 +++++++++++++++++++++++++----------------
1 file changed, 25 insertions(+), 16 deletions(-)
diff --git a/sshfs/file.py b/sshfs/file.py
index 5187d5b..a6711c1 100644
--- a/sshfs/file.py
+++ b/sshfs/file.py
@@ -26,32 +26,37 @@ def __init__(
self.mode = mode
self.max_requests = max_requests or _MAX_SFTP_REQUESTS
- if block_size is None:
- # "The OpenSSH SFTP server will close the connection
- # if it receives a message larger than 256 KB, and
- # limits read requests to returning no more than
- # 64 KB."
- #
- # We are going to use the maximum block_size possible
- # with a 16KB margin (so instead of sending 256 KB data,
- # we'll send 240 KB + headers for write requests)
-
- if self.readable():
- block_size = READ_BLOCK_SIZE
- else:
- block_size = WRITE_BLOCK_SIZE
-
# The blocksize is often used with constructs like
# shutil.copyfileobj(src, dst, length=file.blocksize) and since we are
# using pipelining, we are going to reflect the total size rather than
# a size of chunk to our limits.
- self.blocksize = block_size * self.max_requests
+ self.blocksize = (
+ None if block_size is None else block_size * self.max_requests
+ )
self.kwargs = kwargs
self._file = sync(self.loop, self._open_file)
self._closed = False
+ def _determine_block_size(self, channel):
+ # Use the asyncssh block sizes to ensure the best performance.
+ limits = getattr(channel, "limits", None)
+ if limits:
+ if self.readable():
+ return limits.max_read_len
+ return limits.max_write_len
+
+ # "The OpenSSH SFTP server will close the connection
+ # if it receives a message larger than 256 KB, and
+ # limits read requests to returning no more than
+ # 64 KB."
+ #
+ # We are going to use the maximum block_size possible
+ # with a 16KB margin (so instead of sending 256 KB data,
+ # we'll send 240 KB + headers for write requests)
+ return READ_BLOCK_SIZE if self.readable() else WRITE_BLOCK_SIZE
+
@wrap_exceptions
async def _open_file(self):
# TODO: this needs to keep a reference to the
@@ -61,6 +66,10 @@ async def _open_file(self):
# it's operations but the pool it thinking this
# channel is freed.
async with self.fs._pool.get() as channel:
+ if self.blocksize is None:
+ self.blocksize = (
+ self._determine_block_size(channel) * self.max_requests
+ )
return await channel.open(
self.path,
self.mode,