ObjectTree.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-only
  6. */
  7. namespace OCA\DAV\Connector\Sabre;
  8. use OC\Files\FileInfo;
  9. use OC\Files\Storage\FailedStorage;
  10. use OC\Files\Storage\Storage;
  11. use OC\Files\View;
  12. use OCA\DAV\Connector\Sabre\Exception\FileLocked;
  13. use OCA\DAV\Connector\Sabre\Exception\Forbidden;
  14. use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
  15. use OCP\Files\ForbiddenException;
  16. use OCP\Files\InvalidPathException;
  17. use OCP\Files\Mount\IMountManager;
  18. use OCP\Files\StorageInvalidException;
  19. use OCP\Files\StorageNotAvailableException;
  20. use OCP\Lock\LockedException;
  21. class ObjectTree extends CachingTree {
  22. /**
  23. * @var View
  24. */
  25. protected $fileView;
  26. /**
  27. * @var IMountManager
  28. */
  29. protected $mountManager;
  30. /**
  31. * Creates the object
  32. */
  33. public function __construct() {
  34. }
  35. /**
  36. * @param \Sabre\DAV\INode $rootNode
  37. * @param View $view
  38. * @param IMountManager $mountManager
  39. */
  40. public function init(\Sabre\DAV\INode $rootNode, View $view, IMountManager $mountManager) {
  41. $this->rootNode = $rootNode;
  42. $this->fileView = $view;
  43. $this->mountManager = $mountManager;
  44. }
  45. /**
  46. * Returns the INode object for the requested path
  47. *
  48. * @param string $path
  49. * @return \Sabre\DAV\INode
  50. * @throws InvalidPath
  51. * @throws \Sabre\DAV\Exception\Locked
  52. * @throws \Sabre\DAV\Exception\NotFound
  53. * @throws \Sabre\DAV\Exception\ServiceUnavailable
  54. */
  55. public function getNodeForPath($path) {
  56. if (!$this->fileView) {
  57. throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup');
  58. }
  59. $path = trim($path, '/');
  60. if (isset($this->cache[$path])) {
  61. return $this->cache[$path];
  62. }
  63. if ($path) {
  64. try {
  65. $this->fileView->verifyPath($path, basename($path));
  66. } catch (InvalidPathException $ex) {
  67. throw new InvalidPath($ex->getMessage());
  68. }
  69. }
  70. // Is it the root node?
  71. if (!strlen($path)) {
  72. return $this->rootNode;
  73. }
  74. if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
  75. // read from storage
  76. $absPath = $this->fileView->getAbsolutePath($path);
  77. $mount = $this->fileView->getMount($path);
  78. $storage = $mount->getStorage();
  79. $internalPath = $mount->getInternalPath($absPath);
  80. if ($storage && $storage->file_exists($internalPath)) {
  81. /**
  82. * @var Storage $storage
  83. */
  84. // get data directly
  85. $data = $storage->getMetaData($internalPath);
  86. $info = new FileInfo($absPath, $storage, $internalPath, $data, $mount);
  87. } else {
  88. $info = null;
  89. }
  90. } else {
  91. // read from cache
  92. try {
  93. $info = $this->fileView->getFileInfo($path);
  94. if ($info instanceof \OCP\Files\FileInfo && $info->getStorage()->instanceOfStorage(FailedStorage::class)) {
  95. throw new StorageNotAvailableException();
  96. }
  97. } catch (StorageNotAvailableException $e) {
  98. throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage is temporarily not available', 0, $e);
  99. } catch (StorageInvalidException $e) {
  100. throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid');
  101. } catch (LockedException $e) {
  102. throw new \Sabre\DAV\Exception\Locked();
  103. } catch (ForbiddenException $e) {
  104. throw new \Sabre\DAV\Exception\Forbidden();
  105. }
  106. }
  107. if (!$info) {
  108. throw new \Sabre\DAV\Exception\NotFound('File with name ' . $path . ' could not be located');
  109. }
  110. if ($info->getType() === 'dir') {
  111. $node = new Directory($this->fileView, $info, $this);
  112. } else {
  113. $node = new File($this->fileView, $info);
  114. }
  115. $this->cache[$path] = $node;
  116. return $node;
  117. }
  118. /**
  119. * Copies a file or directory.
  120. *
  121. * This method must work recursively and delete the destination
  122. * if it exists
  123. *
  124. * @param string $sourcePath
  125. * @param string $destinationPath
  126. * @throws FileLocked
  127. * @throws Forbidden
  128. * @throws InvalidPath
  129. * @throws \Exception
  130. * @throws \Sabre\DAV\Exception\Forbidden
  131. * @throws \Sabre\DAV\Exception\Locked
  132. * @throws \Sabre\DAV\Exception\NotFound
  133. * @throws \Sabre\DAV\Exception\ServiceUnavailable
  134. * @return void
  135. */
  136. public function copy($sourcePath, $destinationPath) {
  137. if (!$this->fileView) {
  138. throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup');
  139. }
  140. $info = $this->fileView->getFileInfo(dirname($destinationPath));
  141. if ($this->fileView->file_exists($destinationPath)) {
  142. $destinationPermission = $info && $info->isUpdateable();
  143. } else {
  144. $destinationPermission = $info && $info->isCreatable();
  145. }
  146. if (!$destinationPermission) {
  147. throw new Forbidden('No permissions to copy object.');
  148. }
  149. // this will trigger existence check
  150. $this->getNodeForPath($sourcePath);
  151. [$destinationDir, $destinationName] = \Sabre\Uri\split($destinationPath);
  152. try {
  153. $this->fileView->verifyPath($destinationDir, $destinationName);
  154. } catch (InvalidPathException $ex) {
  155. throw new InvalidPath($ex->getMessage());
  156. }
  157. try {
  158. $this->fileView->copy($sourcePath, $destinationPath);
  159. } catch (StorageNotAvailableException $e) {
  160. throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
  161. } catch (ForbiddenException $ex) {
  162. throw new Forbidden($ex->getMessage(), $ex->getRetry());
  163. } catch (LockedException $e) {
  164. throw new FileLocked($e->getMessage(), $e->getCode(), $e);
  165. }
  166. [$destinationDir,] = \Sabre\Uri\split($destinationPath);
  167. $this->markDirty($destinationDir);
  168. }
  169. }