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 |
||
| 86 | class View { |
||
| 87 | /** @var string */ |
||
| 88 | private $fakeRoot = ''; |
||
| 89 | |||
| 90 | /** |
||
| 91 | * @var \OCP\Lock\ILockingProvider |
||
| 92 | */ |
||
| 93 | private $lockingProvider; |
||
| 94 | |||
| 95 | private $lockingEnabled; |
||
| 96 | |||
| 97 | private $updaterEnabled = true; |
||
| 98 | |||
| 99 | private $userManager; |
||
| 100 | |||
| 101 | /** |
||
| 102 | * @param string $root |
||
| 103 | * @throws \Exception If $root contains an invalid path |
||
| 104 | */ |
||
| 105 | public function __construct($root = '') { |
||
| 106 | if (is_null($root)) { |
||
| 107 | throw new \InvalidArgumentException('Root can\'t be null'); |
||
| 108 | } |
||
| 109 | if (!Filesystem::isValidPath($root)) { |
||
| 110 | throw new \Exception(); |
||
| 111 | } |
||
| 112 | |||
| 113 | $this->fakeRoot = $root; |
||
| 114 | $this->lockingProvider = \OC::$server->getLockingProvider(); |
||
| 115 | $this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider); |
||
| 116 | $this->userManager = \OC::$server->getUserManager(); |
||
| 117 | } |
||
| 118 | |||
| 119 | public function getAbsolutePath($path = '/') { |
||
| 120 | if ($path === null) { |
||
| 121 | return null; |
||
| 122 | } |
||
| 123 | $this->assertPathLength($path); |
||
| 124 | if ($path === '') { |
||
| 125 | $path = '/'; |
||
| 126 | } |
||
| 127 | if ($path[0] !== '/') { |
||
| 128 | $path = '/' . $path; |
||
| 129 | } |
||
| 130 | return $this->fakeRoot . $path; |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * change the root to a fake root |
||
| 135 | * |
||
| 136 | * @param string $fakeRoot |
||
| 137 | * @return boolean|null |
||
| 138 | */ |
||
| 139 | public function chroot($fakeRoot) { |
||
| 140 | if (!$fakeRoot == '') { |
||
| 141 | if ($fakeRoot[0] !== '/') { |
||
| 142 | $fakeRoot = '/' . $fakeRoot; |
||
| 143 | } |
||
| 144 | } |
||
| 145 | $this->fakeRoot = $fakeRoot; |
||
| 146 | } |
||
| 147 | |||
| 148 | /** |
||
| 149 | * get the fake root |
||
| 150 | * |
||
| 151 | * @return string |
||
| 152 | */ |
||
| 153 | public function getRoot() { |
||
| 154 | return $this->fakeRoot; |
||
| 155 | } |
||
| 156 | |||
| 157 | /** |
||
| 158 | * get path relative to the root of the view |
||
| 159 | * |
||
| 160 | * @param string $path |
||
| 161 | * @return string |
||
| 162 | */ |
||
| 163 | public function getRelativePath($path) { |
||
| 164 | $this->assertPathLength($path); |
||
| 165 | if ($this->fakeRoot == '') { |
||
| 166 | return $path; |
||
| 167 | } |
||
| 168 | |||
| 169 | if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) { |
||
| 170 | return '/'; |
||
| 171 | } |
||
| 172 | |||
| 173 | // missing slashes can cause wrong matches! |
||
| 174 | $root = rtrim($this->fakeRoot, '/') . '/'; |
||
| 175 | |||
| 176 | if (strpos($path, $root) !== 0) { |
||
| 177 | return null; |
||
| 178 | } else { |
||
| 179 | $path = substr($path, strlen($this->fakeRoot)); |
||
| 180 | if (strlen($path) === 0) { |
||
| 181 | return '/'; |
||
| 182 | } else { |
||
| 183 | return $path; |
||
| 184 | } |
||
| 185 | } |
||
| 186 | } |
||
| 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 string |
||
| 196 | */ |
||
| 197 | public function getMountPoint($path) { |
||
| 198 | return Filesystem::getMountPoint($this->getAbsolutePath($path)); |
||
| 199 | } |
||
| 200 | |||
| 201 | /** |
||
| 202 | * get the mountpoint of the storage object for a path |
||
| 203 | * ( note: because a storage is not always mounted inside the fakeroot, the |
||
| 204 | * returned mountpoint is relative to the absolute root of the filesystem |
||
| 205 | * and does not take the chroot into account ) |
||
| 206 | * |
||
| 207 | * @param string $path |
||
| 208 | * @return \OCP\Files\Mount\IMountPoint |
||
| 209 | */ |
||
| 210 | public function getMount($path) { |
||
| 211 | return Filesystem::getMountManager()->find($this->getAbsolutePath($path)); |
||
| 212 | } |
||
| 213 | |||
| 214 | /** |
||
| 215 | * resolve a path to a storage and internal path |
||
| 216 | * |
||
| 217 | * @param string $path |
||
| 218 | * @return array an array consisting of the storage and the internal path |
||
| 219 | */ |
||
| 220 | public function resolvePath($path) { |
||
| 221 | $a = $this->getAbsolutePath($path); |
||
| 222 | $p = Filesystem::normalizePath($a); |
||
| 223 | return Filesystem::resolvePath($p); |
||
| 224 | } |
||
| 225 | |||
| 226 | /** |
||
| 227 | * return the path to a local version of the file |
||
| 228 | * we need this because we can't know if a file is stored local or not from |
||
| 229 | * outside the filestorage and for some purposes a local file is needed |
||
| 230 | * |
||
| 231 | * @param string $path |
||
| 232 | * @return string |
||
| 233 | */ |
||
| 234 | View Code Duplication | public function getLocalFile($path) { |
|
|
|
|||
| 235 | $parent = substr($path, 0, strrpos($path, '/')); |
||
| 236 | $path = $this->getAbsolutePath($path); |
||
| 237 | list($storage, $internalPath) = Filesystem::resolvePath($path); |
||
| 238 | if (Filesystem::isValidPath($parent) and $storage) { |
||
| 239 | return $storage->getLocalFile($internalPath); |
||
| 240 | } else { |
||
| 241 | return null; |
||
| 242 | } |
||
| 243 | } |
||
| 244 | |||
| 245 | /** |
||
| 246 | * @param string $path |
||
| 247 | * @return string |
||
| 248 | */ |
||
| 249 | View Code Duplication | public function getLocalFolder($path) { |
|
| 250 | $parent = substr($path, 0, strrpos($path, '/')); |
||
| 251 | $path = $this->getAbsolutePath($path); |
||
| 252 | list($storage, $internalPath) = Filesystem::resolvePath($path); |
||
| 253 | if (Filesystem::isValidPath($parent) and $storage) { |
||
| 254 | return $storage->getLocalFolder($internalPath); |
||
| 255 | } else { |
||
| 256 | return null; |
||
| 257 | } |
||
| 258 | } |
||
| 259 | |||
| 260 | /** |
||
| 261 | * the following functions operate with arguments and return values identical |
||
| 262 | * to those of their PHP built-in equivalents. Mostly they are merely wrappers |
||
| 263 | * for \OC\Files\Storage\Storage via basicOperation(). |
||
| 264 | */ |
||
| 265 | public function mkdir($path) { |
||
| 266 | return $this->basicOperation('mkdir', $path, array('create', 'write')); |
||
| 267 | } |
||
| 268 | |||
| 269 | /** |
||
| 270 | * remove mount point |
||
| 271 | * |
||
| 272 | * @param \OC\Files\Mount\MoveableMount $mount |
||
| 273 | * @param string $path relative to data/ |
||
| 274 | * @return boolean |
||
| 275 | */ |
||
| 276 | protected function removeMount($mount, $path) { |
||
| 277 | if ($mount instanceof MoveableMount) { |
||
| 278 | // cut of /user/files to get the relative path to data/user/files |
||
| 279 | $pathParts = explode('/', $path, 4); |
||
| 280 | $relPath = '/' . $pathParts[3]; |
||
| 281 | $this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true); |
||
| 282 | \OC_Hook::emit( |
||
| 283 | Filesystem::CLASSNAME, "umount", |
||
| 284 | array(Filesystem::signal_param_path => $relPath) |
||
| 285 | ); |
||
| 286 | $this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true); |
||
| 287 | $result = $mount->removeMount(); |
||
| 288 | $this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true); |
||
| 289 | if ($result) { |
||
| 290 | \OC_Hook::emit( |
||
| 291 | Filesystem::CLASSNAME, "post_umount", |
||
| 292 | array(Filesystem::signal_param_path => $relPath) |
||
| 293 | ); |
||
| 294 | } |
||
| 295 | $this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true); |
||
| 296 | return $result; |
||
| 297 | } else { |
||
| 298 | // do not allow deleting the storage's root / the mount point |
||
| 299 | // because for some storages it might delete the whole contents |
||
| 300 | // but isn't supposed to work that way |
||
| 301 | return false; |
||
| 302 | } |
||
| 303 | } |
||
| 304 | |||
| 305 | public function disableCacheUpdate() { |
||
| 306 | $this->updaterEnabled = false; |
||
| 307 | } |
||
| 308 | |||
| 309 | public function enableCacheUpdate() { |
||
| 310 | $this->updaterEnabled = true; |
||
| 311 | } |
||
| 312 | |||
| 313 | protected function writeUpdate(Storage $storage, $internalPath, $time = null) { |
||
| 314 | if ($this->updaterEnabled) { |
||
| 315 | if (is_null($time)) { |
||
| 316 | $time = time(); |
||
| 317 | } |
||
| 318 | $storage->getUpdater()->update($internalPath, $time); |
||
| 319 | } |
||
| 320 | } |
||
| 321 | |||
| 322 | protected function removeUpdate(Storage $storage, $internalPath) { |
||
| 323 | if ($this->updaterEnabled) { |
||
| 324 | $storage->getUpdater()->remove($internalPath); |
||
| 325 | } |
||
| 326 | } |
||
| 327 | |||
| 328 | protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) { |
||
| 329 | if ($this->updaterEnabled) { |
||
| 330 | $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); |
||
| 331 | } |
||
| 332 | } |
||
| 333 | |||
| 334 | /** |
||
| 335 | * @param string $path |
||
| 336 | * @return bool|mixed |
||
| 337 | */ |
||
| 338 | public function rmdir($path) { |
||
| 339 | $absolutePath = $this->getAbsolutePath($path); |
||
| 340 | $mount = Filesystem::getMountManager()->find($absolutePath); |
||
| 341 | if ($mount->getInternalPath($absolutePath) === '') { |
||
| 342 | return $this->removeMount($mount, $absolutePath); |
||
| 343 | } |
||
| 344 | if ($this->is_dir($path)) { |
||
| 345 | $result = $this->basicOperation('rmdir', $path, array('delete')); |
||
| 346 | } else { |
||
| 347 | $result = false; |
||
| 348 | } |
||
| 349 | |||
| 350 | View Code Duplication | if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete |
|
| 351 | $storage = $mount->getStorage(); |
||
| 352 | $internalPath = $mount->getInternalPath($absolutePath); |
||
| 353 | $storage->getUpdater()->remove($internalPath); |
||
| 354 | } |
||
| 355 | return $result; |
||
| 356 | } |
||
| 357 | |||
| 358 | /** |
||
| 359 | * @param string $path |
||
| 360 | * @return resource |
||
| 361 | */ |
||
| 362 | public function opendir($path) { |
||
| 363 | return $this->basicOperation('opendir', $path, array('read')); |
||
| 364 | } |
||
| 365 | |||
| 366 | /** |
||
| 367 | * @param $handle |
||
| 368 | * @return mixed |
||
| 369 | */ |
||
| 370 | public function readdir($handle) { |
||
| 371 | $fsLocal = new Storage\Local(array('datadir' => '/')); |
||
| 372 | return $fsLocal->readdir($handle); |
||
| 373 | } |
||
| 374 | |||
| 375 | /** |
||
| 376 | * @param string $path |
||
| 377 | * @return bool|mixed |
||
| 378 | */ |
||
| 379 | public function is_dir($path) { |
||
| 380 | if ($path == '/') { |
||
| 381 | return true; |
||
| 382 | } |
||
| 383 | return $this->basicOperation('is_dir', $path); |
||
| 384 | } |
||
| 385 | |||
| 386 | /** |
||
| 387 | * @param string $path |
||
| 388 | * @return bool|mixed |
||
| 389 | */ |
||
| 390 | public function is_file($path) { |
||
| 391 | if ($path == '/') { |
||
| 392 | return false; |
||
| 393 | } |
||
| 394 | return $this->basicOperation('is_file', $path); |
||
| 395 | } |
||
| 396 | |||
| 397 | /** |
||
| 398 | * @param string $path |
||
| 399 | * @return mixed |
||
| 400 | */ |
||
| 401 | public function stat($path) { |
||
| 402 | return $this->basicOperation('stat', $path); |
||
| 403 | } |
||
| 404 | |||
| 405 | /** |
||
| 406 | * @param string $path |
||
| 407 | * @return mixed |
||
| 408 | */ |
||
| 409 | public function filetype($path) { |
||
| 410 | return $this->basicOperation('filetype', $path); |
||
| 411 | } |
||
| 412 | |||
| 413 | /** |
||
| 414 | * @param string $path |
||
| 415 | * @return mixed |
||
| 416 | */ |
||
| 417 | public function filesize($path) { |
||
| 418 | return $this->basicOperation('filesize', $path); |
||
| 419 | } |
||
| 420 | |||
| 421 | /** |
||
| 422 | * @param string $path |
||
| 423 | * @return bool|mixed |
||
| 424 | * @throws \OCP\Files\InvalidPathException |
||
| 425 | */ |
||
| 426 | public function readfile($path) { |
||
| 427 | $this->assertPathLength($path); |
||
| 428 | @ob_end_clean(); |
||
| 429 | $handle = $this->fopen($path, 'rb'); |
||
| 430 | if ($handle) { |
||
| 431 | $chunkSize = 8192; // 8 kB chunks |
||
| 432 | while (!feof($handle)) { |
||
| 433 | echo fread($handle, $chunkSize); |
||
| 434 | flush(); |
||
| 435 | } |
||
| 436 | fclose($handle); |
||
| 437 | $size = $this->filesize($path); |
||
| 438 | return $size; |
||
| 439 | } |
||
| 440 | return false; |
||
| 441 | } |
||
| 442 | |||
| 443 | /** |
||
| 444 | * @param string $path |
||
| 445 | * @param int $from |
||
| 446 | * @param int $to |
||
| 447 | * @return bool|mixed |
||
| 448 | * @throws \OCP\Files\InvalidPathException |
||
| 449 | * @throws \OCP\Files\UnseekableException |
||
| 450 | */ |
||
| 451 | public function readfilePart($path, $from, $to) { |
||
| 452 | $this->assertPathLength($path); |
||
| 453 | @ob_end_clean(); |
||
| 454 | $handle = $this->fopen($path, 'rb'); |
||
| 455 | if ($handle) { |
||
| 456 | if (fseek($handle, $from) === 0) { |
||
| 457 | $chunkSize = 8192; // 8 kB chunks |
||
| 458 | $end = $to + 1; |
||
| 459 | while (!feof($handle) && ftell($handle) < $end) { |
||
| 460 | $len = $end - ftell($handle); |
||
| 461 | if ($len > $chunkSize) { |
||
| 462 | $len = $chunkSize; |
||
| 463 | } |
||
| 464 | echo fread($handle, $len); |
||
| 465 | flush(); |
||
| 466 | } |
||
| 467 | $size = ftell($handle) - $from; |
||
| 468 | return $size; |
||
| 469 | } |
||
| 470 | |||
| 471 | throw new \OCP\Files\UnseekableException('fseek error'); |
||
| 472 | } |
||
| 473 | return false; |
||
| 474 | } |
||
| 475 | |||
| 476 | /** |
||
| 477 | * @param string $path |
||
| 478 | * @return mixed |
||
| 479 | */ |
||
| 480 | public function isCreatable($path) { |
||
| 481 | return $this->basicOperation('isCreatable', $path); |
||
| 482 | } |
||
| 483 | |||
| 484 | /** |
||
| 485 | * @param string $path |
||
| 486 | * @return mixed |
||
| 487 | */ |
||
| 488 | public function isReadable($path) { |
||
| 489 | return $this->basicOperation('isReadable', $path); |
||
| 490 | } |
||
| 491 | |||
| 492 | /** |
||
| 493 | * @param string $path |
||
| 494 | * @return mixed |
||
| 495 | */ |
||
| 496 | public function isUpdatable($path) { |
||
| 497 | return $this->basicOperation('isUpdatable', $path); |
||
| 498 | } |
||
| 499 | |||
| 500 | /** |
||
| 501 | * @param string $path |
||
| 502 | * @return bool|mixed |
||
| 503 | */ |
||
| 504 | public function isDeletable($path) { |
||
| 505 | $absolutePath = $this->getAbsolutePath($path); |
||
| 506 | $mount = Filesystem::getMountManager()->find($absolutePath); |
||
| 507 | if ($mount->getInternalPath($absolutePath) === '') { |
||
| 508 | return $mount instanceof MoveableMount; |
||
| 509 | } |
||
| 510 | return $this->basicOperation('isDeletable', $path); |
||
| 511 | } |
||
| 512 | |||
| 513 | /** |
||
| 514 | * @param string $path |
||
| 515 | * @return mixed |
||
| 516 | */ |
||
| 517 | public function isSharable($path) { |
||
| 518 | return $this->basicOperation('isSharable', $path); |
||
| 519 | } |
||
| 520 | |||
| 521 | /** |
||
| 522 | * @param string $path |
||
| 523 | * @return bool|mixed |
||
| 524 | */ |
||
| 525 | public function file_exists($path) { |
||
| 526 | if ($path == '/') { |
||
| 527 | return true; |
||
| 528 | } |
||
| 529 | return $this->basicOperation('file_exists', $path); |
||
| 530 | } |
||
| 531 | |||
| 532 | /** |
||
| 533 | * @param string $path |
||
| 534 | * @return mixed |
||
| 535 | */ |
||
| 536 | public function filemtime($path) { |
||
| 537 | return $this->basicOperation('filemtime', $path); |
||
| 538 | } |
||
| 539 | |||
| 540 | /** |
||
| 541 | * @param string $path |
||
| 542 | * @param int|string $mtime |
||
| 543 | * @return bool |
||
| 544 | */ |
||
| 545 | public function touch($path, $mtime = null) { |
||
| 546 | if (!is_null($mtime) and !is_numeric($mtime)) { |
||
| 547 | $mtime = strtotime($mtime); |
||
| 548 | } |
||
| 549 | |||
| 550 | $hooks = array('touch'); |
||
| 551 | |||
| 552 | if (!$this->file_exists($path)) { |
||
| 553 | $hooks[] = 'create'; |
||
| 554 | $hooks[] = 'write'; |
||
| 555 | } |
||
| 556 | $result = $this->basicOperation('touch', $path, $hooks, $mtime); |
||
| 557 | if (!$result) { |
||
| 558 | // If create file fails because of permissions on external storage like SMB folders, |
||
| 559 | // check file exists and return false if not. |
||
| 560 | if (!$this->file_exists($path)) { |
||
| 561 | return false; |
||
| 562 | } |
||
| 563 | if (is_null($mtime)) { |
||
| 564 | $mtime = time(); |
||
| 565 | } |
||
| 566 | //if native touch fails, we emulate it by changing the mtime in the cache |
||
| 567 | $this->putFileInfo($path, array('mtime' => $mtime)); |
||
| 568 | } |
||
| 569 | return true; |
||
| 570 | } |
||
| 571 | |||
| 572 | /** |
||
| 573 | * @param string $path |
||
| 574 | * @return mixed |
||
| 575 | */ |
||
| 576 | public function file_get_contents($path) { |
||
| 577 | return $this->basicOperation('file_get_contents', $path, array('read')); |
||
| 578 | } |
||
| 579 | |||
| 580 | /** |
||
| 581 | * @param bool $exists |
||
| 582 | * @param string $path |
||
| 583 | * @param bool $run |
||
| 584 | */ |
||
| 585 | protected function emit_file_hooks_pre($exists, $path, &$run) { |
||
| 586 | View Code Duplication | if (!$exists) { |
|
| 587 | \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, array( |
||
| 588 | Filesystem::signal_param_path => $this->getHookPath($path), |
||
| 589 | Filesystem::signal_param_run => &$run, |
||
| 590 | )); |
||
| 591 | } else { |
||
| 592 | \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, array( |
||
| 593 | Filesystem::signal_param_path => $this->getHookPath($path), |
||
| 594 | Filesystem::signal_param_run => &$run, |
||
| 595 | )); |
||
| 596 | } |
||
| 597 | \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, array( |
||
| 598 | Filesystem::signal_param_path => $this->getHookPath($path), |
||
| 599 | Filesystem::signal_param_run => &$run, |
||
| 600 | )); |
||
| 601 | } |
||
| 602 | |||
| 603 | /** |
||
| 604 | * @param bool $exists |
||
| 605 | * @param string $path |
||
| 606 | */ |
||
| 607 | protected function emit_file_hooks_post($exists, $path) { |
||
| 608 | View Code Duplication | if (!$exists) { |
|
| 609 | \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, array( |
||
| 610 | Filesystem::signal_param_path => $this->getHookPath($path), |
||
| 611 | )); |
||
| 612 | } else { |
||
| 613 | \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, array( |
||
| 614 | Filesystem::signal_param_path => $this->getHookPath($path), |
||
| 615 | )); |
||
| 616 | } |
||
| 617 | \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, array( |
||
| 618 | Filesystem::signal_param_path => $this->getHookPath($path), |
||
| 619 | )); |
||
| 620 | } |
||
| 621 | |||
| 622 | /** |
||
| 623 | * @param string $path |
||
| 624 | * @param mixed $data |
||
| 625 | * @return bool|mixed |
||
| 626 | * @throws \Exception |
||
| 627 | */ |
||
| 628 | public function file_put_contents($path, $data) { |
||
| 629 | if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier |
||
| 630 | $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); |
||
| 631 | if (Filesystem::isValidPath($path) |
||
| 632 | and !Filesystem::isFileBlacklisted($path) |
||
| 633 | ) { |
||
| 634 | $path = $this->getRelativePath($absolutePath); |
||
| 635 | |||
| 636 | $this->lockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 637 | |||
| 638 | $exists = $this->file_exists($path); |
||
| 639 | $run = true; |
||
| 640 | if ($this->shouldEmitHooks($path)) { |
||
| 641 | $this->emit_file_hooks_pre($exists, $path, $run); |
||
| 642 | } |
||
| 643 | if (!$run) { |
||
| 644 | $this->unlockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 645 | return false; |
||
| 646 | } |
||
| 647 | |||
| 648 | $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE); |
||
| 649 | |||
| 650 | /** @var \OC\Files\Storage\Storage $storage */ |
||
| 651 | list($storage, $internalPath) = $this->resolvePath($path); |
||
| 652 | $target = $storage->fopen($internalPath, 'w'); |
||
| 653 | if ($target) { |
||
| 654 | list (, $result) = \OC_Helper::streamCopy($data, $target); |
||
| 655 | fclose($target); |
||
| 656 | fclose($data); |
||
| 657 | |||
| 658 | $this->writeUpdate($storage, $internalPath); |
||
| 659 | |||
| 660 | $this->changeLock($path, ILockingProvider::LOCK_SHARED); |
||
| 661 | |||
| 662 | if ($this->shouldEmitHooks($path) && $result !== false) { |
||
| 663 | $this->emit_file_hooks_post($exists, $path); |
||
| 664 | } |
||
| 665 | $this->unlockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 666 | return $result; |
||
| 667 | } else { |
||
| 668 | $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); |
||
| 669 | return false; |
||
| 670 | } |
||
| 671 | } else { |
||
| 672 | return false; |
||
| 673 | } |
||
| 674 | } else { |
||
| 675 | $hooks = ($this->file_exists($path)) ? array('update', 'write') : array('create', 'write'); |
||
| 676 | return $this->basicOperation('file_put_contents', $path, $hooks, $data); |
||
| 677 | } |
||
| 678 | } |
||
| 679 | |||
| 680 | /** |
||
| 681 | * @param string $path |
||
| 682 | * @return bool|mixed |
||
| 683 | */ |
||
| 684 | public function unlink($path) { |
||
| 685 | if ($path === '' || $path === '/') { |
||
| 686 | // do not allow deleting the root |
||
| 687 | return false; |
||
| 688 | } |
||
| 689 | $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; |
||
| 690 | $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); |
||
| 691 | $mount = Filesystem::getMountManager()->find($absolutePath . $postFix); |
||
| 692 | if ($mount and $mount->getInternalPath($absolutePath) === '') { |
||
| 693 | return $this->removeMount($mount, $absolutePath); |
||
| 694 | } |
||
| 695 | $result = $this->basicOperation('unlink', $path, array('delete')); |
||
| 696 | View Code Duplication | if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete |
|
| 697 | $storage = $mount->getStorage(); |
||
| 698 | $internalPath = $mount->getInternalPath($absolutePath); |
||
| 699 | $storage->getUpdater()->remove($internalPath); |
||
| 700 | return true; |
||
| 701 | } else { |
||
| 702 | return $result; |
||
| 703 | } |
||
| 704 | } |
||
| 705 | |||
| 706 | /** |
||
| 707 | * @param string $directory |
||
| 708 | * @return bool|mixed |
||
| 709 | */ |
||
| 710 | public function deleteAll($directory) { |
||
| 711 | return $this->rmdir($directory); |
||
| 712 | } |
||
| 713 | |||
| 714 | /** |
||
| 715 | * Rename/move a file or folder from the source path to target path. |
||
| 716 | * |
||
| 717 | * @param string $path1 source path |
||
| 718 | * @param string $path2 target path |
||
| 719 | * |
||
| 720 | * @return bool|mixed |
||
| 721 | */ |
||
| 722 | public function rename($path1, $path2) { |
||
| 723 | $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); |
||
| 724 | $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); |
||
| 725 | $result = false; |
||
| 726 | if ( |
||
| 727 | Filesystem::isValidPath($path2) |
||
| 728 | and Filesystem::isValidPath($path1) |
||
| 729 | and !Filesystem::isFileBlacklisted($path2) |
||
| 730 | ) { |
||
| 731 | $path1 = $this->getRelativePath($absolutePath1); |
||
| 732 | $path2 = $this->getRelativePath($absolutePath2); |
||
| 733 | $exists = $this->file_exists($path2); |
||
| 734 | |||
| 735 | if ($path1 == null or $path2 == null) { |
||
| 736 | return false; |
||
| 737 | } |
||
| 738 | |||
| 739 | $this->lockFile($path1, ILockingProvider::LOCK_SHARED, true); |
||
| 740 | try { |
||
| 741 | $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true); |
||
| 742 | } catch (LockedException $e) { |
||
| 743 | $this->unlockFile($path1, ILockingProvider::LOCK_SHARED); |
||
| 744 | throw $e; |
||
| 745 | } |
||
| 746 | |||
| 747 | $run = true; |
||
| 748 | if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) { |
||
| 749 | // if it was a rename from a part file to a regular file it was a write and not a rename operation |
||
| 750 | $this->emit_file_hooks_pre($exists, $path2, $run); |
||
| 751 | } elseif ($this->shouldEmitHooks($path1)) { |
||
| 752 | \OC_Hook::emit( |
||
| 753 | Filesystem::CLASSNAME, Filesystem::signal_rename, |
||
| 754 | array( |
||
| 755 | Filesystem::signal_param_oldpath => $this->getHookPath($path1), |
||
| 756 | Filesystem::signal_param_newpath => $this->getHookPath($path2), |
||
| 757 | Filesystem::signal_param_run => &$run |
||
| 758 | ) |
||
| 759 | ); |
||
| 760 | } |
||
| 761 | if ($run) { |
||
| 762 | $this->verifyPath(dirname($path2), basename($path2)); |
||
| 763 | |||
| 764 | $manager = Filesystem::getMountManager(); |
||
| 765 | $mount1 = $this->getMount($path1); |
||
| 766 | $mount2 = $this->getMount($path2); |
||
| 767 | $storage1 = $mount1->getStorage(); |
||
| 768 | $storage2 = $mount2->getStorage(); |
||
| 769 | $internalPath1 = $mount1->getInternalPath($absolutePath1); |
||
| 770 | $internalPath2 = $mount2->getInternalPath($absolutePath2); |
||
| 771 | |||
| 772 | $this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true); |
||
| 773 | $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true); |
||
| 774 | |||
| 775 | if ($internalPath1 === '' and $mount1 instanceof MoveableMount) { |
||
| 776 | if ($this->isTargetAllowed($absolutePath2)) { |
||
| 777 | /** |
||
| 778 | * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1 |
||
| 779 | */ |
||
| 780 | $sourceMountPoint = $mount1->getMountPoint(); |
||
| 781 | $result = $mount1->moveMount($absolutePath2); |
||
| 782 | $manager->moveMount($sourceMountPoint, $mount1->getMountPoint()); |
||
| 783 | } else { |
||
| 784 | $result = false; |
||
| 785 | } |
||
| 786 | // moving a file/folder within the same mount point |
||
| 787 | } elseif ($storage1 === $storage2) { |
||
| 788 | if ($storage1) { |
||
| 789 | $result = $storage1->rename($internalPath1, $internalPath2); |
||
| 790 | } else { |
||
| 791 | $result = false; |
||
| 792 | } |
||
| 793 | // moving a file/folder between storages (from $storage1 to $storage2) |
||
| 794 | } else { |
||
| 795 | $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2); |
||
| 796 | } |
||
| 797 | |||
| 798 | if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { |
||
| 799 | // if it was a rename from a part file to a regular file it was a write and not a rename operation |
||
| 800 | |||
| 801 | $this->writeUpdate($storage2, $internalPath2); |
||
| 802 | } else if ($result) { |
||
| 803 | if ($internalPath1 !== '') { // don't do a cache update for moved mounts |
||
| 804 | $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2); |
||
| 805 | } |
||
| 806 | } |
||
| 807 | |||
| 808 | $this->changeLock($path1, ILockingProvider::LOCK_SHARED, true); |
||
| 809 | $this->changeLock($path2, ILockingProvider::LOCK_SHARED, true); |
||
| 810 | |||
| 811 | if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) { |
||
| 812 | if ($this->shouldEmitHooks()) { |
||
| 813 | $this->emit_file_hooks_post($exists, $path2); |
||
| 814 | } |
||
| 815 | } elseif ($result) { |
||
| 816 | if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) { |
||
| 817 | \OC_Hook::emit( |
||
| 818 | Filesystem::CLASSNAME, |
||
| 819 | Filesystem::signal_post_rename, |
||
| 820 | array( |
||
| 821 | Filesystem::signal_param_oldpath => $this->getHookPath($path1), |
||
| 822 | Filesystem::signal_param_newpath => $this->getHookPath($path2) |
||
| 823 | ) |
||
| 824 | ); |
||
| 825 | } |
||
| 826 | } |
||
| 827 | } |
||
| 828 | $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true); |
||
| 829 | $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true); |
||
| 830 | } |
||
| 831 | return $result; |
||
| 832 | } |
||
| 833 | |||
| 834 | /** |
||
| 835 | * Copy a file/folder from the source path to target path |
||
| 836 | * |
||
| 837 | * @param string $path1 source path |
||
| 838 | * @param string $path2 target path |
||
| 839 | * @param bool $preserveMtime whether to preserve mtime on the copy |
||
| 840 | * |
||
| 841 | * @return bool|mixed |
||
| 842 | */ |
||
| 843 | public function copy($path1, $path2, $preserveMtime = false) { |
||
| 844 | $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1)); |
||
| 845 | $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2)); |
||
| 846 | $result = false; |
||
| 847 | if ( |
||
| 848 | Filesystem::isValidPath($path2) |
||
| 849 | and Filesystem::isValidPath($path1) |
||
| 850 | and !Filesystem::isFileBlacklisted($path2) |
||
| 851 | ) { |
||
| 852 | $path1 = $this->getRelativePath($absolutePath1); |
||
| 853 | $path2 = $this->getRelativePath($absolutePath2); |
||
| 854 | |||
| 855 | if ($path1 == null or $path2 == null) { |
||
| 856 | return false; |
||
| 857 | } |
||
| 858 | $run = true; |
||
| 859 | |||
| 860 | $this->lockFile($path2, ILockingProvider::LOCK_SHARED); |
||
| 861 | $this->lockFile($path1, ILockingProvider::LOCK_SHARED); |
||
| 862 | $lockTypePath1 = ILockingProvider::LOCK_SHARED; |
||
| 863 | $lockTypePath2 = ILockingProvider::LOCK_SHARED; |
||
| 864 | |||
| 865 | try { |
||
| 866 | |||
| 867 | $exists = $this->file_exists($path2); |
||
| 868 | View Code Duplication | if ($this->shouldEmitHooks()) { |
|
| 869 | \OC_Hook::emit( |
||
| 870 | Filesystem::CLASSNAME, |
||
| 871 | Filesystem::signal_copy, |
||
| 872 | array( |
||
| 873 | Filesystem::signal_param_oldpath => $this->getHookPath($path1), |
||
| 874 | Filesystem::signal_param_newpath => $this->getHookPath($path2), |
||
| 875 | Filesystem::signal_param_run => &$run |
||
| 876 | ) |
||
| 877 | ); |
||
| 878 | $this->emit_file_hooks_pre($exists, $path2, $run); |
||
| 879 | } |
||
| 880 | if ($run) { |
||
| 881 | $mount1 = $this->getMount($path1); |
||
| 882 | $mount2 = $this->getMount($path2); |
||
| 883 | $storage1 = $mount1->getStorage(); |
||
| 884 | $internalPath1 = $mount1->getInternalPath($absolutePath1); |
||
| 885 | $storage2 = $mount2->getStorage(); |
||
| 886 | $internalPath2 = $mount2->getInternalPath($absolutePath2); |
||
| 887 | |||
| 888 | $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE); |
||
| 889 | $lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE; |
||
| 890 | |||
| 891 | if ($mount1->getMountPoint() == $mount2->getMountPoint()) { |
||
| 892 | if ($storage1) { |
||
| 893 | $result = $storage1->copy($internalPath1, $internalPath2); |
||
| 894 | } else { |
||
| 895 | $result = false; |
||
| 896 | } |
||
| 897 | } else { |
||
| 898 | $result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2); |
||
| 899 | } |
||
| 900 | |||
| 901 | $this->writeUpdate($storage2, $internalPath2); |
||
| 902 | |||
| 903 | $this->changeLock($path2, ILockingProvider::LOCK_SHARED); |
||
| 904 | $lockTypePath2 = ILockingProvider::LOCK_SHARED; |
||
| 905 | |||
| 906 | View Code Duplication | if ($this->shouldEmitHooks() && $result !== false) { |
|
| 907 | \OC_Hook::emit( |
||
| 908 | Filesystem::CLASSNAME, |
||
| 909 | Filesystem::signal_post_copy, |
||
| 910 | array( |
||
| 911 | Filesystem::signal_param_oldpath => $this->getHookPath($path1), |
||
| 912 | Filesystem::signal_param_newpath => $this->getHookPath($path2) |
||
| 913 | ) |
||
| 914 | ); |
||
| 915 | $this->emit_file_hooks_post($exists, $path2); |
||
| 916 | } |
||
| 917 | |||
| 918 | } |
||
| 919 | } catch (\Exception $e) { |
||
| 920 | $this->unlockFile($path2, $lockTypePath2); |
||
| 921 | $this->unlockFile($path1, $lockTypePath1); |
||
| 922 | throw $e; |
||
| 923 | } |
||
| 924 | |||
| 925 | $this->unlockFile($path2, $lockTypePath2); |
||
| 926 | $this->unlockFile($path1, $lockTypePath1); |
||
| 927 | |||
| 928 | } |
||
| 929 | return $result; |
||
| 930 | } |
||
| 931 | |||
| 932 | /** |
||
| 933 | * @param string $path |
||
| 934 | * @param string $mode 'r' or 'w' |
||
| 935 | * @return resource |
||
| 936 | */ |
||
| 937 | public function fopen($path, $mode) { |
||
| 938 | $mode = str_replace('b', '', $mode); // the binary flag is a windows only feature which we do not support |
||
| 939 | $hooks = array(); |
||
| 940 | switch ($mode) { |
||
| 941 | case 'r': |
||
| 942 | $hooks[] = 'read'; |
||
| 943 | break; |
||
| 944 | case 'r+': |
||
| 945 | case 'w+': |
||
| 946 | case 'x+': |
||
| 947 | case 'a+': |
||
| 948 | $hooks[] = 'read'; |
||
| 949 | $hooks[] = 'write'; |
||
| 950 | break; |
||
| 951 | case 'w': |
||
| 952 | case 'x': |
||
| 953 | case 'a': |
||
| 954 | $hooks[] = 'write'; |
||
| 955 | break; |
||
| 956 | default: |
||
| 957 | \OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR); |
||
| 958 | } |
||
| 959 | |||
| 960 | if ($mode !== 'r' && $mode !== 'w') { |
||
| 961 | \OC::$server->getLogger()->info('Trying to open a file with a mode other than "r" or "w" can cause severe performance issues with some backends'); |
||
| 962 | } |
||
| 963 | |||
| 964 | return $this->basicOperation('fopen', $path, $hooks, $mode); |
||
| 965 | } |
||
| 966 | |||
| 967 | /** |
||
| 968 | * @param string $path |
||
| 969 | * @return bool|string |
||
| 970 | * @throws \OCP\Files\InvalidPathException |
||
| 971 | */ |
||
| 972 | public function toTmpFile($path) { |
||
| 988 | |||
| 989 | /** |
||
| 990 | * @param string $tmpFile |
||
| 991 | * @param string $path |
||
| 992 | * @return bool|mixed |
||
| 993 | * @throws \OCP\Files\InvalidPathException |
||
| 994 | */ |
||
| 995 | public function fromTmpFile($tmpFile, $path) { |
||
| 1028 | |||
| 1029 | |||
| 1030 | /** |
||
| 1031 | * @param string $path |
||
| 1032 | * @return mixed |
||
| 1033 | * @throws \OCP\Files\InvalidPathException |
||
| 1034 | */ |
||
| 1035 | public function getMimeType($path) { |
||
| 1039 | |||
| 1040 | /** |
||
| 1041 | * @param string $type |
||
| 1042 | * @param string $path |
||
| 1043 | * @param bool $raw |
||
| 1044 | * @return bool|null|string |
||
| 1045 | */ |
||
| 1046 | public function hash($type, $path, $raw = false) { |
||
| 1069 | |||
| 1070 | /** |
||
| 1071 | * @param string $path |
||
| 1072 | * @return mixed |
||
| 1073 | * @throws \OCP\Files\InvalidPathException |
||
| 1074 | */ |
||
| 1075 | public function free_space($path = '/') { |
||
| 1079 | |||
| 1080 | /** |
||
| 1081 | * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage |
||
| 1082 | * |
||
| 1083 | * @param string $operation |
||
| 1084 | * @param string $path |
||
| 1085 | * @param array $hooks (optional) |
||
| 1086 | * @param mixed $extraParam (optional) |
||
| 1087 | * @return mixed |
||
| 1088 | * @throws \Exception |
||
| 1089 | * |
||
| 1090 | * This method takes requests for basic filesystem functions (e.g. reading & writing |
||
| 1091 | * files), processes hooks and proxies, sanitises paths, and finally passes them on to |
||
| 1092 | * \OC\Files\Storage\Storage for delegation to a storage backend for execution |
||
| 1093 | */ |
||
| 1094 | private function basicOperation($operation, $path, $hooks = [], $extraParam = null) { |
||
| 1095 | $postFix = (substr($path, -1, 1) === '/') ? '/' : ''; |
||
| 1096 | $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); |
||
| 1097 | if (Filesystem::isValidPath($path) |
||
| 1098 | and !Filesystem::isFileBlacklisted($path) |
||
| 1099 | ) { |
||
| 1100 | $path = $this->getRelativePath($absolutePath); |
||
| 1101 | if ($path == null) { |
||
| 1102 | return false; |
||
| 1103 | } |
||
| 1104 | |||
| 1105 | if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) { |
||
| 1106 | // always a shared lock during pre-hooks so the hook can read the file |
||
| 1107 | $this->lockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 1108 | } |
||
| 1109 | |||
| 1110 | $run = $this->runHooks($hooks, $path); |
||
| 1111 | /** @var \OC\Files\Storage\Storage $storage */ |
||
| 1112 | list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); |
||
| 1113 | if ($run and $storage) { |
||
| 1114 | if (in_array('write', $hooks) || in_array('delete', $hooks)) { |
||
| 1115 | $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE); |
||
| 1116 | } |
||
| 1117 | try { |
||
| 1118 | if (!is_null($extraParam)) { |
||
| 1119 | $result = $storage->$operation($internalPath, $extraParam); |
||
| 1120 | } else { |
||
| 1121 | $result = $storage->$operation($internalPath); |
||
| 1122 | } |
||
| 1123 | } catch (\Exception $e) { |
||
| 1124 | View Code Duplication | if (in_array('write', $hooks) || in_array('delete', $hooks)) { |
|
| 1125 | $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); |
||
| 1126 | } else if (in_array('read', $hooks)) { |
||
| 1127 | $this->unlockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 1128 | } |
||
| 1129 | throw $e; |
||
| 1130 | } |
||
| 1131 | |||
| 1132 | if ($result && in_array('delete', $hooks) and $result) { |
||
| 1133 | $this->removeUpdate($storage, $internalPath); |
||
| 1134 | } |
||
| 1135 | if ($result && in_array('write', $hooks) and $operation !== 'fopen') { |
||
| 1136 | $this->writeUpdate($storage, $internalPath); |
||
| 1137 | } |
||
| 1138 | if ($result && in_array('touch', $hooks)) { |
||
| 1139 | $this->writeUpdate($storage, $internalPath, $extraParam); |
||
| 1140 | } |
||
| 1141 | |||
| 1142 | if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) { |
||
| 1143 | $this->changeLock($path, ILockingProvider::LOCK_SHARED); |
||
| 1144 | } |
||
| 1145 | |||
| 1146 | $unlockLater = false; |
||
| 1147 | if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) { |
||
| 1148 | $unlockLater = true; |
||
| 1149 | $result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) { |
||
| 1150 | View Code Duplication | if (in_array('write', $hooks)) { |
|
| 1151 | $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE); |
||
| 1152 | } else if (in_array('read', $hooks)) { |
||
| 1153 | $this->unlockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 1154 | } |
||
| 1155 | }); |
||
| 1156 | } |
||
| 1157 | |||
| 1158 | if ($this->shouldEmitHooks($path) && $result !== false) { |
||
| 1159 | if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open |
||
| 1160 | $this->runHooks($hooks, $path, true); |
||
| 1161 | } |
||
| 1162 | } |
||
| 1163 | |||
| 1164 | View Code Duplication | if (!$unlockLater |
|
| 1165 | && (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) |
||
| 1166 | ) { |
||
| 1167 | $this->unlockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 1168 | } |
||
| 1169 | return $result; |
||
| 1170 | } else { |
||
| 1171 | $this->unlockFile($path, ILockingProvider::LOCK_SHARED); |
||
| 1172 | } |
||
| 1173 | } |
||
| 1174 | return null; |
||
| 1175 | } |
||
| 1176 | |||
| 1177 | /** |
||
| 1178 | * get the path relative to the default root for hook usage |
||
| 1179 | * |
||
| 1180 | * @param string $path |
||
| 1181 | * @return string |
||
| 1182 | */ |
||
| 1183 | private function getHookPath($path) { |
||
| 1189 | |||
| 1190 | private function shouldEmitHooks($path = '') { |
||
| 1212 | |||
| 1213 | /** |
||
| 1214 | * @param string[] $hooks |
||
| 1215 | * @param string $path |
||
| 1216 | * @param bool $post |
||
| 1217 | * @return bool |
||
| 1218 | */ |
||
| 1219 | private function runHooks($hooks, $path, $post = false) { |
||
| 1248 | |||
| 1249 | /** |
||
| 1250 | * check if a file or folder has been updated since $time |
||
| 1251 | * |
||
| 1252 | * @param string $path |
||
| 1253 | * @param int $time |
||
| 1254 | * @return bool |
||
| 1255 | */ |
||
| 1256 | public function hasUpdated($path, $time) { |
||
| 1259 | |||
| 1260 | /** |
||
| 1261 | * @param string $ownerId |
||
| 1262 | * @return \OC\User\User |
||
| 1263 | */ |
||
| 1264 | private function getUserObjectForOwner($ownerId) { |
||
| 1272 | |||
| 1273 | /** |
||
| 1274 | * Get file info from cache |
||
| 1275 | * |
||
| 1276 | * If the file is not in cached it will be scanned |
||
| 1277 | * If the file has changed on storage the cache will be updated |
||
| 1278 | * |
||
| 1279 | * @param \OC\Files\Storage\Storage $storage |
||
| 1280 | * @param string $internalPath |
||
| 1281 | * @param string $relativePath |
||
| 1282 | * @return array|bool |
||
| 1283 | */ |
||
| 1284 | private function getCacheEntry($storage, $internalPath, $relativePath) { |
||
| 1314 | |||
| 1315 | /** |
||
| 1316 | * get the filesystem info |
||
| 1317 | * |
||
| 1318 | * @param string $path |
||
| 1319 | * @param boolean|string $includeMountPoints true to add mountpoint sizes, |
||
| 1320 | * 'ext' to add only ext storage mount point sizes. Defaults to true. |
||
| 1321 | * defaults to true |
||
| 1322 | * @return \OC\Files\FileInfo|false False if file does not exist |
||
| 1323 | */ |
||
| 1324 | public function getFileInfo($path, $includeMountPoints = true) { |
||
| 1369 | |||
| 1370 | /** |
||
| 1371 | * get the content of a directory |
||
| 1372 | * |
||
| 1373 | * @param string $directory path under datadirectory |
||
| 1374 | * @param string $mimetype_filter limit returned content to this mimetype or mimepart |
||
| 1375 | * @return FileInfo[] |
||
| 1376 | */ |
||
| 1377 | public function getDirectoryContent($directory, $mimetype_filter = '') { |
||
| 1501 | |||
| 1502 | /** |
||
| 1503 | * change file metadata |
||
| 1504 | * |
||
| 1505 | * @param string $path |
||
| 1506 | * @param array|\OCP\Files\FileInfo $data |
||
| 1507 | * @return int |
||
| 1508 | * |
||
| 1509 | * returns the fileid of the updated file |
||
| 1510 | */ |
||
| 1511 | public function putFileInfo($path, $data) { |
||
| 1535 | |||
| 1536 | /** |
||
| 1537 | * search for files with the name matching $query |
||
| 1538 | * |
||
| 1539 | * @param string $query |
||
| 1540 | * @return FileInfo[] |
||
| 1541 | */ |
||
| 1542 | public function search($query) { |
||
| 1545 | |||
| 1546 | /** |
||
| 1547 | * search for files with the name matching $query |
||
| 1548 | * |
||
| 1549 | * @param string $query |
||
| 1550 | * @return FileInfo[] |
||
| 1551 | */ |
||
| 1552 | public function searchRaw($query) { |
||
| 1555 | |||
| 1556 | /** |
||
| 1557 | * search for files by mimetype |
||
| 1558 | * |
||
| 1559 | * @param string $mimetype |
||
| 1560 | * @return FileInfo[] |
||
| 1561 | */ |
||
| 1562 | public function searchByMime($mimetype) { |
||
| 1565 | |||
| 1566 | /** |
||
| 1567 | * search for files by tag |
||
| 1568 | * |
||
| 1569 | * @param string|int $tag name or tag id |
||
| 1570 | * @param string $userId owner of the tags |
||
| 1571 | * @return FileInfo[] |
||
| 1572 | */ |
||
| 1573 | public function searchByTag($tag, $userId) { |
||
| 1576 | |||
| 1577 | /** |
||
| 1578 | * @param string $method cache method |
||
| 1579 | * @param array $args |
||
| 1580 | * @return FileInfo[] |
||
| 1581 | */ |
||
| 1582 | private function searchCommon($method, $args) { |
||
| 1626 | |||
| 1627 | /** |
||
| 1628 | * Get the owner for a file or folder |
||
| 1629 | * |
||
| 1630 | * @param string $path |
||
| 1631 | * @return string the user id of the owner |
||
| 1632 | * @throws NotFoundException |
||
| 1633 | */ |
||
| 1634 | public function getOwner($path) { |
||
| 1641 | |||
| 1642 | /** |
||
| 1643 | * get the ETag for a file or folder |
||
| 1644 | * |
||
| 1645 | * @param string $path |
||
| 1646 | * @return string |
||
| 1647 | */ |
||
| 1648 | public function getETag($path) { |
||
| 1660 | |||
| 1661 | /** |
||
| 1662 | * Get the path of a file by id, relative to the view |
||
| 1663 | * |
||
| 1664 | * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file |
||
| 1665 | * |
||
| 1666 | * @param int $id |
||
| 1667 | * @throws NotFoundException |
||
| 1668 | * @return string |
||
| 1669 | */ |
||
| 1670 | public function getPath($id) { |
||
| 1695 | |||
| 1696 | /** |
||
| 1697 | * @param string $path |
||
| 1698 | * @throws InvalidPathException |
||
| 1699 | */ |
||
| 1700 | private function assertPathLength($path) { |
||
| 1709 | |||
| 1710 | /** |
||
| 1711 | * check if it is allowed to move a mount point to a given target. |
||
| 1712 | * It is not allowed to move a mount point into a different mount point or |
||
| 1713 | * into an already shared folder |
||
| 1714 | * |
||
| 1715 | * @param string $target path |
||
| 1716 | * @return boolean |
||
| 1717 | */ |
||
| 1718 | private function isTargetAllowed($target) { |
||
| 1753 | |||
| 1754 | /** |
||
| 1755 | * Get a fileinfo object for files that are ignored in the cache (part files) |
||
| 1756 | * |
||
| 1757 | * @param string $path |
||
| 1758 | * @return \OCP\Files\FileInfo |
||
| 1759 | */ |
||
| 1760 | private function getPartFileInfo($path) { |
||
| 1783 | |||
| 1784 | /** |
||
| 1785 | * @param string $path |
||
| 1786 | * @param string $fileName |
||
| 1787 | * @throws InvalidPathException |
||
| 1788 | */ |
||
| 1789 | public function verifyPath($path, $fileName) { |
||
| 1790 | try { |
||
| 1791 | /** @type \OCP\Files\Storage $storage */ |
||
| 1792 | list($storage, $internalPath) = $this->resolvePath($path); |
||
| 1793 | $storage->verifyPath($internalPath, $fileName); |
||
| 1794 | } catch (ReservedWordException $ex) { |
||
| 1795 | $l = \OC::$server->getL10N('lib'); |
||
| 1796 | throw new InvalidPathException($l->t('File name is a reserved word')); |
||
| 1797 | } catch (InvalidCharacterInPathException $ex) { |
||
| 1798 | $l = \OC::$server->getL10N('lib'); |
||
| 1799 | throw new InvalidPathException($l->t('File name contains at least one invalid character')); |
||
| 1800 | } catch (FileNameTooLongException $ex) { |
||
| 1801 | $l = \OC::$server->getL10N('lib'); |
||
| 1802 | throw new InvalidPathException($l->t('File name is too long')); |
||
| 1803 | } catch (InvalidDirectoryException $ex) { |
||
| 1804 | $l = \OC::$server->getL10N('lib'); |
||
| 1805 | throw new InvalidPathException($l->t('Dot files are not allowed')); |
||
| 1806 | } catch (EmptyFileNameException $ex) { |
||
| 1807 | $l = \OC::$server->getL10N('lib'); |
||
| 1808 | throw new InvalidPathException($l->t('Empty filename is not allowed')); |
||
| 1809 | } |
||
| 1810 | } |
||
| 1811 | |||
| 1812 | /** |
||
| 1813 | * get all parent folders of $path |
||
| 1814 | * |
||
| 1815 | * @param string $path |
||
| 1816 | * @return string[] |
||
| 1817 | */ |
||
| 1818 | private function getParents($path) { |
||
| 1819 | $path = trim($path, '/'); |
||
| 1820 | if (!$path) { |
||
| 1821 | return []; |
||
| 1822 | } |
||
| 1823 | |||
| 1824 | $parts = explode('/', $path); |
||
| 1825 | |||
| 1826 | // remove the single file |
||
| 1827 | array_pop($parts); |
||
| 1828 | $result = array('/'); |
||
| 1829 | $resultPath = ''; |
||
| 1838 | |||
| 1839 | /** |
||
| 1840 | * Returns the mount point for which to lock |
||
| 1841 | * |
||
| 1842 | * @param string $absolutePath absolute path |
||
| 1843 | * @param bool $useParentMount true to return parent mount instead of whatever |
||
| 1844 | * is mounted directly on the given path, false otherwise |
||
| 1845 | * @return \OC\Files\Mount\MountPoint mount point for which to apply locks |
||
| 1846 | */ |
||
| 1847 | private function getMountForLock($absolutePath, $useParentMount = false) { |
||
| 1865 | |||
| 1866 | /** |
||
| 1867 | * Lock the given path |
||
| 1868 | * |
||
| 1869 | * @param string $path the path of the file to lock, relative to the view |
||
| 1870 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1871 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1872 | * |
||
| 1873 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1874 | * @throws \OCP\Lock\LockedException if the path is already locked |
||
| 1875 | */ |
||
| 1876 | View Code Duplication | private function lockPath($path, $type, $lockMountPoint = false) { |
|
| 1905 | |||
| 1906 | /** |
||
| 1907 | * Change the lock type |
||
| 1908 | * |
||
| 1909 | * @param string $path the path of the file to lock, relative to the view |
||
| 1910 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1911 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1912 | * |
||
| 1913 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1914 | * @throws \OCP\Lock\LockedException if the path is already locked |
||
| 1915 | */ |
||
| 1916 | View Code Duplication | public function changeLock($path, $type, $lockMountPoint = false) { |
|
| 1946 | |||
| 1947 | /** |
||
| 1948 | * Unlock the given path |
||
| 1949 | * |
||
| 1950 | * @param string $path the path of the file to unlock, 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 | private function unlockPath($path, $type, $lockMountPoint = false) { |
||
| 1977 | |||
| 1978 | /** |
||
| 1979 | * Lock a path and all its parents up to the root of the view |
||
| 1980 | * |
||
| 1981 | * @param string $path the path of the file to lock relative to the view |
||
| 1982 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 1983 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 1984 | * |
||
| 1985 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 1986 | */ |
||
| 1987 | View Code Duplication | public function lockFile($path, $type, $lockMountPoint = false) { |
|
| 2003 | |||
| 2004 | /** |
||
| 2005 | * Unlock a path and all its parents up to the root of the view |
||
| 2006 | * |
||
| 2007 | * @param string $path the path of the file to lock relative to the view |
||
| 2008 | * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
||
| 2009 | * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage |
||
| 2010 | * |
||
| 2011 | * @return bool False if the path is excluded from locking, true otherwise |
||
| 2012 | */ |
||
| 2013 | View Code Duplication | public function unlockFile($path, $type, $lockMountPoint = false) { |
|
| 2029 | |||
| 2030 | /** |
||
| 2031 | * Only lock files in data/user/files/ |
||
| 2032 | * |
||
| 2033 | * @param string $path Absolute path to the file/folder we try to (un)lock |
||
| 2034 | * @return bool |
||
| 2035 | */ |
||
| 2036 | protected function shouldLockFile($path) { |
||
| 2047 | |||
| 2048 | /** |
||
| 2049 | * Shortens the given absolute path to be relative to |
||
| 2050 | * "$user/files". |
||
| 2051 | * |
||
| 2052 | * @param string $absolutePath absolute path which is under "files" |
||
| 2053 | * |
||
| 2054 | * @return string path relative to "files" with trimmed slashes or null |
||
| 2055 | * if the path was NOT relative to files |
||
| 2056 | * |
||
| 2057 | * @throws \InvalidArgumentException if the given path was not under "files" |
||
| 2058 | * @since 8.1.0 |
||
| 2059 | */ |
||
| 2060 | public function getPathRelativeToFiles($absolutePath) { |
||
| 2072 | |||
| 2073 | /** |
||
| 2074 | * @param string $filename |
||
| 2075 | * @return array |
||
| 2076 | * @throws \OC\User\NoUserException |
||
| 2077 | * @throws NotFoundException |
||
| 2078 | */ |
||
| 2079 | public function getUidAndFilename($filename) { |
||
| 2096 | |||
| 2097 | /** |
||
| 2098 | * Creates parent non-existing folders |
||
| 2099 | * |
||
| 2100 | * @param string $filePath |
||
| 2101 | * @return bool |
||
| 2102 | */ |
||
| 2103 | private function createParentDirectories($filePath) { |
||
| 2119 | } |
||
| 2120 |
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.