Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
31 changes: 27 additions & 4 deletions lib/private/Files/Cache/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -899,10 +899,23 @@ public function getIncompleteChildrenCount($fileId) {
* calculate the size of a folder and set it in the cache
*
* @param string $path
* @param array $entry (optional) meta data of the folder
* @param array|null|ICacheEntry $entry (optional) meta data of the folder
* @return int
*/
public function calculateFolderSize($path, $entry = null) {
return $this->calculateFolderSizeInner($path, $entry);
}


/**
* inner function because we can't add new params to the public function without breaking any child classes
*
* @param string $path
* @param array|null|ICacheEntry $entry (optional) meta data of the folder
* @param bool $ignoreUnknown don't mark the folder size as unknown if any of it's children are unknown
* @return int
*/
protected function calculateFolderSizeInner(string $path, $entry = null, bool $ignoreUnknown = false) {
$totalSize = 0;
if (is_null($entry) || !isset($entry['fileid'])) {
$entry = $this->get($path);
Expand All @@ -914,6 +927,9 @@ public function calculateFolderSize($path, $entry = null) {
$query->select('size', 'unencrypted_size')
->from('filecache')
->whereParent($id);
if ($ignoreUnknown) {
$query->andWhere($query->expr()->gte('size', $query->createNamedParameter(0)));
}

$result = $query->execute();
$rows = $result->fetchAll();
Expand Down Expand Up @@ -954,9 +970,16 @@ public function calculateFolderSize($path, $entry = null) {
$unencryptedTotal = 0;
$unencryptedMax = 0;
}
if ($entry['size'] !== $totalSize) {
// only set unencrypted size for a folder if any child entries have it set, or the folder is empty
if ($unencryptedMax > 0 || $totalSize === 0) {

// only set unencrypted size for a folder if any child entries have it set, or the folder is empty
$shouldWriteUnEncryptedSize = $unencryptedMax > 0 || $totalSize === 0 || $entry['unencrypted_size'] > 0;
if ($entry['size'] !== $totalSize || ($entry['unencrypted_size'] !== $unencryptedTotal && $shouldWriteUnEncryptedSize)) {
if ($shouldWriteUnEncryptedSize) {
// if all children have an unencrypted size of 0, just set the folder unencrypted size to 0 instead of summing the sizes
if ($unencryptedMax === 0) {
$unencryptedTotal = 0;
}

$this->update($id, [
'size' => $totalSize,
'unencrypted_size' => $unencryptedTotal,
Expand Down
34 changes: 3 additions & 31 deletions lib/private/Files/Cache/HomeCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class HomeCache extends Cache {
* get the size of a folder and set it in the cache
*
* @param string $path
* @param array $entry (optional) meta data of the folder
* @param array|null|ICacheEntry $entry (optional) meta data of the folder
* @return int
*/
public function calculateFolderSize($path, $entry = null) {
Expand All @@ -44,37 +44,9 @@ public function calculateFolderSize($path, $entry = null) {
} elseif ($path === '' or $path === '/') {
// since the size of / isn't used (the size of /files is used instead) there is no use in calculating it
return 0;
} else {
return $this->calculateFolderSizeInner($path, $entry, true);
}

$totalSize = 0;
if (is_null($entry)) {
$entry = $this->get($path);
}
if ($entry && $entry['mimetype'] === 'httpd/unix-directory') {
$id = $entry['fileid'];

$query = $this->connection->getQueryBuilder();
$query->selectAlias($query->func()->sum('size'), 'f1')
->from('filecache')
->where($query->expr()->eq('parent', $query->createNamedParameter($id)))
->andWhere($query->expr()->eq('storage', $query->createNamedParameter($this->getNumericStorageId())))
->andWhere($query->expr()->gte('size', $query->createNamedParameter(0)));

$result = $query->execute();
$row = $result->fetch();
$result->closeCursor();

if ($row) {
[$sum] = array_values($row);
$totalSize = 0 + $sum;
$entry['size'] += 0;
if ($entry['size'] !== $totalSize) {
$this->update($id, ['size' => $totalSize]);
}
}
$result->closeCursor();
}
return $totalSize;
}

/**
Expand Down
22 changes: 19 additions & 3 deletions lib/private/Files/Cache/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
namespace OC\Files\Cache;

use Doctrine\DBAL\Exception;
use OC\Files\Storage\Wrapper\Encryption;
use OCP\Files\Cache\IScanner;
use OCP\Files\ForbiddenException;
use OCP\Files\Storage\IReliableEtagStorage;
Expand Down Expand Up @@ -207,9 +208,17 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =
$data['etag'] = $etag;
}
}

// we only updated unencrypted_size if it's already set
if ($cacheData['unencrypted_size'] === 0) {
unset($data['unencrypted_size']);
}

// Only update metadata that has changed
$newData = array_diff_assoc($data, $cacheData->getData());
} else {
// we only updated unencrypted_size if it's already set
unset($data['unencrypted_size']);
$newData = $data;
$fileId = -1;
}
Expand All @@ -219,7 +228,7 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =
$newData['parent'] = $parentId;
$data['fileid'] = $this->addToCache($file, $newData, $fileId);
}

$data['oldSize'] = ($cacheData && isset($cacheData['size'])) ? $cacheData['size'] : 0;

if ($cacheData && isset($cacheData['encrypted'])) {
Expand Down Expand Up @@ -390,8 +399,15 @@ protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse
}
}
$oldSize = $data['size'] ?? null;
if ($this->cacheActive && $oldSize !== $size) {
$this->cache->update($folderId, ['size' => $size]);

// for encrypted storages, we trigger a regular folder size calculation instead of using the calculated size
// to make sure we also updated the unencrypted-size where applicable
if ($this->storage->instanceOfStorage(Encryption::class)) {
$this->cache->calculateFolderSize($path);
} else {
if ($this->cacheActive && $oldSize !== $size) {
$this->cache->update($folderId, ['size' => $size]);
}
}
$this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', [$path, $this->storageId]);
return $size;
Expand Down
2 changes: 1 addition & 1 deletion lib/private/Files/Cache/Wrapper/CacheJail.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ public function correctFolderSize($path, $data = null, $isBackgroundScan = false
* get the size of a folder and set it in the cache
*
* @param string $path
* @param array $entry (optional) meta data of the folder
* @param array|null|ICacheEntry $entry (optional) meta data of the folder
* @return int
*/
public function calculateFolderSize($path, $entry = null) {
Expand Down
2 changes: 1 addition & 1 deletion lib/private/Files/Cache/Wrapper/CacheWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ public function correctFolderSize($path, $data = null, $isBackgroundScan = false
* get the size of a folder and set it in the cache
*
* @param string $path
* @param array $entry (optional) meta data of the folder
* @param array|null|ICacheEntry $entry (optional) meta data of the folder
* @return int
*/
public function calculateFolderSize($path, $entry = null) {
Expand Down
5 changes: 4 additions & 1 deletion lib/private/Files/Storage/Wrapper/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,12 @@ private function modifyMetaData(string $path, array $data): array {
if (isset($this->unencryptedSize[$fullPath])) {
$data['encrypted'] = true;
$data['size'] = $this->unencryptedSize[$fullPath];
$data['unencrypted_size'] = $data['size'];
} else {
if (isset($info['fileid']) && $info['encrypted']) {
$data['size'] = $this->verifyUnencryptedSize($path, $info->getUnencryptedSize());
$data['encrypted'] = true;
$data['unencrypted_size'] = $data['size'];
}
}

Expand Down Expand Up @@ -494,7 +496,8 @@ protected function verifyUnencryptedSize(string $path, int $unencryptedSize): in
$result = $unencryptedSize;

if ($unencryptedSize < 0 ||
($size > 0 && $unencryptedSize === $size)
($size > 0 && $unencryptedSize === $size) ||
$unencryptedSize > $size
) {
// check if we already calculate the unencrypted size for the
// given path to avoid recursions
Expand Down