From b900782513a750e5e100c7d55278632754a8df19 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 16 Oct 2015 18:28:45 +0200 Subject: [PATCH] Also adjust storage_mtime of target after rename Some storages like Dropbox change their mtime on rename... --- lib/private/files/cache/cache.php | 10 ++++++- lib/private/files/cache/updater.php | 14 ++++++++++ tests/lib/files/cache/updater.php | 41 +++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index f3e22701f4..231dbe3769 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -313,6 +313,14 @@ class Cache { $fields = array( 'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'etag', 'permissions'); + + $doNotCopyStorageMTime = false; + if (array_key_exists('mtime', $data) && $data['mtime'] === null) { + // this horrific magic tells it to not copy storage_mtime to mtime + unset($data['mtime']); + $doNotCopyStorageMTime = true; + } + $params = array(); $queryParts = array(); foreach ($data as $name => $value) { @@ -325,7 +333,7 @@ class Cache { $queryParts[] = '`mimepart`'; $value = $this->mimetypeLoader->getId($value); } elseif ($name === 'storage_mtime') { - if (!isset($data['mtime'])) { + if (!$doNotCopyStorageMTime && !isset($data['mtime'])) { $params[] = $value; $queryParts[] = '`mtime`'; } diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index 2de0c8fe06..c82ee33a1b 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -193,12 +193,26 @@ class Updater { $targetCache->correctFolderSize($targetInternalPath); $this->correctParentStorageMtime($sourceStorage, $sourceInternalPath); $this->correctParentStorageMtime($targetStorage, $targetInternalPath); + $this->updateStorageMTimeOnly($targetStorage, $targetInternalPath); $this->propagator->addChange($source); $this->propagator->addChange($target); $this->propagator->propagateChanges(); } } + private function updateStorageMTimeOnly($storage, $internalPath) { + $cache = $storage->getCache(); + $fileId = $cache->getId($internalPath); + if ($fileId !== -1) { + $cache->update( + $fileId, [ + 'mtime' => null, // this magic tells it to not overwrite mtime + 'storage_mtime' => $storage->filemtime($internalPath) + ] + ); + } + } + /** * update the storage_mtime of the direct parent in the cache to the mtime from the storage * diff --git a/tests/lib/files/cache/updater.php b/tests/lib/files/cache/updater.php index e3fa26829b..b7e76aeace 100644 --- a/tests/lib/files/cache/updater.php +++ b/tests/lib/files/cache/updater.php @@ -161,6 +161,47 @@ class Updater extends \Test\TestCase { $this->assertEquals($cached['fileid'], $cachedTarget['fileid']); } + public function testUpdateStorageMTime() { + $this->storage->mkdir('sub'); + $this->storage->mkdir('sub2'); + $this->storage->file_put_contents('sub/foo.txt', 'qwerty'); + + $this->updater->update('sub'); + $this->updater->update('sub/foo.txt'); + $this->updater->update('sub2'); + + $cachedSourceParent = $this->cache->get('sub'); + $cachedSource = $this->cache->get('sub/foo.txt'); + + $this->storage->rename('sub/foo.txt', 'sub2/bar.txt'); + + // simulate storage having a different mtime + $testmtime = 1433323578; + + // source storage mtime change + $this->storage->touch('sub', $testmtime); + + // target storage mtime change + $this->storage->touch('sub2', $testmtime); + // some storages (like Dropbox) change storage mtime on rename + $this->storage->touch('sub2/bar.txt', $testmtime); + + $this->updater->rename('sub/foo.txt', 'sub2/bar.txt'); + + $cachedTargetParent = $this->cache->get('sub2'); + $cachedTarget = $this->cache->get('sub2/bar.txt'); + + $this->assertEquals($cachedSource['mtime'], $cachedTarget['mtime'], 'file mtime preserved'); + + $this->assertNotEquals($cachedTarget['storage_mtime'], $cachedTarget['mtime'], 'mtime is not storage_mtime for moved file'); + + $this->assertEquals($testmtime, $cachedTarget['storage_mtime'], 'target file storage_mtime propagated'); + $this->assertNotEquals($testmtime, $cachedTarget['mtime'], 'target file mtime changed, not from storage'); + + $this->assertEquals($testmtime, $cachedTargetParent['storage_mtime'], 'target parent storage_mtime propagated'); + $this->assertNotEquals($testmtime, $cachedTargetParent['mtime'], 'target folder mtime changed, not from storage'); + } + public function testNewFileDisabled() { $this->storage->file_put_contents('foo.txt', 'bar'); $this->assertFalse($this->cache->inCache('foo.txt'));