@@ -36,230 +36,230 @@ |
||
| 36 | 36 | * Shared mount points can be moved by the user |
| 37 | 37 | */ |
| 38 | 38 | class SharedMount extends MountPoint implements MoveableMount { |
| 39 | - /** |
|
| 40 | - * @var \OCA\Files_Sharing\SharedStorage $storage |
|
| 41 | - */ |
|
| 42 | - protected $storage = null; |
|
| 43 | - |
|
| 44 | - /** |
|
| 45 | - * @var \OC\Files\View |
|
| 46 | - */ |
|
| 47 | - private $recipientView; |
|
| 48 | - |
|
| 49 | - /** |
|
| 50 | - * @var string |
|
| 51 | - */ |
|
| 52 | - private $user; |
|
| 53 | - |
|
| 54 | - /** @var \OCP\Share\IShare */ |
|
| 55 | - private $superShare; |
|
| 56 | - |
|
| 57 | - /** @var \OCP\Share\IShare[] */ |
|
| 58 | - private $groupedShares; |
|
| 59 | - |
|
| 60 | - /** |
|
| 61 | - * @param string $storage |
|
| 62 | - * @param SharedMount[] $mountpoints |
|
| 63 | - * @param array|null $arguments |
|
| 64 | - * @param \OCP\Files\Storage\IStorageFactory $loader |
|
| 65 | - */ |
|
| 66 | - public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) { |
|
| 67 | - $this->user = $arguments['user']; |
|
| 68 | - $this->recipientView = new View('/' . $this->user . '/files'); |
|
| 69 | - |
|
| 70 | - $this->superShare = $arguments['superShare']; |
|
| 71 | - $this->groupedShares = $arguments['groupedShares']; |
|
| 72 | - |
|
| 73 | - $newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints); |
|
| 74 | - $absMountPoint = '/' . $this->user . '/files' . $newMountPoint; |
|
| 75 | - $arguments['ownerView'] = new View('/' . $this->superShare->getShareOwner() . '/files'); |
|
| 76 | - parent::__construct($storage, $absMountPoint, $arguments, $loader); |
|
| 77 | - } |
|
| 78 | - |
|
| 79 | - /** |
|
| 80 | - * check if the parent folder exists otherwise move the mount point up |
|
| 81 | - * |
|
| 82 | - * @param \OCP\Share\IShare $share |
|
| 83 | - * @param SharedMount[] $mountpoints |
|
| 84 | - * @return string |
|
| 85 | - */ |
|
| 86 | - private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints) { |
|
| 87 | - |
|
| 88 | - $mountPoint = basename($share->getTarget()); |
|
| 89 | - $parent = dirname($share->getTarget()); |
|
| 90 | - |
|
| 91 | - if (!$this->recipientView->is_dir($parent)) { |
|
| 92 | - $parent = Helper::getShareFolder($this->recipientView); |
|
| 93 | - } |
|
| 94 | - |
|
| 95 | - $newMountPoint = $this->generateUniqueTarget( |
|
| 96 | - \OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint), |
|
| 97 | - $this->recipientView, |
|
| 98 | - $mountpoints |
|
| 99 | - ); |
|
| 100 | - |
|
| 101 | - if ($newMountPoint !== $share->getTarget()) { |
|
| 102 | - $this->updateFileTarget($newMountPoint, $share); |
|
| 103 | - } |
|
| 104 | - |
|
| 105 | - return $newMountPoint; |
|
| 106 | - } |
|
| 107 | - |
|
| 108 | - /** |
|
| 109 | - * update fileTarget in the database if the mount point changed |
|
| 110 | - * |
|
| 111 | - * @param string $newPath |
|
| 112 | - * @param \OCP\Share\IShare $share |
|
| 113 | - * @return bool |
|
| 114 | - */ |
|
| 115 | - private function updateFileTarget($newPath, &$share) { |
|
| 116 | - $share->setTarget($newPath); |
|
| 117 | - |
|
| 118 | - foreach ($this->groupedShares as $tmpShare) { |
|
| 119 | - $tmpShare->setTarget($newPath); |
|
| 120 | - \OC::$server->getShareManager()->moveShare($tmpShare, $this->user); |
|
| 121 | - } |
|
| 122 | - } |
|
| 123 | - |
|
| 124 | - |
|
| 125 | - /** |
|
| 126 | - * @param string $path |
|
| 127 | - * @param View $view |
|
| 128 | - * @param SharedMount[] $mountpoints |
|
| 129 | - * @return mixed |
|
| 130 | - */ |
|
| 131 | - private function generateUniqueTarget($path, $view, array $mountpoints) { |
|
| 132 | - $pathinfo = pathinfo($path); |
|
| 133 | - $ext = (isset($pathinfo['extension'])) ? '.' . $pathinfo['extension'] : ''; |
|
| 134 | - $name = $pathinfo['filename']; |
|
| 135 | - $dir = $pathinfo['dirname']; |
|
| 136 | - |
|
| 137 | - // Helper function to find existing mount points |
|
| 138 | - $mountpointExists = function ($path) use ($mountpoints) { |
|
| 139 | - foreach ($mountpoints as $mountpoint) { |
|
| 140 | - if ($mountpoint->getShare()->getTarget() === $path) { |
|
| 141 | - return true; |
|
| 142 | - } |
|
| 143 | - } |
|
| 144 | - return false; |
|
| 145 | - }; |
|
| 146 | - |
|
| 147 | - $i = 2; |
|
| 148 | - while ($view->file_exists($path) || $mountpointExists($path)) { |
|
| 149 | - $path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext); |
|
| 150 | - $i++; |
|
| 151 | - } |
|
| 152 | - |
|
| 153 | - return $path; |
|
| 154 | - } |
|
| 155 | - |
|
| 156 | - /** |
|
| 157 | - * Format a path to be relative to the /user/files/ directory |
|
| 158 | - * |
|
| 159 | - * @param string $path the absolute path |
|
| 160 | - * @return string e.g. turns '/admin/files/test.txt' into '/test.txt' |
|
| 161 | - * @throws \OCA\Files_Sharing\Exceptions\BrokenPath |
|
| 162 | - */ |
|
| 163 | - protected function stripUserFilesPath($path) { |
|
| 164 | - $trimmed = ltrim($path, '/'); |
|
| 165 | - $split = explode('/', $trimmed); |
|
| 166 | - |
|
| 167 | - // it is not a file relative to data/user/files |
|
| 168 | - if (count($split) < 3 || $split[1] !== 'files') { |
|
| 169 | - \OCP\Util::writeLog('file sharing', |
|
| 170 | - 'Can not strip userid and "files/" from path: ' . $path, |
|
| 171 | - \OCP\Util::ERROR); |
|
| 172 | - throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10); |
|
| 173 | - } |
|
| 174 | - |
|
| 175 | - // skip 'user' and 'files' |
|
| 176 | - $sliced = array_slice($split, 2); |
|
| 177 | - $relPath = implode('/', $sliced); |
|
| 178 | - |
|
| 179 | - return '/' . $relPath; |
|
| 180 | - } |
|
| 181 | - |
|
| 182 | - /** |
|
| 183 | - * Move the mount point to $target |
|
| 184 | - * |
|
| 185 | - * @param string $target the target mount point |
|
| 186 | - * @return bool |
|
| 187 | - */ |
|
| 188 | - public function moveMount($target) { |
|
| 189 | - |
|
| 190 | - $relTargetPath = $this->stripUserFilesPath($target); |
|
| 191 | - $share = $this->storage->getShare(); |
|
| 192 | - |
|
| 193 | - $result = true; |
|
| 194 | - |
|
| 195 | - try { |
|
| 196 | - $this->updateFileTarget($relTargetPath, $share); |
|
| 197 | - $this->setMountPoint($target); |
|
| 198 | - $this->storage->setMountPoint($relTargetPath); |
|
| 199 | - } catch (\Exception $e) { |
|
| 200 | - \OCP\Util::writeLog('file sharing', |
|
| 201 | - 'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"', |
|
| 202 | - \OCP\Util::ERROR); |
|
| 203 | - } |
|
| 204 | - |
|
| 205 | - return $result; |
|
| 206 | - } |
|
| 207 | - |
|
| 208 | - /** |
|
| 209 | - * Remove the mount points |
|
| 210 | - * |
|
| 211 | - * @return bool |
|
| 212 | - */ |
|
| 213 | - public function removeMount() { |
|
| 214 | - $mountManager = \OC\Files\Filesystem::getMountManager(); |
|
| 215 | - /** @var $storage \OCA\Files_Sharing\SharedStorage */ |
|
| 216 | - $storage = $this->getStorage(); |
|
| 217 | - $result = $storage->unshareStorage(); |
|
| 218 | - $mountManager->removeMount($this->mountPoint); |
|
| 219 | - |
|
| 220 | - return $result; |
|
| 221 | - } |
|
| 222 | - |
|
| 223 | - /** |
|
| 224 | - * @return \OCP\Share\IShare |
|
| 225 | - */ |
|
| 226 | - public function getShare() { |
|
| 227 | - return $this->superShare; |
|
| 228 | - } |
|
| 229 | - |
|
| 230 | - /** |
|
| 231 | - * Get the file id of the root of the storage |
|
| 232 | - * |
|
| 233 | - * @return int |
|
| 234 | - */ |
|
| 235 | - public function getStorageRootId() { |
|
| 236 | - return $this->getShare()->getNodeId(); |
|
| 237 | - } |
|
| 238 | - |
|
| 239 | - /** |
|
| 240 | - * @return int |
|
| 241 | - */ |
|
| 242 | - public function getNumericStorageId() { |
|
| 243 | - if (!is_null($this->getShare()->getNodeCacheEntry())) { |
|
| 244 | - return $this->getShare()->getNodeCacheEntry()->getStorageId(); |
|
| 245 | - } else { |
|
| 246 | - $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); |
|
| 247 | - |
|
| 248 | - $query = $builder->select('storage') |
|
| 249 | - ->from('filecache') |
|
| 250 | - ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($this->getStorageRootId()))); |
|
| 251 | - |
|
| 252 | - $result = $query->execute(); |
|
| 253 | - $row = $result->fetch(); |
|
| 254 | - $result->closeCursor(); |
|
| 255 | - if ($row) { |
|
| 256 | - return (int)$row['storage']; |
|
| 257 | - } |
|
| 258 | - return -1; |
|
| 259 | - } |
|
| 260 | - } |
|
| 261 | - |
|
| 262 | - public function getMountType() { |
|
| 263 | - return 'shared'; |
|
| 264 | - } |
|
| 39 | + /** |
|
| 40 | + * @var \OCA\Files_Sharing\SharedStorage $storage |
|
| 41 | + */ |
|
| 42 | + protected $storage = null; |
|
| 43 | + |
|
| 44 | + /** |
|
| 45 | + * @var \OC\Files\View |
|
| 46 | + */ |
|
| 47 | + private $recipientView; |
|
| 48 | + |
|
| 49 | + /** |
|
| 50 | + * @var string |
|
| 51 | + */ |
|
| 52 | + private $user; |
|
| 53 | + |
|
| 54 | + /** @var \OCP\Share\IShare */ |
|
| 55 | + private $superShare; |
|
| 56 | + |
|
| 57 | + /** @var \OCP\Share\IShare[] */ |
|
| 58 | + private $groupedShares; |
|
| 59 | + |
|
| 60 | + /** |
|
| 61 | + * @param string $storage |
|
| 62 | + * @param SharedMount[] $mountpoints |
|
| 63 | + * @param array|null $arguments |
|
| 64 | + * @param \OCP\Files\Storage\IStorageFactory $loader |
|
| 65 | + */ |
|
| 66 | + public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) { |
|
| 67 | + $this->user = $arguments['user']; |
|
| 68 | + $this->recipientView = new View('/' . $this->user . '/files'); |
|
| 69 | + |
|
| 70 | + $this->superShare = $arguments['superShare']; |
|
| 71 | + $this->groupedShares = $arguments['groupedShares']; |
|
| 72 | + |
|
| 73 | + $newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints); |
|
| 74 | + $absMountPoint = '/' . $this->user . '/files' . $newMountPoint; |
|
| 75 | + $arguments['ownerView'] = new View('/' . $this->superShare->getShareOwner() . '/files'); |
|
| 76 | + parent::__construct($storage, $absMountPoint, $arguments, $loader); |
|
| 77 | + } |
|
| 78 | + |
|
| 79 | + /** |
|
| 80 | + * check if the parent folder exists otherwise move the mount point up |
|
| 81 | + * |
|
| 82 | + * @param \OCP\Share\IShare $share |
|
| 83 | + * @param SharedMount[] $mountpoints |
|
| 84 | + * @return string |
|
| 85 | + */ |
|
| 86 | + private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints) { |
|
| 87 | + |
|
| 88 | + $mountPoint = basename($share->getTarget()); |
|
| 89 | + $parent = dirname($share->getTarget()); |
|
| 90 | + |
|
| 91 | + if (!$this->recipientView->is_dir($parent)) { |
|
| 92 | + $parent = Helper::getShareFolder($this->recipientView); |
|
| 93 | + } |
|
| 94 | + |
|
| 95 | + $newMountPoint = $this->generateUniqueTarget( |
|
| 96 | + \OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint), |
|
| 97 | + $this->recipientView, |
|
| 98 | + $mountpoints |
|
| 99 | + ); |
|
| 100 | + |
|
| 101 | + if ($newMountPoint !== $share->getTarget()) { |
|
| 102 | + $this->updateFileTarget($newMountPoint, $share); |
|
| 103 | + } |
|
| 104 | + |
|
| 105 | + return $newMountPoint; |
|
| 106 | + } |
|
| 107 | + |
|
| 108 | + /** |
|
| 109 | + * update fileTarget in the database if the mount point changed |
|
| 110 | + * |
|
| 111 | + * @param string $newPath |
|
| 112 | + * @param \OCP\Share\IShare $share |
|
| 113 | + * @return bool |
|
| 114 | + */ |
|
| 115 | + private function updateFileTarget($newPath, &$share) { |
|
| 116 | + $share->setTarget($newPath); |
|
| 117 | + |
|
| 118 | + foreach ($this->groupedShares as $tmpShare) { |
|
| 119 | + $tmpShare->setTarget($newPath); |
|
| 120 | + \OC::$server->getShareManager()->moveShare($tmpShare, $this->user); |
|
| 121 | + } |
|
| 122 | + } |
|
| 123 | + |
|
| 124 | + |
|
| 125 | + /** |
|
| 126 | + * @param string $path |
|
| 127 | + * @param View $view |
|
| 128 | + * @param SharedMount[] $mountpoints |
|
| 129 | + * @return mixed |
|
| 130 | + */ |
|
| 131 | + private function generateUniqueTarget($path, $view, array $mountpoints) { |
|
| 132 | + $pathinfo = pathinfo($path); |
|
| 133 | + $ext = (isset($pathinfo['extension'])) ? '.' . $pathinfo['extension'] : ''; |
|
| 134 | + $name = $pathinfo['filename']; |
|
| 135 | + $dir = $pathinfo['dirname']; |
|
| 136 | + |
|
| 137 | + // Helper function to find existing mount points |
|
| 138 | + $mountpointExists = function ($path) use ($mountpoints) { |
|
| 139 | + foreach ($mountpoints as $mountpoint) { |
|
| 140 | + if ($mountpoint->getShare()->getTarget() === $path) { |
|
| 141 | + return true; |
|
| 142 | + } |
|
| 143 | + } |
|
| 144 | + return false; |
|
| 145 | + }; |
|
| 146 | + |
|
| 147 | + $i = 2; |
|
| 148 | + while ($view->file_exists($path) || $mountpointExists($path)) { |
|
| 149 | + $path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext); |
|
| 150 | + $i++; |
|
| 151 | + } |
|
| 152 | + |
|
| 153 | + return $path; |
|
| 154 | + } |
|
| 155 | + |
|
| 156 | + /** |
|
| 157 | + * Format a path to be relative to the /user/files/ directory |
|
| 158 | + * |
|
| 159 | + * @param string $path the absolute path |
|
| 160 | + * @return string e.g. turns '/admin/files/test.txt' into '/test.txt' |
|
| 161 | + * @throws \OCA\Files_Sharing\Exceptions\BrokenPath |
|
| 162 | + */ |
|
| 163 | + protected function stripUserFilesPath($path) { |
|
| 164 | + $trimmed = ltrim($path, '/'); |
|
| 165 | + $split = explode('/', $trimmed); |
|
| 166 | + |
|
| 167 | + // it is not a file relative to data/user/files |
|
| 168 | + if (count($split) < 3 || $split[1] !== 'files') { |
|
| 169 | + \OCP\Util::writeLog('file sharing', |
|
| 170 | + 'Can not strip userid and "files/" from path: ' . $path, |
|
| 171 | + \OCP\Util::ERROR); |
|
| 172 | + throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10); |
|
| 173 | + } |
|
| 174 | + |
|
| 175 | + // skip 'user' and 'files' |
|
| 176 | + $sliced = array_slice($split, 2); |
|
| 177 | + $relPath = implode('/', $sliced); |
|
| 178 | + |
|
| 179 | + return '/' . $relPath; |
|
| 180 | + } |
|
| 181 | + |
|
| 182 | + /** |
|
| 183 | + * Move the mount point to $target |
|
| 184 | + * |
|
| 185 | + * @param string $target the target mount point |
|
| 186 | + * @return bool |
|
| 187 | + */ |
|
| 188 | + public function moveMount($target) { |
|
| 189 | + |
|
| 190 | + $relTargetPath = $this->stripUserFilesPath($target); |
|
| 191 | + $share = $this->storage->getShare(); |
|
| 192 | + |
|
| 193 | + $result = true; |
|
| 194 | + |
|
| 195 | + try { |
|
| 196 | + $this->updateFileTarget($relTargetPath, $share); |
|
| 197 | + $this->setMountPoint($target); |
|
| 198 | + $this->storage->setMountPoint($relTargetPath); |
|
| 199 | + } catch (\Exception $e) { |
|
| 200 | + \OCP\Util::writeLog('file sharing', |
|
| 201 | + 'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"', |
|
| 202 | + \OCP\Util::ERROR); |
|
| 203 | + } |
|
| 204 | + |
|
| 205 | + return $result; |
|
| 206 | + } |
|
| 207 | + |
|
| 208 | + /** |
|
| 209 | + * Remove the mount points |
|
| 210 | + * |
|
| 211 | + * @return bool |
|
| 212 | + */ |
|
| 213 | + public function removeMount() { |
|
| 214 | + $mountManager = \OC\Files\Filesystem::getMountManager(); |
|
| 215 | + /** @var $storage \OCA\Files_Sharing\SharedStorage */ |
|
| 216 | + $storage = $this->getStorage(); |
|
| 217 | + $result = $storage->unshareStorage(); |
|
| 218 | + $mountManager->removeMount($this->mountPoint); |
|
| 219 | + |
|
| 220 | + return $result; |
|
| 221 | + } |
|
| 222 | + |
|
| 223 | + /** |
|
| 224 | + * @return \OCP\Share\IShare |
|
| 225 | + */ |
|
| 226 | + public function getShare() { |
|
| 227 | + return $this->superShare; |
|
| 228 | + } |
|
| 229 | + |
|
| 230 | + /** |
|
| 231 | + * Get the file id of the root of the storage |
|
| 232 | + * |
|
| 233 | + * @return int |
|
| 234 | + */ |
|
| 235 | + public function getStorageRootId() { |
|
| 236 | + return $this->getShare()->getNodeId(); |
|
| 237 | + } |
|
| 238 | + |
|
| 239 | + /** |
|
| 240 | + * @return int |
|
| 241 | + */ |
|
| 242 | + public function getNumericStorageId() { |
|
| 243 | + if (!is_null($this->getShare()->getNodeCacheEntry())) { |
|
| 244 | + return $this->getShare()->getNodeCacheEntry()->getStorageId(); |
|
| 245 | + } else { |
|
| 246 | + $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder(); |
|
| 247 | + |
|
| 248 | + $query = $builder->select('storage') |
|
| 249 | + ->from('filecache') |
|
| 250 | + ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($this->getStorageRootId()))); |
|
| 251 | + |
|
| 252 | + $result = $query->execute(); |
|
| 253 | + $row = $result->fetch(); |
|
| 254 | + $result->closeCursor(); |
|
| 255 | + if ($row) { |
|
| 256 | + return (int)$row['storage']; |
|
| 257 | + } |
|
| 258 | + return -1; |
|
| 259 | + } |
|
| 260 | + } |
|
| 261 | + |
|
| 262 | + public function getMountType() { |
|
| 263 | + return 'shared'; |
|
| 264 | + } |
|
| 265 | 265 | } |
@@ -37,231 +37,231 @@ |
||
| 37 | 37 | * Helper class for manipulating file information |
| 38 | 38 | */ |
| 39 | 39 | class Helper { |
| 40 | - /** |
|
| 41 | - * @param string $dir |
|
| 42 | - * @return array |
|
| 43 | - * @throws \OCP\Files\NotFoundException |
|
| 44 | - */ |
|
| 45 | - public static function buildFileStorageStatistics($dir) { |
|
| 46 | - // information about storage capacities |
|
| 47 | - $storageInfo = \OC_Helper::getStorageInfo($dir); |
|
| 48 | - $l = \OC::$server->getL10N('files'); |
|
| 49 | - $maxUploadFileSize = \OCP\Util::maxUploadFilesize($dir, $storageInfo['free']); |
|
| 50 | - $maxHumanFileSize = \OCP\Util::humanFileSize($maxUploadFileSize); |
|
| 51 | - $maxHumanFileSize = $l->t('Upload (max. %s)', array($maxHumanFileSize)); |
|
| 40 | + /** |
|
| 41 | + * @param string $dir |
|
| 42 | + * @return array |
|
| 43 | + * @throws \OCP\Files\NotFoundException |
|
| 44 | + */ |
|
| 45 | + public static function buildFileStorageStatistics($dir) { |
|
| 46 | + // information about storage capacities |
|
| 47 | + $storageInfo = \OC_Helper::getStorageInfo($dir); |
|
| 48 | + $l = \OC::$server->getL10N('files'); |
|
| 49 | + $maxUploadFileSize = \OCP\Util::maxUploadFilesize($dir, $storageInfo['free']); |
|
| 50 | + $maxHumanFileSize = \OCP\Util::humanFileSize($maxUploadFileSize); |
|
| 51 | + $maxHumanFileSize = $l->t('Upload (max. %s)', array($maxHumanFileSize)); |
|
| 52 | 52 | |
| 53 | - return [ |
|
| 54 | - 'uploadMaxFilesize' => $maxUploadFileSize, |
|
| 55 | - 'maxHumanFilesize' => $maxHumanFileSize, |
|
| 56 | - 'freeSpace' => $storageInfo['free'], |
|
| 57 | - 'usedSpacePercent' => (int)$storageInfo['relative'], |
|
| 58 | - 'owner' => $storageInfo['owner'], |
|
| 59 | - 'ownerDisplayName' => $storageInfo['ownerDisplayName'], |
|
| 60 | - ]; |
|
| 61 | - } |
|
| 53 | + return [ |
|
| 54 | + 'uploadMaxFilesize' => $maxUploadFileSize, |
|
| 55 | + 'maxHumanFilesize' => $maxHumanFileSize, |
|
| 56 | + 'freeSpace' => $storageInfo['free'], |
|
| 57 | + 'usedSpacePercent' => (int)$storageInfo['relative'], |
|
| 58 | + 'owner' => $storageInfo['owner'], |
|
| 59 | + 'ownerDisplayName' => $storageInfo['ownerDisplayName'], |
|
| 60 | + ]; |
|
| 61 | + } |
|
| 62 | 62 | |
| 63 | - /** |
|
| 64 | - * Determine icon for a given file |
|
| 65 | - * |
|
| 66 | - * @param \OCP\Files\FileInfo $file file info |
|
| 67 | - * @return string icon URL |
|
| 68 | - */ |
|
| 69 | - public static function determineIcon($file) { |
|
| 70 | - if($file['type'] === 'dir') { |
|
| 71 | - $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir'); |
|
| 72 | - // TODO: move this part to the client side, using mountType |
|
| 73 | - if ($file->isShared()) { |
|
| 74 | - $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-shared'); |
|
| 75 | - } elseif ($file->isMounted()) { |
|
| 76 | - $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-external'); |
|
| 77 | - } |
|
| 78 | - }else{ |
|
| 79 | - $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon($file->getMimetype()); |
|
| 80 | - } |
|
| 63 | + /** |
|
| 64 | + * Determine icon for a given file |
|
| 65 | + * |
|
| 66 | + * @param \OCP\Files\FileInfo $file file info |
|
| 67 | + * @return string icon URL |
|
| 68 | + */ |
|
| 69 | + public static function determineIcon($file) { |
|
| 70 | + if($file['type'] === 'dir') { |
|
| 71 | + $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir'); |
|
| 72 | + // TODO: move this part to the client side, using mountType |
|
| 73 | + if ($file->isShared()) { |
|
| 74 | + $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-shared'); |
|
| 75 | + } elseif ($file->isMounted()) { |
|
| 76 | + $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-external'); |
|
| 77 | + } |
|
| 78 | + }else{ |
|
| 79 | + $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon($file->getMimetype()); |
|
| 80 | + } |
|
| 81 | 81 | |
| 82 | - return substr($icon, 0, -3) . 'svg'; |
|
| 83 | - } |
|
| 82 | + return substr($icon, 0, -3) . 'svg'; |
|
| 83 | + } |
|
| 84 | 84 | |
| 85 | - /** |
|
| 86 | - * Comparator function to sort files alphabetically and have |
|
| 87 | - * the directories appear first |
|
| 88 | - * |
|
| 89 | - * @param \OCP\Files\FileInfo $a file |
|
| 90 | - * @param \OCP\Files\FileInfo $b file |
|
| 91 | - * @return int -1 if $a must come before $b, 1 otherwise |
|
| 92 | - */ |
|
| 93 | - public static function compareFileNames(FileInfo $a, FileInfo $b) { |
|
| 94 | - $aType = $a->getType(); |
|
| 95 | - $bType = $b->getType(); |
|
| 96 | - if ($aType === 'dir' and $bType !== 'dir') { |
|
| 97 | - return -1; |
|
| 98 | - } elseif ($aType !== 'dir' and $bType === 'dir') { |
|
| 99 | - return 1; |
|
| 100 | - } else { |
|
| 101 | - return \OCP\Util::naturalSortCompare($a->getName(), $b->getName()); |
|
| 102 | - } |
|
| 103 | - } |
|
| 85 | + /** |
|
| 86 | + * Comparator function to sort files alphabetically and have |
|
| 87 | + * the directories appear first |
|
| 88 | + * |
|
| 89 | + * @param \OCP\Files\FileInfo $a file |
|
| 90 | + * @param \OCP\Files\FileInfo $b file |
|
| 91 | + * @return int -1 if $a must come before $b, 1 otherwise |
|
| 92 | + */ |
|
| 93 | + public static function compareFileNames(FileInfo $a, FileInfo $b) { |
|
| 94 | + $aType = $a->getType(); |
|
| 95 | + $bType = $b->getType(); |
|
| 96 | + if ($aType === 'dir' and $bType !== 'dir') { |
|
| 97 | + return -1; |
|
| 98 | + } elseif ($aType !== 'dir' and $bType === 'dir') { |
|
| 99 | + return 1; |
|
| 100 | + } else { |
|
| 101 | + return \OCP\Util::naturalSortCompare($a->getName(), $b->getName()); |
|
| 102 | + } |
|
| 103 | + } |
|
| 104 | 104 | |
| 105 | - /** |
|
| 106 | - * Comparator function to sort files by date |
|
| 107 | - * |
|
| 108 | - * @param \OCP\Files\FileInfo $a file |
|
| 109 | - * @param \OCP\Files\FileInfo $b file |
|
| 110 | - * @return int -1 if $a must come before $b, 1 otherwise |
|
| 111 | - */ |
|
| 112 | - public static function compareTimestamp(FileInfo $a, FileInfo $b) { |
|
| 113 | - $aTime = $a->getMTime(); |
|
| 114 | - $bTime = $b->getMTime(); |
|
| 115 | - return ($aTime < $bTime) ? -1 : 1; |
|
| 116 | - } |
|
| 105 | + /** |
|
| 106 | + * Comparator function to sort files by date |
|
| 107 | + * |
|
| 108 | + * @param \OCP\Files\FileInfo $a file |
|
| 109 | + * @param \OCP\Files\FileInfo $b file |
|
| 110 | + * @return int -1 if $a must come before $b, 1 otherwise |
|
| 111 | + */ |
|
| 112 | + public static function compareTimestamp(FileInfo $a, FileInfo $b) { |
|
| 113 | + $aTime = $a->getMTime(); |
|
| 114 | + $bTime = $b->getMTime(); |
|
| 115 | + return ($aTime < $bTime) ? -1 : 1; |
|
| 116 | + } |
|
| 117 | 117 | |
| 118 | - /** |
|
| 119 | - * Comparator function to sort files by size |
|
| 120 | - * |
|
| 121 | - * @param \OCP\Files\FileInfo $a file |
|
| 122 | - * @param \OCP\Files\FileInfo $b file |
|
| 123 | - * @return int -1 if $a must come before $b, 1 otherwise |
|
| 124 | - */ |
|
| 125 | - public static function compareSize(FileInfo $a, FileInfo $b) { |
|
| 126 | - $aSize = $a->getSize(); |
|
| 127 | - $bSize = $b->getSize(); |
|
| 128 | - return ($aSize < $bSize) ? -1 : 1; |
|
| 129 | - } |
|
| 118 | + /** |
|
| 119 | + * Comparator function to sort files by size |
|
| 120 | + * |
|
| 121 | + * @param \OCP\Files\FileInfo $a file |
|
| 122 | + * @param \OCP\Files\FileInfo $b file |
|
| 123 | + * @return int -1 if $a must come before $b, 1 otherwise |
|
| 124 | + */ |
|
| 125 | + public static function compareSize(FileInfo $a, FileInfo $b) { |
|
| 126 | + $aSize = $a->getSize(); |
|
| 127 | + $bSize = $b->getSize(); |
|
| 128 | + return ($aSize < $bSize) ? -1 : 1; |
|
| 129 | + } |
|
| 130 | 130 | |
| 131 | - /** |
|
| 132 | - * Formats the file info to be returned as JSON to the client. |
|
| 133 | - * |
|
| 134 | - * @param \OCP\Files\FileInfo $i |
|
| 135 | - * @return array formatted file info |
|
| 136 | - */ |
|
| 137 | - public static function formatFileInfo(FileInfo $i) { |
|
| 138 | - $entry = array(); |
|
| 131 | + /** |
|
| 132 | + * Formats the file info to be returned as JSON to the client. |
|
| 133 | + * |
|
| 134 | + * @param \OCP\Files\FileInfo $i |
|
| 135 | + * @return array formatted file info |
|
| 136 | + */ |
|
| 137 | + public static function formatFileInfo(FileInfo $i) { |
|
| 138 | + $entry = array(); |
|
| 139 | 139 | |
| 140 | - $entry['id'] = $i['fileid']; |
|
| 141 | - $entry['parentId'] = $i['parent']; |
|
| 142 | - $entry['mtime'] = $i['mtime'] * 1000; |
|
| 143 | - // only pick out the needed attributes |
|
| 144 | - $entry['name'] = $i->getName(); |
|
| 145 | - $entry['permissions'] = $i['permissions']; |
|
| 146 | - $entry['mimetype'] = $i['mimetype']; |
|
| 147 | - $entry['size'] = $i['size']; |
|
| 148 | - $entry['type'] = $i['type']; |
|
| 149 | - $entry['etag'] = $i['etag']; |
|
| 150 | - if (isset($i['tags'])) { |
|
| 151 | - $entry['tags'] = $i['tags']; |
|
| 152 | - } |
|
| 153 | - if (isset($i['displayname_owner'])) { |
|
| 154 | - $entry['shareOwner'] = $i['displayname_owner']; |
|
| 155 | - } |
|
| 156 | - if (isset($i['is_share_mount_point'])) { |
|
| 157 | - $entry['isShareMountPoint'] = $i['is_share_mount_point']; |
|
| 158 | - } |
|
| 159 | - $mountType = null; |
|
| 160 | - $mount = $i->getMountPoint(); |
|
| 161 | - $mountType = $mount->getMountType(); |
|
| 162 | - if ($mountType !== '') { |
|
| 163 | - if ($i->getInternalPath() === '') { |
|
| 164 | - $mountType .= '-root'; |
|
| 165 | - } |
|
| 166 | - $entry['mountType'] = $mountType; |
|
| 167 | - } |
|
| 168 | - if (isset($i['extraData'])) { |
|
| 169 | - $entry['extraData'] = $i['extraData']; |
|
| 170 | - } |
|
| 171 | - return $entry; |
|
| 172 | - } |
|
| 140 | + $entry['id'] = $i['fileid']; |
|
| 141 | + $entry['parentId'] = $i['parent']; |
|
| 142 | + $entry['mtime'] = $i['mtime'] * 1000; |
|
| 143 | + // only pick out the needed attributes |
|
| 144 | + $entry['name'] = $i->getName(); |
|
| 145 | + $entry['permissions'] = $i['permissions']; |
|
| 146 | + $entry['mimetype'] = $i['mimetype']; |
|
| 147 | + $entry['size'] = $i['size']; |
|
| 148 | + $entry['type'] = $i['type']; |
|
| 149 | + $entry['etag'] = $i['etag']; |
|
| 150 | + if (isset($i['tags'])) { |
|
| 151 | + $entry['tags'] = $i['tags']; |
|
| 152 | + } |
|
| 153 | + if (isset($i['displayname_owner'])) { |
|
| 154 | + $entry['shareOwner'] = $i['displayname_owner']; |
|
| 155 | + } |
|
| 156 | + if (isset($i['is_share_mount_point'])) { |
|
| 157 | + $entry['isShareMountPoint'] = $i['is_share_mount_point']; |
|
| 158 | + } |
|
| 159 | + $mountType = null; |
|
| 160 | + $mount = $i->getMountPoint(); |
|
| 161 | + $mountType = $mount->getMountType(); |
|
| 162 | + if ($mountType !== '') { |
|
| 163 | + if ($i->getInternalPath() === '') { |
|
| 164 | + $mountType .= '-root'; |
|
| 165 | + } |
|
| 166 | + $entry['mountType'] = $mountType; |
|
| 167 | + } |
|
| 168 | + if (isset($i['extraData'])) { |
|
| 169 | + $entry['extraData'] = $i['extraData']; |
|
| 170 | + } |
|
| 171 | + return $entry; |
|
| 172 | + } |
|
| 173 | 173 | |
| 174 | - /** |
|
| 175 | - * Format file info for JSON |
|
| 176 | - * @param \OCP\Files\FileInfo[] $fileInfos file infos |
|
| 177 | - * @return array |
|
| 178 | - */ |
|
| 179 | - public static function formatFileInfos($fileInfos) { |
|
| 180 | - $files = array(); |
|
| 181 | - foreach ($fileInfos as $i) { |
|
| 182 | - $files[] = self::formatFileInfo($i); |
|
| 183 | - } |
|
| 174 | + /** |
|
| 175 | + * Format file info for JSON |
|
| 176 | + * @param \OCP\Files\FileInfo[] $fileInfos file infos |
|
| 177 | + * @return array |
|
| 178 | + */ |
|
| 179 | + public static function formatFileInfos($fileInfos) { |
|
| 180 | + $files = array(); |
|
| 181 | + foreach ($fileInfos as $i) { |
|
| 182 | + $files[] = self::formatFileInfo($i); |
|
| 183 | + } |
|
| 184 | 184 | |
| 185 | - return $files; |
|
| 186 | - } |
|
| 185 | + return $files; |
|
| 186 | + } |
|
| 187 | 187 | |
| 188 | - /** |
|
| 189 | - * Retrieves the contents of the given directory and |
|
| 190 | - * returns it as a sorted array of FileInfo. |
|
| 191 | - * |
|
| 192 | - * @param string $dir path to the directory |
|
| 193 | - * @param string $sortAttribute attribute to sort on |
|
| 194 | - * @param bool $sortDescending true for descending sort, false otherwise |
|
| 195 | - * @param string $mimetypeFilter limit returned content to this mimetype or mimepart |
|
| 196 | - * @return \OCP\Files\FileInfo[] files |
|
| 197 | - */ |
|
| 198 | - public static function getFiles($dir, $sortAttribute = 'name', $sortDescending = false, $mimetypeFilter = '') { |
|
| 199 | - $content = \OC\Files\Filesystem::getDirectoryContent($dir, $mimetypeFilter); |
|
| 188 | + /** |
|
| 189 | + * Retrieves the contents of the given directory and |
|
| 190 | + * returns it as a sorted array of FileInfo. |
|
| 191 | + * |
|
| 192 | + * @param string $dir path to the directory |
|
| 193 | + * @param string $sortAttribute attribute to sort on |
|
| 194 | + * @param bool $sortDescending true for descending sort, false otherwise |
|
| 195 | + * @param string $mimetypeFilter limit returned content to this mimetype or mimepart |
|
| 196 | + * @return \OCP\Files\FileInfo[] files |
|
| 197 | + */ |
|
| 198 | + public static function getFiles($dir, $sortAttribute = 'name', $sortDescending = false, $mimetypeFilter = '') { |
|
| 199 | + $content = \OC\Files\Filesystem::getDirectoryContent($dir, $mimetypeFilter); |
|
| 200 | 200 | |
| 201 | - return self::sortFiles($content, $sortAttribute, $sortDescending); |
|
| 202 | - } |
|
| 201 | + return self::sortFiles($content, $sortAttribute, $sortDescending); |
|
| 202 | + } |
|
| 203 | 203 | |
| 204 | - /** |
|
| 205 | - * Populate the result set with file tags |
|
| 206 | - * |
|
| 207 | - * @param array $fileList |
|
| 208 | - * @param string $fileIdentifier identifier attribute name for values in $fileList |
|
| 209 | - * @return array file list populated with tags |
|
| 210 | - */ |
|
| 211 | - public static function populateTags(array $fileList, $fileIdentifier = 'fileid') { |
|
| 212 | - $filesById = []; |
|
| 213 | - foreach ($fileList as $fileData) { |
|
| 214 | - $filesById[$fileData[$fileIdentifier]] = $fileData; |
|
| 215 | - } |
|
| 216 | - $tagger = \OC::$server->getTagManager()->load('files'); |
|
| 217 | - $tags = $tagger->getTagsForObjects(array_keys($filesById)); |
|
| 204 | + /** |
|
| 205 | + * Populate the result set with file tags |
|
| 206 | + * |
|
| 207 | + * @param array $fileList |
|
| 208 | + * @param string $fileIdentifier identifier attribute name for values in $fileList |
|
| 209 | + * @return array file list populated with tags |
|
| 210 | + */ |
|
| 211 | + public static function populateTags(array $fileList, $fileIdentifier = 'fileid') { |
|
| 212 | + $filesById = []; |
|
| 213 | + foreach ($fileList as $fileData) { |
|
| 214 | + $filesById[$fileData[$fileIdentifier]] = $fileData; |
|
| 215 | + } |
|
| 216 | + $tagger = \OC::$server->getTagManager()->load('files'); |
|
| 217 | + $tags = $tagger->getTagsForObjects(array_keys($filesById)); |
|
| 218 | 218 | |
| 219 | - if (!is_array($tags)) { |
|
| 220 | - throw new \UnexpectedValueException('$tags must be an array'); |
|
| 221 | - } |
|
| 219 | + if (!is_array($tags)) { |
|
| 220 | + throw new \UnexpectedValueException('$tags must be an array'); |
|
| 221 | + } |
|
| 222 | 222 | |
| 223 | - if (!empty($tags)) { |
|
| 224 | - foreach ($tags as $fileId => $fileTags) { |
|
| 225 | - $filesById[$fileId]['tags'] = $fileTags; |
|
| 226 | - } |
|
| 223 | + if (!empty($tags)) { |
|
| 224 | + foreach ($tags as $fileId => $fileTags) { |
|
| 225 | + $filesById[$fileId]['tags'] = $fileTags; |
|
| 226 | + } |
|
| 227 | 227 | |
| 228 | - foreach ($filesById as $key => $fileWithTags) { |
|
| 229 | - foreach($fileList as $key2 => $file){ |
|
| 230 | - if( $file[$fileIdentifier] == $key){ |
|
| 231 | - $fileList[$key2] = $fileWithTags; |
|
| 232 | - } |
|
| 233 | - } |
|
| 234 | - } |
|
| 228 | + foreach ($filesById as $key => $fileWithTags) { |
|
| 229 | + foreach($fileList as $key2 => $file){ |
|
| 230 | + if( $file[$fileIdentifier] == $key){ |
|
| 231 | + $fileList[$key2] = $fileWithTags; |
|
| 232 | + } |
|
| 233 | + } |
|
| 234 | + } |
|
| 235 | 235 | |
| 236 | - foreach ($fileList as $key => $file) { |
|
| 237 | - if (!array_key_exists('tags', $file)) { |
|
| 238 | - $fileList[$key]['tags'] = []; |
|
| 239 | - } |
|
| 240 | - } |
|
| 236 | + foreach ($fileList as $key => $file) { |
|
| 237 | + if (!array_key_exists('tags', $file)) { |
|
| 238 | + $fileList[$key]['tags'] = []; |
|
| 239 | + } |
|
| 240 | + } |
|
| 241 | 241 | |
| 242 | - } |
|
| 243 | - return $fileList; |
|
| 244 | - } |
|
| 242 | + } |
|
| 243 | + return $fileList; |
|
| 244 | + } |
|
| 245 | 245 | |
| 246 | - /** |
|
| 247 | - * Sort the given file info array |
|
| 248 | - * |
|
| 249 | - * @param \OCP\Files\FileInfo[] $files files to sort |
|
| 250 | - * @param string $sortAttribute attribute to sort on |
|
| 251 | - * @param bool $sortDescending true for descending sort, false otherwise |
|
| 252 | - * @return \OCP\Files\FileInfo[] sorted files |
|
| 253 | - */ |
|
| 254 | - public static function sortFiles($files, $sortAttribute = 'name', $sortDescending = false) { |
|
| 255 | - $sortFunc = 'compareFileNames'; |
|
| 256 | - if ($sortAttribute === 'mtime') { |
|
| 257 | - $sortFunc = 'compareTimestamp'; |
|
| 258 | - } else if ($sortAttribute === 'size') { |
|
| 259 | - $sortFunc = 'compareSize'; |
|
| 260 | - } |
|
| 261 | - usort($files, array('\OCA\Files\Helper', $sortFunc)); |
|
| 262 | - if ($sortDescending) { |
|
| 263 | - $files = array_reverse($files); |
|
| 264 | - } |
|
| 265 | - return $files; |
|
| 266 | - } |
|
| 246 | + /** |
|
| 247 | + * Sort the given file info array |
|
| 248 | + * |
|
| 249 | + * @param \OCP\Files\FileInfo[] $files files to sort |
|
| 250 | + * @param string $sortAttribute attribute to sort on |
|
| 251 | + * @param bool $sortDescending true for descending sort, false otherwise |
|
| 252 | + * @return \OCP\Files\FileInfo[] sorted files |
|
| 253 | + */ |
|
| 254 | + public static function sortFiles($files, $sortAttribute = 'name', $sortDescending = false) { |
|
| 255 | + $sortFunc = 'compareFileNames'; |
|
| 256 | + if ($sortAttribute === 'mtime') { |
|
| 257 | + $sortFunc = 'compareTimestamp'; |
|
| 258 | + } else if ($sortAttribute === 'size') { |
|
| 259 | + $sortFunc = 'compareSize'; |
|
| 260 | + } |
|
| 261 | + usort($files, array('\OCA\Files\Helper', $sortFunc)); |
|
| 262 | + if ($sortDescending) { |
|
| 263 | + $files = array_reverse($files); |
|
| 264 | + } |
|
| 265 | + return $files; |
|
| 266 | + } |
|
| 267 | 267 | } |
@@ -48,398 +48,398 @@ |
||
| 48 | 48 | |
| 49 | 49 | class FilesPlugin extends ServerPlugin { |
| 50 | 50 | |
| 51 | - // namespace |
|
| 52 | - const NS_OWNCLOUD = 'http://owncloud.org/ns'; |
|
| 53 | - const NS_NEXTCLOUD = 'http://nextcloud.org/ns'; |
|
| 54 | - const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id'; |
|
| 55 | - const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid'; |
|
| 56 | - const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions'; |
|
| 57 | - const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions'; |
|
| 58 | - const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL'; |
|
| 59 | - const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size'; |
|
| 60 | - const GETETAG_PROPERTYNAME = '{DAV:}getetag'; |
|
| 61 | - const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; |
|
| 62 | - const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id'; |
|
| 63 | - const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name'; |
|
| 64 | - const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums'; |
|
| 65 | - const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint'; |
|
| 66 | - const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview'; |
|
| 67 | - const MOUNT_TYPE_PROPERTYNAME = '{http://nextcloud.org/ns}mount-type'; |
|
| 68 | - |
|
| 69 | - /** |
|
| 70 | - * Reference to main server object |
|
| 71 | - * |
|
| 72 | - * @var \Sabre\DAV\Server |
|
| 73 | - */ |
|
| 74 | - private $server; |
|
| 75 | - |
|
| 76 | - /** |
|
| 77 | - * @var Tree |
|
| 78 | - */ |
|
| 79 | - private $tree; |
|
| 80 | - |
|
| 81 | - /** |
|
| 82 | - * Whether this is public webdav. |
|
| 83 | - * If true, some returned information will be stripped off. |
|
| 84 | - * |
|
| 85 | - * @var bool |
|
| 86 | - */ |
|
| 87 | - private $isPublic; |
|
| 88 | - |
|
| 89 | - /** |
|
| 90 | - * @var View |
|
| 91 | - */ |
|
| 92 | - private $fileView; |
|
| 93 | - |
|
| 94 | - /** |
|
| 95 | - * @var bool |
|
| 96 | - */ |
|
| 97 | - private $downloadAttachment; |
|
| 98 | - |
|
| 99 | - /** |
|
| 100 | - * @var IConfig |
|
| 101 | - */ |
|
| 102 | - private $config; |
|
| 103 | - |
|
| 104 | - /** |
|
| 105 | - * @var IRequest |
|
| 106 | - */ |
|
| 107 | - private $request; |
|
| 108 | - |
|
| 109 | - /** |
|
| 110 | - * @var IPreview |
|
| 111 | - */ |
|
| 112 | - private $previewManager; |
|
| 113 | - |
|
| 114 | - /** |
|
| 115 | - * @param Tree $tree |
|
| 116 | - * @param IConfig $config |
|
| 117 | - * @param IRequest $request |
|
| 118 | - * @param IPreview $previewManager |
|
| 119 | - * @param bool $isPublic |
|
| 120 | - * @param bool $downloadAttachment |
|
| 121 | - */ |
|
| 122 | - public function __construct(Tree $tree, |
|
| 123 | - IConfig $config, |
|
| 124 | - IRequest $request, |
|
| 125 | - IPreview $previewManager, |
|
| 126 | - $isPublic = false, |
|
| 127 | - $downloadAttachment = true) { |
|
| 128 | - $this->tree = $tree; |
|
| 129 | - $this->config = $config; |
|
| 130 | - $this->request = $request; |
|
| 131 | - $this->isPublic = $isPublic; |
|
| 132 | - $this->downloadAttachment = $downloadAttachment; |
|
| 133 | - $this->previewManager = $previewManager; |
|
| 134 | - } |
|
| 135 | - |
|
| 136 | - /** |
|
| 137 | - * This initializes the plugin. |
|
| 138 | - * |
|
| 139 | - * This function is called by \Sabre\DAV\Server, after |
|
| 140 | - * addPlugin is called. |
|
| 141 | - * |
|
| 142 | - * This method should set up the required event subscriptions. |
|
| 143 | - * |
|
| 144 | - * @param \Sabre\DAV\Server $server |
|
| 145 | - * @return void |
|
| 146 | - */ |
|
| 147 | - public function initialize(\Sabre\DAV\Server $server) { |
|
| 148 | - |
|
| 149 | - $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; |
|
| 150 | - $server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc'; |
|
| 151 | - $server->protectedProperties[] = self::FILEID_PROPERTYNAME; |
|
| 152 | - $server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME; |
|
| 153 | - $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME; |
|
| 154 | - $server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME; |
|
| 155 | - $server->protectedProperties[] = self::SIZE_PROPERTYNAME; |
|
| 156 | - $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME; |
|
| 157 | - $server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME; |
|
| 158 | - $server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME; |
|
| 159 | - $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME; |
|
| 160 | - $server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME; |
|
| 161 | - $server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME; |
|
| 162 | - $server->protectedProperties[] = self::MOUNT_TYPE_PROPERTYNAME; |
|
| 163 | - |
|
| 164 | - // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH |
|
| 165 | - $allowedProperties = ['{DAV:}getetag']; |
|
| 166 | - $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties); |
|
| 167 | - |
|
| 168 | - $this->server = $server; |
|
| 169 | - $this->server->on('propFind', array($this, 'handleGetProperties')); |
|
| 170 | - $this->server->on('propPatch', array($this, 'handleUpdateProperties')); |
|
| 171 | - $this->server->on('afterBind', array($this, 'sendFileIdHeader')); |
|
| 172 | - $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader')); |
|
| 173 | - $this->server->on('afterMethod:GET', [$this,'httpGet']); |
|
| 174 | - $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken')); |
|
| 175 | - $this->server->on('afterResponse', function($request, ResponseInterface $response) { |
|
| 176 | - $body = $response->getBody(); |
|
| 177 | - if (is_resource($body)) { |
|
| 178 | - fclose($body); |
|
| 179 | - } |
|
| 180 | - }); |
|
| 181 | - $this->server->on('beforeMove', [$this, 'checkMove']); |
|
| 182 | - } |
|
| 183 | - |
|
| 184 | - /** |
|
| 185 | - * Plugin that checks if a move can actually be performed. |
|
| 186 | - * |
|
| 187 | - * @param string $source source path |
|
| 188 | - * @param string $destination destination path |
|
| 189 | - * @throws Forbidden |
|
| 190 | - * @throws NotFound |
|
| 191 | - */ |
|
| 192 | - function checkMove($source, $destination) { |
|
| 193 | - $sourceNode = $this->tree->getNodeForPath($source); |
|
| 194 | - if (!$sourceNode instanceof Node) { |
|
| 195 | - return; |
|
| 196 | - } |
|
| 197 | - list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source); |
|
| 198 | - list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination); |
|
| 199 | - |
|
| 200 | - if ($sourceDir !== $destinationDir) { |
|
| 201 | - $sourceNodeFileInfo = $sourceNode->getFileInfo(); |
|
| 202 | - if (is_null($sourceNodeFileInfo)) { |
|
| 203 | - throw new NotFound($source . ' does not exist'); |
|
| 204 | - } |
|
| 205 | - |
|
| 206 | - if (!$sourceNodeFileInfo->isDeletable()) { |
|
| 207 | - throw new Forbidden($source . " cannot be deleted"); |
|
| 208 | - } |
|
| 209 | - } |
|
| 210 | - } |
|
| 211 | - |
|
| 212 | - /** |
|
| 213 | - * This sets a cookie to be able to recognize the start of the download |
|
| 214 | - * the content must not be longer than 32 characters and must only contain |
|
| 215 | - * alphanumeric characters |
|
| 216 | - * |
|
| 217 | - * @param RequestInterface $request |
|
| 218 | - * @param ResponseInterface $response |
|
| 219 | - */ |
|
| 220 | - function handleDownloadToken(RequestInterface $request, ResponseInterface $response) { |
|
| 221 | - $queryParams = $request->getQueryParameters(); |
|
| 222 | - |
|
| 223 | - /** |
|
| 224 | - * this sets a cookie to be able to recognize the start of the download |
|
| 225 | - * the content must not be longer than 32 characters and must only contain |
|
| 226 | - * alphanumeric characters |
|
| 227 | - */ |
|
| 228 | - if (isset($queryParams['downloadStartSecret'])) { |
|
| 229 | - $token = $queryParams['downloadStartSecret']; |
|
| 230 | - if (!isset($token[32]) |
|
| 231 | - && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) { |
|
| 232 | - // FIXME: use $response->setHeader() instead |
|
| 233 | - setcookie('ocDownloadStarted', $token, time() + 20, '/'); |
|
| 234 | - } |
|
| 235 | - } |
|
| 236 | - } |
|
| 237 | - |
|
| 238 | - /** |
|
| 239 | - * Add headers to file download |
|
| 240 | - * |
|
| 241 | - * @param RequestInterface $request |
|
| 242 | - * @param ResponseInterface $response |
|
| 243 | - */ |
|
| 244 | - function httpGet(RequestInterface $request, ResponseInterface $response) { |
|
| 245 | - // Only handle valid files |
|
| 246 | - $node = $this->tree->getNodeForPath($request->getPath()); |
|
| 247 | - if (!($node instanceof IFile)) return; |
|
| 248 | - |
|
| 249 | - // adds a 'Content-Disposition: attachment' header in case no disposition |
|
| 250 | - // header has been set before |
|
| 251 | - if ($this->downloadAttachment && |
|
| 252 | - $response->getHeader('Content-Disposition') === null) { |
|
| 253 | - $filename = $node->getName(); |
|
| 254 | - if ($this->request->isUserAgent( |
|
| 255 | - [ |
|
| 256 | - \OC\AppFramework\Http\Request::USER_AGENT_IE, |
|
| 257 | - \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME, |
|
| 258 | - \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX, |
|
| 259 | - ])) { |
|
| 260 | - $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"'); |
|
| 261 | - } else { |
|
| 262 | - $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename) |
|
| 263 | - . '; filename="' . rawurlencode($filename) . '"'); |
|
| 264 | - } |
|
| 265 | - } |
|
| 266 | - |
|
| 267 | - if ($node instanceof \OCA\DAV\Connector\Sabre\File) { |
|
| 268 | - //Add OC-Checksum header |
|
| 269 | - /** @var $node File */ |
|
| 270 | - $checksum = $node->getChecksum(); |
|
| 271 | - if ($checksum !== null && $checksum !== '') { |
|
| 272 | - $response->addHeader('OC-Checksum', $checksum); |
|
| 273 | - } |
|
| 274 | - } |
|
| 275 | - } |
|
| 276 | - |
|
| 277 | - /** |
|
| 278 | - * Adds all ownCloud-specific properties |
|
| 279 | - * |
|
| 280 | - * @param PropFind $propFind |
|
| 281 | - * @param \Sabre\DAV\INode $node |
|
| 282 | - * @return void |
|
| 283 | - */ |
|
| 284 | - public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) { |
|
| 285 | - |
|
| 286 | - $httpRequest = $this->server->httpRequest; |
|
| 287 | - |
|
| 288 | - if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { |
|
| 289 | - |
|
| 290 | - $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) { |
|
| 291 | - return $node->getFileId(); |
|
| 292 | - }); |
|
| 293 | - |
|
| 294 | - $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) { |
|
| 295 | - return $node->getInternalFileId(); |
|
| 296 | - }); |
|
| 297 | - |
|
| 298 | - $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) { |
|
| 299 | - $perms = $node->getDavPermissions(); |
|
| 300 | - if ($this->isPublic) { |
|
| 301 | - // remove mount information |
|
| 302 | - $perms = str_replace(['S', 'M'], '', $perms); |
|
| 303 | - } |
|
| 304 | - return $perms; |
|
| 305 | - }); |
|
| 306 | - |
|
| 307 | - $propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) { |
|
| 308 | - return $node->getSharePermissions( |
|
| 309 | - $httpRequest->getRawServerValue('PHP_AUTH_USER') |
|
| 310 | - ); |
|
| 311 | - }); |
|
| 312 | - |
|
| 313 | - $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) { |
|
| 314 | - return $node->getETag(); |
|
| 315 | - }); |
|
| 316 | - |
|
| 317 | - $propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) { |
|
| 318 | - $owner = $node->getOwner(); |
|
| 319 | - if (!$owner) { |
|
| 320 | - return null; |
|
| 321 | - } else { |
|
| 322 | - return $owner->getUID(); |
|
| 323 | - } |
|
| 324 | - }); |
|
| 325 | - $propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) { |
|
| 326 | - $owner = $node->getOwner(); |
|
| 327 | - if (!$owner) { |
|
| 328 | - return null; |
|
| 329 | - } else { |
|
| 330 | - return $owner->getDisplayName(); |
|
| 331 | - } |
|
| 332 | - }); |
|
| 333 | - |
|
| 334 | - $propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) { |
|
| 335 | - return json_encode($this->previewManager->isAvailable($node->getFileInfo())); |
|
| 336 | - }); |
|
| 337 | - $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) { |
|
| 338 | - return $node->getSize(); |
|
| 339 | - }); |
|
| 340 | - } |
|
| 341 | - |
|
| 342 | - if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { |
|
| 343 | - $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) { |
|
| 344 | - return $this->config->getSystemValue('data-fingerprint', ''); |
|
| 345 | - }); |
|
| 346 | - } |
|
| 347 | - |
|
| 348 | - if ($node instanceof \OCA\DAV\Connector\Sabre\File) { |
|
| 349 | - $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) { |
|
| 350 | - /** @var $node \OCA\DAV\Connector\Sabre\File */ |
|
| 351 | - try { |
|
| 352 | - $directDownloadUrl = $node->getDirectDownload(); |
|
| 353 | - if (isset($directDownloadUrl['url'])) { |
|
| 354 | - return $directDownloadUrl['url']; |
|
| 355 | - } |
|
| 356 | - } catch (StorageNotAvailableException $e) { |
|
| 357 | - return false; |
|
| 358 | - } catch (ForbiddenException $e) { |
|
| 359 | - return false; |
|
| 360 | - } |
|
| 361 | - return false; |
|
| 362 | - }); |
|
| 363 | - |
|
| 364 | - $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) { |
|
| 365 | - $checksum = $node->getChecksum(); |
|
| 366 | - if ($checksum === NULL || $checksum === '') { |
|
| 367 | - return null; |
|
| 368 | - } |
|
| 369 | - |
|
| 370 | - return new ChecksumList($checksum); |
|
| 371 | - }); |
|
| 372 | - |
|
| 373 | - } |
|
| 374 | - |
|
| 375 | - if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) { |
|
| 376 | - $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) { |
|
| 377 | - return $node->getSize(); |
|
| 378 | - }); |
|
| 379 | - } |
|
| 380 | - |
|
| 381 | - $propFind->handle(self::MOUNT_TYPE_PROPERTYNAME, function () use ($node) { |
|
| 382 | - return $node->getFileInfo()->getMountPoint()->getMountType(); |
|
| 383 | - }); |
|
| 384 | - } |
|
| 385 | - |
|
| 386 | - /** |
|
| 387 | - * Update ownCloud-specific properties |
|
| 388 | - * |
|
| 389 | - * @param string $path |
|
| 390 | - * @param PropPatch $propPatch |
|
| 391 | - * |
|
| 392 | - * @return void |
|
| 393 | - */ |
|
| 394 | - public function handleUpdateProperties($path, PropPatch $propPatch) { |
|
| 395 | - $node = $this->tree->getNodeForPath($path); |
|
| 396 | - if (!($node instanceof \OCA\DAV\Connector\Sabre\Node)) { |
|
| 397 | - return; |
|
| 398 | - } |
|
| 399 | - |
|
| 400 | - $propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($node) { |
|
| 401 | - if (empty($time)) { |
|
| 402 | - return false; |
|
| 403 | - } |
|
| 404 | - $node->touch($time); |
|
| 405 | - return true; |
|
| 406 | - }); |
|
| 407 | - $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($node) { |
|
| 408 | - if (empty($etag)) { |
|
| 409 | - return false; |
|
| 410 | - } |
|
| 411 | - if ($node->setEtag($etag) !== -1) { |
|
| 412 | - return true; |
|
| 413 | - } |
|
| 414 | - return false; |
|
| 415 | - }); |
|
| 416 | - } |
|
| 417 | - |
|
| 418 | - /** |
|
| 419 | - * @param string $filePath |
|
| 420 | - * @param \Sabre\DAV\INode $node |
|
| 421 | - * @throws \Sabre\DAV\Exception\BadRequest |
|
| 422 | - */ |
|
| 423 | - public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) { |
|
| 424 | - // chunked upload handling |
|
| 425 | - if (isset($_SERVER['HTTP_OC_CHUNKED'])) { |
|
| 426 | - list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath); |
|
| 427 | - $info = \OC_FileChunking::decodeName($name); |
|
| 428 | - if (!empty($info)) { |
|
| 429 | - $filePath = $path . '/' . $info['name']; |
|
| 430 | - } |
|
| 431 | - } |
|
| 432 | - |
|
| 433 | - // we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder |
|
| 434 | - if (!$this->server->tree->nodeExists($filePath)) { |
|
| 435 | - return; |
|
| 436 | - } |
|
| 437 | - $node = $this->server->tree->getNodeForPath($filePath); |
|
| 438 | - if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { |
|
| 439 | - $fileId = $node->getFileId(); |
|
| 440 | - if (!is_null($fileId)) { |
|
| 441 | - $this->server->httpResponse->setHeader('OC-FileId', $fileId); |
|
| 442 | - } |
|
| 443 | - } |
|
| 444 | - } |
|
| 51 | + // namespace |
|
| 52 | + const NS_OWNCLOUD = 'http://owncloud.org/ns'; |
|
| 53 | + const NS_NEXTCLOUD = 'http://nextcloud.org/ns'; |
|
| 54 | + const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id'; |
|
| 55 | + const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid'; |
|
| 56 | + const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions'; |
|
| 57 | + const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions'; |
|
| 58 | + const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL'; |
|
| 59 | + const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size'; |
|
| 60 | + const GETETAG_PROPERTYNAME = '{DAV:}getetag'; |
|
| 61 | + const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; |
|
| 62 | + const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id'; |
|
| 63 | + const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name'; |
|
| 64 | + const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums'; |
|
| 65 | + const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint'; |
|
| 66 | + const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview'; |
|
| 67 | + const MOUNT_TYPE_PROPERTYNAME = '{http://nextcloud.org/ns}mount-type'; |
|
| 68 | + |
|
| 69 | + /** |
|
| 70 | + * Reference to main server object |
|
| 71 | + * |
|
| 72 | + * @var \Sabre\DAV\Server |
|
| 73 | + */ |
|
| 74 | + private $server; |
|
| 75 | + |
|
| 76 | + /** |
|
| 77 | + * @var Tree |
|
| 78 | + */ |
|
| 79 | + private $tree; |
|
| 80 | + |
|
| 81 | + /** |
|
| 82 | + * Whether this is public webdav. |
|
| 83 | + * If true, some returned information will be stripped off. |
|
| 84 | + * |
|
| 85 | + * @var bool |
|
| 86 | + */ |
|
| 87 | + private $isPublic; |
|
| 88 | + |
|
| 89 | + /** |
|
| 90 | + * @var View |
|
| 91 | + */ |
|
| 92 | + private $fileView; |
|
| 93 | + |
|
| 94 | + /** |
|
| 95 | + * @var bool |
|
| 96 | + */ |
|
| 97 | + private $downloadAttachment; |
|
| 98 | + |
|
| 99 | + /** |
|
| 100 | + * @var IConfig |
|
| 101 | + */ |
|
| 102 | + private $config; |
|
| 103 | + |
|
| 104 | + /** |
|
| 105 | + * @var IRequest |
|
| 106 | + */ |
|
| 107 | + private $request; |
|
| 108 | + |
|
| 109 | + /** |
|
| 110 | + * @var IPreview |
|
| 111 | + */ |
|
| 112 | + private $previewManager; |
|
| 113 | + |
|
| 114 | + /** |
|
| 115 | + * @param Tree $tree |
|
| 116 | + * @param IConfig $config |
|
| 117 | + * @param IRequest $request |
|
| 118 | + * @param IPreview $previewManager |
|
| 119 | + * @param bool $isPublic |
|
| 120 | + * @param bool $downloadAttachment |
|
| 121 | + */ |
|
| 122 | + public function __construct(Tree $tree, |
|
| 123 | + IConfig $config, |
|
| 124 | + IRequest $request, |
|
| 125 | + IPreview $previewManager, |
|
| 126 | + $isPublic = false, |
|
| 127 | + $downloadAttachment = true) { |
|
| 128 | + $this->tree = $tree; |
|
| 129 | + $this->config = $config; |
|
| 130 | + $this->request = $request; |
|
| 131 | + $this->isPublic = $isPublic; |
|
| 132 | + $this->downloadAttachment = $downloadAttachment; |
|
| 133 | + $this->previewManager = $previewManager; |
|
| 134 | + } |
|
| 135 | + |
|
| 136 | + /** |
|
| 137 | + * This initializes the plugin. |
|
| 138 | + * |
|
| 139 | + * This function is called by \Sabre\DAV\Server, after |
|
| 140 | + * addPlugin is called. |
|
| 141 | + * |
|
| 142 | + * This method should set up the required event subscriptions. |
|
| 143 | + * |
|
| 144 | + * @param \Sabre\DAV\Server $server |
|
| 145 | + * @return void |
|
| 146 | + */ |
|
| 147 | + public function initialize(\Sabre\DAV\Server $server) { |
|
| 148 | + |
|
| 149 | + $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; |
|
| 150 | + $server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc'; |
|
| 151 | + $server->protectedProperties[] = self::FILEID_PROPERTYNAME; |
|
| 152 | + $server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME; |
|
| 153 | + $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME; |
|
| 154 | + $server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME; |
|
| 155 | + $server->protectedProperties[] = self::SIZE_PROPERTYNAME; |
|
| 156 | + $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME; |
|
| 157 | + $server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME; |
|
| 158 | + $server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME; |
|
| 159 | + $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME; |
|
| 160 | + $server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME; |
|
| 161 | + $server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME; |
|
| 162 | + $server->protectedProperties[] = self::MOUNT_TYPE_PROPERTYNAME; |
|
| 163 | + |
|
| 164 | + // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH |
|
| 165 | + $allowedProperties = ['{DAV:}getetag']; |
|
| 166 | + $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties); |
|
| 167 | + |
|
| 168 | + $this->server = $server; |
|
| 169 | + $this->server->on('propFind', array($this, 'handleGetProperties')); |
|
| 170 | + $this->server->on('propPatch', array($this, 'handleUpdateProperties')); |
|
| 171 | + $this->server->on('afterBind', array($this, 'sendFileIdHeader')); |
|
| 172 | + $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader')); |
|
| 173 | + $this->server->on('afterMethod:GET', [$this,'httpGet']); |
|
| 174 | + $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken')); |
|
| 175 | + $this->server->on('afterResponse', function($request, ResponseInterface $response) { |
|
| 176 | + $body = $response->getBody(); |
|
| 177 | + if (is_resource($body)) { |
|
| 178 | + fclose($body); |
|
| 179 | + } |
|
| 180 | + }); |
|
| 181 | + $this->server->on('beforeMove', [$this, 'checkMove']); |
|
| 182 | + } |
|
| 183 | + |
|
| 184 | + /** |
|
| 185 | + * Plugin that checks if a move can actually be performed. |
|
| 186 | + * |
|
| 187 | + * @param string $source source path |
|
| 188 | + * @param string $destination destination path |
|
| 189 | + * @throws Forbidden |
|
| 190 | + * @throws NotFound |
|
| 191 | + */ |
|
| 192 | + function checkMove($source, $destination) { |
|
| 193 | + $sourceNode = $this->tree->getNodeForPath($source); |
|
| 194 | + if (!$sourceNode instanceof Node) { |
|
| 195 | + return; |
|
| 196 | + } |
|
| 197 | + list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source); |
|
| 198 | + list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination); |
|
| 199 | + |
|
| 200 | + if ($sourceDir !== $destinationDir) { |
|
| 201 | + $sourceNodeFileInfo = $sourceNode->getFileInfo(); |
|
| 202 | + if (is_null($sourceNodeFileInfo)) { |
|
| 203 | + throw new NotFound($source . ' does not exist'); |
|
| 204 | + } |
|
| 205 | + |
|
| 206 | + if (!$sourceNodeFileInfo->isDeletable()) { |
|
| 207 | + throw new Forbidden($source . " cannot be deleted"); |
|
| 208 | + } |
|
| 209 | + } |
|
| 210 | + } |
|
| 211 | + |
|
| 212 | + /** |
|
| 213 | + * This sets a cookie to be able to recognize the start of the download |
|
| 214 | + * the content must not be longer than 32 characters and must only contain |
|
| 215 | + * alphanumeric characters |
|
| 216 | + * |
|
| 217 | + * @param RequestInterface $request |
|
| 218 | + * @param ResponseInterface $response |
|
| 219 | + */ |
|
| 220 | + function handleDownloadToken(RequestInterface $request, ResponseInterface $response) { |
|
| 221 | + $queryParams = $request->getQueryParameters(); |
|
| 222 | + |
|
| 223 | + /** |
|
| 224 | + * this sets a cookie to be able to recognize the start of the download |
|
| 225 | + * the content must not be longer than 32 characters and must only contain |
|
| 226 | + * alphanumeric characters |
|
| 227 | + */ |
|
| 228 | + if (isset($queryParams['downloadStartSecret'])) { |
|
| 229 | + $token = $queryParams['downloadStartSecret']; |
|
| 230 | + if (!isset($token[32]) |
|
| 231 | + && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) { |
|
| 232 | + // FIXME: use $response->setHeader() instead |
|
| 233 | + setcookie('ocDownloadStarted', $token, time() + 20, '/'); |
|
| 234 | + } |
|
| 235 | + } |
|
| 236 | + } |
|
| 237 | + |
|
| 238 | + /** |
|
| 239 | + * Add headers to file download |
|
| 240 | + * |
|
| 241 | + * @param RequestInterface $request |
|
| 242 | + * @param ResponseInterface $response |
|
| 243 | + */ |
|
| 244 | + function httpGet(RequestInterface $request, ResponseInterface $response) { |
|
| 245 | + // Only handle valid files |
|
| 246 | + $node = $this->tree->getNodeForPath($request->getPath()); |
|
| 247 | + if (!($node instanceof IFile)) return; |
|
| 248 | + |
|
| 249 | + // adds a 'Content-Disposition: attachment' header in case no disposition |
|
| 250 | + // header has been set before |
|
| 251 | + if ($this->downloadAttachment && |
|
| 252 | + $response->getHeader('Content-Disposition') === null) { |
|
| 253 | + $filename = $node->getName(); |
|
| 254 | + if ($this->request->isUserAgent( |
|
| 255 | + [ |
|
| 256 | + \OC\AppFramework\Http\Request::USER_AGENT_IE, |
|
| 257 | + \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME, |
|
| 258 | + \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX, |
|
| 259 | + ])) { |
|
| 260 | + $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"'); |
|
| 261 | + } else { |
|
| 262 | + $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename) |
|
| 263 | + . '; filename="' . rawurlencode($filename) . '"'); |
|
| 264 | + } |
|
| 265 | + } |
|
| 266 | + |
|
| 267 | + if ($node instanceof \OCA\DAV\Connector\Sabre\File) { |
|
| 268 | + //Add OC-Checksum header |
|
| 269 | + /** @var $node File */ |
|
| 270 | + $checksum = $node->getChecksum(); |
|
| 271 | + if ($checksum !== null && $checksum !== '') { |
|
| 272 | + $response->addHeader('OC-Checksum', $checksum); |
|
| 273 | + } |
|
| 274 | + } |
|
| 275 | + } |
|
| 276 | + |
|
| 277 | + /** |
|
| 278 | + * Adds all ownCloud-specific properties |
|
| 279 | + * |
|
| 280 | + * @param PropFind $propFind |
|
| 281 | + * @param \Sabre\DAV\INode $node |
|
| 282 | + * @return void |
|
| 283 | + */ |
|
| 284 | + public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) { |
|
| 285 | + |
|
| 286 | + $httpRequest = $this->server->httpRequest; |
|
| 287 | + |
|
| 288 | + if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { |
|
| 289 | + |
|
| 290 | + $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) { |
|
| 291 | + return $node->getFileId(); |
|
| 292 | + }); |
|
| 293 | + |
|
| 294 | + $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) { |
|
| 295 | + return $node->getInternalFileId(); |
|
| 296 | + }); |
|
| 297 | + |
|
| 298 | + $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) { |
|
| 299 | + $perms = $node->getDavPermissions(); |
|
| 300 | + if ($this->isPublic) { |
|
| 301 | + // remove mount information |
|
| 302 | + $perms = str_replace(['S', 'M'], '', $perms); |
|
| 303 | + } |
|
| 304 | + return $perms; |
|
| 305 | + }); |
|
| 306 | + |
|
| 307 | + $propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) { |
|
| 308 | + return $node->getSharePermissions( |
|
| 309 | + $httpRequest->getRawServerValue('PHP_AUTH_USER') |
|
| 310 | + ); |
|
| 311 | + }); |
|
| 312 | + |
|
| 313 | + $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) { |
|
| 314 | + return $node->getETag(); |
|
| 315 | + }); |
|
| 316 | + |
|
| 317 | + $propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) { |
|
| 318 | + $owner = $node->getOwner(); |
|
| 319 | + if (!$owner) { |
|
| 320 | + return null; |
|
| 321 | + } else { |
|
| 322 | + return $owner->getUID(); |
|
| 323 | + } |
|
| 324 | + }); |
|
| 325 | + $propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) { |
|
| 326 | + $owner = $node->getOwner(); |
|
| 327 | + if (!$owner) { |
|
| 328 | + return null; |
|
| 329 | + } else { |
|
| 330 | + return $owner->getDisplayName(); |
|
| 331 | + } |
|
| 332 | + }); |
|
| 333 | + |
|
| 334 | + $propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) { |
|
| 335 | + return json_encode($this->previewManager->isAvailable($node->getFileInfo())); |
|
| 336 | + }); |
|
| 337 | + $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) { |
|
| 338 | + return $node->getSize(); |
|
| 339 | + }); |
|
| 340 | + } |
|
| 341 | + |
|
| 342 | + if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { |
|
| 343 | + $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) { |
|
| 344 | + return $this->config->getSystemValue('data-fingerprint', ''); |
|
| 345 | + }); |
|
| 346 | + } |
|
| 347 | + |
|
| 348 | + if ($node instanceof \OCA\DAV\Connector\Sabre\File) { |
|
| 349 | + $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) { |
|
| 350 | + /** @var $node \OCA\DAV\Connector\Sabre\File */ |
|
| 351 | + try { |
|
| 352 | + $directDownloadUrl = $node->getDirectDownload(); |
|
| 353 | + if (isset($directDownloadUrl['url'])) { |
|
| 354 | + return $directDownloadUrl['url']; |
|
| 355 | + } |
|
| 356 | + } catch (StorageNotAvailableException $e) { |
|
| 357 | + return false; |
|
| 358 | + } catch (ForbiddenException $e) { |
|
| 359 | + return false; |
|
| 360 | + } |
|
| 361 | + return false; |
|
| 362 | + }); |
|
| 363 | + |
|
| 364 | + $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) { |
|
| 365 | + $checksum = $node->getChecksum(); |
|
| 366 | + if ($checksum === NULL || $checksum === '') { |
|
| 367 | + return null; |
|
| 368 | + } |
|
| 369 | + |
|
| 370 | + return new ChecksumList($checksum); |
|
| 371 | + }); |
|
| 372 | + |
|
| 373 | + } |
|
| 374 | + |
|
| 375 | + if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) { |
|
| 376 | + $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) { |
|
| 377 | + return $node->getSize(); |
|
| 378 | + }); |
|
| 379 | + } |
|
| 380 | + |
|
| 381 | + $propFind->handle(self::MOUNT_TYPE_PROPERTYNAME, function () use ($node) { |
|
| 382 | + return $node->getFileInfo()->getMountPoint()->getMountType(); |
|
| 383 | + }); |
|
| 384 | + } |
|
| 385 | + |
|
| 386 | + /** |
|
| 387 | + * Update ownCloud-specific properties |
|
| 388 | + * |
|
| 389 | + * @param string $path |
|
| 390 | + * @param PropPatch $propPatch |
|
| 391 | + * |
|
| 392 | + * @return void |
|
| 393 | + */ |
|
| 394 | + public function handleUpdateProperties($path, PropPatch $propPatch) { |
|
| 395 | + $node = $this->tree->getNodeForPath($path); |
|
| 396 | + if (!($node instanceof \OCA\DAV\Connector\Sabre\Node)) { |
|
| 397 | + return; |
|
| 398 | + } |
|
| 399 | + |
|
| 400 | + $propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($node) { |
|
| 401 | + if (empty($time)) { |
|
| 402 | + return false; |
|
| 403 | + } |
|
| 404 | + $node->touch($time); |
|
| 405 | + return true; |
|
| 406 | + }); |
|
| 407 | + $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($node) { |
|
| 408 | + if (empty($etag)) { |
|
| 409 | + return false; |
|
| 410 | + } |
|
| 411 | + if ($node->setEtag($etag) !== -1) { |
|
| 412 | + return true; |
|
| 413 | + } |
|
| 414 | + return false; |
|
| 415 | + }); |
|
| 416 | + } |
|
| 417 | + |
|
| 418 | + /** |
|
| 419 | + * @param string $filePath |
|
| 420 | + * @param \Sabre\DAV\INode $node |
|
| 421 | + * @throws \Sabre\DAV\Exception\BadRequest |
|
| 422 | + */ |
|
| 423 | + public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) { |
|
| 424 | + // chunked upload handling |
|
| 425 | + if (isset($_SERVER['HTTP_OC_CHUNKED'])) { |
|
| 426 | + list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath); |
|
| 427 | + $info = \OC_FileChunking::decodeName($name); |
|
| 428 | + if (!empty($info)) { |
|
| 429 | + $filePath = $path . '/' . $info['name']; |
|
| 430 | + } |
|
| 431 | + } |
|
| 432 | + |
|
| 433 | + // we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder |
|
| 434 | + if (!$this->server->tree->nodeExists($filePath)) { |
|
| 435 | + return; |
|
| 436 | + } |
|
| 437 | + $node = $this->server->tree->getNodeForPath($filePath); |
|
| 438 | + if ($node instanceof \OCA\DAV\Connector\Sabre\Node) { |
|
| 439 | + $fileId = $node->getFileId(); |
|
| 440 | + if (!is_null($fileId)) { |
|
| 441 | + $this->server->httpResponse->setHeader('OC-FileId', $fileId); |
|
| 442 | + } |
|
| 443 | + } |
|
| 444 | + } |
|
| 445 | 445 | } |
@@ -170,7 +170,7 @@ discard block |
||
| 170 | 170 | $this->server->on('propPatch', array($this, 'handleUpdateProperties')); |
| 171 | 171 | $this->server->on('afterBind', array($this, 'sendFileIdHeader')); |
| 172 | 172 | $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader')); |
| 173 | - $this->server->on('afterMethod:GET', [$this,'httpGet']); |
|
| 173 | + $this->server->on('afterMethod:GET', [$this, 'httpGet']); |
|
| 174 | 174 | $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken')); |
| 175 | 175 | $this->server->on('afterResponse', function($request, ResponseInterface $response) { |
| 176 | 176 | $body = $response->getBody(); |
@@ -200,11 +200,11 @@ discard block |
||
| 200 | 200 | if ($sourceDir !== $destinationDir) { |
| 201 | 201 | $sourceNodeFileInfo = $sourceNode->getFileInfo(); |
| 202 | 202 | if (is_null($sourceNodeFileInfo)) { |
| 203 | - throw new NotFound($source . ' does not exist'); |
|
| 203 | + throw new NotFound($source.' does not exist'); |
|
| 204 | 204 | } |
| 205 | 205 | |
| 206 | 206 | if (!$sourceNodeFileInfo->isDeletable()) { |
| 207 | - throw new Forbidden($source . " cannot be deleted"); |
|
| 207 | + throw new Forbidden($source." cannot be deleted"); |
|
| 208 | 208 | } |
| 209 | 209 | } |
| 210 | 210 | } |
@@ -257,10 +257,10 @@ discard block |
||
| 257 | 257 | \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME, |
| 258 | 258 | \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX, |
| 259 | 259 | ])) { |
| 260 | - $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"'); |
|
| 260 | + $response->addHeader('Content-Disposition', 'attachment; filename="'.rawurlencode($filename).'"'); |
|
| 261 | 261 | } else { |
| 262 | - $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename) |
|
| 263 | - . '; filename="' . rawurlencode($filename) . '"'); |
|
| 262 | + $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\''.rawurlencode($filename) |
|
| 263 | + . '; filename="'.rawurlencode($filename).'"'); |
|
| 264 | 264 | } |
| 265 | 265 | } |
| 266 | 266 | |
@@ -331,7 +331,7 @@ discard block |
||
| 331 | 331 | } |
| 332 | 332 | }); |
| 333 | 333 | |
| 334 | - $propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) { |
|
| 334 | + $propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function() use ($node) { |
|
| 335 | 335 | return json_encode($this->previewManager->isAvailable($node->getFileInfo())); |
| 336 | 336 | }); |
| 337 | 337 | $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) { |
@@ -378,7 +378,7 @@ discard block |
||
| 378 | 378 | }); |
| 379 | 379 | } |
| 380 | 380 | |
| 381 | - $propFind->handle(self::MOUNT_TYPE_PROPERTYNAME, function () use ($node) { |
|
| 381 | + $propFind->handle(self::MOUNT_TYPE_PROPERTYNAME, function() use ($node) { |
|
| 382 | 382 | return $node->getFileInfo()->getMountPoint()->getMountType(); |
| 383 | 383 | }); |
| 384 | 384 | } |
@@ -426,7 +426,7 @@ discard block |
||
| 426 | 426 | list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath); |
| 427 | 427 | $info = \OC_FileChunking::decodeName($name); |
| 428 | 428 | if (!empty($info)) { |
| 429 | - $filePath = $path . '/' . $info['name']; |
|
| 429 | + $filePath = $path.'/'.$info['name']; |
|
| 430 | 430 | } |
| 431 | 431 | } |
| 432 | 432 | |
@@ -24,7 +24,7 @@ |
||
| 24 | 24 | use OC\Files\Mount\MountPoint; |
| 25 | 25 | |
| 26 | 26 | class ExternalMountPoint extends MountPoint { |
| 27 | - public function getMountType() { |
|
| 28 | - return 'external'; |
|
| 29 | - } |
|
| 27 | + public function getMountType() { |
|
| 28 | + return 'external'; |
|
| 29 | + } |
|
| 30 | 30 | } |
@@ -35,247 +35,247 @@ |
||
| 35 | 35 | use OCP\Files\Mount\IMountPoint; |
| 36 | 36 | |
| 37 | 37 | class MountPoint implements IMountPoint { |
| 38 | - /** |
|
| 39 | - * @var \OC\Files\Storage\Storage $storage |
|
| 40 | - */ |
|
| 41 | - protected $storage = null; |
|
| 42 | - protected $class; |
|
| 43 | - protected $storageId; |
|
| 44 | - protected $rootId = null; |
|
| 38 | + /** |
|
| 39 | + * @var \OC\Files\Storage\Storage $storage |
|
| 40 | + */ |
|
| 41 | + protected $storage = null; |
|
| 42 | + protected $class; |
|
| 43 | + protected $storageId; |
|
| 44 | + protected $rootId = null; |
|
| 45 | 45 | |
| 46 | - /** |
|
| 47 | - * Configuration options for the storage backend |
|
| 48 | - * |
|
| 49 | - * @var array |
|
| 50 | - */ |
|
| 51 | - protected $arguments = array(); |
|
| 52 | - protected $mountPoint; |
|
| 46 | + /** |
|
| 47 | + * Configuration options for the storage backend |
|
| 48 | + * |
|
| 49 | + * @var array |
|
| 50 | + */ |
|
| 51 | + protected $arguments = array(); |
|
| 52 | + protected $mountPoint; |
|
| 53 | 53 | |
| 54 | - /** |
|
| 55 | - * Mount specific options |
|
| 56 | - * |
|
| 57 | - * @var array |
|
| 58 | - */ |
|
| 59 | - protected $mountOptions = array(); |
|
| 54 | + /** |
|
| 55 | + * Mount specific options |
|
| 56 | + * |
|
| 57 | + * @var array |
|
| 58 | + */ |
|
| 59 | + protected $mountOptions = array(); |
|
| 60 | 60 | |
| 61 | - /** |
|
| 62 | - * @var \OC\Files\Storage\StorageFactory $loader |
|
| 63 | - */ |
|
| 64 | - private $loader; |
|
| 61 | + /** |
|
| 62 | + * @var \OC\Files\Storage\StorageFactory $loader |
|
| 63 | + */ |
|
| 64 | + private $loader; |
|
| 65 | 65 | |
| 66 | - /** |
|
| 67 | - * Specified whether the storage is invalid after failing to |
|
| 68 | - * instantiate it. |
|
| 69 | - * |
|
| 70 | - * @var bool |
|
| 71 | - */ |
|
| 72 | - private $invalidStorage = false; |
|
| 66 | + /** |
|
| 67 | + * Specified whether the storage is invalid after failing to |
|
| 68 | + * instantiate it. |
|
| 69 | + * |
|
| 70 | + * @var bool |
|
| 71 | + */ |
|
| 72 | + private $invalidStorage = false; |
|
| 73 | 73 | |
| 74 | - /** @var int|null */ |
|
| 75 | - protected $mountId; |
|
| 74 | + /** @var int|null */ |
|
| 75 | + protected $mountId; |
|
| 76 | 76 | |
| 77 | - /** |
|
| 78 | - * @param string|\OC\Files\Storage\Storage $storage |
|
| 79 | - * @param string $mountpoint |
|
| 80 | - * @param array $arguments (optional) configuration for the storage backend |
|
| 81 | - * @param \OCP\Files\Storage\IStorageFactory $loader |
|
| 82 | - * @param array $mountOptions mount specific options |
|
| 83 | - * @param int|null $mountId |
|
| 84 | - * @throws \Exception |
|
| 85 | - */ |
|
| 86 | - public function __construct($storage, $mountpoint, $arguments = null, $loader = null, $mountOptions = null, $mountId = null) { |
|
| 87 | - if (is_null($arguments)) { |
|
| 88 | - $arguments = array(); |
|
| 89 | - } |
|
| 90 | - if (is_null($loader)) { |
|
| 91 | - $this->loader = new StorageFactory(); |
|
| 92 | - } else { |
|
| 93 | - $this->loader = $loader; |
|
| 94 | - } |
|
| 77 | + /** |
|
| 78 | + * @param string|\OC\Files\Storage\Storage $storage |
|
| 79 | + * @param string $mountpoint |
|
| 80 | + * @param array $arguments (optional) configuration for the storage backend |
|
| 81 | + * @param \OCP\Files\Storage\IStorageFactory $loader |
|
| 82 | + * @param array $mountOptions mount specific options |
|
| 83 | + * @param int|null $mountId |
|
| 84 | + * @throws \Exception |
|
| 85 | + */ |
|
| 86 | + public function __construct($storage, $mountpoint, $arguments = null, $loader = null, $mountOptions = null, $mountId = null) { |
|
| 87 | + if (is_null($arguments)) { |
|
| 88 | + $arguments = array(); |
|
| 89 | + } |
|
| 90 | + if (is_null($loader)) { |
|
| 91 | + $this->loader = new StorageFactory(); |
|
| 92 | + } else { |
|
| 93 | + $this->loader = $loader; |
|
| 94 | + } |
|
| 95 | 95 | |
| 96 | - if (!is_null($mountOptions)) { |
|
| 97 | - $this->mountOptions = $mountOptions; |
|
| 98 | - } |
|
| 96 | + if (!is_null($mountOptions)) { |
|
| 97 | + $this->mountOptions = $mountOptions; |
|
| 98 | + } |
|
| 99 | 99 | |
| 100 | - $mountpoint = $this->formatPath($mountpoint); |
|
| 101 | - $this->mountPoint = $mountpoint; |
|
| 102 | - if ($storage instanceof Storage) { |
|
| 103 | - $this->class = get_class($storage); |
|
| 104 | - $this->storage = $this->loader->wrap($this, $storage); |
|
| 105 | - } else { |
|
| 106 | - // Update old classes to new namespace |
|
| 107 | - if (strpos($storage, 'OC_Filestorage_') !== false) { |
|
| 108 | - $storage = '\OC\Files\Storage\\' . substr($storage, 15); |
|
| 109 | - } |
|
| 110 | - $this->class = $storage; |
|
| 111 | - $this->arguments = $arguments; |
|
| 112 | - } |
|
| 113 | - $this->mountId = $mountId; |
|
| 114 | - } |
|
| 100 | + $mountpoint = $this->formatPath($mountpoint); |
|
| 101 | + $this->mountPoint = $mountpoint; |
|
| 102 | + if ($storage instanceof Storage) { |
|
| 103 | + $this->class = get_class($storage); |
|
| 104 | + $this->storage = $this->loader->wrap($this, $storage); |
|
| 105 | + } else { |
|
| 106 | + // Update old classes to new namespace |
|
| 107 | + if (strpos($storage, 'OC_Filestorage_') !== false) { |
|
| 108 | + $storage = '\OC\Files\Storage\\' . substr($storage, 15); |
|
| 109 | + } |
|
| 110 | + $this->class = $storage; |
|
| 111 | + $this->arguments = $arguments; |
|
| 112 | + } |
|
| 113 | + $this->mountId = $mountId; |
|
| 114 | + } |
|
| 115 | 115 | |
| 116 | - /** |
|
| 117 | - * get complete path to the mount point, relative to data/ |
|
| 118 | - * |
|
| 119 | - * @return string |
|
| 120 | - */ |
|
| 121 | - public function getMountPoint() { |
|
| 122 | - return $this->mountPoint; |
|
| 123 | - } |
|
| 116 | + /** |
|
| 117 | + * get complete path to the mount point, relative to data/ |
|
| 118 | + * |
|
| 119 | + * @return string |
|
| 120 | + */ |
|
| 121 | + public function getMountPoint() { |
|
| 122 | + return $this->mountPoint; |
|
| 123 | + } |
|
| 124 | 124 | |
| 125 | - /** |
|
| 126 | - * Sets the mount point path, relative to data/ |
|
| 127 | - * |
|
| 128 | - * @param string $mountPoint new mount point |
|
| 129 | - */ |
|
| 130 | - public function setMountPoint($mountPoint) { |
|
| 131 | - $this->mountPoint = $this->formatPath($mountPoint); |
|
| 132 | - } |
|
| 125 | + /** |
|
| 126 | + * Sets the mount point path, relative to data/ |
|
| 127 | + * |
|
| 128 | + * @param string $mountPoint new mount point |
|
| 129 | + */ |
|
| 130 | + public function setMountPoint($mountPoint) { |
|
| 131 | + $this->mountPoint = $this->formatPath($mountPoint); |
|
| 132 | + } |
|
| 133 | 133 | |
| 134 | - /** |
|
| 135 | - * create the storage that is mounted |
|
| 136 | - */ |
|
| 137 | - private function createStorage() { |
|
| 138 | - if ($this->invalidStorage) { |
|
| 139 | - return; |
|
| 140 | - } |
|
| 134 | + /** |
|
| 135 | + * create the storage that is mounted |
|
| 136 | + */ |
|
| 137 | + private function createStorage() { |
|
| 138 | + if ($this->invalidStorage) { |
|
| 139 | + return; |
|
| 140 | + } |
|
| 141 | 141 | |
| 142 | - if (class_exists($this->class)) { |
|
| 143 | - try { |
|
| 144 | - $class = $this->class; |
|
| 145 | - // prevent recursion by setting the storage before applying wrappers |
|
| 146 | - $this->storage = new $class($this->arguments); |
|
| 147 | - $this->storage = $this->loader->wrap($this, $this->storage); |
|
| 148 | - } catch (\Exception $exception) { |
|
| 149 | - $this->storage = null; |
|
| 150 | - $this->invalidStorage = true; |
|
| 151 | - if ($this->mountPoint === '/') { |
|
| 152 | - // the root storage could not be initialized, show the user! |
|
| 153 | - throw new \Exception('The root storage could not be initialized. Please contact your local administrator.', $exception->getCode(), $exception); |
|
| 154 | - } else { |
|
| 155 | - \OCP\Util::writeLog('core', $exception->getMessage(), \OCP\Util::ERROR); |
|
| 156 | - } |
|
| 157 | - return; |
|
| 158 | - } |
|
| 159 | - } else { |
|
| 160 | - \OCP\Util::writeLog('core', 'storage backend ' . $this->class . ' not found', \OCP\Util::ERROR); |
|
| 161 | - $this->invalidStorage = true; |
|
| 162 | - return; |
|
| 163 | - } |
|
| 164 | - } |
|
| 142 | + if (class_exists($this->class)) { |
|
| 143 | + try { |
|
| 144 | + $class = $this->class; |
|
| 145 | + // prevent recursion by setting the storage before applying wrappers |
|
| 146 | + $this->storage = new $class($this->arguments); |
|
| 147 | + $this->storage = $this->loader->wrap($this, $this->storage); |
|
| 148 | + } catch (\Exception $exception) { |
|
| 149 | + $this->storage = null; |
|
| 150 | + $this->invalidStorage = true; |
|
| 151 | + if ($this->mountPoint === '/') { |
|
| 152 | + // the root storage could not be initialized, show the user! |
|
| 153 | + throw new \Exception('The root storage could not be initialized. Please contact your local administrator.', $exception->getCode(), $exception); |
|
| 154 | + } else { |
|
| 155 | + \OCP\Util::writeLog('core', $exception->getMessage(), \OCP\Util::ERROR); |
|
| 156 | + } |
|
| 157 | + return; |
|
| 158 | + } |
|
| 159 | + } else { |
|
| 160 | + \OCP\Util::writeLog('core', 'storage backend ' . $this->class . ' not found', \OCP\Util::ERROR); |
|
| 161 | + $this->invalidStorage = true; |
|
| 162 | + return; |
|
| 163 | + } |
|
| 164 | + } |
|
| 165 | 165 | |
| 166 | - /** |
|
| 167 | - * @return \OC\Files\Storage\Storage |
|
| 168 | - */ |
|
| 169 | - public function getStorage() { |
|
| 170 | - if (is_null($this->storage)) { |
|
| 171 | - $this->createStorage(); |
|
| 172 | - } |
|
| 173 | - return $this->storage; |
|
| 174 | - } |
|
| 166 | + /** |
|
| 167 | + * @return \OC\Files\Storage\Storage |
|
| 168 | + */ |
|
| 169 | + public function getStorage() { |
|
| 170 | + if (is_null($this->storage)) { |
|
| 171 | + $this->createStorage(); |
|
| 172 | + } |
|
| 173 | + return $this->storage; |
|
| 174 | + } |
|
| 175 | 175 | |
| 176 | - /** |
|
| 177 | - * @return string |
|
| 178 | - */ |
|
| 179 | - public function getStorageId() { |
|
| 180 | - if (!$this->storageId) { |
|
| 181 | - if (is_null($this->storage)) { |
|
| 182 | - $storage = $this->createStorage(); //FIXME: start using exceptions |
|
| 183 | - if (is_null($storage)) { |
|
| 184 | - return null; |
|
| 185 | - } |
|
| 176 | + /** |
|
| 177 | + * @return string |
|
| 178 | + */ |
|
| 179 | + public function getStorageId() { |
|
| 180 | + if (!$this->storageId) { |
|
| 181 | + if (is_null($this->storage)) { |
|
| 182 | + $storage = $this->createStorage(); //FIXME: start using exceptions |
|
| 183 | + if (is_null($storage)) { |
|
| 184 | + return null; |
|
| 185 | + } |
|
| 186 | 186 | |
| 187 | - $this->storage = $storage; |
|
| 188 | - } |
|
| 189 | - $this->storageId = $this->storage->getId(); |
|
| 190 | - if (strlen($this->storageId) > 64) { |
|
| 191 | - $this->storageId = md5($this->storageId); |
|
| 192 | - } |
|
| 193 | - } |
|
| 194 | - return $this->storageId; |
|
| 195 | - } |
|
| 187 | + $this->storage = $storage; |
|
| 188 | + } |
|
| 189 | + $this->storageId = $this->storage->getId(); |
|
| 190 | + if (strlen($this->storageId) > 64) { |
|
| 191 | + $this->storageId = md5($this->storageId); |
|
| 192 | + } |
|
| 193 | + } |
|
| 194 | + return $this->storageId; |
|
| 195 | + } |
|
| 196 | 196 | |
| 197 | - /** |
|
| 198 | - * @return int |
|
| 199 | - */ |
|
| 200 | - public function getNumericStorageId() { |
|
| 201 | - return $this->getStorage()->getStorageCache()->getNumericId(); |
|
| 202 | - } |
|
| 197 | + /** |
|
| 198 | + * @return int |
|
| 199 | + */ |
|
| 200 | + public function getNumericStorageId() { |
|
| 201 | + return $this->getStorage()->getStorageCache()->getNumericId(); |
|
| 202 | + } |
|
| 203 | 203 | |
| 204 | - /** |
|
| 205 | - * @param string $path |
|
| 206 | - * @return string |
|
| 207 | - */ |
|
| 208 | - public function getInternalPath($path) { |
|
| 209 | - $path = Filesystem::normalizePath($path, true, false, true); |
|
| 210 | - if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) { |
|
| 211 | - $internalPath = ''; |
|
| 212 | - } else { |
|
| 213 | - $internalPath = substr($path, strlen($this->mountPoint)); |
|
| 214 | - } |
|
| 215 | - // substr returns false instead of an empty string, we always want a string |
|
| 216 | - return (string)$internalPath; |
|
| 217 | - } |
|
| 204 | + /** |
|
| 205 | + * @param string $path |
|
| 206 | + * @return string |
|
| 207 | + */ |
|
| 208 | + public function getInternalPath($path) { |
|
| 209 | + $path = Filesystem::normalizePath($path, true, false, true); |
|
| 210 | + if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) { |
|
| 211 | + $internalPath = ''; |
|
| 212 | + } else { |
|
| 213 | + $internalPath = substr($path, strlen($this->mountPoint)); |
|
| 214 | + } |
|
| 215 | + // substr returns false instead of an empty string, we always want a string |
|
| 216 | + return (string)$internalPath; |
|
| 217 | + } |
|
| 218 | 218 | |
| 219 | - /** |
|
| 220 | - * @param string $path |
|
| 221 | - * @return string |
|
| 222 | - */ |
|
| 223 | - private function formatPath($path) { |
|
| 224 | - $path = Filesystem::normalizePath($path); |
|
| 225 | - if (strlen($path) > 1) { |
|
| 226 | - $path .= '/'; |
|
| 227 | - } |
|
| 228 | - return $path; |
|
| 229 | - } |
|
| 219 | + /** |
|
| 220 | + * @param string $path |
|
| 221 | + * @return string |
|
| 222 | + */ |
|
| 223 | + private function formatPath($path) { |
|
| 224 | + $path = Filesystem::normalizePath($path); |
|
| 225 | + if (strlen($path) > 1) { |
|
| 226 | + $path .= '/'; |
|
| 227 | + } |
|
| 228 | + return $path; |
|
| 229 | + } |
|
| 230 | 230 | |
| 231 | - /** |
|
| 232 | - * @param callable $wrapper |
|
| 233 | - */ |
|
| 234 | - public function wrapStorage($wrapper) { |
|
| 235 | - $storage = $this->getStorage(); |
|
| 236 | - // storage can be null if it couldn't be initialized |
|
| 237 | - if ($storage != null) { |
|
| 238 | - $this->storage = $wrapper($this->mountPoint, $storage, $this); |
|
| 239 | - } |
|
| 240 | - } |
|
| 231 | + /** |
|
| 232 | + * @param callable $wrapper |
|
| 233 | + */ |
|
| 234 | + public function wrapStorage($wrapper) { |
|
| 235 | + $storage = $this->getStorage(); |
|
| 236 | + // storage can be null if it couldn't be initialized |
|
| 237 | + if ($storage != null) { |
|
| 238 | + $this->storage = $wrapper($this->mountPoint, $storage, $this); |
|
| 239 | + } |
|
| 240 | + } |
|
| 241 | 241 | |
| 242 | - /** |
|
| 243 | - * Get a mount option |
|
| 244 | - * |
|
| 245 | - * @param string $name Name of the mount option to get |
|
| 246 | - * @param mixed $default Default value for the mount option |
|
| 247 | - * @return mixed |
|
| 248 | - */ |
|
| 249 | - public function getOption($name, $default) { |
|
| 250 | - return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; |
|
| 251 | - } |
|
| 242 | + /** |
|
| 243 | + * Get a mount option |
|
| 244 | + * |
|
| 245 | + * @param string $name Name of the mount option to get |
|
| 246 | + * @param mixed $default Default value for the mount option |
|
| 247 | + * @return mixed |
|
| 248 | + */ |
|
| 249 | + public function getOption($name, $default) { |
|
| 250 | + return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default; |
|
| 251 | + } |
|
| 252 | 252 | |
| 253 | - /** |
|
| 254 | - * Get all options for the mount |
|
| 255 | - * |
|
| 256 | - * @return array |
|
| 257 | - */ |
|
| 258 | - public function getOptions() { |
|
| 259 | - return $this->mountOptions; |
|
| 260 | - } |
|
| 253 | + /** |
|
| 254 | + * Get all options for the mount |
|
| 255 | + * |
|
| 256 | + * @return array |
|
| 257 | + */ |
|
| 258 | + public function getOptions() { |
|
| 259 | + return $this->mountOptions; |
|
| 260 | + } |
|
| 261 | 261 | |
| 262 | - /** |
|
| 263 | - * Get the file id of the root of the storage |
|
| 264 | - * |
|
| 265 | - * @return int |
|
| 266 | - */ |
|
| 267 | - public function getStorageRootId() { |
|
| 268 | - if (is_null($this->rootId)) { |
|
| 269 | - $this->rootId = (int)$this->getStorage()->getCache()->getId(''); |
|
| 270 | - } |
|
| 271 | - return $this->rootId; |
|
| 272 | - } |
|
| 262 | + /** |
|
| 263 | + * Get the file id of the root of the storage |
|
| 264 | + * |
|
| 265 | + * @return int |
|
| 266 | + */ |
|
| 267 | + public function getStorageRootId() { |
|
| 268 | + if (is_null($this->rootId)) { |
|
| 269 | + $this->rootId = (int)$this->getStorage()->getCache()->getId(''); |
|
| 270 | + } |
|
| 271 | + return $this->rootId; |
|
| 272 | + } |
|
| 273 | 273 | |
| 274 | - public function getMountId() { |
|
| 275 | - return $this->mountId; |
|
| 276 | - } |
|
| 274 | + public function getMountId() { |
|
| 275 | + return $this->mountId; |
|
| 276 | + } |
|
| 277 | 277 | |
| 278 | - public function getMountType() { |
|
| 279 | - return ''; |
|
| 280 | - } |
|
| 278 | + public function getMountType() { |
|
| 279 | + return ''; |
|
| 280 | + } |
|
| 281 | 281 | } |
@@ -29,102 +29,102 @@ |
||
| 29 | 29 | */ |
| 30 | 30 | interface IMountPoint { |
| 31 | 31 | |
| 32 | - /** |
|
| 33 | - * get complete path to the mount point |
|
| 34 | - * |
|
| 35 | - * @return string |
|
| 36 | - * @since 8.0.0 |
|
| 37 | - */ |
|
| 38 | - public function getMountPoint(); |
|
| 32 | + /** |
|
| 33 | + * get complete path to the mount point |
|
| 34 | + * |
|
| 35 | + * @return string |
|
| 36 | + * @since 8.0.0 |
|
| 37 | + */ |
|
| 38 | + public function getMountPoint(); |
|
| 39 | 39 | |
| 40 | - /** |
|
| 41 | - * Set the mountpoint |
|
| 42 | - * |
|
| 43 | - * @param string $mountPoint new mount point |
|
| 44 | - * @since 8.0.0 |
|
| 45 | - */ |
|
| 46 | - public function setMountPoint($mountPoint); |
|
| 40 | + /** |
|
| 41 | + * Set the mountpoint |
|
| 42 | + * |
|
| 43 | + * @param string $mountPoint new mount point |
|
| 44 | + * @since 8.0.0 |
|
| 45 | + */ |
|
| 46 | + public function setMountPoint($mountPoint); |
|
| 47 | 47 | |
| 48 | - /** |
|
| 49 | - * Get the storage that is mounted |
|
| 50 | - * |
|
| 51 | - * @return \OC\Files\Storage\Storage |
|
| 52 | - * @since 8.0.0 |
|
| 53 | - */ |
|
| 54 | - public function getStorage(); |
|
| 48 | + /** |
|
| 49 | + * Get the storage that is mounted |
|
| 50 | + * |
|
| 51 | + * @return \OC\Files\Storage\Storage |
|
| 52 | + * @since 8.0.0 |
|
| 53 | + */ |
|
| 54 | + public function getStorage(); |
|
| 55 | 55 | |
| 56 | - /** |
|
| 57 | - * Get the id of the storages |
|
| 58 | - * |
|
| 59 | - * @return string |
|
| 60 | - * @since 8.0.0 |
|
| 61 | - */ |
|
| 62 | - public function getStorageId(); |
|
| 56 | + /** |
|
| 57 | + * Get the id of the storages |
|
| 58 | + * |
|
| 59 | + * @return string |
|
| 60 | + * @since 8.0.0 |
|
| 61 | + */ |
|
| 62 | + public function getStorageId(); |
|
| 63 | 63 | |
| 64 | - /** |
|
| 65 | - * Get the id of the storages |
|
| 66 | - * |
|
| 67 | - * @return int |
|
| 68 | - * @since 9.1.0 |
|
| 69 | - */ |
|
| 70 | - public function getNumericStorageId(); |
|
| 64 | + /** |
|
| 65 | + * Get the id of the storages |
|
| 66 | + * |
|
| 67 | + * @return int |
|
| 68 | + * @since 9.1.0 |
|
| 69 | + */ |
|
| 70 | + public function getNumericStorageId(); |
|
| 71 | 71 | |
| 72 | - /** |
|
| 73 | - * Get the path relative to the mountpoint |
|
| 74 | - * |
|
| 75 | - * @param string $path absolute path to a file or folder |
|
| 76 | - * @return string |
|
| 77 | - * @since 8.0.0 |
|
| 78 | - */ |
|
| 79 | - public function getInternalPath($path); |
|
| 72 | + /** |
|
| 73 | + * Get the path relative to the mountpoint |
|
| 74 | + * |
|
| 75 | + * @param string $path absolute path to a file or folder |
|
| 76 | + * @return string |
|
| 77 | + * @since 8.0.0 |
|
| 78 | + */ |
|
| 79 | + public function getInternalPath($path); |
|
| 80 | 80 | |
| 81 | - /** |
|
| 82 | - * Apply a storage wrapper to the mounted storage |
|
| 83 | - * |
|
| 84 | - * @param callable $wrapper |
|
| 85 | - * @since 8.0.0 |
|
| 86 | - */ |
|
| 87 | - public function wrapStorage($wrapper); |
|
| 81 | + /** |
|
| 82 | + * Apply a storage wrapper to the mounted storage |
|
| 83 | + * |
|
| 84 | + * @param callable $wrapper |
|
| 85 | + * @since 8.0.0 |
|
| 86 | + */ |
|
| 87 | + public function wrapStorage($wrapper); |
|
| 88 | 88 | |
| 89 | - /** |
|
| 90 | - * Get a mount option |
|
| 91 | - * |
|
| 92 | - * @param string $name Name of the mount option to get |
|
| 93 | - * @param mixed $default Default value for the mount option |
|
| 94 | - * @return mixed |
|
| 95 | - * @since 8.0.0 |
|
| 96 | - */ |
|
| 97 | - public function getOption($name, $default); |
|
| 89 | + /** |
|
| 90 | + * Get a mount option |
|
| 91 | + * |
|
| 92 | + * @param string $name Name of the mount option to get |
|
| 93 | + * @param mixed $default Default value for the mount option |
|
| 94 | + * @return mixed |
|
| 95 | + * @since 8.0.0 |
|
| 96 | + */ |
|
| 97 | + public function getOption($name, $default); |
|
| 98 | 98 | |
| 99 | - /** |
|
| 100 | - * Get all options for the mount |
|
| 101 | - * |
|
| 102 | - * @return array |
|
| 103 | - * @since 8.1.0 |
|
| 104 | - */ |
|
| 105 | - public function getOptions(); |
|
| 99 | + /** |
|
| 100 | + * Get all options for the mount |
|
| 101 | + * |
|
| 102 | + * @return array |
|
| 103 | + * @since 8.1.0 |
|
| 104 | + */ |
|
| 105 | + public function getOptions(); |
|
| 106 | 106 | |
| 107 | - /** |
|
| 108 | - * Get the file id of the root of the storage |
|
| 109 | - * |
|
| 110 | - * @return int |
|
| 111 | - * @since 9.1.0 |
|
| 112 | - */ |
|
| 113 | - public function getStorageRootId(); |
|
| 107 | + /** |
|
| 108 | + * Get the file id of the root of the storage |
|
| 109 | + * |
|
| 110 | + * @return int |
|
| 111 | + * @since 9.1.0 |
|
| 112 | + */ |
|
| 113 | + public function getStorageRootId(); |
|
| 114 | 114 | |
| 115 | - /** |
|
| 116 | - * Get the id of the configured mount |
|
| 117 | - * |
|
| 118 | - * @return int|null mount id or null if not applicable |
|
| 119 | - * @since 9.1.0 |
|
| 120 | - */ |
|
| 121 | - public function getMountId(); |
|
| 115 | + /** |
|
| 116 | + * Get the id of the configured mount |
|
| 117 | + * |
|
| 118 | + * @return int|null mount id or null if not applicable |
|
| 119 | + * @since 9.1.0 |
|
| 120 | + */ |
|
| 121 | + public function getMountId(); |
|
| 122 | 122 | |
| 123 | - /** |
|
| 124 | - * Get the type of mount point, used to distinguish things like shares and external storages |
|
| 125 | - * in the web interface |
|
| 126 | - * |
|
| 127 | - * @return string |
|
| 128 | - */ |
|
| 129 | - public function getMountType(); |
|
| 123 | + /** |
|
| 124 | + * Get the type of mount point, used to distinguish things like shares and external storages |
|
| 125 | + * in the web interface |
|
| 126 | + * |
|
| 127 | + * @return string |
|
| 128 | + */ |
|
| 129 | + public function getMountType(); |
|
| 130 | 130 | } |