Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
implement fseek for sftp read stream
Signed-off-by: Robin Appelman <[email protected]>
  • Loading branch information
icewind1991 authored and backportbot-nextcloud[bot] committed Sep 18, 2023
commit 373bd09fbfcd6875b0fe4e3d2d756e9aaab9ad42
5 changes: 3 additions & 2 deletions apps/files_external/lib/Lib/Storage/SFTP.php
Original file line number Diff line number Diff line change
Expand Up @@ -381,11 +381,12 @@ public function fopen($path, $mode) {
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':
Expand Down
28 changes: 27 additions & 1 deletion apps/files_external/lib/Lib/Storage/SFTPReadStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -76,6 +77,9 @@ protected function loadContext($name) {
} else {
throw new \BadMethodCallException('Invalid context, session not set');
}
if (isset($context['size'])) {
$this->size = $context['size'];
}
return $context;
}

Expand Down Expand Up @@ -119,7 +123,25 @@ public function stream_open($path, $mode, $options, &$opened_path) {
}

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() {
Expand All @@ -143,6 +165,10 @@ public function stream_read($count) {
}

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);
Expand Down