This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @author Arthur Schiwon <[email protected]> |
||
4 | * @author Björn Schießle <[email protected]> |
||
5 | * @author Daniel Jagszent <[email protected]> |
||
6 | * @author Jörn Friedrich Dreyer <[email protected]> |
||
7 | * @author Lukas Reschke <[email protected]> |
||
8 | * @author Martin Mattel <[email protected]> |
||
9 | * @author Michael Gapczynski <[email protected]> |
||
10 | * @author Morris Jobke <[email protected]> |
||
11 | * @author Owen Winkler <[email protected]> |
||
12 | * @author Robin Appelman <[email protected]> |
||
13 | * @author Robin McCorkell <[email protected]> |
||
14 | * @author Roeland Jago Douma <[email protected]> |
||
15 | * @author Thomas Müller <[email protected]> |
||
16 | * @author Vincent Petry <[email protected]> |
||
17 | * |
||
18 | * @copyright Copyright (c) 2018, ownCloud GmbH |
||
19 | * @license AGPL-3.0 |
||
20 | * |
||
21 | * This code is free software: you can redistribute it and/or modify |
||
22 | * it under the terms of the GNU Affero General Public License, version 3, |
||
23 | * as published by the Free Software Foundation. |
||
24 | * |
||
25 | * This program is distributed in the hope that it will be useful, |
||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
28 | * GNU Affero General Public License for more details. |
||
29 | * |
||
30 | * You should have received a copy of the GNU Affero General Public License, version 3, |
||
31 | * along with this program. If not, see <http://www.gnu.org/licenses/> |
||
32 | * |
||
33 | */ |
||
34 | |||
35 | namespace OC\Files\Cache; |
||
36 | |||
37 | use OC\Files\Filesystem; |
||
38 | use OC\Files\Utils\FileUtils; |
||
39 | use OC\Hooks\BasicEmitter; |
||
40 | use OCA\Files_Sharing\ISharedStorage; |
||
41 | use OCP\Files\Cache\IScanner; |
||
42 | use OCP\Files\ForbiddenException; |
||
43 | use OCP\Files\IHomeStorage; |
||
44 | use OCP\Files\Storage\ILockingStorage; |
||
45 | use OCP\Lock\ILockingProvider; |
||
46 | |||
47 | /** |
||
48 | * Class Scanner |
||
49 | * |
||
50 | * Hooks available in scope \OC\Files\Cache\Scanner: |
||
51 | * - scanFile(string $path, string $storageId) |
||
52 | * - scanFolder(string $path, string $storageId) |
||
53 | * - postScanFile(string $path, string $storageId) |
||
54 | * - postScanFolder(string $path, string $storageId) |
||
55 | * |
||
56 | * @package OC\Files\Cache |
||
57 | */ |
||
58 | class Scanner extends BasicEmitter implements IScanner { |
||
59 | /** |
||
60 | * @var \OC\Files\Storage\Storage $storage |
||
61 | */ |
||
62 | protected $storage; |
||
63 | |||
64 | /** |
||
65 | * @var string $storageId |
||
66 | */ |
||
67 | protected $storageId; |
||
68 | |||
69 | /** |
||
70 | * @var \OC\Files\Cache\Cache $cache |
||
71 | */ |
||
72 | protected $cache; |
||
73 | |||
74 | /** |
||
75 | * @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache |
||
76 | */ |
||
77 | protected $cacheActive; |
||
78 | |||
79 | /** |
||
80 | * @var bool $useTransactions whether to use transactions |
||
81 | */ |
||
82 | protected $useTransactions = true; |
||
83 | |||
84 | /** |
||
85 | * @var \OCP\Lock\ILockingProvider |
||
86 | */ |
||
87 | protected $lockingProvider; |
||
88 | |||
89 | public function __construct(\OC\Files\Storage\Storage $storage) { |
||
90 | $this->storage = $storage; |
||
91 | $this->storageId = $this->storage->getId(); |
||
92 | $this->cache = $storage->getCache(); |
||
93 | $this->cacheActive = !\OC::$server->getConfig()->getSystemValue('filesystem_cache_readonly', false); |
||
94 | $this->lockingProvider = \OC::$server->getLockingProvider(); |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Whether to wrap the scanning of a folder in a database transaction |
||
99 | * On default transactions are used |
||
100 | * |
||
101 | * @param bool $useTransactions |
||
102 | */ |
||
103 | public function setUseTransactions($useTransactions) { |
||
104 | $this->useTransactions = $useTransactions; |
||
105 | } |
||
106 | |||
107 | /** |
||
108 | * get all the metadata of a file or folder |
||
109 | * * |
||
110 | * |
||
111 | * @param string $path |
||
112 | * @return array an array of metadata of the file |
||
113 | * @throws \OCP\Files\StorageNotAvailableException |
||
114 | */ |
||
115 | protected function getData($path) { |
||
116 | $data = $this->storage->getMetaData($path); |
||
117 | if ($data === null) { |
||
118 | \OCP\Util::writeLog(Scanner::class, "!!! Path '$path' is not accessible or present !!!", \OCP\Util::DEBUG); |
||
119 | // Last Line of Defence against potential Metadata-loss |
||
120 | if ($this->storage->instanceOfStorage(IHomeStorage::class) |
||
121 | && !$this->storage->instanceOfStorage(ISharedStorage::class) |
||
122 | && ($path === '' || $path === 'files') |
||
123 | ) { |
||
124 | $errorMsg = \sprintf('Missing important folder "%s" in home storage - %s', $path, $this->storageId); |
||
125 | \OCP\Util::writeLog(Scanner::class, $errorMsg, \OCP\Util::ERROR); |
||
126 | throw new \OCP\Files\StorageNotAvailableException($errorMsg); |
||
127 | } |
||
128 | } |
||
129 | return $data; |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * scan a single file and store it in the cache |
||
134 | * |
||
135 | * @param string $file |
||
136 | * @param int $reuseExisting |
||
137 | * @param int $parentId |
||
138 | * @param array | null $cacheData existing data in the cache for the file to be scanned |
||
139 | * @param bool $lock set to false to disable getting an additional read lock during scanning |
||
140 | * @return array an array of metadata of the scanned file |
||
141 | * @throws \OCP\Files\StorageNotAvailableException |
||
142 | * @throws \OCP\Lock\LockedException |
||
143 | * @throws \OC\HintException |
||
144 | * @throws \OC\ServerNotAvailableException |
||
145 | */ |
||
146 | public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true) { |
||
147 | |||
148 | // only proceed if $file is not a partial file nor a blacklisted file |
||
149 | if (!FileUtils::isPartialFile($file) and !Filesystem::isFileBlacklisted($file)) { |
||
150 | |||
151 | //acquire a lock |
||
152 | View Code Duplication | if ($lock && $this->storage->instanceOfStorage(ILockingStorage::class)) { |
|
153 | $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); |
||
154 | } |
||
155 | |||
156 | try { |
||
157 | $data = $this->getData($file); |
||
158 | if ($data) { |
||
159 | |||
160 | // pre-emit only if it was a file. By that we avoid counting/treating folders as files |
||
161 | View Code Duplication | if ($data['mimetype'] !== 'httpd/unix-directory') { |
|
0 ignored issues
–
show
|
|||
162 | $this->emit('\OC\Files\Cache\Scanner', 'scanFile', [$file, $this->storageId]); |
||
163 | \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', ['path' => $file, 'storage' => $this->storageId]); |
||
164 | } |
||
165 | |||
166 | $parent = \dirname($file); |
||
167 | if ($parent === '.' or $parent === '/') { |
||
168 | $parent = ''; |
||
169 | } |
||
170 | if ($parentId === -1) { |
||
171 | $parentId = $this->cache->getId($parent); |
||
172 | } |
||
173 | |||
174 | // scan the parent if it's not in the cache (id -1) and the current file is not the root folder |
||
175 | if ($file and $parentId === -1) { |
||
176 | $parentData = $this->scanFile($parent); |
||
177 | $parentId = $parentData['fileid']; |
||
178 | } |
||
179 | if ($parent) { |
||
180 | $data['parent'] = $parentId; |
||
181 | } |
||
182 | if ($cacheData === null) { |
||
183 | /** @var CacheEntry $cacheData */ |
||
184 | $cacheData = $this->cache->get($file); |
||
185 | } |
||
186 | if ($cacheData and $reuseExisting and isset($cacheData['fileid'])) { |
||
187 | // prevent empty etag |
||
188 | if (empty($cacheData['etag'])) { |
||
189 | $etag = $data['etag']; |
||
190 | } else { |
||
191 | $etag = $cacheData['etag']; |
||
192 | } |
||
193 | $fileId = $cacheData['fileid']; |
||
194 | $data['fileid'] = $fileId; |
||
195 | // only reuse data if the file hasn't explicitly changed |
||
196 | if (isset($data['storage_mtime'], $cacheData['storage_mtime']) && $data['storage_mtime'] === $cacheData['storage_mtime']) { |
||
197 | $data['mtime'] = $cacheData['mtime']; |
||
198 | if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) { |
||
199 | $data['size'] = $cacheData['size']; |
||
200 | } |
||
201 | if ($reuseExisting & self::REUSE_ETAG) { |
||
202 | $data['etag'] = $etag; |
||
203 | } |
||
204 | } |
||
205 | // Only update metadata that has changed |
||
206 | $newData = \array_diff_assoc($data, $cacheData->getData()); |
||
207 | } else { |
||
208 | $newData = $data; |
||
209 | $fileId = -1; |
||
210 | } |
||
211 | if (!empty($newData)) { |
||
212 | // Only reset checksum on file change |
||
213 | if ($fileId > 0 && !isset($newData['checksum'])) { |
||
214 | foreach (['size', 'storage_mtime', 'mtime', 'etag'] as $dataKey) { |
||
215 | if (isset($newData[$dataKey])) { |
||
216 | $newData['checksum'] = ''; |
||
217 | break; |
||
218 | } |
||
219 | } |
||
220 | } |
||
221 | |||
222 | $data['fileid'] = $this->addToCache($file, $newData, $fileId); |
||
223 | } |
||
224 | if (isset($cacheData['size'])) { |
||
225 | $data['oldSize'] = $cacheData['size']; |
||
226 | } else { |
||
227 | $data['oldSize'] = 0; |
||
228 | } |
||
229 | |||
230 | if (isset($cacheData['encrypted'])) { |
||
231 | $data['encrypted'] = $cacheData['encrypted']; |
||
232 | } |
||
233 | |||
234 | // post-emit only if it was a file. By that we avoid counting/treating folders as files |
||
235 | View Code Duplication | if ($data['mimetype'] !== 'httpd/unix-directory') { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
236 | $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', [$file, $this->storageId]); |
||
237 | \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', ['path' => $file, 'storage' => $this->storageId]); |
||
238 | } |
||
239 | } else { |
||
240 | $this->removeFromCache($file); |
||
241 | } |
||
242 | |||
243 | if ($data && !isset($data['encrypted'])) { |
||
244 | $data['encrypted'] = false; |
||
245 | } |
||
246 | return $data; |
||
247 | } catch (ForbiddenException $e) { |
||
248 | return null; |
||
249 | } finally { |
||
250 | //release the acquired lock |
||
251 | View Code Duplication | if ($lock && $this->storage->instanceOfStorage(ILockingStorage::class)) { |
|
252 | $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); |
||
253 | } |
||
254 | } |
||
255 | } |
||
256 | |||
257 | return null; |
||
258 | } |
||
259 | |||
260 | protected function removeFromCache($path) { |
||
261 | \OC_Hook::emit('Scanner', 'removeFromCache', ['file' => $path]); |
||
262 | $this->emit('\OC\Files\Cache\Scanner', 'removeFromCache', [$path]); |
||
263 | if ($this->cacheActive) { |
||
264 | $this->cache->remove($path); |
||
265 | } |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * @param string $path |
||
270 | * @param array $data |
||
271 | * @param int $fileId |
||
272 | * @return int the id of the added file |
||
273 | * @throws \OC\HintException |
||
274 | * @throws \OC\ServerNotAvailableException |
||
275 | */ |
||
276 | protected function addToCache($path, $data, $fileId = -1) { |
||
277 | \OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]); |
||
278 | $this->emit('\OC\Files\Cache\Scanner', 'addToCache', [$path, $this->storageId, $data]); |
||
279 | View Code Duplication | if ($this->cacheActive) { |
|
280 | if ($fileId !== -1) { |
||
281 | $this->cache->update($fileId, $data); |
||
282 | return $fileId; |
||
283 | } |
||
284 | |||
285 | return $this->cache->put($path, $data); |
||
286 | } |
||
287 | |||
288 | return -1; |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * @param string $path |
||
293 | * @param array $data |
||
294 | * @param int $fileId |
||
295 | * @throws \OC\HintException |
||
296 | * @throws \OC\ServerNotAvailableException |
||
297 | */ |
||
298 | protected function updateCache($path, $data, $fileId = -1) { |
||
299 | \OC_Hook::emit('Scanner', 'addToCache', ['file' => $path, 'data' => $data]); |
||
300 | $this->emit('\OC\Files\Cache\Scanner', 'updateCache', [$path, $this->storageId, $data]); |
||
301 | View Code Duplication | if ($this->cacheActive) { |
|
302 | if ($fileId !== -1) { |
||
303 | $this->cache->update($fileId, $data); |
||
304 | } else { |
||
305 | $this->cache->put($path, $data); |
||
306 | } |
||
307 | } |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * scan a folder and all it's children |
||
312 | * |
||
313 | * @param string $path |
||
314 | * @param bool $recursive |
||
315 | * @param int $reuse |
||
316 | * @param bool $lock set to false to disable getting an additional read lock during scanning |
||
317 | * @return array an array of the meta data of the scanned file or folder |
||
318 | * @throws \OCP\Lock\LockedException |
||
319 | * @throws \OC\ServerNotAvailableException |
||
320 | */ |
||
321 | public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true) { |
||
322 | View Code Duplication | if ($reuse === -1) { |
|
323 | $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; |
||
324 | } |
||
325 | View Code Duplication | if ($lock && $this->storage->instanceOfStorage(ILockingStorage::class)) { |
|
326 | $this->storage->acquireLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider); |
||
327 | $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); |
||
328 | } |
||
329 | try { |
||
330 | $data = $this->scanFile($path, $reuse, -1, null, $lock); |
||
331 | if ($data and $data['mimetype'] === 'httpd/unix-directory') { |
||
332 | $size = $this->scanChildren($path, $recursive, $reuse, $data['fileid'], $lock); |
||
333 | $data['size'] = $size; |
||
334 | } |
||
335 | } finally { |
||
336 | View Code Duplication | if ($lock && $this->storage->instanceOfStorage(ILockingStorage::class)) { |
|
337 | $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); |
||
338 | $this->storage->releaseLock('scanner::' . $path, ILockingProvider::LOCK_EXCLUSIVE, $this->lockingProvider); |
||
339 | } |
||
340 | } |
||
341 | return $data; |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * Get the children currently in the cache |
||
346 | * |
||
347 | * @param int $folderId |
||
348 | * @return array[] |
||
349 | */ |
||
350 | protected function getExistingChildren($folderId) { |
||
351 | $existingChildren = []; |
||
352 | $children = $this->cache->getFolderContentsById($folderId); |
||
353 | foreach ($children as $child) { |
||
354 | $existingChildren[$child['name']] = $child; |
||
355 | } |
||
356 | return $existingChildren; |
||
357 | } |
||
358 | |||
359 | /** |
||
360 | * Get the children from the storage |
||
361 | * |
||
362 | * @param string $folder |
||
363 | * @return string[] |
||
364 | */ |
||
365 | protected function getNewChildren($folder) { |
||
366 | $children = []; |
||
367 | if ($dh = $this->storage->opendir($folder)) { |
||
368 | if (\is_resource($dh)) { |
||
369 | while (($file = \readdir($dh)) !== false) { |
||
370 | if (!Filesystem::isIgnoredDir($file) && !Filesystem::isForbiddenFileOrDir($file)) { |
||
371 | $children[] = \trim(\OC\Files\Filesystem::normalizePath($file), '/'); |
||
372 | } |
||
373 | } |
||
374 | } |
||
375 | } |
||
376 | return $children; |
||
377 | } |
||
378 | |||
379 | /** |
||
380 | * scan all the files and folders in a folder |
||
381 | * |
||
382 | * @param string $path |
||
383 | * @param bool $recursive |
||
384 | * @param int $reuse |
||
385 | * @param int $folderId id for the folder to be scanned |
||
386 | * @param bool $lock set to false to disable getting an additional read lock during scanning |
||
387 | * @return int the size of the scanned folder or -1 if the size is unknown at this stage |
||
388 | * @throws \OCP\Lock\LockedException |
||
389 | */ |
||
390 | protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true) { |
||
391 | View Code Duplication | if ($reuse === -1) { |
|
392 | $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; |
||
393 | } |
||
394 | $this->emit('\OC\Files\Cache\Scanner', 'scanFolder', [$path, $this->storageId]); |
||
395 | $size = 0; |
||
396 | if ($folderId !== null) { |
||
397 | $folderId = $this->cache->getId($path); |
||
398 | } |
||
399 | $childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size); |
||
400 | |||
401 | foreach ($childQueue as $child => $childId) { |
||
402 | $childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock); |
||
403 | if ($childSize === -1) { |
||
404 | $size = -1; |
||
405 | } elseif ($size !== -1) { |
||
406 | $size += $childSize; |
||
407 | } |
||
408 | } |
||
409 | if ($this->cacheActive) { |
||
410 | $this->cache->update($folderId, ['size' => $size]); |
||
411 | } |
||
412 | $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', [$path, $this->storageId]); |
||
413 | return $size; |
||
414 | } |
||
415 | |||
416 | private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$size) { |
||
417 | // we put this in it's own function so it cleans up the memory before we start recursing |
||
418 | $existingChildren = $this->getExistingChildren($folderId); |
||
419 | $newChildren = $this->getNewChildren($path); |
||
420 | |||
421 | if ($this->useTransactions) { |
||
422 | \OC::$server->getDatabaseConnection()->beginTransaction(); |
||
423 | } |
||
424 | |||
425 | $exceptionOccurred = false; |
||
426 | $childQueue = []; |
||
427 | foreach ($newChildren as $file) { |
||
428 | $child = $path ? $path . '/' . $file : $file; |
||
429 | try { |
||
430 | $existingData = isset($existingChildren[$file]) ? $existingChildren[$file] : null; |
||
431 | $data = $this->scanFile($child, $reuse, $folderId, $existingData, $lock); |
||
432 | if ($data) { |
||
433 | if ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE) { |
||
434 | $childQueue[$child] = $data['fileid']; |
||
435 | } elseif ($data['mimetype'] === 'httpd/unix-directory' and $recursive === self::SCAN_RECURSIVE_INCOMPLETE and $data['size'] === -1) { |
||
436 | // only recurse into folders which aren't fully scanned |
||
437 | $childQueue[$child] = $data['fileid']; |
||
438 | } elseif (!isset($data['size']) || $data['size'] === -1) { |
||
439 | $size = -1; |
||
440 | } elseif ($size !== -1) { |
||
441 | $size += $data['size']; |
||
442 | } |
||
443 | } |
||
444 | } catch (\Doctrine\DBAL\DBALException $ex) { |
||
445 | // might happen if inserting duplicate while a scanning |
||
446 | // process is running in parallel |
||
447 | // log and ignore |
||
448 | \OCP\Util::writeLog('core', 'Exception while scanning file "' . $child . '": ' . $ex->getMessage(), \OCP\Util::DEBUG); |
||
449 | $exceptionOccurred = true; |
||
450 | } catch (\OCP\Lock\LockedException $e) { |
||
451 | if ($this->useTransactions) { |
||
452 | \OC::$server->getDatabaseConnection()->rollBack(); |
||
453 | } |
||
454 | throw $e; |
||
455 | } |
||
456 | } |
||
457 | $removedChildren = \array_diff(\array_keys($existingChildren), $newChildren); |
||
458 | foreach ($removedChildren as $childName) { |
||
459 | $child = $path ? $path . '/' . $childName : $childName; |
||
460 | $this->removeFromCache($child); |
||
461 | } |
||
462 | if ($this->useTransactions) { |
||
463 | \OC::$server->getDatabaseConnection()->commit(); |
||
464 | } |
||
465 | if ($exceptionOccurred) { |
||
466 | // It might happen that the parallel scan process has already |
||
467 | // inserted mimetypes but those weren't available yet inside the transaction |
||
468 | // To make sure to have the updated mime types in such cases, |
||
469 | // we reload them here |
||
470 | \OC::$server->getMimeTypeLoader()->reset(); |
||
471 | } |
||
472 | return $childQueue; |
||
473 | } |
||
474 | |||
475 | /** |
||
476 | * walk over any folders that are not fully scanned yet and scan them |
||
477 | */ |
||
478 | public function backgroundScan() { |
||
479 | if (!$this->cache->inCache('')) { |
||
480 | $this->runBackgroundScanJob(function () { |
||
481 | $this->scan('', self::SCAN_RECURSIVE, self::REUSE_ETAG); |
||
482 | }, ''); |
||
483 | } else { |
||
484 | $lastPath = null; |
||
485 | while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) { |
||
486 | $this->runBackgroundScanJob(function () use ($path) { |
||
487 | $this->scan($path, self::SCAN_RECURSIVE_INCOMPLETE, self::REUSE_ETAG | self::REUSE_SIZE); |
||
488 | }, $path); |
||
489 | // FIXME: this won't proceed with the next item, needs revamping of getIncomplete() |
||
490 | // to make this possible |
||
491 | $lastPath = $path; |
||
492 | } |
||
493 | } |
||
494 | } |
||
495 | |||
496 | private function runBackgroundScanJob(callable $callback, $path) { |
||
497 | try { |
||
498 | $callback(); |
||
499 | \OC_Hook::emit('Scanner', 'correctFolderSize', ['path' => $path]); |
||
500 | if ($this->cacheActive && $this->cache instanceof Cache) { |
||
501 | $this->cache->correctFolderSize($path); |
||
502 | } |
||
503 | } catch (\OCP\Files\StorageInvalidException $e) { |
||
504 | // skip unavailable storages |
||
505 | } catch (\OCP\Files\StorageNotAvailableException $e) { |
||
506 | // skip unavailable storages |
||
507 | } catch (\OCP\Files\ForbiddenException $e) { |
||
508 | // skip forbidden storages |
||
509 | } catch (\OCP\Lock\LockedException $e) { |
||
510 | // skip unavailable storages |
||
511 | } |
||
512 | } |
||
513 | |||
514 | /** |
||
515 | * @inheritdoc |
||
516 | * @deprecated use FileUtils |
||
517 | */ |
||
518 | public static function isPartialFile($file) { |
||
519 | return FileUtils::isPartialFile($file); |
||
520 | } |
||
521 | } |
||
522 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.