aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2023-08-31 15:39:56 +0200
committerbackportbot-nextcloud[bot] <backportbot-nextcloud[bot]@users.noreply.github.com>2023-09-18 17:33:43 +0000
commit373bd09fbfcd6875b0fe4e3d2d756e9aaab9ad42 (patch)
tree9d09408efc484113e6374c1f24aa4382f03cc473
parent02a50bd99c725b70a29c98a66037fc7534b67ea0 (diff)
downloadnextcloud-server-373bd09fbfcd6875b0fe4e3d2d756e9aaab9ad42.tar.gz
nextcloud-server-373bd09fbfcd6875b0fe4e3d2d756e9aaab9ad42.zip
implement fseek for sftp read stream
Signed-off-by: Robin Appelman <robin@icewind.nl>
-rw-r--r--apps/files_external/lib/Lib/Storage/SFTP.php5
-rw-r--r--apps/files_external/lib/Lib/Storage/SFTPReadStream.php28
2 files changed, 30 insertions, 3 deletions
diff --git a/apps/files_external/lib/Lib/Storage/SFTP.php b/apps/files_external/lib/Lib/Storage/SFTP.php
index d41963de82c..83d29edb3f6 100644
--- a/apps/files_external/lib/Lib/Storage/SFTP.php
+++ b/apps/files_external/lib/Lib/Storage/SFTP.php
@@ -381,11 +381,12 @@ class SFTP extends Common {
switch ($mode) {
case 'r':
case 'rb':
- if (!$this->file_exists($path)) {
+ $stat = $this->stat($path);
+ if (!$stat) {
return false;
}
SFTPReadStream::register();
- $context = stream_context_create(['sftp' => ['session' => $connection]]);
+ $context = stream_context_create(['sftp' => ['session' => $connection, 'size' => $stat['size']]]);
$handle = fopen('sftpread://' . trim($absPath, '/'), 'r', false, $context);
return RetryWrapper::wrap($handle);
case 'w':
diff --git a/apps/files_external/lib/Lib/Storage/SFTPReadStream.php b/apps/files_external/lib/Lib/Storage/SFTPReadStream.php
index 7a53f41aa61..aaae811c57b 100644
--- a/apps/files_external/lib/Lib/Storage/SFTPReadStream.php
+++ b/apps/files_external/lib/Lib/Storage/SFTPReadStream.php
@@ -50,6 +50,7 @@ class SFTPReadStream implements File {
private $buffer = '';
private bool $pendingRead = false;
+ private int $size = 0;
public static function register($protocol = 'sftpread') {
if (in_array($protocol, stream_get_wrappers(), true)) {
@@ -76,6 +77,9 @@ class SFTPReadStream implements File {
} else {
throw new \BadMethodCallException('Invalid context, session not set');
}
+ if (isset($context['size'])) {
+ $this->size = $context['size'];
+ }
return $context;
}
@@ -119,7 +123,25 @@ class SFTPReadStream implements File {
}
public function stream_seek($offset, $whence = SEEK_SET) {
- return false;
+ switch ($whence) {
+ case SEEK_SET:
+ $this->seekTo($offset);
+ break;
+ case SEEK_CUR:
+ $this->seekTo($this->readPosition + $offset);
+ break;
+ case SEEK_END:
+ $this->seekTo($this->size + $offset);
+ break;
+ }
+ return true;
+ }
+
+ private function seekTo(int $offset) {
+ $this->internalPosition = $offset;
+ $this->readPosition = $offset;
+ $this->buffer = '';
+ $this->request_chunk(256 * 1024);
}
public function stream_tell() {
@@ -143,6 +165,10 @@ class SFTPReadStream implements File {
}
private function request_chunk($size) {
+ if ($this->pendingRead) {
+ $this->sftp->_get_sftp_packet();
+ }
+
$packet = pack('Na*N3', strlen($this->handle), $this->handle, $this->internalPosition / 4294967296, $this->internalPosition, $size);
$this->pendingRead = true;
return $this->sftp->_send_sftp_packet(NET_SFTP_READ, $packet);