You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

748 lines
21 KiB

10 years ago
10 years ago
11 years ago
11 years ago
  1. <?php
  2. /**
  3. * @author Bart Visscher <bartv@thisnet.nl>
  4. * @author Björn Schießle <schiessle@owncloud.com>
  5. * @author Joas Schilling <nickvergessen@owncloud.com>
  6. * @author Michael Gapczynski <GapczynskiM@gmail.com>
  7. * @author Morris Jobke <hey@morrisjobke.de>
  8. * @author Robin Appelman <icewind@owncloud.com>
  9. * @author Robin McCorkell <robin@mccorkell.me.uk>
  10. * @author Roeland Jago Douma <rullzer@owncloud.com>
  11. * @author scambra <sergio@entrecables.com>
  12. * @author Vincent Petry <pvince81@owncloud.com>
  13. *
  14. * @copyright Copyright (c) 2016, ownCloud, Inc.
  15. * @license AGPL-3.0
  16. *
  17. * This code is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License, version 3,
  19. * as published by the Free Software Foundation.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU Affero General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU Affero General Public License, version 3,
  27. * along with this program. If not, see <http://www.gnu.org/licenses/>
  28. *
  29. */
  30. namespace OC\Files\Storage;
  31. use OC\Files\Filesystem;
  32. use OC\Files\Cache\FailedCache;
  33. use OCA\Files_Sharing\ISharedStorage;
  34. use OCP\Constants;
  35. use OCP\Files\Cache\ICacheEntry;
  36. use OCP\Files\Storage\IStorage;
  37. use OCP\Lock\ILockingProvider;
  38. /**
  39. * Convert target path to source path and pass the function call to the correct storage provider
  40. */
  41. class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
  42. private $share; // the shared resource
  43. private $files = array();
  44. /**
  45. * @var \OC\Files\View
  46. */
  47. private $ownerView;
  48. /**
  49. * @var string
  50. */
  51. private $user;
  52. private $initialized = false;
  53. /**
  54. * @var ICacheEntry
  55. */
  56. private $sourceRootInfo;
  57. /**
  58. * @var IStorage
  59. */
  60. private $sourceStorage;
  61. /**
  62. * @var \OCP\ILogger
  63. */
  64. private $logger;
  65. public function __construct($arguments) {
  66. $this->share = $arguments['share'];
  67. $this->ownerView = $arguments['ownerView'];
  68. $this->user = $arguments['user'];
  69. $this->logger = \OC::$server->getLogger();
  70. }
  71. private function init() {
  72. if ($this->initialized) {
  73. return;
  74. }
  75. $this->initialized = true;
  76. try {
  77. Filesystem::initMountPoints($this->share['uid_owner']);
  78. $sourcePath = $this->ownerView->getPath($this->share['file_source']);
  79. list($this->sourceStorage, $sourceInternalPath) = $this->ownerView->resolvePath($sourcePath);
  80. $this->sourceRootInfo = $this->sourceStorage->getCache()->get($sourceInternalPath);
  81. } catch (\Exception $e) {
  82. $this->logger->logException($e);
  83. }
  84. }
  85. private function isValid() {
  86. $this->init();
  87. return $this->sourceRootInfo && ($this->sourceRootInfo->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
  88. }
  89. /**
  90. * get id of the mount point
  91. *
  92. * @return string
  93. */
  94. public function getId() {
  95. return 'shared::' . $this->getMountPoint();
  96. }
  97. /**
  98. * get file cache of the shared item source
  99. *
  100. * @return int
  101. */
  102. public function getSourceId() {
  103. return (int)$this->share['file_source'];
  104. }
  105. /**
  106. * Get the source file path, permissions, and owner for a shared file
  107. *
  108. * @param string $target Shared target file path
  109. * @return array Returns array with the keys path, permissions, and owner or false if not found
  110. */
  111. public function getFile($target) {
  112. $this->init();
  113. if (!isset($this->files[$target])) {
  114. // Check for partial files
  115. if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
  116. $source = \OC_Share_Backend_File::getSource(substr($target, 0, -5), $this->getShare());
  117. if ($source) {
  118. $source['path'] .= '.part';
  119. // All partial files have delete permission
  120. $source['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
  121. }
  122. } else {
  123. $source = \OC_Share_Backend_File::getSource($target, $this->getShare());
  124. }
  125. $this->files[$target] = $source;
  126. }
  127. return $this->files[$target];
  128. }
  129. /**
  130. * Get the source file path for a shared file
  131. *
  132. * @param string $target Shared target file path
  133. * @return string|false source file path or false if not found
  134. */
  135. public function getSourcePath($target) {
  136. if (!$this->isValid()){
  137. return false;
  138. }
  139. $source = $this->getFile($target);
  140. if ($source) {
  141. if (!isset($source['fullPath'])) {
  142. \OC\Files\Filesystem::initMountPoints($source['fileOwner']);
  143. $mount = \OC\Files\Filesystem::getMountByNumericId($source['storage']);
  144. if (is_array($mount) && !empty($mount)) {
  145. $this->files[$target]['fullPath'] = $mount[key($mount)]->getMountPoint() . $source['path'];
  146. } else {
  147. $this->files[$target]['fullPath'] = false;
  148. \OCP\Util::writeLog('files_sharing', "Unable to get mount for shared storage '" . $source['storage'] . "' user '" . $source['fileOwner'] . "'", \OCP\Util::ERROR);
  149. }
  150. }
  151. return $this->files[$target]['fullPath'];
  152. }
  153. return false;
  154. }
  155. /**
  156. * Get the permissions granted for a shared file
  157. *
  158. * @param string $target Shared target file path
  159. * @return int CRUDS permissions granted
  160. */
  161. public function getPermissions($target = '') {
  162. if (!$this->isValid()) {
  163. return 0;
  164. }
  165. $permissions = $this->share['permissions'];
  166. // part files and the mount point always have delete permissions
  167. if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
  168. $permissions |= \OCP\Constants::PERMISSION_DELETE;
  169. }
  170. if (\OCP\Util::isSharingDisabledForUser()) {
  171. $permissions &= ~\OCP\Constants::PERMISSION_SHARE;
  172. }
  173. return $permissions;
  174. }
  175. public function mkdir($path) {
  176. if ($path == '' || $path == '/' || !$this->isCreatable(dirname($path))) {
  177. return false;
  178. } else if ($source = $this->getSourcePath($path)) {
  179. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  180. return $storage->mkdir($internalPath);
  181. }
  182. return false;
  183. }
  184. /**
  185. * Delete the directory if DELETE permission is granted
  186. *
  187. * @param string $path
  188. * @return boolean
  189. */
  190. public function rmdir($path) {
  191. // never delete a share mount point
  192. if (empty($path)) {
  193. return false;
  194. }
  195. if (($source = $this->getSourcePath($path)) && $this->isDeletable($path)) {
  196. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  197. return $storage->rmdir($internalPath);
  198. }
  199. return false;
  200. }
  201. public function opendir($path) {
  202. $source = $this->getSourcePath($path);
  203. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  204. return $storage->opendir($internalPath);
  205. }
  206. public function is_dir($path) {
  207. $source = $this->getSourcePath($path);
  208. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  209. return $storage->is_dir($internalPath);
  210. }
  211. public function is_file($path) {
  212. if ($source = $this->getSourcePath($path)) {
  213. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  214. return $storage->is_file($internalPath);
  215. }
  216. return false;
  217. }
  218. public function stat($path) {
  219. if ($path == '' || $path == '/') {
  220. $stat['size'] = $this->filesize($path);
  221. $stat['mtime'] = $this->filemtime($path);
  222. return $stat;
  223. } else if ($source = $this->getSourcePath($path)) {
  224. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  225. return $storage->stat($internalPath);
  226. }
  227. return false;
  228. }
  229. public function filetype($path) {
  230. if ($path == '' || $path == '/') {
  231. return 'dir';
  232. } else if ($source = $this->getSourcePath($path)) {
  233. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  234. return $storage->filetype($internalPath);
  235. }
  236. return false;
  237. }
  238. public function filesize($path) {
  239. $source = $this->getSourcePath($path);
  240. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  241. return $storage->filesize($internalPath);
  242. }
  243. public function isCreatable($path) {
  244. return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_CREATE);
  245. }
  246. public function isReadable($path) {
  247. if (!$this->isValid()) {
  248. return false;
  249. }
  250. if (!$this->file_exists($path)) {
  251. return false;
  252. }
  253. list($storage, $internalPath) = $this->resolvePath($path);
  254. return $storage->isReadable($internalPath);
  255. }
  256. public function isUpdatable($path) {
  257. return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_UPDATE);
  258. }
  259. public function isDeletable($path) {
  260. return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_DELETE);
  261. }
  262. public function isSharable($path) {
  263. if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
  264. return false;
  265. }
  266. return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
  267. }
  268. public function file_exists($path) {
  269. if ($path == '' || $path == '/') {
  270. return true;
  271. } else if ($source = $this->getSourcePath($path)) {
  272. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  273. return $storage->file_exists($internalPath);
  274. }
  275. return false;
  276. }
  277. public function filemtime($path) {
  278. $source = $this->getSourcePath($path);
  279. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  280. return $storage->filemtime($internalPath);
  281. }
  282. public function file_get_contents($path) {
  283. $source = $this->getSourcePath($path);
  284. if ($source) {
  285. $info = array(
  286. 'target' => $this->getMountPoint() . $path,
  287. 'source' => $source,
  288. );
  289. \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
  290. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  291. return $storage->file_get_contents($internalPath);
  292. }
  293. }
  294. public function file_put_contents($path, $data) {
  295. if ($source = $this->getSourcePath($path)) {
  296. // Check if permission is granted
  297. if (($this->file_exists($path) && !$this->isUpdatable($path))
  298. || ($this->is_dir($path) && !$this->isCreatable($path))
  299. ) {
  300. return false;
  301. }
  302. $info = array(
  303. 'target' => $this->getMountPoint() . '/' . $path,
  304. 'source' => $source,
  305. );
  306. \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
  307. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  308. $result = $storage->file_put_contents($internalPath, $data);
  309. return $result;
  310. }
  311. return false;
  312. }
  313. /**
  314. * Delete the file if DELETE permission is granted
  315. *
  316. * @param string $path
  317. * @return boolean
  318. */
  319. public function unlink($path) {
  320. // never delete a share mount point
  321. if (empty($path)) {
  322. return false;
  323. }
  324. if ($source = $this->getSourcePath($path)) {
  325. if ($this->isDeletable($path)) {
  326. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  327. return $storage->unlink($internalPath);
  328. }
  329. }
  330. return false;
  331. }
  332. public function rename($path1, $path2) {
  333. $this->init();
  334. // we need the paths relative to data/user/files
  335. $relPath1 = $this->getMountPoint() . '/' . $path1;
  336. $relPath2 = $this->getMountPoint() . '/' . $path2;
  337. $pathinfo = pathinfo($relPath1);
  338. $isPartFile = (isset($pathinfo['extension']) && $pathinfo['extension'] === 'part');
  339. $targetExists = $this->file_exists($path2);
  340. $sameFolder = (dirname($relPath1) === dirname($relPath2));
  341. if ($targetExists || ($sameFolder && !$isPartFile)) {
  342. // note that renaming a share mount point is always allowed
  343. if (!$this->isUpdatable('')) {
  344. return false;
  345. }
  346. } else {
  347. if (!$this->isCreatable('')) {
  348. return false;
  349. }
  350. }
  351. /**
  352. * @var \OC\Files\Storage\Storage $sourceStorage
  353. */
  354. list($sourceStorage, $sourceInternalPath) = $this->resolvePath($path1);
  355. /**
  356. * @var \OC\Files\Storage\Storage $targetStorage
  357. */
  358. list($targetStorage, $targetInternalPath) = $this->resolvePath($path2);
  359. return $targetStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
  360. }
  361. public function copy($path1, $path2) {
  362. // Copy the file if CREATE permission is granted
  363. if ($this->isCreatable(dirname($path2))) {
  364. /**
  365. * @var \OC\Files\Storage\Storage $sourceStorage
  366. */
  367. list($sourceStorage, $sourceInternalPath) = $this->resolvePath($path1);
  368. /**
  369. * @var \OC\Files\Storage\Storage $targetStorage
  370. */
  371. list($targetStorage, $targetInternalPath) = $this->resolvePath($path2);
  372. return $targetStorage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
  373. }
  374. return false;
  375. }
  376. public function fopen($path, $mode) {
  377. if ($source = $this->getSourcePath($path)) {
  378. switch ($mode) {
  379. case 'r+':
  380. case 'rb+':
  381. case 'w+':
  382. case 'wb+':
  383. case 'x+':
  384. case 'xb+':
  385. case 'a+':
  386. case 'ab+':
  387. case 'w':
  388. case 'wb':
  389. case 'x':
  390. case 'xb':
  391. case 'a':
  392. case 'ab':
  393. $creatable = $this->isCreatable($path);
  394. $updatable = $this->isUpdatable($path);
  395. // if neither permissions given, no need to continue
  396. if (!$creatable && !$updatable) {
  397. return false;
  398. }
  399. $exists = $this->file_exists($path);
  400. // if a file exists, updatable permissions are required
  401. if ($exists && !$updatable) {
  402. return false;
  403. }
  404. // part file is allowed if !$creatable but the final file is $updatable
  405. if (pathinfo($path, PATHINFO_EXTENSION) !== 'part') {
  406. if (!$exists && !$creatable) {
  407. return false;
  408. }
  409. }
  410. }
  411. $info = array(
  412. 'target' => $this->getMountPoint() . $path,
  413. 'source' => $source,
  414. 'mode' => $mode,
  415. );
  416. \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info);
  417. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  418. return $storage->fopen($internalPath, $mode);
  419. }
  420. return false;
  421. }
  422. public function getMimeType($path) {
  423. if ($source = $this->getSourcePath($path)) {
  424. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  425. return $storage->getMimeType($internalPath);
  426. }
  427. return false;
  428. }
  429. public function free_space($path) {
  430. $source = $this->getSourcePath($path);
  431. if ($source) {
  432. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  433. return $storage->free_space($internalPath);
  434. }
  435. return \OCP\Files\FileInfo::SPACE_UNKNOWN;
  436. }
  437. public function getLocalFile($path) {
  438. if ($source = $this->getSourcePath($path)) {
  439. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  440. return $storage->getLocalFile($internalPath);
  441. }
  442. return false;
  443. }
  444. public function touch($path, $mtime = null) {
  445. if ($source = $this->getSourcePath($path)) {
  446. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  447. return $storage->touch($internalPath, $mtime);
  448. }
  449. return false;
  450. }
  451. /**
  452. * return mount point of share, relative to data/user/files
  453. *
  454. * @return string
  455. */
  456. public function getMountPoint() {
  457. return $this->share['file_target'];
  458. }
  459. public function setMountPoint($path) {
  460. $this->share['file_target'] = $path;
  461. }
  462. public function getShareType() {
  463. return $this->share['share_type'];
  464. }
  465. /**
  466. * does the group share already has a user specific unique name
  467. *
  468. * @return bool
  469. */
  470. public function uniqueNameSet() {
  471. return (isset($this->share['unique_name']) && $this->share['unique_name']);
  472. }
  473. /**
  474. * the share now uses a unique name of this user
  475. *
  476. * @brief the share now uses a unique name of this user
  477. */
  478. public function setUniqueName() {
  479. $this->share['unique_name'] = true;
  480. }
  481. /**
  482. * get share ID
  483. *
  484. * @return integer unique share ID
  485. */
  486. public function getShareId() {
  487. return $this->share['id'];
  488. }
  489. /**
  490. * get the user who shared the file
  491. *
  492. * @return string
  493. */
  494. public function getSharedFrom() {
  495. return $this->share['uid_owner'];
  496. }
  497. /**
  498. * @return array
  499. */
  500. public function getShare() {
  501. return $this->share;
  502. }
  503. /**
  504. * return share type, can be "file" or "folder"
  505. *
  506. * @return string
  507. */
  508. public function getItemType() {
  509. return $this->share['item_type'];
  510. }
  511. public function hasUpdated($path, $time) {
  512. return $this->filemtime($path) > $time;
  513. }
  514. public function getCache($path = '', $storage = null) {
  515. $this->init();
  516. if (is_null($this->sourceStorage)) {
  517. return new FailedCache(false);
  518. }
  519. if (!$storage) {
  520. $storage = $this;
  521. }
  522. return new \OC\Files\Cache\Shared_Cache($storage, $this->sourceStorage, $this->sourceRootInfo);
  523. }
  524. public function getScanner($path = '', $storage = null) {
  525. if (!$storage) {
  526. $storage = $this;
  527. }
  528. return new \OC\Files\Cache\SharedScanner($storage);
  529. }
  530. public function getPropagator($storage = null) {
  531. if (!$storage) {
  532. $storage = $this;
  533. }
  534. return new \OCA\Files_Sharing\SharedPropagator($storage);
  535. }
  536. public function getOwner($path) {
  537. if ($path == '') {
  538. $path = $this->getMountPoint();
  539. }
  540. $source = $this->getFile($path);
  541. if ($source) {
  542. return $source['fileOwner'];
  543. }
  544. return false;
  545. }
  546. public function getETag($path) {
  547. if ($source = $this->getSourcePath($path)) {
  548. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($source);
  549. return $storage->getETag($internalPath);
  550. }
  551. return null;
  552. }
  553. /**
  554. * unshare complete storage, also the grouped shares
  555. *
  556. * @return bool
  557. */
  558. public function unshareStorage() {
  559. $result = true;
  560. if (!empty($this->share['grouped'])) {
  561. foreach ($this->share['grouped'] as $share) {
  562. $result = $result && \OCP\Share::unshareFromSelf($share['item_type'], $share['file_target']);
  563. }
  564. }
  565. $result = $result && \OCP\Share::unshareFromSelf($this->getItemType(), $this->getMountPoint());
  566. return $result;
  567. }
  568. /**
  569. * Resolve the path for the source of the share
  570. *
  571. * @param string $path
  572. * @return array
  573. */
  574. public function resolvePath($path) {
  575. $source = $this->getSourcePath($path);
  576. return \OC\Files\Filesystem::resolvePath($source);
  577. }
  578. /**
  579. * @param \OCP\Files\Storage $sourceStorage
  580. * @param string $sourceInternalPath
  581. * @param string $targetInternalPath
  582. * @return bool
  583. */
  584. public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
  585. /** @var \OCP\Files\Storage $targetStorage */
  586. list($targetStorage, $targetInternalPath) = $this->resolvePath($targetInternalPath);
  587. return $targetStorage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
  588. }
  589. /**
  590. * @param \OCP\Files\Storage $sourceStorage
  591. * @param string $sourceInternalPath
  592. * @param string $targetInternalPath
  593. * @return bool
  594. */
  595. public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
  596. /** @var \OCP\Files\Storage $targetStorage */
  597. list($targetStorage, $targetInternalPath) = $this->resolvePath($targetInternalPath);
  598. return $targetStorage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
  599. }
  600. /**
  601. * @param string $path
  602. * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
  603. * @param \OCP\Lock\ILockingProvider $provider
  604. * @throws \OCP\Lock\LockedException
  605. */
  606. public function acquireLock($path, $type, ILockingProvider $provider) {
  607. /** @var \OCP\Files\Storage $targetStorage */
  608. list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
  609. $targetStorage->acquireLock($targetInternalPath, $type, $provider);
  610. // lock the parent folders of the owner when locking the share as recipient
  611. if ($path === '') {
  612. $sourcePath = $this->ownerView->getPath($this->share['file_source']);
  613. $this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
  614. }
  615. }
  616. /**
  617. * @param string $path
  618. * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
  619. * @param \OCP\Lock\ILockingProvider $provider
  620. */
  621. public function releaseLock($path, $type, ILockingProvider $provider) {
  622. /** @var \OCP\Files\Storage $targetStorage */
  623. list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
  624. $targetStorage->releaseLock($targetInternalPath, $type, $provider);
  625. // unlock the parent folders of the owner when unlocking the share as recipient
  626. if ($path === '') {
  627. $sourcePath = $this->ownerView->getPath($this->share['file_source']);
  628. $this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
  629. }
  630. }
  631. /**
  632. * @param string $path
  633. * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
  634. * @param \OCP\Lock\ILockingProvider $provider
  635. */
  636. public function changeLock($path, $type, ILockingProvider $provider) {
  637. /** @var \OCP\Files\Storage $targetStorage */
  638. list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
  639. $targetStorage->changeLock($targetInternalPath, $type, $provider);
  640. }
  641. /**
  642. * @return array [ available, last_checked ]
  643. */
  644. public function getAvailability() {
  645. // shares do not participate in availability logic
  646. return [
  647. 'available' => true,
  648. 'last_checked' => 0
  649. ];
  650. }
  651. /**
  652. * @param bool $available
  653. */
  654. public function setAvailability($available) {
  655. // shares do not participate in availability logic
  656. }
  657. public function isLocal() {
  658. $this->init();
  659. $ownerPath = $this->ownerView->getPath($this->share['item_source']);
  660. list($targetStorage) = $this->ownerView->resolvePath($ownerPath);
  661. return $targetStorage->isLocal();
  662. }
  663. public function getSourceStorage() {
  664. return $this->sourceStorage;
  665. }
  666. }