sharedstorage.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Michael Gapczynski
  6. * @copyright 2011 Michael Gapczynski GapczynskiM@gmail.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. require_once( 'lib_share.php' );
  23. /**
  24. * Convert target path to source path and pass the function call to the correct storage provider
  25. */
  26. class OC_Filestorage_Shared extends OC_Filestorage {
  27. private $datadir;
  28. private $sourcePaths = array();
  29. public function __construct($arguments) {
  30. $this->datadir = $arguments['datadir'];
  31. $this->datadir .= "/";
  32. }
  33. public function getInternalPath($path) {
  34. $mountPoint = OC_Filesystem::getMountPoint($path);
  35. $internalPath = substr($path, strlen($mountPoint));
  36. return $internalPath;
  37. }
  38. public function getSource($target) {
  39. $target = $this->datadir.$target;
  40. if (array_key_exists($target, $this->sourcePaths)) {
  41. return $this->sourcePaths[$target];
  42. } else {
  43. $source = OC_Share::getSource($target);
  44. $this->sourcePaths[$target] = $source;
  45. return $source;
  46. }
  47. }
  48. public function mkdir($path) {
  49. if ($path == "" || $path == "/" || !$this->is_writable($path)) {
  50. return false;
  51. } else {
  52. $source = $this->getSource($path);
  53. if ($source) {
  54. $storage = OC_Filesystem::getStorage($source);
  55. return $storage->mkdir($this->getInternalPath($source));
  56. }
  57. }
  58. }
  59. public function rmdir($path) {
  60. // The folder will be removed from the database, but won't be deleted from the owner's filesystem
  61. OC_Share::unshareFromMySelf($this->datadir.$path);
  62. $this->clearFolderSizeCache($path);
  63. }
  64. public function opendir($path) {
  65. if ($path == "" || $path == "/") {
  66. $path = $this->datadir.$path;
  67. $sharedItems = OC_Share::getItemsInFolder($path);
  68. $files = array();
  69. foreach ($sharedItems as $item) {
  70. // If item is in the root of the shared storage provider and the item exists add it to the fakedirs
  71. if (dirname($item['target'])."/" == $path && $this->file_exists(basename($item['target']))) {
  72. $files[] = basename($item['target']);
  73. }
  74. }
  75. OC_FakeDirStream::$dirs['shared'.$path] = $files;
  76. return opendir('fakedir://shared'.$path);
  77. } else {
  78. $source = $this->getSource($path);
  79. if ($source) {
  80. $storage = OC_Filesystem::getStorage($source);
  81. $dh = $storage->opendir($this->getInternalPath($source));
  82. $modifiedItems = OC_Share::getItemsInFolder($source);
  83. if ($modifiedItems && $dh) {
  84. $sources = array();
  85. $targets = array();
  86. // Remove any duplicate or trailing '/'
  87. $path = preg_replace('{(/)\1+}', "/", $path);
  88. $targetFolder = rtrim($this->datadir.$path, "/");
  89. foreach ($modifiedItems as $item) {
  90. // If the item is in the current directory and the item exists add it to the arrays
  91. if (dirname($item['target']) == $targetFolder && $this->file_exists($path."/".basename($item['target']))) {
  92. // If the item was unshared from self, add it it to the arrays
  93. if ($item['permissions'] == OC_Share::UNSHARED) {
  94. $sources[] = basename($item['source']);
  95. $targets[] = "";
  96. } else {
  97. $sources[] = basename($item['source']);
  98. $targets[] = basename($item['target']);
  99. }
  100. }
  101. }
  102. // Don't waste time if there aren't any modified items in the current directory
  103. if (empty($sources)) {
  104. return $dh;
  105. } else {
  106. global $FAKEDIRS;
  107. $files = array();
  108. while (($filename = readdir($dh)) !== false) {
  109. if ($filename != "." && $filename != "..") {
  110. // If the file isn't in the sources array it isn't modified and can be added as is
  111. if (!in_array($filename, $sources)) {
  112. $files[] = $filename;
  113. // The file has a different name than the source and is added to the fakedirs
  114. } else {
  115. $target = $targets[array_search($filename, $sources)];
  116. // Don't add the file if it was unshared from self by the user
  117. if ($target != "") {
  118. $files[] = $target;
  119. }
  120. }
  121. }
  122. }
  123. $FAKEDIRS['shared'] = $files;
  124. return opendir('fakedir://shared');
  125. }
  126. } else {
  127. return $dh;
  128. }
  129. }
  130. }
  131. }
  132. public function is_dir($path) {
  133. if ($path == "" || $path == "/") {
  134. return true;
  135. } else {
  136. $source = $this->getSource($path);
  137. if ($source) {
  138. $storage = OC_Filesystem::getStorage($source);
  139. return $storage->is_dir($this->getInternalPath($source));
  140. }
  141. }
  142. }
  143. public function is_file($path) {
  144. $source = $this->getSource($path);
  145. if ($source) {
  146. $storage = OC_Filesystem::getStorage($source);
  147. return $storage->is_file($this->getInternalPath($source));
  148. }
  149. }
  150. // TODO fill in other components of array
  151. public function stat($path) {
  152. if ($path == "" || $path == "/") {
  153. $stat["size"] = $this->filesize($path);
  154. $stat["mtime"] = $this->filemtime($path);
  155. $stat["ctime"] = $this->filectime($path);
  156. return $stat;
  157. } else {
  158. $source = $this->getSource($path);
  159. if ($source) {
  160. $storage = OC_Filesystem::getStorage($source);
  161. return $storage->stat($this->getInternalPath($source));
  162. }
  163. }
  164. }
  165. public function filetype($path) {
  166. if ($path == "" || $path == "/") {
  167. return "dir";
  168. } else {
  169. $source = $this->getSource($path);
  170. if ($source) {
  171. $storage = OC_Filesystem::getStorage($source);
  172. return $storage->filetype($this->getInternalPath($source));
  173. }
  174. }
  175. }
  176. public function filesize($path) {
  177. if ($path == "" || $path == "/" || $this->is_dir($path)) {
  178. return $this->getFolderSize($path);
  179. } else {
  180. $source = $this->getSource($path);
  181. if ($source) {
  182. $storage = OC_Filesystem::getStorage($source);
  183. return $storage->filesize($this->getInternalPath($source));
  184. }
  185. }
  186. }
  187. public function getFolderSize($path) {
  188. return 0; //depricated
  189. }
  190. private function calculateFolderSize($path) {
  191. if ($this->is_file($path)) {
  192. $path = dirname($path);
  193. }
  194. $size = 0;
  195. if ($dh = $this->opendir($path)) {
  196. while (($filename = readdir($dh)) !== false) {
  197. if ($filename != "." && $filename != "..") {
  198. $subFile = $path."/".$filename;
  199. if ($this->is_file($subFile)) {
  200. $size += $this->filesize($subFile);
  201. } else {
  202. $size += $this->getFolderSize($subFile);
  203. }
  204. }
  205. }
  206. if ($size > 0) {
  207. $dbpath = rtrim($this->datadir.$path, "/");
  208. // $query = OCP\DB::prepare("INSERT INTO `*PREFIX*foldersize` VALUES(?,?)");
  209. // $result = $query->execute(array($dbpath, $size));
  210. }
  211. }
  212. return $size;
  213. }
  214. private function clearFolderSizeCache($path) {
  215. $path = rtrim($path, "/");
  216. $path = preg_replace('{(/)\1+}', "/", $path);
  217. if ($this->is_file($path)) {
  218. $path = dirname($path);
  219. }
  220. $dbpath = rtrim($this->datadir.$path, "/");
  221. // $query = OCP\DB::prepare("DELETE FROM `*PREFIX*/*foldersize*/` WHERE `path` = ?");
  222. // $result = $query->execute(array($dbpath));
  223. if ($path != "/" && $path != "") {
  224. $parts = explode("/", $path);
  225. $part = array_pop($parts);
  226. if (empty($part)) {
  227. array_pop($parts);
  228. }
  229. $parent = implode("/", $parts);
  230. $this->clearFolderSizeCache($parent);
  231. }
  232. }
  233. public function is_readable($path) {
  234. return true;
  235. }
  236. public function is_writable($path) {
  237. if($path == "" || $path == "/"){
  238. return false;
  239. }elseif (OC_Share::getPermissions($this->datadir.$path) & OC_Share::WRITE) {
  240. return true;
  241. } else {
  242. return false;
  243. }
  244. }
  245. public function file_exists($path) {
  246. if ($path == "" || $path == "/") {
  247. return true;
  248. } else {
  249. $source = $this->getSource($path);
  250. if ($source) {
  251. $storage = OC_Filesystem::getStorage($source);
  252. return $storage->file_exists($this->getInternalPath($source));
  253. }
  254. }
  255. }
  256. public function filectime($path) {
  257. if ($path == "" || $path == "/") {
  258. $ctime = 0;
  259. if ($dh = $this->opendir($path)) {
  260. while (($filename = readdir($dh)) !== false) {
  261. $tempctime = $this->filectime($filename);
  262. if ($tempctime < $ctime) {
  263. $ctime = $tempctime;
  264. }
  265. }
  266. }
  267. return $ctime;
  268. } else {
  269. $source = $this->getSource($path);
  270. if ($source) {
  271. $storage = OC_Filesystem::getStorage($source);
  272. return $storage->filectime($this->getInternalPath($source));
  273. }
  274. }
  275. }
  276. public function filemtime($path) {
  277. if ($path == "" || $path == "/") {
  278. $mtime = 0;
  279. if ($dh = $this->opendir($path)) {
  280. while (($filename = readdir($dh)) !== false) {
  281. $tempmtime = $this->filemtime($filename);
  282. if ($tempmtime > $mtime) {
  283. $mtime = $tempmtime;
  284. }
  285. }
  286. }
  287. return $mtime;
  288. } else {
  289. $source = $this->getSource($path);
  290. if ($source) {
  291. $storage = OC_Filesystem::getStorage($source);
  292. return $storage->filemtime($this->getInternalPath($source));
  293. }
  294. }
  295. }
  296. public function file_get_contents($path) {
  297. $source = $this->getSource($path);
  298. if ($source) {
  299. $storage = OC_Filesystem::getStorage($source);
  300. return $storage->file_get_contents($this->getInternalPath($source));
  301. }
  302. }
  303. public function file_put_contents($path, $data) {
  304. if ($this->is_writable($path)) {
  305. $source = $this->getSource($path);
  306. if ($source) {
  307. $storage = OC_Filesystem::getStorage($source);
  308. $result = $storage->file_put_contents($this->getInternalPath($source), $data);
  309. if ($result) {
  310. $this->clearFolderSizeCache($path);
  311. }
  312. return $result;
  313. }
  314. }
  315. }
  316. public function unlink($path) {
  317. // The item will be removed from the database, but won't be touched on the owner's filesystem
  318. $target = $this->datadir.$path;
  319. // Check if the item is inside a shared folder
  320. if (OC_Share::getParentFolders($target)) {
  321. // If entry for item already exists
  322. if (OC_Share::getItem($target)) {
  323. OC_Share::unshareFromMySelf($target, false);
  324. } else {
  325. OC_Share::pullOutOfFolder($target, $target);
  326. OC_Share::unshareFromMySelf($target, false);
  327. }
  328. // Delete the database entry
  329. } else {
  330. OC_Share::unshareFromMySelf($target);
  331. }
  332. $this->clearFolderSizeCache($this->getInternalPath($target));
  333. return true;
  334. }
  335. public function rename($path1, $path2) {
  336. $oldTarget = $this->datadir.$path1;
  337. $newTarget = $this->datadir.$path2;
  338. // Check if the item is inside a shared folder
  339. if ($folders = OC_Share::getParentFolders($oldTarget)) {
  340. $root1 = substr($path1, 0, strpos($path1, "/"));
  341. $root2 = substr($path1, 0, strpos($path2, "/"));
  342. // Prevent items from being moved into different shared folders until versioning (cut and paste) and prevent items going into 'Shared'
  343. if ($root1 !== $root2) {
  344. return false;
  345. // Check if both paths have write permission
  346. } else if ($this->is_writable($path1) && $this->is_writable($path2)) {
  347. $oldSource = $this->getSource($path1);
  348. $newSource = $folders['source'].substr($newTarget, strlen($folders['target']));
  349. if ($oldSource) {
  350. $storage = OC_Filesystem::getStorage($oldSource);
  351. return $storage->rename($this->getInternalPath($oldSource), $this->getInternalPath($newSource));
  352. }
  353. // If the user doesn't have write permission, items can only be renamed and not moved
  354. } else if (dirname($path1) !== dirname($path2)) {
  355. return false;
  356. // The item will be renamed in the database, but won't be touched on the owner's filesystem
  357. } else {
  358. OC_Share::pullOutOfFolder($oldTarget, $newTarget);
  359. // If this is a folder being renamed, call setTarget in case there are any database entries inside the folder
  360. if (self::is_dir($path1)) {
  361. OC_Share::setTarget($oldTarget, $newTarget);
  362. }
  363. }
  364. } else {
  365. OC_Share::setTarget($oldTarget, $newTarget);
  366. }
  367. $this->clearFolderSizeCache($this->getInternalPath($oldTarget));
  368. $this->clearFolderSizeCache($this->getInternalPath($newTarget));
  369. return true;
  370. }
  371. public function copy($path1, $path2) {
  372. if ($path2 == "" || $path2 == "/") {
  373. // TODO Construct new shared item or should this not be allowed?
  374. } else {
  375. if ($this->is_writable($path2)) {
  376. $tmpFile = $this->toTmpFile($path1);
  377. $result = $this->fromTmpFile($tmpFile, $path2);
  378. if ($result) {
  379. $this->clearFolderSizeCache($path2);
  380. }
  381. return $result;
  382. } else {
  383. return false;
  384. }
  385. }
  386. }
  387. public function fopen($path, $mode) {
  388. $source = $this->getSource($path);
  389. if ($source) {
  390. $storage = OC_Filesystem::getStorage($source);
  391. return $storage->fopen($this->getInternalPath($source), $mode);
  392. }
  393. }
  394. public function toTmpFile($path) {
  395. $source = $this->getSource($path);
  396. if ($source) {
  397. $storage = OC_Filesystem::getStorage($source);
  398. return $storage->toTmpFile($this->getInternalPath($source));
  399. }
  400. }
  401. public function fromTmpFile($tmpFile, $path) {
  402. if ($this->is_writable($path)) {
  403. $source = $this->getSource($path);
  404. if ($source) {
  405. $storage = OC_Filesystem::getStorage($source);
  406. $result = $storage->fromTmpFile($tmpFile, $this->getInternalPath($source));
  407. if ($result) {
  408. $this->clearFolderSizeCache($path);
  409. }
  410. return $result;
  411. }
  412. } else {
  413. return false;
  414. }
  415. }
  416. public function getMimeType($path) {
  417. if ($path == "" || $path == "/") {
  418. return 'httpd/unix-directory';
  419. }
  420. $source = $this->getSource($path);
  421. if ($source) {
  422. $storage = OC_Filesystem::getStorage($source);
  423. return $storage->getMimeType($this->getInternalPath($source));
  424. }
  425. }
  426. public function hash($type, $path, $raw = false) {
  427. $source = $this->getSource($path);
  428. if ($source) {
  429. $storage = OC_Filesystem::getStorage($source);
  430. return $storage->hash($type, $this->getInternalPath($source), $raw);
  431. }
  432. }
  433. public function free_space($path) {
  434. $source = $this->getSource($path);
  435. if ($source) {
  436. $storage = OC_Filesystem::getStorage($source);
  437. return $storage->free_space($this->getInternalPath($source));
  438. }
  439. }
  440. public function search($query) {
  441. return $this->searchInDir($query);
  442. }
  443. private function searchInDir($query, $path = "") {
  444. $files = array();
  445. if ($dh = $this->opendir($path)) {
  446. while (($filename = readdir($dh)) !== false) {
  447. if ($filename != "." && $filename != "..") {
  448. if (strstr(strtolower($filename), strtolower($query))) {
  449. $files[] = $path."/".$filename;
  450. }
  451. if ($this->is_dir($path."/".$filename)) {
  452. $files = array_merge($files, $this->searchInDir($query, $path."/".$filename));
  453. }
  454. }
  455. }
  456. }
  457. return $files;
  458. }
  459. public function getLocalFile($path) {
  460. $source = $this->getSource($path);
  461. if ($source) {
  462. $storage = OC_Filesystem::getStorage($source);
  463. return $storage->getLocalFile($this->getInternalPath($source));
  464. }
  465. }
  466. public function touch($path, $mtime=null){
  467. $source = $this->getSource($path);
  468. if ($source) {
  469. $storage = OC_Filesystem::getStorage($source);
  470. return $storage->touch($this->getInternalPath($source),$time);
  471. }
  472. }
  473. public static function setup() {
  474. OC_Filesystem::mount('OC_Filestorage_Shared', array('datadir' => '/'.OCP\USER::getUser().'/files/Shared'), '/'.OCP\USER::getUser().'/files/Shared/');
  475. }
  476. }
  477. if (OCP\USER::isLoggedIn()) {
  478. OC_Filestorage_Shared::setup();
  479. } else {
  480. OCP\Util::connectHook('OC_User', 'post_login', 'OC_Filestorage_Shared', 'setup');
  481. }
  482. ?>