PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/files_sharing/lib/sharedstorage.php

https://github.com/jlgg/simple_trash
PHP | 458 lines | 364 code | 35 blank | 59 comment | 124 complexity | a8e121655deee2c2bd4c7c642eb3a819 MD5 | raw file
Possible License(s): AGPL-3.0, AGPL-1.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Michael Gapczynski
  6. * @copyright 2011 Michael Gapczynski mtgap@owncloud.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. /**
  23. * Convert target path to source path and pass the function call to the correct storage provider
  24. */
  25. class OC_Filestorage_Shared extends OC_Filestorage_Common {
  26. private $sharedFolder;
  27. private $files = array();
  28. public function __construct($arguments) {
  29. $this->sharedFolder = $arguments['sharedFolder'];
  30. }
  31. /**
  32. * @brief Get the source file path and the permissions granted for a shared file
  33. * @param string Shared target file path
  34. * @return Returns array with the keys path and permissions or false if not found
  35. */
  36. private function getFile($target) {
  37. $target = '/'.$target;
  38. $target = rtrim($target, '/');
  39. if (isset($this->files[$target])) {
  40. return $this->files[$target];
  41. } else {
  42. $pos = strpos($target, '/', 1);
  43. // Get shared folder name
  44. if ($pos !== false) {
  45. $folder = substr($target, 0, $pos);
  46. if (isset($this->files[$folder])) {
  47. $file = $this->files[$folder];
  48. } else {
  49. $file = OCP\Share::getItemSharedWith('folder', $folder, OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
  50. }
  51. if ($file) {
  52. $this->files[$target]['path'] = $file['path'].substr($target, strlen($folder));
  53. $this->files[$target]['permissions'] = $file['permissions'];
  54. return $this->files[$target];
  55. }
  56. } else {
  57. $file = OCP\Share::getItemSharedWith('file', $target, OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
  58. if ($file) {
  59. $this->files[$target] = $file;
  60. return $this->files[$target];
  61. }
  62. }
  63. OCP\Util::writeLog('files_sharing', 'File source not found for: '.$target, OCP\Util::ERROR);
  64. return false;
  65. }
  66. }
  67. /**
  68. * @brief Get the source file path for a shared file
  69. * @param string Shared target file path
  70. * @return Returns source file path or false if not found
  71. */
  72. private function getSourcePath($target) {
  73. $file = $this->getFile($target);
  74. if (isset($file['path'])) {
  75. $uid = substr($file['path'], 1, strpos($file['path'], '/', 1) - 1);
  76. OC_Filesystem::mount('OC_Filestorage_Local', array('datadir' => OC_User::getHome($uid)), $uid);
  77. return $file['path'];
  78. }
  79. return false;
  80. }
  81. /**
  82. * @brief Get the permissions granted for a shared file
  83. * @param string Shared target file path
  84. * @return Returns CRUDS permissions granted or false if not found
  85. */
  86. private function getPermissions($target) {
  87. $file = $this->getFile($target);
  88. if (isset($file['permissions'])) {
  89. return $file['permissions'];
  90. }
  91. return false;
  92. }
  93. /**
  94. * @brief Get the internal path to pass to the storage filesystem call
  95. * @param string Source file path
  96. * @return Source file path with mount point stripped out
  97. */
  98. private function getInternalPath($path) {
  99. $mountPoint = OC_Filesystem::getMountPoint($path);
  100. $internalPath = substr($path, strlen($mountPoint));
  101. return $internalPath;
  102. }
  103. public function getOwner($target) {
  104. $shared_item = OCP\Share::getItemSharedWith('folder', $target, OC_Share_Backend_File::FORMAT_SHARED_STORAGE);
  105. if ($shared_item) {
  106. return $shared_item[0]["uid_owner"];
  107. }
  108. return null;
  109. }
  110. public function mkdir($path) {
  111. if ($path == '' || $path == '/' || !$this->isCreatable(dirname($path))) {
  112. return false;
  113. } else if ($source = $this->getSourcePath($path)) {
  114. $storage = OC_Filesystem::getStorage($source);
  115. return $storage->mkdir($this->getInternalPath($source));
  116. }
  117. return false;
  118. }
  119. public function rmdir($path) {
  120. if (($source = $this->getSourcePath($path)) && $this->isDeletable($path)) {
  121. $storage = OC_Filesystem::getStorage($source);
  122. return $storage->rmdir($this->getInternalPath($source));
  123. }
  124. return false;
  125. }
  126. public function opendir($path) {
  127. if ($path == '' || $path == '/') {
  128. $files = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_Folder::FORMAT_OPENDIR);
  129. OC_FakeDirStream::$dirs['shared'] = $files;
  130. return opendir('fakedir://shared');
  131. } else if ($source = $this->getSourcePath($path)) {
  132. $storage = OC_Filesystem::getStorage($source);
  133. return $storage->opendir($this->getInternalPath($source));
  134. }
  135. return false;
  136. }
  137. public function is_dir($path) {
  138. if ($path == '' || $path == '/') {
  139. return true;
  140. } else if ($source = $this->getSourcePath($path)) {
  141. $storage = OC_Filesystem::getStorage($source);
  142. return $storage->is_dir($this->getInternalPath($source));
  143. }
  144. return false;
  145. }
  146. public function is_file($path) {
  147. if ($source = $this->getSourcePath($path)) {
  148. $storage = OC_Filesystem::getStorage($source);
  149. return $storage->is_file($this->getInternalPath($source));
  150. }
  151. return false;
  152. }
  153. public function stat($path) {
  154. if ($path == '' || $path == '/') {
  155. $stat['size'] = $this->filesize($path);
  156. $stat['mtime'] = $this->filemtime($path);
  157. $stat['ctime'] = $this->filectime($path);
  158. return $stat;
  159. } else if ($source = $this->getSourcePath($path)) {
  160. $storage = OC_Filesystem::getStorage($source);
  161. return $storage->stat($this->getInternalPath($source));
  162. }
  163. return false;
  164. }
  165. public function filetype($path) {
  166. if ($path == '' || $path == '/') {
  167. return 'dir';
  168. } else if ($source = $this->getSourcePath($path)) {
  169. $storage = OC_Filesystem::getStorage($source);
  170. return $storage->filetype($this->getInternalPath($source));
  171. }
  172. return false;
  173. }
  174. public function filesize($path) {
  175. if ($path == '' || $path == '/' || $this->is_dir($path)) {
  176. return 0;
  177. } else if ($source = $this->getSourcePath($path)) {
  178. $storage = OC_Filesystem::getStorage($source);
  179. return $storage->filesize($this->getInternalPath($source));
  180. }
  181. return false;
  182. }
  183. public function isCreatable($path) {
  184. if ($path == '') {
  185. return false;
  186. }
  187. return ($this->getPermissions($path) & OCP\PERMISSION_CREATE);
  188. }
  189. public function isReadable($path) {
  190. return $this->file_exists($path);
  191. }
  192. public function isUpdatable($path) {
  193. if ($path == '') {
  194. return false;
  195. }
  196. return ($this->getPermissions($path) & OCP\PERMISSION_UPDATE);
  197. }
  198. public function isDeletable($path) {
  199. if ($path == '') {
  200. return true;
  201. }
  202. return ($this->getPermissions($path) & OCP\PERMISSION_DELETE);
  203. }
  204. public function isSharable($path) {
  205. if ($path == '') {
  206. return false;
  207. }
  208. return ($this->getPermissions($path) & OCP\PERMISSION_SHARE);
  209. }
  210. public function file_exists($path) {
  211. if ($path == '' || $path == '/') {
  212. return true;
  213. } else if ($source = $this->getSourcePath($path)) {
  214. $storage = OC_Filesystem::getStorage($source);
  215. return $storage->file_exists($this->getInternalPath($source));
  216. }
  217. return false;
  218. }
  219. public function filectime($path) {
  220. if ($path == '' || $path == '/') {
  221. $ctime = 0;
  222. if ($dh = $this->opendir($path)) {
  223. while (($filename = readdir($dh)) !== false) {
  224. $tempctime = $this->filectime($filename);
  225. if ($tempctime < $ctime) {
  226. $ctime = $tempctime;
  227. }
  228. }
  229. }
  230. return $ctime;
  231. } else {
  232. $source = $this->getSourcePath($path);
  233. if ($source) {
  234. $storage = OC_Filesystem::getStorage($source);
  235. return $storage->filectime($this->getInternalPath($source));
  236. }
  237. }
  238. }
  239. public function filemtime($path) {
  240. if ($path == '' || $path == '/') {
  241. $mtime = 0;
  242. if ($dh = $this->opendir($path)) {
  243. while (($filename = readdir($dh)) !== false) {
  244. $tempmtime = $this->filemtime($filename);
  245. if ($tempmtime > $mtime) {
  246. $mtime = $tempmtime;
  247. }
  248. }
  249. }
  250. return $mtime;
  251. } else {
  252. $source = $this->getSourcePath($path);
  253. if ($source) {
  254. $storage = OC_Filesystem::getStorage($source);
  255. return $storage->filemtime($this->getInternalPath($source));
  256. }
  257. }
  258. }
  259. public function file_get_contents($path) {
  260. $source = $this->getSourcePath($path);
  261. if ($source) {
  262. $info = array(
  263. 'target' => $this->sharedFolder.$path,
  264. 'source' => $source,
  265. );
  266. OCP\Util::emitHook('OC_Filestorage_Shared', 'file_get_contents', $info);
  267. $storage = OC_Filesystem::getStorage($source);
  268. return $storage->file_get_contents($this->getInternalPath($source));
  269. }
  270. }
  271. public function file_put_contents($path, $data) {
  272. if ($source = $this->getSourcePath($path)) {
  273. // Check if permission is granted
  274. if (($this->file_exists($path) && !$this->isUpdatable($path)) || ($this->is_dir($path) && !$this->isCreatable($path))) {
  275. return false;
  276. }
  277. $info = array(
  278. 'target' => $this->sharedFolder.$path,
  279. 'source' => $source,
  280. );
  281. OCP\Util::emitHook('OC_Filestorage_Shared', 'file_put_contents', $info);
  282. $storage = OC_Filesystem::getStorage($source);
  283. $result = $storage->file_put_contents($this->getInternalPath($source), $data);
  284. return $result;
  285. }
  286. return false;
  287. }
  288. public function unlink($path) {
  289. // Delete the file if DELETE permission is granted
  290. if ($source = $this->getSourcePath($path)) {
  291. if ($this->isDeletable($path)) {
  292. $storage = OC_Filesystem::getStorage($source);
  293. return $storage->unlink($this->getInternalPath($source));
  294. } else if (dirname($path) == '/' || dirname($path) == '.') {
  295. // Unshare the file from the user if in the root of the Shared folder
  296. if ($this->is_dir($path)) {
  297. $itemType = 'folder';
  298. } else {
  299. $itemType = 'file';
  300. }
  301. return OCP\Share::unshareFromSelf($itemType, $path);
  302. }
  303. }
  304. return false;
  305. }
  306. public function rename($path1, $path2) {
  307. // Renaming/moving is only allowed within shared folders
  308. $pos1 = strpos($path1, '/', 1);
  309. $pos2 = strpos($path2, '/', 1);
  310. if ($pos1 !== false && $pos2 !== false && ($oldSource = $this->getSourcePath($path1))) {
  311. $newSource = $this->getSourcePath(dirname($path2)).'/'.basename($path2);
  312. if (dirname($path1) == dirname($path2)) {
  313. // Rename the file if UPDATE permission is granted
  314. if ($this->isUpdatable($path1)) {
  315. $storage = OC_Filesystem::getStorage($oldSource);
  316. return $storage->rename($this->getInternalPath($oldSource), $this->getInternalPath($newSource));
  317. }
  318. } else {
  319. // Move the file if DELETE and CREATE permissions are granted
  320. if ($this->isDeletable($path1) && $this->isCreatable(dirname($path2))) {
  321. // Get the root shared folder
  322. $folder1 = substr($path1, 0, $pos1);
  323. $folder2 = substr($path2, 0, $pos2);
  324. // Copy and unlink the file if it exists in a different shared folder
  325. if ($folder1 != $folder2) {
  326. if ($this->copy($path1, $path2)) {
  327. return $this->unlink($path1);
  328. }
  329. } else {
  330. $storage = OC_Filesystem::getStorage($oldSource);
  331. return $storage->rename($this->getInternalPath($oldSource), $this->getInternalPath($newSource));
  332. }
  333. }
  334. }
  335. }
  336. return false;
  337. }
  338. public function copy($path1, $path2) {
  339. // Copy the file if CREATE permission is granted
  340. if ($this->isCreatable(dirname($path2))) {
  341. $source = $this->fopen($path1, 'r');
  342. $target = $this->fopen($path2, 'w');
  343. return OC_Helper::streamCopy($source, $target);
  344. }
  345. return false;
  346. }
  347. public function fopen($path, $mode) {
  348. if ($source = $this->getSourcePath($path)) {
  349. switch ($mode) {
  350. case 'r+':
  351. case 'rb+':
  352. case 'w+':
  353. case 'wb+':
  354. case 'x+':
  355. case 'xb+':
  356. case 'a+':
  357. case 'ab+':
  358. case 'w':
  359. case 'wb':
  360. case 'x':
  361. case 'xb':
  362. case 'a':
  363. case 'ab':
  364. if (!$this->isUpdatable($path)) {
  365. return false;
  366. }
  367. }
  368. $info = array(
  369. 'target' => $this->sharedFolder.$path,
  370. 'source' => $source,
  371. 'mode' => $mode,
  372. );
  373. OCP\Util::emitHook('OC_Filestorage_Shared', 'fopen', $info);
  374. $storage = OC_Filesystem::getStorage($source);
  375. return $storage->fopen($this->getInternalPath($source), $mode);
  376. }
  377. return false;
  378. }
  379. public function getMimeType($path) {
  380. if ($path == '' || $path == '/') {
  381. return 'httpd/unix-directory';
  382. }
  383. if ($source = $this->getSourcePath($path)) {
  384. $storage = OC_Filesystem::getStorage($source);
  385. return $storage->getMimeType($this->getInternalPath($source));
  386. }
  387. return false;
  388. }
  389. public function free_space($path) {
  390. $source = $this->getSourcePath($path);
  391. if ($source) {
  392. $storage = OC_Filesystem::getStorage($source);
  393. return $storage->free_space($this->getInternalPath($source));
  394. }
  395. }
  396. public function getLocalFile($path) {
  397. if ($source = $this->getSourcePath($path)) {
  398. $storage = OC_Filesystem::getStorage($source);
  399. return $storage->getLocalFile($this->getInternalPath($source));
  400. }
  401. return false;
  402. }
  403. public function touch($path, $mtime = null) {
  404. if ($source = $this->getSourcePath($path)) {
  405. $storage = OC_Filesystem::getStorage($source);
  406. return $storage->touch($this->getInternalPath($source), $mtime);
  407. }
  408. return false;
  409. }
  410. public static function setup($options) {
  411. $user_dir = $options['user_dir'];
  412. OC_Filesystem::mount('OC_Filestorage_Shared', array('sharedFolder' => '/Shared'), $user_dir.'/Shared/');
  413. }
  414. /**
  415. * check if a file or folder has been updated since $time
  416. * @param int $time
  417. * @return bool
  418. */
  419. public function hasUpdated($path, $time) {
  420. //TODO
  421. return false;
  422. }
  423. }