@@ -200,6 +200,7 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =
200200 $ data ['fileid ' ] = $ fileId ;
201201 // only reuse data if the file hasn't explicitly changed
202202 $ mtimeUnchanged = isset ($ data ['storage_mtime ' ]) && isset ($ cacheData ['storage_mtime ' ]) && $ data ['storage_mtime ' ] === $ cacheData ['storage_mtime ' ];
203+ // if the folder is marked as unscanned, never reuse etags
203204 if ($ mtimeUnchanged && $ cacheData ['size ' ] !== -1 ) {
204205 $ data ['mtime ' ] = $ cacheData ['mtime ' ];
205206 if (($ reuseExisting & self ::REUSE_SIZE ) && ($ data ['size ' ] === -1 )) {
@@ -217,6 +218,11 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =
217218
218219 // Only update metadata that has changed
219220 $ newData = array_diff_assoc ($ data , $ cacheData ->getData ());
221+
222+ // make it known to the caller that etag has been changed and needs propagation
223+ if (isset ($ newData ['etag ' ])) {
224+ $ data ['etag_changed ' ] = true ;
225+ }
220226 } else {
221227 // we only updated unencrypted_size if it's already set
222228 unset($ data ['unencrypted_size ' ]);
@@ -380,7 +386,7 @@ protected function getExistingChildren($folderId) {
380386 * @param array $data the data of the folder before (re)scanning the children
381387 * @return int|float the size of the scanned folder or -1 if the size is unknown at this stage
382388 */
383- protected function scanChildren ($ path , $ recursive = self ::SCAN_RECURSIVE , $ reuse = -1 , $ folderId = null , $ lock = true , array $ data = []) {
389+ protected function scanChildren ($ path , $ recursive = self ::SCAN_RECURSIVE , $ reuse = -1 , $ folderId = null , $ lock = true , array $ data = [], & $ etagChanged = false ) {
384390 if ($ reuse === -1 ) {
385391 $ reuse = ($ recursive === self ::SCAN_SHALLOW ) ? self ::REUSE_ETAG | self ::REUSE_SIZE : self ::REUSE_ETAG ;
386392 }
@@ -389,10 +395,14 @@ protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse
389395 if (!is_null ($ folderId )) {
390396 $ folderId = $ this ->cache ->getId ($ path );
391397 }
392- $ childQueue = $ this ->handleChildren ($ path , $ recursive , $ reuse , $ folderId , $ lock , $ size );
398+ $ childQueue = $ this ->handleChildren ($ path , $ recursive , $ reuse , $ folderId , $ lock , $ size, $ etagChanged );
393399
394400 foreach ($ childQueue as $ child => $ childId ) {
395- $ childSize = $ this ->scanChildren ($ child , $ recursive , $ reuse , $ childId , $ lock );
401+ // "etag changed" propagates up, but not down, so we pass `false` to the children even if we already know that the etag of the current folder changed
402+ $ childEtagChanged = false ;
403+ $ childSize = $ this ->scanChildren ($ child , $ recursive , $ reuse , $ childId , $ lock , [], $ childEtagChanged );
404+ $ etagChanged |= $ childEtagChanged ;
405+
396406 if ($ childSize === -1 ) {
397407 $ size = -1 ;
398408 } elseif ($ size !== -1 ) {
@@ -406,15 +416,24 @@ protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse
406416 if ($ this ->storage ->instanceOfStorage (Encryption::class)) {
407417 $ this ->cache ->calculateFolderSize ($ path );
408418 } else {
409- if ($ this ->cacheActive && $ oldSize !== $ size ) {
410- $ this ->cache ->update ($ folderId , ['size ' => $ size ]);
419+ if ($ this ->cacheActive ) {
420+ $ updatedData = [];
421+ if ($ oldSize !== $ size ) {
422+ $ updatedData ['size ' ] = $ size ;
423+ }
424+ if ($ etagChanged ) {
425+ $ updatedData ['etag ' ] = uniqid ();
426+ }
427+ if ($ updatedData ) {
428+ $ this ->cache ->update ($ folderId , $ updatedData );
429+ }
411430 }
412431 }
413432 $ this ->emit ('\OC\Files\Cache\Scanner ' , 'postScanFolder ' , [$ path , $ this ->storageId ]);
414433 return $ size ;
415434 }
416435
417- private function handleChildren ($ path , $ recursive , $ reuse , $ folderId , $ lock , &$ size ) {
436+ private function handleChildren ($ path , $ recursive , $ reuse , $ folderId , $ lock , &$ size, bool & $ etagChanged ) {
418437 // we put this in it's own function so it cleans up the memory before we start recursing
419438 $ existingChildren = $ this ->getExistingChildren ($ folderId );
420439 $ newChildren = iterator_to_array ($ this ->storage ->getDirectoryContent ($ path ));
@@ -462,6 +481,10 @@ private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$s
462481 } elseif ($ size !== -1 ) {
463482 $ size += $ data ['size ' ];
464483 }
484+
485+ if (isset ($ data ['etag_changed ' ]) && $ data ['etag_changed ' ]) {
486+ $ etagChanged = true ;
487+ }
465488 }
466489 } catch (Exception $ ex ) {
467490 // might happen if inserting duplicate while a scanning
0 commit comments