aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Files/Storage/Wrapper
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Files/Storage/Wrapper')
-rw-r--r--lib/private/Files/Storage/Wrapper/Encoding.php2
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php48
-rw-r--r--lib/private/Files/Storage/Wrapper/Jail.php5
-rw-r--r--lib/private/Files/Storage/Wrapper/KnownMtime.php142
-rw-r--r--lib/private/Files/Storage/Wrapper/PermissionsMask.php4
-rw-r--r--lib/private/Files/Storage/Wrapper/Wrapper.php11
6 files changed, 175 insertions, 37 deletions
diff --git a/lib/private/Files/Storage/Wrapper/Encoding.php b/lib/private/Files/Storage/Wrapper/Encoding.php
index 6633cbf41e3..1bdb0e39f14 100644
--- a/lib/private/Files/Storage/Wrapper/Encoding.php
+++ b/lib/private/Files/Storage/Wrapper/Encoding.php
@@ -28,8 +28,8 @@
*/
namespace OC\Files\Storage\Wrapper;
-use OCP\Cache\CappedMemoryCache;
use OC\Files\Filesystem;
+use OCP\Cache\CappedMemoryCache;
use OCP\Files\Storage\IStorage;
use OCP\ICache;
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index a27f499a210..7ce4338256f 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -100,6 +100,8 @@ class Encryption extends Wrapper {
/** @var CappedMemoryCache<bool> */
private CappedMemoryCache $encryptedPaths;
+ private $enabled = true;
+
/**
* @param array $parameters
*/
@@ -392,6 +394,10 @@ class Encryption extends Wrapper {
return $this->storage->fopen($path, $mode);
}
+ if (!$this->enabled) {
+ return $this->storage->fopen($path, $mode);
+ }
+
$encryptionEnabled = $this->encryptionManager->isEnabled();
$shouldEncrypt = false;
$encryptionModule = null;
@@ -938,34 +944,6 @@ class Encryption extends Wrapper {
}
/**
- * parse raw header to array
- *
- * @param string $rawHeader
- * @return array
- */
- protected function parseRawHeader($rawHeader) {
- $result = [];
- if (str_starts_with($rawHeader, Util::HEADER_START)) {
- $header = $rawHeader;
- $endAt = strpos($header, Util::HEADER_END);
- if ($endAt !== false) {
- $header = substr($header, 0, $endAt + strlen(Util::HEADER_END));
-
- // +1 to not start with an ':' which would result in empty element at the beginning
- $exploded = explode(':', substr($header, strlen(Util::HEADER_START) + 1));
-
- $element = array_shift($exploded);
- while ($element !== Util::HEADER_END) {
- $result[$element] = array_shift($exploded);
- $element = array_shift($exploded);
- }
- }
- }
-
- return $result;
- }
-
- /**
* read header from file
*
* @param string $path
@@ -988,7 +966,7 @@ class Encryption extends Wrapper {
if ($isEncrypted) {
$firstBlock = $this->readFirstBlock($path);
- $result = $this->parseRawHeader($firstBlock);
+ $result = $this->util->parseRawHeader($firstBlock);
// if the header doesn't contain a encryption module we check if it is a
// legacy file. If true, we add the default encryption module
@@ -1093,7 +1071,7 @@ class Encryption extends Wrapper {
// object store, stores the size after write and doesn't update this during scan
// manually store the unencrypted size
- if ($result && $this->getWrapperStorage()->instanceOfStorage(ObjectStoreStorage::class)) {
+ if ($result && $this->getWrapperStorage()->instanceOfStorage(ObjectStoreStorage::class) && $this->shouldEncrypt($path)) {
$this->getCache()->put($path, ['unencrypted_size' => $count]);
}
@@ -1103,4 +1081,14 @@ class Encryption extends Wrapper {
public function clearIsEncryptedCache(): void {
$this->encryptedPaths->clear();
}
+
+ /**
+ * Allow temporarily disabling the wrapper
+ *
+ * @param bool $enabled
+ * @return void
+ */
+ public function setEnabled(bool $enabled): void {
+ $this->enabled = $enabled;
+ }
}
diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php
index 1921ac27848..592acd418ec 100644
--- a/lib/private/Files/Storage/Wrapper/Jail.php
+++ b/lib/private/Files/Storage/Wrapper/Jail.php
@@ -396,10 +396,7 @@ class Jail extends Wrapper {
* @return \OC\Files\Cache\Cache
*/
public function getCache($path = '', $storage = null) {
- if (!$storage) {
- $storage = $this->getWrapperStorage();
- }
- $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path), $storage);
+ $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path));
return new CacheJail($sourceCache, $this->rootPath);
}
diff --git a/lib/private/Files/Storage/Wrapper/KnownMtime.php b/lib/private/Files/Storage/Wrapper/KnownMtime.php
new file mode 100644
index 00000000000..dde209c44ab
--- /dev/null
+++ b/lib/private/Files/Storage/Wrapper/KnownMtime.php
@@ -0,0 +1,142 @@
+<?php
+
+namespace OC\Files\Storage\Wrapper;
+
+use OCP\Cache\CappedMemoryCache;
+use OCP\Files\Storage\IStorage;
+use Psr\Clock\ClockInterface;
+
+/**
+ * Wrapper that overwrites the mtime return by stat/getMetaData if the returned value
+ * is lower than when we last modified the file.
+ *
+ * This is useful because some storage servers can return an outdated mtime right after writes
+ */
+class KnownMtime extends Wrapper {
+ private CappedMemoryCache $knowMtimes;
+ private ClockInterface $clock;
+
+ public function __construct($arguments) {
+ parent::__construct($arguments);
+ $this->knowMtimes = new CappedMemoryCache();
+ $this->clock = $arguments['clock'];
+ }
+
+ public function file_put_contents($path, $data) {
+ $result = parent::file_put_contents($path, $data);
+ if ($result) {
+ $now = $this->clock->now()->getTimestamp();
+ $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function stat($path) {
+ $stat = parent::stat($path);
+ if ($stat) {
+ $this->applyKnownMtime($path, $stat);
+ }
+ return $stat;
+ }
+
+ public function getMetaData($path) {
+ $stat = parent::getMetaData($path);
+ if ($stat) {
+ $this->applyKnownMtime($path, $stat);
+ }
+ return $stat;
+ }
+
+ private function applyKnownMtime(string $path, array &$stat) {
+ if (isset($stat['mtime'])) {
+ $knownMtime = $this->knowMtimes->get($path) ?? 0;
+ $stat['mtime'] = max($stat['mtime'], $knownMtime);
+ }
+ }
+
+ public function filemtime($path) {
+ $knownMtime = $this->knowMtimes->get($path) ?? 0;
+ return max(parent::filemtime($path), $knownMtime);
+ }
+
+ public function mkdir($path) {
+ $result = parent::mkdir($path);
+ if ($result) {
+ $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function rmdir($path) {
+ $result = parent::rmdir($path);
+ if ($result) {
+ $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function unlink($path) {
+ $result = parent::unlink($path);
+ if ($result) {
+ $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function rename($source, $target) {
+ $result = parent::rename($source, $target);
+ if ($result) {
+ $this->knowMtimes->set($target, $this->clock->now()->getTimestamp());
+ $this->knowMtimes->set($source, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function copy($source, $target) {
+ $result = parent::copy($source, $target);
+ if ($result) {
+ $this->knowMtimes->set($target, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function fopen($path, $mode) {
+ $result = parent::fopen($path, $mode);
+ if ($result && $mode === 'w') {
+ $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function touch($path, $mtime = null) {
+ $result = parent::touch($path, $mtime);
+ if ($result) {
+ $this->knowMtimes->set($path, $mtime ?? $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ $result = parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ if ($result) {
+ $this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ $result = parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ if ($result) {
+ $this->knowMtimes->set($targetInternalPath, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+
+ public function writeStream(string $path, $stream, int $size = null): int {
+ $result = parent::writeStream($path, $stream, $size);
+ if ($result) {
+ $this->knowMtimes->set($path, $this->clock->now()->getTimestamp());
+ }
+ return $result;
+ }
+}
diff --git a/lib/private/Files/Storage/Wrapper/PermissionsMask.php b/lib/private/Files/Storage/Wrapper/PermissionsMask.php
index 0d140e0a39d..a79eaad0569 100644
--- a/lib/private/Files/Storage/Wrapper/PermissionsMask.php
+++ b/lib/private/Files/Storage/Wrapper/PermissionsMask.php
@@ -140,7 +140,7 @@ class PermissionsMask extends Wrapper {
$data = parent::getMetaData($path);
if ($data && isset($data['permissions'])) {
- $data['scan_permissions'] = isset($data['scan_permissions']) ? $data['scan_permissions'] : $data['permissions'];
+ $data['scan_permissions'] = $data['scan_permissions'] ?? $data['permissions'];
$data['permissions'] &= $this->mask;
}
return $data;
@@ -155,7 +155,7 @@ class PermissionsMask extends Wrapper {
public function getDirectoryContent($directory): \Traversable {
foreach ($this->getWrapperStorage()->getDirectoryContent($directory) as $data) {
- $data['scan_permissions'] = isset($data['scan_permissions']) ? $data['scan_permissions'] : $data['permissions'];
+ $data['scan_permissions'] = $data['scan_permissions'] ?? $data['permissions'];
$data['permissions'] &= $this->mask;
yield $data;
diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php
index 9f5564b4490..665914df2a7 100644
--- a/lib/private/Files/Storage/Wrapper/Wrapper.php
+++ b/lib/private/Files/Storage/Wrapper/Wrapper.php
@@ -654,4 +654,15 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
public function getDirectoryContent($directory): \Traversable {
return $this->getWrapperStorage()->getDirectoryContent($directory);
}
+
+ public function isWrapperOf(IStorage $storage) {
+ $wrapped = $this->getWrapperStorage();
+ if ($wrapped === $storage) {
+ return true;
+ }
+ if ($wrapped instanceof Wrapper) {
+ return $wrapped->isWrapperOf($storage);
+ }
+ return false;
+ }
}