diff --git a/apps/files_external/lib/Lib/Storage/SFTP.php b/apps/files_external/lib/Lib/Storage/SFTP.php index 532c50808db23..664e063b586cb 100644 --- a/apps/files_external/lib/Lib/Storage/SFTP.php +++ b/apps/files_external/lib/Lib/Storage/SFTP.php @@ -36,15 +36,19 @@ */ namespace OCA\Files_External\Lib\Storage; +use Icewind\Streams\CallbackWrapper; use Icewind\Streams\IteratorDirectory; use Icewind\Streams\RetryWrapper; +use OC\Files\Storage\Common; +use OCP\Cache\CappedMemoryCache; +use OCP\Files\Storage\IWriteStreamStorage; use phpseclib\Net\SFTP\Stream; /** * Uses phpseclib's Net\SFTP class and the Net\SFTP\Stream stream wrapper to * provide access to SFTP servers. */ -class SFTP extends \OC\Files\Storage\Common { +class SFTP extends Common implements IWriteStreamStorage { private $host; private $user; private $root; @@ -56,6 +60,7 @@ class SFTP extends \OC\Files\Storage\Common { * @var \phpseclib\Net\SFTP */ protected $client; + private CappedMemoryCache $knownMTimes; /** * @param string $host protocol://server:port @@ -111,6 +116,8 @@ public function __construct($params) { $this->root = '/' . ltrim($this->root, '/'); $this->root = rtrim($this->root, '/') . '/'; + + $this->knownMTimes = new CappedMemoryCache(); } /** @@ -368,6 +375,7 @@ public function unlink($path) { * {@inheritdoc} */ public function fopen($path, $mode) { + $path = $this->cleanPath($path); try { $absPath = $this->absPath($path); switch ($mode) { @@ -384,7 +392,13 @@ public function fopen($path, $mode) { case 'wb': SFTPWriteStream::register(); $context = stream_context_create(['sftp' => ['session' => $this->getConnection()]]); - return fopen('sftpwrite://' . trim($absPath, '/'), 'w', false, $context); + $fh = fopen('sftpwrite://' . trim($absPath, '/'), 'w', false, $context); + if ($fh) { + $fh = CallbackWrapper::wrap($fh, null, null, function() use ($path) { + $this->knownMTimes->set($path, time()); + }); + } + return $fh; case 'a': case 'ab': case 'r+': @@ -413,14 +427,13 @@ public function touch($path, $mtime = null) { return false; } if (!$this->file_exists($path)) { - $this->getConnection()->put($this->absPath($path), ''); + return $this->getConnection()->put($this->absPath($path), ''); } else { return false; } } catch (\Exception $e) { return false; } - return true; } /** @@ -454,11 +467,17 @@ public function rename($source, $target) { */ public function stat($path) { try { + $this->cleanPath($path); $stat = $this->getConnection()->stat($this->absPath($path)); $mtime = $stat ? $stat['mtime'] : -1; $size = $stat ? $stat['size'] : 0; + // the mtime can't be less than when we last touched it + if ($knownMTime = $this->knownMTimes->get($path)) { + $mtime = max($mtime, $knownMTime); + } + return ['mtime' => $mtime, 'size' => $size, 'ctime' => -1]; } catch (\Exception $e) { return false;