1<?php 2/** 3 * @author Bernhard Posselt <dev@bernhard-posselt.com> 4 * @author Joas Schilling <coding@schilljs.com> 5 * @author Jörn Friedrich Dreyer <jfd@butonic.de> 6 * @author Morris Jobke <hey@morrisjobke.de> 7 * @author Robin Appelman <icewind@owncloud.com> 8 * @author Roeland Jago Douma <rullzer@owncloud.com> 9 * @author Stefan Weil <sw@weilnetz.de> 10 * @author Thomas Müller <thomas.mueller@tmit.eu> 11 * @author Vincent Petry <pvince81@owncloud.com> 12 * 13 * @copyright Copyright (c) 2018, ownCloud GmbH 14 * @license AGPL-3.0 15 * 16 * This code is free software: you can redistribute it and/or modify 17 * it under the terms of the GNU Affero General Public License, version 3, 18 * as published by the Free Software Foundation. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU Affero General Public License for more details. 24 * 25 * You should have received a copy of the GNU Affero General Public License, version 3, 26 * along with this program. If not, see <http://www.gnu.org/licenses/> 27 * 28 */ 29 30namespace OC\Files\Node; 31 32use OC\Files\Meta\MetaRootNode; 33use OC\Files\Mount\MountPoint; 34use OC\User\NoUserException; 35use OCP\Constants; 36use OCP\Files\NotFoundException; 37use OCP\Files\NotPermittedException; 38use OC\Hooks\PublicEmitter; 39use OCP\Files\IRootFolder; 40 41/** 42 * Class Root 43 * 44 * Hooks available in scope \OC\Files 45 * - preWrite(\OCP\Files\Node $node) 46 * - postWrite(\OCP\Files\Node $node) 47 * - preCreate(\OCP\Files\Node $node) 48 * - postCreate(\OCP\Files\Node $node) 49 * - preDelete(\OCP\Files\Node $node) 50 * - postDelete(\OCP\Files\Node $node) 51 * - preTouch(\OC\FilesP\Node $node, int $mtime) 52 * - postTouch(\OCP\Files\Node $node) 53 * - preCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) 54 * - postCopy(\OCP\Files\Node $source, \OCP\Files\Node $target) 55 * - preRename(\OCP\Files\Node $source, \OCP\Files\Node $target) 56 * - postRename(\OCP\Files\Node $source, \OCP\Files\Node $target) 57 * 58 * @package OC\Files\Node 59 */ 60class Root extends Folder implements IRootFolder { 61 62 /** 63 * @var \OC\Files\Mount\Manager $mountManager 64 */ 65 private $mountManager; 66 67 /** 68 * @var \OC\Hooks\PublicEmitter 69 */ 70 private $emitter; 71 72 /** 73 * @var \OC\User\User $user 74 */ 75 private $user; 76 77 /** 78 * @param \OC\Files\Mount\Manager $manager 79 * @param \OC\Files\View $view 80 * @param \OC\User\User|null $user 81 */ 82 public function __construct($manager, $view, $user) { 83 parent::__construct($this, $view, ''); 84 $this->mountManager = $manager; 85 $this->user = $user; 86 $this->emitter = new PublicEmitter(); 87 } 88 89 /** 90 * Get the user for which the filesystem is setup 91 * 92 * @return \OC\User\User 93 */ 94 public function getUser() { 95 return $this->user; 96 } 97 98 /** 99 * @param string $scope 100 * @param string $method 101 * @param callable $callback 102 */ 103 public function listen($scope, $method, callable $callback) { 104 $this->emitter->listen($scope, $method, $callback); 105 } 106 107 /** 108 * @param string $scope optional 109 * @param string $method optional 110 * @param callable $callback optional 111 */ 112 public function removeListener($scope = null, $method = null, callable $callback = null) { 113 $this->emitter->removeListener($scope, $method, $callback); 114 } 115 116 /** 117 * @param string $scope 118 * @param string $method 119 * @param Node[] $arguments 120 */ 121 public function emit($scope, $method, $arguments = []) { 122 $this->emitter->emit($scope, $method, $arguments); 123 } 124 125 /** 126 * @param \OC\Files\Storage\Storage $storage 127 * @param string $mountPoint 128 * @param array $arguments 129 */ 130 public function mount($storage, $mountPoint, $arguments = []) { 131 $mount = new MountPoint($storage, $mountPoint, $arguments); 132 $this->mountManager->addMount($mount); 133 } 134 135 /** 136 * @param string $mountPoint 137 * @return \OC\Files\Mount\MountPoint 138 */ 139 public function getMount($mountPoint) { 140 return $this->mountManager->find($mountPoint); 141 } 142 143 /** 144 * @param string $mountPoint 145 * @return \OC\Files\Mount\MountPoint[] 146 */ 147 public function getMountsIn($mountPoint) { 148 return $this->mountManager->findIn($mountPoint); 149 } 150 151 /** 152 * @param string $storageId 153 * @return \OC\Files\Mount\MountPoint[] 154 */ 155 public function getMountByStorageId($storageId) { 156 return $this->mountManager->findByStorageId($storageId); 157 } 158 159 /** 160 * @param int $numericId 161 * @return MountPoint[] 162 */ 163 public function getMountByNumericStorageId($numericId) { 164 return $this->mountManager->findByNumericId($numericId); 165 } 166 167 /** 168 * @param \OC\Files\Mount\MountPoint $mount 169 */ 170 public function unMount($mount) { 171 // ToDo: why doesn't this call removeMount ? 172 /* @phan-suppress-next-line PhanUndeclaredMethod */ 173 $this->mountManager->remove($mount); 174 } 175 176 /** 177 * @param string $path 178 * @throws \OCP\Files\NotFoundException 179 * @throws \OCP\Files\NotPermittedException 180 * @return File|Folder 181 */ 182 public function get($path) { 183 $path = $this->normalizePath($path); 184 if ($this->isValidPath($path)) { 185 $fullPath = $this->getFullPath($path); 186 $virtualNode = $this->resolveVirtualNode($fullPath); 187 if ($virtualNode !== null) { 188 return $virtualNode; 189 } 190 $fileExists = $this->view->file_exists($fullPath); 191 if ($fileExists) { 192 return $this->createNode($fullPath); 193 } else { 194 // try getting the fileinfo in case we have data in the filecache 195 $fileInfo = $this->view->getFileInfo($fullPath); 196 if (!$fileInfo) { 197 throw new NotFoundException($path); 198 } 199 return $this->createNode($fullPath, $fileInfo); 200 } 201 } else { 202 throw new NotPermittedException(); 203 } 204 } 205 206 //most operations can't be done on the root 207 208 /** 209 * @param string $targetPath 210 * @throws \OCP\Files\NotPermittedException 211 * @return \OC\Files\Node\Node 212 */ 213 public function rename($targetPath) { 214 throw new NotPermittedException(); 215 } 216 217 public function delete() { 218 throw new NotPermittedException(); 219 } 220 221 /** 222 * @param string $targetPath 223 * @throws \OCP\Files\NotPermittedException 224 * @return \OC\Files\Node\Node 225 */ 226 public function copy($targetPath) { 227 throw new NotPermittedException(); 228 } 229 230 /** 231 * @param int $mtime 232 * @throws \OCP\Files\NotPermittedException 233 */ 234 public function touch($mtime = null) { 235 throw new NotPermittedException(); 236 } 237 238 /** 239 * @return \OC\Files\Storage\Storage 240 * @throws \OCP\Files\NotFoundException 241 */ 242 public function getStorage() { 243 throw new NotFoundException(); 244 } 245 246 /** 247 * @return string 248 */ 249 public function getPath() { 250 return '/'; 251 } 252 253 /** 254 * @return string 255 */ 256 public function getInternalPath() { 257 return ''; 258 } 259 260 /** 261 * @return int 262 */ 263 public function getId() { 264 return null; 265 } 266 267 /** 268 * @return array 269 */ 270 public function stat() { 271 return null; 272 } 273 274 /** 275 * @return int 276 */ 277 public function getMTime() { 278 return null; 279 } 280 281 /** 282 * @return int 283 */ 284 public function getSize() { 285 return null; 286 } 287 288 /** 289 * @return string 290 */ 291 public function getEtag() { 292 return null; 293 } 294 295 /** 296 * @return int 297 */ 298 public function getPermissions() { 299 return Constants::PERMISSION_CREATE; 300 } 301 302 /** 303 * @return bool 304 */ 305 public function isReadable() { 306 return false; 307 } 308 309 /** 310 * @return bool 311 */ 312 public function isUpdateable() { 313 return false; 314 } 315 316 /** 317 * @return bool 318 */ 319 public function isDeletable() { 320 return false; 321 } 322 323 /** 324 * @return bool 325 */ 326 public function isShareable() { 327 return false; 328 } 329 330 /** 331 * @return Node 332 * @throws \OCP\Files\NotFoundException 333 */ 334 public function getParent() { 335 throw new NotFoundException(); 336 } 337 338 /** 339 * @return string 340 */ 341 public function getName() { 342 return ''; 343 } 344 345 /** 346 * Returns a view to user's files folder 347 * 348 * @param String $userId user ID 349 * @return \OCP\Files\Folder 350 * @throws NoUserException 351 */ 352 public function getUserFolder($userId) { 353 $userObject = \OC::$server->getUserManager()->get($userId); 354 355 if ($userObject === null) { 356 $msg = "Backends provided no user object for $userId"; 357 \OC::$server->getLogger()->error($msg, ['app' => __CLASS__]); 358 throw new NoUserException($msg); 359 } 360 361 $userId = $userObject->getUID(); 362 363 \OC\Files\Filesystem::initMountPoints($userId); 364 $dir = '/' . $userId; 365 $folder = null; 366 367 try { 368 $folder = $this->get($dir); 369 } catch (NotFoundException $e) { 370 $folder = $this->newFolder($dir); 371 } 372 373 $dir = '/files'; 374 try { 375 $folder = $folder->get($dir); 376 } catch (NotFoundException $e) { 377 '@phan-var \OC\Files\Node\Folder $folder'; 378 $folder = $folder->newFolder($dir); 379 } 380 381 return $folder; 382 } 383 384 private function resolveVirtualNode($fullPath) { 385 $pieces = \explode('/', $fullPath); 386 if ($pieces[1] !== 'meta') { 387 return null; 388 } 389 \array_shift($pieces); 390 \array_shift($pieces); 391 $userSession = \OC::$server->getUserSession(); 392 $node = new MetaRootNode($this, $userSession); 393 if (empty($pieces)) { 394 return $node; 395 } 396 return $node->get(\implode('/', $pieces)); 397 } 398} 399