implement fseek for sftp read stream

Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
Robin Appelman 2023-08-31 15:39:56 +02:00 committed by backportbot-nextcloud[bot]
parent 02a50bd99c
commit 373bd09fbf
2 changed files with 30 additions and 3 deletions

View file

@ -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':

View file

@ -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);