Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like View often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use View, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 76 | class View { |
||
| 77 | /** @var string */ |
||
| 78 | private $fakeRoot = ''; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * @var \OCP\Lock\ILockingProvider |
||
| 82 | */ |
||
| 83 | private $lockingProvider; |
||
| 84 | |||
| 85 | private $lockingEnabled; |
||
| 86 | |||
| 87 | private $updaterEnabled = true; |
||
| 88 | |||
| 89 | /** |
||
| 90 | * @param string $root |
||
| 91 | * @throws \Exception If $root contains an invalid path |
||
| 92 | */ |
||
| 93 | 1392 | public function __construct($root = '') { |
|
| 105 | |||
| 106 | 965 | public function getAbsolutePath($path = '/') { |
|
| 119 | |||
| 120 | /** |
||
| 121 | * change the root to a fake root |
||
| 122 | * |
||
| 123 | * @param string $fakeRoot |
||
| 124 | * @return boolean|null |
||
| 125 | */ |
||
| 126 | 50 | public function chroot($fakeRoot) { |
|
| 134 | |||
| 135 | /** |
||
| 136 | * get the fake root |
||
| 137 | * |
||
| 138 | * @return string |
||
| 139 | */ |
||
| 140 | 938 | public function getRoot() { |
|
| 143 | |||
| 144 | /** |
||
| 145 | * get path relative to the root of the view |
||
| 146 | * |
||
| 147 | * @param string $path |
||
| 148 | * @return string |
||
| 149 | */ |
||
| 150 | 948 | public function getRelativePath($path) { |
|
| 174 | |||
| 175 | /** |
||
| 176 | * get the mountpoint of the storage object for a path |
||
| 177 | * ( note: because a storage is not always mounted inside the fakeroot, the |
||
| 178 | * returned mountpoint is relative to the absolute root of the filesystem |
||
| 179 | * and does not take the chroot into account ) |
||
| 180 | * |
||
| 181 | * @param string $path |
||
| 182 | * @return string |
||
| 183 | */ |
||
| 184 | 1 | public function getMountPoint($path) { |
|
| 187 | |||
| 188 | /** |
||
| 189 | * get the mountpoint of the storage object for a path |
||
| 190 | * ( note: because a storage is not always mounted inside the fakeroot, the |
||
| 191 | * returned mountpoint is relative to the absolute root of the filesystem |
||
| 192 | * and does not take the chroot into account ) |
||
| 193 | * |
||
| 194 | * @param string $path |
||
| 195 | * @return \OCP\Files\Mount\IMountPoint |
||
| 196 | */ |
||
| 197 | 341 | public function getMount($path) { |
|
| 200 | |||
| 201 | /** |
||
| 202 | * resolve a path to a storage and internal path |
||
| 203 | * |
||
| 204 | * @param string $path |
||
| 205 | * @return array an array consisting of the storage and the internal path |
||
| 206 | */ |
||
| 207 | 573 | public function resolvePath($path) { |
|
| 212 | |||
| 213 | /** |
||
| 214 | * return the path to a local version of the file |
||
| 215 | * we need this because we can't know if a file is stored local or not from |
||
| 216 | * outside the filestorage and for some purposes a local file is needed |
||
| 217 | * |
||
| 218 | * @param string $path |
||
| 219 | * @return string |
||
| 220 | */ |
||
| 221 | 129 | View Code Duplication | public function getLocalFile($path) { |
| 231 | |||
| 232 | /** |
||
| 233 | * @param string $path |
||
| 234 | * @return string |
||
| 235 | */ |
||
| 236 | 1 | View Code Duplication | public function getLocalFolder($path) { |
| 246 | |||
| 247 | /** |
||
| 248 | * the following functions operate with arguments and return values identical |
||
| 249 | * to those of their PHP built-in equivalents. Mostly they are merely wrappers |
||
| 250 | * for \OC\Files\Storage\Storage via basicOperation(). |
||
| 251 | */ |
||
| 252 | 796 | public function mkdir($path) { |
|
| 255 | |||
| 256 | /** |
||
| 257 | * remove mount point |
||
| 258 | * |
||
| 259 | * @param \OC\Files\Mount\MoveableMount $mount |
||
| 260 | * @param string $path relative to data/ |
||
| 261 | * @return boolean |
||
| 262 | */ |
||
| 263 | 8 | protected function removeMount($mount, $path) { |
|
| 287 | |||
| 288 | 4 | public function disableCacheUpdate() { |
|
| 291 | |||
| 292 | public function enableCacheUpdate() { |
||
| 295 | |||
| 296 | 811 | protected function writeUpdate(Storage $storage, $internalPath, $time = null) { |
|
| 304 | |||
| 305 | 272 | protected function removeUpdate(Storage $storage, $internalPath) { |
|
| 310 | |||
| 311 | 48 | protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) { |
|
| 316 | |||
| 317 | /** |
||
| 318 | * @param string $path |
||
| 319 | * @return bool|mixed |
||
| 320 | */ |
||
| 321 | 223 | public function rmdir($path) { |
|
| 333 | |||
| 334 | /** |
||
| 335 | * @param string $path |
||
| 336 | * @return resource |
||
| 337 | */ |
||
| 338 | 309 | public function opendir($path) { |
|
| 341 | |||
| 342 | /** |
||
| 343 | * @param $handle |
||
| 344 | * @return mixed |
||
| 345 | */ |
||
| 346 | public function readdir($handle) { |
||
| 350 | |||
| 351 | /** |
||
| 352 | * @param string $path |
||
| 353 | * @return bool|mixed |
||
| 354 | */ |
||
| 355 | 560 | public function is_dir($path) { |
|
| 361 | |||
| 362 | /** |
||
| 363 | * @param string $path |
||
| 364 | * @return bool|mixed |
||
| 365 | */ |
||
| 366 | 36 | public function is_file($path) { |
|
| 372 | |||
| 373 | /** |
||
| 374 | * @param string $path |
||
| 375 | * @return mixed |
||
| 376 | */ |
||
| 377 | 5 | public function stat($path) { |
|
| 380 | |||
| 381 | /** |
||
| 382 | * @param string $path |
||
| 383 | * @return mixed |
||
| 384 | */ |
||
| 385 | 4 | public function filetype($path) { |
|
| 388 | |||
| 389 | /** |
||
| 390 | * @param string $path |
||
| 391 | * @return mixed |
||
| 392 | */ |
||
| 393 | 66 | public function filesize($path) { |
|
| 396 | |||
| 397 | /** |
||
| 398 | * @param string $path |
||
| 399 | * @return bool|mixed |
||
| 400 | * @throws \OCP\Files\InvalidPathException |
||
| 401 | */ |
||
| 402 | 1 | public function readfile($path) { |
|
| 417 | |||
| 418 | /** |
||
| 419 | * @param string $path |
||
| 420 | * @return mixed |
||
| 421 | */ |
||
| 422 | 21 | public function isCreatable($path) { |
|
| 425 | |||
| 426 | /** |
||
| 427 | * @param string $path |
||
| 428 | * @return mixed |
||
| 429 | */ |
||
| 430 | 31 | public function isReadable($path) { |
|
| 433 | |||
| 434 | /** |
||
| 435 | * @param string $path |
||
| 436 | * @return mixed |
||
| 437 | */ |
||
| 438 | 4 | public function isUpdatable($path) { |
|
| 441 | |||
| 442 | /** |
||
| 443 | * @param string $path |
||
| 444 | * @return bool|mixed |
||
| 445 | */ |
||
| 446 | 4 | public function isDeletable($path) { |
|
| 454 | |||
| 455 | /** |
||
| 456 | * @param string $path |
||
| 457 | * @return mixed |
||
| 458 | */ |
||
| 459 | 153 | public function isSharable($path) { |
|
| 462 | |||
| 463 | /** |
||
| 464 | * @param string $path |
||
| 465 | * @return bool|mixed |
||
| 466 | */ |
||
| 467 | 937 | public function file_exists($path) { |
|
| 473 | |||
| 474 | /** |
||
| 475 | * @param string $path |
||
| 476 | * @return mixed |
||
| 477 | */ |
||
| 478 | 39 | public function filemtime($path) { |
|
| 481 | |||
| 482 | /** |
||
| 483 | * @param string $path |
||
| 484 | * @param int|string $mtime |
||
| 485 | * @return bool |
||
| 486 | */ |
||
| 487 | 508 | public function touch($path, $mtime = null) { |
|
| 513 | |||
| 514 | /** |
||
| 515 | * @param string $path |
||
| 516 | * @return mixed |
||
| 517 | */ |
||
| 518 | 94 | public function file_get_contents($path) { |
|
| 521 | |||
| 522 | /** |
||
| 523 | * @param bool $exists |
||
| 524 | * @param string $path |
||
| 525 | * @param bool $run |
||
| 526 | */ |
||
| 527 | 7 | protected function emit_file_hooks_pre($exists, $path, &$run) { |
|
| 544 | |||
| 545 | /** |
||
| 546 | * @param bool $exists |
||
| 547 | * @param string $path |
||
| 548 | */ |
||
| 549 | 8 | protected function emit_file_hooks_post($exists, $path) { |
|
| 563 | |||
| 564 | /** |
||
| 565 | * @param string $path |
||
| 566 | * @param mixed $data |
||
| 567 | * @return bool|mixed |
||
| 568 | * @throws \Exception |
||
| 569 | */ |
||
| 570 | 448 | public function file_put_contents($path, $data) { |
|
| 621 | |||
| 622 | /** |
||
| 623 | * @param string $path |
||
| 624 | * @return bool|mixed |
||
| 625 | */ |
||
| 626 | 138 | public function unlink($path) { |
|
| 639 | |||
| 640 | /** |
||
| 641 | * @param string $directory |
||
| 642 | * @return bool|mixed |
||
| 643 | */ |
||
| 644 | 209 | public function deleteAll($directory) { |
|
| 647 | |||
| 648 | /** |
||
| 649 | * Rename/move a file or folder from the source path to target path. |
||
| 650 | * |
||
| 651 | * @param string $path1 source path |
||
| 652 | * @param string $path2 target path |
||
| 653 | * |
||
| 654 | * @return bool|mixed |
||
| 655 | */ |
||
| 656 | 119 | public function rename($path1, $path2) { |
|
| 657 | 119 | $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); |
|
| 658 | 118 | $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); |
|
| 659 | 118 | $result = false; |
|
| 660 | if ( |
||
| 661 | 118 | Filesystem::isValidPath($path2) |
|
| 662 | 118 | and Filesystem::isValidPath($path1) |
|
| 663 | 118 | and !Filesystem::isFileBlacklisted($path2) |
|
| 664 | 118 | ) { |
|
| 665 | 118 | $path1 = $this->getRelativePath($absolutePath1); |
|
| 666 | 118 | $path2 = $this->getRelativePath($absolutePath2); |
|
| 667 | 118 | $exists = $this->file_exists($path2); |
|
| 668 | |||
| 669 | 118 | if ($path1 == null or $path2 == null) { |
|
| 670 | return false; |
||
| 671 | } |
||
| 672 | |||
| 673 | 118 | $this->lockFile($path1, ILockingProvider::LOCK_SHARED, true); |
|
| 674 | try { |
||
| 675 | 118 | $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true); |
|
| 676 | 118 | } catch (LockedException $e) { |
|
| 677 | 1 | $this->unlockFile($path1, ILockingProvider::LOCK_SHARED); |
|
| 678 | 1 | throw $e; |
|
| 679 | } |
||
| 680 | |||
| 681 | 117 | $run = true; |
|
| 682 | 117 | if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) { |
|
| 683 | // if it was a rename from a part file to a regular file it was a write and not a rename operation |
||
| 684 | $this->emit_file_hooks_pre($exists, $path2, $run); |
||
| 685 | 117 | } elseif ($this->shouldEmitHooks($path1)) { |
|
| 686 | 65 | \OC_Hook::emit( |
|
| 687 | 65 | Filesystem::CLASSNAME, Filesystem::signal_rename, |
|
| 688 | array( |
||
| 689 | 65 | Filesystem::signal_param_oldpath => $this->getHookPath($path1), |
|
| 690 | 65 | Filesystem::signal_param_newpath => $this->getHookPath($path2), |
|
| 691 | 65 | Filesystem::signal_param_run => &$run |
|
| 692 | 65 | ) |
|
| 693 | 65 | ); |
|
| 694 | 65 | } |
|
| 695 | 117 | if ($run) { |
|
| 696 | 117 | $this->verifyPath(dirname($path2), basename($path2)); |
|
| 697 | |||
| 698 | 117 | $manager = Filesystem::getMountManager(); |
|
| 699 | 117 | $mount1 = $this->getMount($path1); |
|
| 700 | 117 | $mount2 = $this->getMount($path2); |
|
| 701 | 117 | $storage1 = $mount1->getStorage(); |
|
| 702 | 117 | $storage2 = $mount2->getStorage(); |
|
| 703 | 117 | $internalPath1 = $mount1->getInternalPath($absolutePath1); |
|
| 704 | 117 | $internalPath2 = $mount2->getInternalPath($absolutePath2); |
|
| 705 | |||
| 706 | 117 | $this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true); |
|
| 707 | 116 | $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true); |
|
| 708 | |||
| 709 | 116 | if ($internalPath1 === '' and $mount1 instanceof MoveableMount) { |
|
| 710 | 45 | if ($this->isTargetAllowed($absolutePath2)) { |
|
| 711 | /** |
||
| 712 | * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1 |
||
| 713 | */ |
||
| 714 | 43 | $sourceMountPoint = $mount1->getMountPoint(); |
|
| 715 | 43 | $result = $mount1->moveMount($absolutePath2); |
|
| 716 | 43 | $manager->moveMount($sourceMountPoint, $mount1->getMountPoint()); |
|
| 717 | 43 | } else { |
|
| 718 | 2 | $result = false; |
|
| 719 | } |
||
| 720 | // moving a file/folder within the same mount point |
||
| 721 | 116 | } elseif ($storage1 == $storage2) { |
|
| 722 | 77 | if ($storage1) { |
|
| 723 | 77 | $result = $storage1->rename($internalPath1, $internalPath2); |
|
| 724 | 77 | } else { |
|
| 725 | $result = false; |
||
| 726 | } |
||
| 727 | // moving a file/folder between storages (from $storage1 to $storage2) |
||
| 728 | 77 | } else { |
|
| 729 | 13 | $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2); |
|
| 730 | } |
||
| 731 | |||
| 732 | 116 | if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { |
|
| 733 | // if it was a rename from a part file to a regular file it was a write and not a rename operation |
||
| 734 | |||
| 735 | 34 | $this->writeUpdate($storage2, $internalPath2); |
|
| 736 | 116 | } else if ($result) { |
|
| 737 | 77 | if ($internalPath1 !== '') { // dont do a cache update for moved mounts |
|
| 738 | 48 | $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2); |
|
| 739 | 48 | } |
|
| 740 | 77 | } |
|
| 741 | |||
| 742 | 116 | $this->changeLock($path1, ILockingProvider::LOCK_SHARED, true); |
|
| 743 | 116 | $this->changeLock($path2, ILockingProvider::LOCK_SHARED, true); |
|
| 744 | |||
| 745 | 116 | if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { |
|
| 746 | 34 | if ($this->shouldEmitHooks()) { |
|
| 747 | 2 | $this->emit_file_hooks_post($exists, $path2); |
|
| 748 | 2 | } |
|
| 749 | 116 | } elseif ($result) { |
|
| 750 | 77 | if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) { |
|
| 751 | 59 | \OC_Hook::emit( |
|
| 752 | 59 | Filesystem::CLASSNAME, |
|
| 753 | 59 | Filesystem::signal_post_rename, |
|
| 754 | array( |
||
| 755 | 59 | Filesystem::signal_param_oldpath => $this->getHookPath($path1), |
|
| 756 | 59 | Filesystem::signal_param_newpath => $this->getHookPath($path2) |
|
| 757 | 59 | ) |
|
| 758 | 59 | ); |
|
| 759 | 59 | } |
|
| 760 | 77 | } |
|
| 761 | 116 | } |
|
| 762 | 116 | $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true); |
|
| 763 | 116 | $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true); |
|
| 764 | 116 | } |
|
| 765 | 116 | return $result; |
|
| 766 | } |
||
| 767 | |||
| 768 | /** |
||
| 769 | * Copy a file/folder from the source path to target path |
||
| 770 | * |
||
| 771 | * @param string $path1 source path |
||
| 772 | * @param string $path2 target path |
||
| 773 | * @param bool $preserveMtime whether to preserve mtime on the copy |
||
| 774 | * |
||
| 775 | * @return bool|mixed |
||
| 776 | */ |
||
| 777 | 25 | public function copy($path1, $path2, $preserveMtime = false) { |
|
| 865 | |||
| 866 | /** |
||
| 867 | * @param string $path |
||
| 868 | * @param string $mode |
||
| 869 | * @return resource |
||
| 870 | */ |
||
| 871 | 566 | public function fopen($path, $mode) { |
|
| 903 | |||
| 904 | /** |
||
| 905 | * @param string $path |
||
| 906 | * @return bool|string |
||
| 907 | * @throws \OCP\Files\InvalidPathException |
||
| 908 | */ |
||
| 909 | 49 | public function toTmpFile($path) { |
|
| 925 | |||
| 926 | /** |
||
| 927 | * @param string $tmpFile |
||
| 928 | * @param string $path |
||
| 929 | * @return bool|mixed |
||
| 930 | * @throws \OCP\Files\InvalidPathException |
||
| 931 | */ |
||
| 932 | 1 | public function fromTmpFile($tmpFile, $path) { |
|
| 962 | |||
| 963 | |||
| 964 | /** |
||
| 965 | * @param string $path |
||
| 966 | * @return mixed |
||
| 967 | * @throws \OCP\Files\InvalidPathException |
||
| 968 | */ |
||
| 969 | 2 | public function getMimeType($path) { |
|
| 973 | |||
| 974 | /** |
||
| 975 | * @param string $type |
||
| 976 | * @param string $path |
||
| 977 | * @param bool $raw |
||
| 978 | * @return bool|null|string |
||
| 979 | */ |
||
| 980 | 1 | public function hash($type, $path, $raw = false) { |
|
| 1003 | |||
| 1004 | /** |
||
| 1005 | * @param string $path |
||
| 1006 | * @return mixed |
||
| 1007 | * @throws \OCP\Files\InvalidPathException |
||
| 1008 | */ |
||
| 1009 | 48 | public function free_space($path = '/') { |
|
| 1013 | |||
| 1014 | /** |
||
| 1015 | * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage |
||
| 1016 | * |
||
| 1017 | * @param string $operation |
||
| 1018 | * @param string $path |
||
| 1019 | * @param array $hooks (optional) |
||
| 1020 | * @param mixed $extraParam (optional) |
||
| 1021 | * @return mixed |
||
| 1022 | * @throws \Exception |
||
| 1023 | * |
||
| 1024 | * This method takes requests for basic filesystem functions (e.g. reading & writing |
||
| 1025 | * files), processes hooks and proxies, sanitises paths, and finally passes them on to |
||
| 1026 | * \OC\Files\Storage\Storage for delegation to a storage backend for execution |
||
| 1027 | */ |
||
| 1028 | 944 | private function basicOperation($operation, $path, $hooks = [], $extraParam = null) { |
|
| 1110 | |||
| 1111 | /** |
||
| 1112 | * get the path relative to the default root for hook usage |
||
| 1113 | * |
||
| 1114 | * @param string $path |
||
| 1115 | * @return string |
||
| 1116 | */ |
||
| 1117 | 944 | private function getHookPath($path) { |
|
| 1123 | |||
| 1124 | 944 | private function shouldEmitHooks($path = '') { |
|
| 1125 | 944 | if ($path && Cache\Scanner::isPartialFile($path)) { |
|
| 1126 | 38 | return false; |
|
| 1127 | } |
||
| 1128 | 944 | if (!Filesystem::$loaded) { |
|
| 1129 | return false; |
||
| 1130 | } |
||
| 1131 | 944 | $defaultRoot = Filesystem::getRoot(); |
|
| 1132 | 944 | if ($defaultRoot === null) { |
|
| 1133 | 7 | return false; |
|
| 1134 | } |
||
| 1135 | 938 | if ($this->fakeRoot === $defaultRoot) { |
|
| 1136 | 264 | return true; |
|
| 1137 | } |
||
| 1138 | 920 | $fullPath = $this->getAbsolutePath($path); |
|
| 1139 | |||
| 1140 | 920 | if ($fullPath === $defaultRoot) { |
|
| 1141 | 905 | return true; |
|
| 1142 | } |
||
| 1143 | |||
| 1144 | 920 | return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/'); |
|
| 1145 | } |
||
| 1146 | |||
| 1147 | /** |
||
| 1148 | * @param string[] $hooks |
||
| 1149 | * @param string $path |
||
| 1150 | * @param bool $post |
||
| 1151 | * @return bool |
||
| 1152 | */ |
||
| 1153 | 944 | private function runHooks($hooks, $path, $post = false) { |
|
| 1182 | |||
| 1183 | /** |
||
| 1184 | * check if a file or folder has been updated since $time |
||
| 1185 | * |
||
| 1186 | * @param string $path |
||
| 1187 | * @param int $time |
||
| 1188 | * @return bool |
||
| 1189 | */ |
||
| 1190 | 1 | public function hasUpdated($path, $time) { |
|
| 1193 | |||
| 1194 | /** |
||
| 1195 | * @param string $ownerId |
||
| 1196 | * @return \OC\User\User |
||
| 1197 | */ |
||
| 1198 | 797 | private function getUserObjectForOwner($ownerId) { |
|
| 1199 | 797 | $owner = \OC::$server->getUserManager()->get($ownerId); |
|
| 1200 | 797 | if ($owner instanceof IUser) { |
|
| 1201 | 775 | return $owner; |
|
| 1202 | } else { |
||
| 1203 | 22 | return new User($ownerId, null); |
|
| 1204 | } |
||
| 1205 | } |
||
| 1206 | |||
| 1207 | /** |
||
| 1208 | * Get file info from cache |
||
| 1209 | * |
||
| 1210 | * If the file is not in cached it will be scanned |
||
| 1211 | * If the file has changed on storage the cache will be updated |
||
| 1212 | * |
||
| 1213 | * @param \OC\Files\Storage\Storage $storage |
||
| 1214 | * @param string $internalPath |
||
| 1215 | * @param string $relativePath |
||
| 1216 | * @return array|bool |
||
| 1217 | */ |
||
| 1218 | 798 | private function getCacheEntry($storage, $internalPath, $relativePath) { |
|
| 1219 | 798 | $cache = $storage->getCache($internalPath); |
|
| 1220 | 798 | $data = $cache->get($internalPath); |
|
| 1221 | 798 | $watcher = $storage->getWatcher($internalPath); |
|
| 1222 | |||
| 1223 | try { |
||
| 1224 | // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data |
||
| 1225 | 798 | if (!$data || $data['size'] === -1) { |
|
| 1226 | 276 | $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); |
|
| 1227 | 270 | if (!$storage->file_exists($internalPath)) { |
|
| 1228 | 224 | $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); |
|
| 1229 | 224 | return false; |
|
| 1230 | } |
||
| 1231 | 50 | $scanner = $storage->getScanner($internalPath); |
|
| 1232 | 50 | $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); |
|
| 1233 | 50 | $data = $cache->get($internalPath); |
|
| 1234 | 50 | $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); |
|
| 1235 | 797 | } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) { |
|
| 1236 | 3 | $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED); |
|
| 1237 | 3 | $watcher->update($internalPath, $data); |
|
| 1238 | 3 | $storage->getPropagator()->propagateChange($internalPath, time()); |
|
| 1239 | 3 | $data = $cache->get($internalPath); |
|
| 1240 | 3 | $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED); |
|
| 1241 | 3 | } |
|
| 1242 | 797 | } catch (LockedException $e) { |
|
| 1243 | // if the file is locked we just use the old cache info |
||
| 1244 | } |
||
| 1245 | |||
| 1246 | 797 | return $data; |
|
| 1247 | } |
||
| 1248 | |||
| 1249 | /** |
||
| 1250 | * get the filesystem info |
||
| 1251 | * |
||
| 1252 | * @param string $path |
||
| 1253 | * @param boolean|string $includeMountPoints true to add mountpoint sizes, |
||
| 1254 | * 'ext' to add only ext storage mount point sizes. Defaults to true. |
||
| 1255 | * defaults to true |
||
| 1256 | * @return \OC\Files\FileInfo|bool False if file does not exist |
||
| 1257 | */ |
||
| 1258 | 798 | public function getFileInfo($path, $includeMountPoints = true) { |
|
| 1259 | 798 | $this->assertPathLength($path); |
|
| 1260 | 798 | if (!Filesystem::isValidPath($path)) { |
|
| 1261 | return false; |
||
| 1262 | } |
||
| 1263 | 798 | if (Cache\Scanner::isPartialFile($path)) { |
|
| 1264 | 1 | return $this->getPartFileInfo($path); |
|
| 1265 | } |
||
| 1266 | 798 | $relativePath = $path; |
|
| 1267 | 798 | $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); |
|
| 1268 | |||
| 1269 | 798 | $mount = Filesystem::getMountManager()->find($path); |
|
| 1270 | 798 | $storage = $mount->getStorage(); |
|
| 1271 | 798 | $internalPath = $mount->getInternalPath($path); |
|
| 1272 | 798 | if ($storage) { |
|
| 1273 | 798 | $data = $this->getCacheEntry($storage, $internalPath, $relativePath); |
|
| 1274 | |||
| 1275 | 798 | if (!is_array($data)) { |
|
| 1276 | 62 | return false; |
|
| 1277 | } |
||
| 1278 | |||
| 1279 | 797 | if ($mount instanceof MoveableMount && $internalPath === '') { |
|
| 1280 | 27 | $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE; |
|
| 1281 | 27 | } |
|
| 1282 | |||
| 1283 | 797 | $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath)); |
|
| 1284 | 797 | $info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner); |
|
| 1285 | |||
| 1286 | 797 | if ($data and isset($data['fileid'])) { |
|
| 1287 | 797 | if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') { |
|
| 1288 | //add the sizes of other mount points to the folder |
||
| 1289 | 584 | $extOnly = ($includeMountPoints === 'ext'); |
|
| 1290 | 584 | $mounts = Filesystem::getMountManager()->findIn($path); |
|
| 1291 | 584 | foreach ($mounts as $mount) { |
|
| 1292 | 60 | $subStorage = $mount->getStorage(); |
|
| 1293 | 60 | if ($subStorage) { |
|
| 1294 | // exclude shared storage ? |
||
| 1295 | 60 | if ($extOnly && $subStorage instanceof \OC\Files\Storage\Shared) { |
|
| 1296 | continue; |
||
| 1297 | } |
||
| 1298 | 60 | $subCache = $subStorage->getCache(''); |
|
| 1299 | 60 | $rootEntry = $subCache->get(''); |
|
| 1300 | 60 | $info->addSubEntry($rootEntry, $mount->getMountPoint()); |
|
| 1301 | 60 | } |
|
| 1302 | 584 | } |
|
| 1303 | 584 | } |
|
| 1304 | 797 | } |
|
| 1305 | |||
| 1306 | 797 | return $info; |
|
| 1307 | } |
||
| 1308 | |||
| 1309 | return false; |
||
| 1310 | } |
||
| 1311 | |||
| 1312 | /** |
||
| 1313 | * get the content of a directory |
||
| 1314 | * |
||
| 1315 | * @param string $directory path under datadirectory |
||
| 1316 | * @param string $mimetype_filter limit returned content to this mimetype or mimepart |
||
| 1317 | * @return FileInfo[] |
||
| 1318 | */ |
||
| 1319 | 201 | public function getDirectoryContent($directory, $mimetype_filter = '') { |
|
| 1320 | 201 | $this->assertPathLength($directory); |
|
| 1321 | 200 | if (!Filesystem::isValidPath($directory)) { |
|
| 1322 | return []; |
||
| 1323 | } |
||
| 1324 | 200 | $path = $this->getAbsolutePath($directory); |
|
| 1325 | 200 | $path = Filesystem::normalizePath($path); |
|
| 1326 | 200 | $mount = $this->getMount($directory); |
|
| 1327 | 200 | $storage = $mount->getStorage(); |
|
| 1328 | 200 | $internalPath = $mount->getInternalPath($path); |
|
| 1329 | 200 | if ($storage) { |
|
| 1330 | 200 | $cache = $storage->getCache($internalPath); |
|
| 1331 | 200 | $user = \OC_User::getUser(); |
|
| 1332 | |||
| 1333 | 200 | $data = $this->getCacheEntry($storage, $internalPath, $directory); |
|
| 1334 | |||
| 1335 | 200 | if (!is_array($data) || !isset($data['fileid'])) { |
|
| 1336 | 174 | return []; |
|
| 1337 | } |
||
| 1338 | |||
| 1339 | 198 | $folderId = $data['fileid']; |
|
| 1340 | 198 | $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter |
|
| 1341 | |||
| 1342 | /** |
||
| 1343 | * @var \OC\Files\FileInfo[] $files |
||
| 1344 | */ |
||
| 1345 | $files = array_map(function (array $content) use ($path, $storage, $mount) { |
||
| 1346 | 128 | if (\OCP\Util::isSharingDisabledForUser()) { |
|
| 1347 | 1 | $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; |
|
| 1348 | 1 | } |
|
| 1349 | 128 | $owner = $this->getUserObjectForOwner($storage->getOwner($content['path'])); |
|
| 1350 | 128 | return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner); |
|
| 1351 | 198 | }, $contents); |
|
| 1352 | |||
| 1353 | //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders |
||
| 1354 | 198 | $mounts = Filesystem::getMountManager()->findIn($path); |
|
| 1355 | 198 | $dirLength = strlen($path); |
|
| 1356 | 198 | foreach ($mounts as $mount) { |
|
| 1357 | 12 | $mountPoint = $mount->getMountPoint(); |
|
| 1358 | 12 | $subStorage = $mount->getStorage(); |
|
| 1359 | 12 | if ($subStorage) { |
|
| 1360 | 12 | $subCache = $subStorage->getCache(''); |
|
| 1361 | |||
| 1362 | 12 | $rootEntry = $subCache->get(''); |
|
| 1363 | 12 | if (!$rootEntry) { |
|
| 1364 | 3 | $subScanner = $subStorage->getScanner(''); |
|
| 1365 | try { |
||
| 1366 | 3 | $subScanner->scanFile(''); |
|
| 1367 | 3 | } catch (\OCP\Files\StorageNotAvailableException $e) { |
|
| 1368 | continue; |
||
| 1369 | } catch (\OCP\Files\StorageInvalidException $e) { |
||
| 1370 | continue; |
||
| 1371 | } catch (\Exception $e) { |
||
| 1372 | // sometimes when the storage is not available it can be any exception |
||
| 1373 | \OCP\Util::writeLog( |
||
| 1374 | 'core', |
||
| 1375 | 'Exception while scanning storage "' . $subStorage->getId() . '": ' . |
||
| 1376 | get_class($e) . ': ' . $e->getMessage(), |
||
| 1377 | \OCP\Util::ERROR |
||
| 1378 | ); |
||
| 1379 | continue; |
||
| 1380 | } |
||
| 1381 | 3 | $rootEntry = $subCache->get(''); |
|
| 1382 | 3 | } |
|
| 1383 | |||
| 1384 | 12 | if ($rootEntry) { |
|
| 1385 | 12 | $relativePath = trim(substr($mountPoint, $dirLength), '/'); |
|
| 1386 | 12 | if ($pos = strpos($relativePath, '/')) { |
|
| 1387 | //mountpoint inside subfolder add size to the correct folder |
||
| 1388 | 1 | $entryName = substr($relativePath, 0, $pos); |
|
| 1389 | 1 | foreach ($files as &$entry) { |
|
| 1390 | 1 | if ($entry->getName() === $entryName) { |
|
| 1391 | 1 | $entry->addSubEntry($rootEntry, $mountPoint); |
|
| 1392 | 1 | } |
|
| 1393 | 1 | } |
|
| 1394 | 1 | } else { //mountpoint in this folder, add an entry for it |
|
| 1395 | 12 | $rootEntry['name'] = $relativePath; |
|
| 1396 | 12 | $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; |
|
| 1397 | 12 | $permissions = $rootEntry['permissions']; |
|
| 1398 | // do not allow renaming/deleting the mount point if they are not shared files/folders |
||
| 1399 | // for shared files/folders we use the permissions given by the owner |
||
| 1400 | 12 | if ($mount instanceof MoveableMount) { |
|
| 1401 | 5 | $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE; |
|
| 1402 | 5 | } else { |
|
| 1403 | 7 | $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)); |
|
| 1404 | } |
||
| 1405 | |||
| 1406 | //remove any existing entry with the same name |
||
| 1407 | 12 | foreach ($files as $i => $file) { |
|
| 1408 | 12 | if ($file['name'] === $rootEntry['name']) { |
|
| 1409 | 1 | unset($files[$i]); |
|
| 1410 | 1 | break; |
|
| 1411 | } |
||
| 1412 | 12 | } |
|
| 1413 | 12 | $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/ |
|
| 1414 | |||
| 1415 | // if sharing was disabled for the user we remove the share permissions |
||
| 1416 | 12 | if (\OCP\Util::isSharingDisabledForUser()) { |
|
| 1417 | 1 | $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; |
|
| 1418 | 1 | } |
|
| 1419 | |||
| 1420 | 12 | $owner = $this->getUserObjectForOwner($subStorage->getOwner('')); |
|
| 1421 | 12 | $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner); |
|
| 1422 | } |
||
| 1423 | 12 | } |
|
| 1424 | 12 | } |
|
| 1425 | 198 | } |
|
| 1426 | |||
| 1427 | 198 | if ($mimetype_filter) { |
|
| 1428 | $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) { |
||
| 1429 | if (strpos($mimetype_filter, '/')) { |
||
| 1430 | if ($file->getMimetype() === $mimetype_filter) { |
||
| 1431 | $result[] = $file; |
||
| 1432 | } |
||
| 1433 | } else { |
||
| 1434 | if ($file->getMimePart() === $mimetype_filter) { |
||
| 1435 | $result[] = $file; |
||
| 1436 | } |
||
| 1437 | } |
||
| 1438 | }); |
||
| 1439 | } |
||
| 1440 | |||
| 1441 | 198 | return $files; |
|
| 1442 | } else { |
||
| 1443 | return []; |
||
| 1444 | } |
||
| 1445 | } |
||
| 1446 | |||
| 1447 | /** |
||
| 1448 | * change file metadata |
||
| 1449 | * |
||
| 1450 | * @param string $path |
||
| 1451 | * @param array|\OCP\Files\FileInfo $data |
||
| 1452 | * @return int |
||
| 1453 | * |
||
| 1454 | * returns the fileid of the updated file |
||
| 1455 | */ |
||
| 1456 | 31 | public function putFileInfo($path, $data) { |
|
| 1480 | |||
| 1481 | /** |
||
| 1482 | * search for files with the name matching $query |
||
| 1483 | * |
||
| 1484 | * @param string $query |
||
| 1485 | * @return FileInfo[] |
||
| 1486 | */ |
||
| 1487 | 2 | public function search($query) { |
|
| 1490 | |||
| 1491 | /** |
||
| 1492 | * search for files with the name matching $query |
||
| 1493 | * |
||
| 1494 | * @param string $query |
||
| 1495 | * @return FileInfo[] |
||
| 1496 | */ |
||
| 1497 | 10 | public function searchRaw($query) { |
|
| 1500 | |||
| 1501 | /** |
||
| 1502 | * search for files by mimetype |
||
| 1503 | * |
||
| 1504 | * @param string $mimetype |
||
| 1505 | * @return FileInfo[] |
||
| 1506 | */ |
||
| 1507 | 1 | public function searchByMime($mimetype) { |
|
| 1510 | |||
| 1511 | /** |
||
| 1512 | * search for files by tag |
||
| 1513 | * |
||
| 1514 | * @param string|int $tag name or tag id |
||
| 1515 | * @param string $userId owner of the tags |
||
| 1516 | * @return FileInfo[] |
||
| 1517 | */ |
||
| 1518 | public function searchByTag($tag, $userId) { |
||
| 1521 | |||
| 1522 | /** |
||
| 1523 | * @param string $method cache method |
||
| 1524 | * @param array $args |
||
| 1525 | * @return FileInfo[] |
||
| 1526 | */ |
||
| 1527 | 12 | private function searchCommon($method, $args) { |
|
| 1571 | |||
| 1572 | /** |
||
| 1573 | * Get the owner for a file or folder |
||
| 1574 | * |
||
| 1575 | * @param string $path |
||
| 1576 | * @return string |
||
| 1577 | */ |
||
| 1578 | 77 | public function getOwner($path) { |
|
| 1581 | |||
| 1582 | /** |
||
| 1583 | * get the ETag for a file or folder |
||
| 1584 | * |
||
| 1585 | * @param string $path |
||
| 1586 | * @return string |
||
| 1587 | */ |
||
| 1588 | 27 | public function getETag($path) { |
|
| 1600 | |||
| 1601 | /** |
||
| 1602 | * Get the path of a file by id, relative to the view |
||
| 1603 | * |
||
| 1604 | * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file |
||
| 1605 | * |
||
| 1606 | * @param int $id |
||
| 1607 | * @throws NotFoundException |
||
| 1608 | * @return string |
||
| 1609 | */ |
||
| 1610 | 156 | public function getPath($id) { |
|
| 1635 | |||
| 1636 | /** |
||
| 1637 | * @param string $path |
||
| 1638 | * @throws InvalidPathException |
||
| 1639 | */ |
||
| 1640 | 965 | private function assertPathLength($path) { |
|
| 1649 | |||
| 1650 | /** |
||
| 1651 | * check if it is allowed to move a mount point to a given target. |
||
| 1652 | * It is not allowed to move a mount point into a different mount point or |
||
| 1653 | * into an already shared folder |
||
| 1654 | * |
||
| 1655 | * @param string $target path |
||
| 1656 | * @return boolean |
||
| 1657 | */ |
||
| 1658 | 45 | private function isTargetAllowed($target) { |
|
| 1693 | |||
| 1694 | /** |
||
| 1695 | * Get a fileinfo object for files that are ignored in the cache (part files) |
||
| 1696 | * |
||
| 1697 | * @param string $path |
||
| 1698 | * @return \OCP\Files\FileInfo |
||
| 1699 | */ |
||
| 1700 | 1 | private function getPartFileInfo($path) { |
|
| 1723 | |||
| 1724 | /** |
||
| 1725 | * @param string $path |
||
| 1726 | * @param string $fileName |
||
| 1727 | * @throws InvalidPathException |
||
| 1728 | */ |
||
| 1729 | 169 | public function verifyPath($path, $fileName) { |
|
| 1763 | |||
| 1764 | /** |
||
| 1765 | * get all parent folders of $path |
||
| 1766 | * |
||
| 1767 | * @param string $path |
||
| 1768 | * @return string[] |
||
| 1769 | */ |
||
| 1770 | 805 | private function getParents($path) { |
|
| 1790 | |||
| 1791 | /** |
||
| 1792 | * Returns the mount point for which to lock |
||
| 1793 | * |
||
| 1794 | * @param string $absolutePath absolute path |
||
| 1795 | * @param bool $useParentMount true to return parent mount instead of whatever |
||
| 1796 | * is mounted directly on the given path, false otherwise |
||
| 1797 | * @return \OC\Files\Mount\MountPoint mount point for which to apply locks |
||
| 1798 | */ |
||
| 1799 | 805 | private function getMountForLock($absolutePath, $useParentMount = false) { |
|
| 1817 | |||
| 1818 | /** |
||
| 1819 | * Lock the given path |
||
| 1820 | * |
||
| 1821 | * @param string $path the path of the file to lock, relative to the view |
||
| 1822 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1823 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1824 | * |
||
| 1825 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1826 | * @throws \OCP\Lock\LockedException if the path is already locked |
||
| 1827 | */ |
||
| 1828 | 805 | View Code Duplication | private function lockPath($path, $type, $lockMountPoint = false) { |
| 1854 | |||
| 1855 | /** |
||
| 1856 | * Change the lock type |
||
| 1857 | * |
||
| 1858 | * @param string $path the path of the file to lock, relative to the view |
||
| 1859 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1860 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1861 | * |
||
| 1862 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1863 | * @throws \OCP\Lock\LockedException if the path is already locked |
||
| 1864 | */ |
||
| 1865 | 812 | View Code Duplication | public function changeLock($path, $type, $lockMountPoint = false) { |
| 1892 | |||
| 1893 | /** |
||
| 1894 | * Unlock the given path |
||
| 1895 | * |
||
| 1896 | * @param string $path the path of the file to unlock, relative to the view |
||
| 1897 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1898 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1899 | * |
||
| 1900 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1901 | */ |
||
| 1902 | 805 | View Code Duplication | private function unlockPath($path, $type, $lockMountPoint = false) { |
| 1920 | |||
| 1921 | /** |
||
| 1922 | * Lock a path and all its parents up to the root of the view |
||
| 1923 | * |
||
| 1924 | * @param string $path the path of the file to lock relative to the view |
||
| 1925 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1926 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1927 | * |
||
| 1928 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1929 | */ |
||
| 1930 | 930 | View Code Duplication | public function lockFile($path, $type, $lockMountPoint = false) { |
| 1946 | |||
| 1947 | /** |
||
| 1948 | * Unlock a path and all its parents up to the root of the view |
||
| 1949 | * |
||
| 1950 | * @param string $path the path of the file to lock relative to the view |
||
| 1951 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1952 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1953 | * |
||
| 1954 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1955 | */ |
||
| 1956 | 930 | View Code Duplication | public function unlockFile($path, $type, $lockMountPoint = false) { |
| 1972 | |||
| 1973 | /** |
||
| 1974 | * Only lock files in data/user/files/ |
||
| 1975 | * |
||
| 1976 | * @param string $path Absolute path to the file/folder we try to (un)lock |
||
| 1977 | * @return bool |
||
| 1978 | */ |
||
| 1979 | 930 | protected function shouldLockFile($path) { |
|
| 1990 | |||
| 1991 | /** |
||
| 1992 | * Shortens the given absolute path to be relative to |
||
| 1993 | * "$user/files". |
||
| 1994 | * |
||
| 1995 | * @param string $absolutePath absolute path which is under "files" |
||
| 1996 | * |
||
| 1997 | * @return string path relative to "files" with trimmed slashes or null |
||
| 1998 | * if the path was NOT relative to files |
||
| 1999 | * |
||
| 2000 | * @throws \InvalidArgumentException if the given path was not under "files" |
||
| 2001 | * @since 8.1.0 |
||
| 2002 | */ |
||
| 2003 | 55 | public function getPathRelativeToFiles($absolutePath) { |
|
| 2015 | } |
||
| 2016 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: