PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/files_external/lib/swift.php

https://github.com/jlgg/simple_trash
PHP | 555 lines | 493 code | 37 blank | 25 comment | 40 complexity | 399f6bf78e7b0d5d036ff77a458fa0d0 MD5 | raw file
Possible License(s): AGPL-3.0, AGPL-1.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. require_once 'php-cloudfiles/cloudfiles.php';
  9. class OC_FileStorage_SWIFT extends OC_Filestorage_Common{
  10. private $host;
  11. private $root;
  12. private $user;
  13. private $token;
  14. private $secure;
  15. /**
  16. * @var CF_Authentication auth
  17. */
  18. private $auth;
  19. /**
  20. * @var CF_Connection conn
  21. */
  22. private $conn;
  23. /**
  24. * @var CF_Container rootContainer
  25. */
  26. private $rootContainer;
  27. private static $tempFiles=array();
  28. private $objects=array();
  29. private $containers=array();
  30. const SUBCONTAINER_FILE='.subcontainers';
  31. /**
  32. * translate directory path to container name
  33. * @param string path
  34. * @return string
  35. */
  36. private function getContainerName($path) {
  37. $path=trim(trim($this->root, '/')."/".$path, '/.');
  38. return str_replace('/', '\\', $path);
  39. }
  40. /**
  41. * get container by path
  42. * @param string path
  43. * @return CF_Container
  44. */
  45. private function getContainer($path) {
  46. if ($path=='' or $path=='/') {
  47. return $this->rootContainer;
  48. }
  49. if (isset($this->containers[$path])) {
  50. return $this->containers[$path];
  51. }
  52. try {
  53. $container=$this->conn->get_container($this->getContainerName($path));
  54. $this->containers[$path]=$container;
  55. return $container;
  56. } catch(NoSuchContainerException $e) {
  57. return null;
  58. }
  59. }
  60. /**
  61. * create container
  62. * @param string path
  63. * @return CF_Container
  64. */
  65. private function createContainer($path) {
  66. if ($path=='' or $path=='/' or $path=='.') {
  67. return $this->conn->create_container($this->getContainerName($path));
  68. }
  69. $parent=dirname($path);
  70. if ($parent=='' or $parent=='/' or $parent=='.') {
  71. $parentContainer=$this->rootContainer;
  72. } else {
  73. if ( ! $this->containerExists($parent)) {
  74. $parentContainer=$this->createContainer($parent);
  75. } else {
  76. $parentContainer=$this->getContainer($parent);
  77. }
  78. }
  79. $this->addSubContainer($parentContainer, basename($path));
  80. return $this->conn->create_container($this->getContainerName($path));
  81. }
  82. /**
  83. * get object by path
  84. * @param string path
  85. * @return CF_Object
  86. */
  87. private function getObject($path) {
  88. if (isset($this->objects[$path])) {
  89. return $this->objects[$path];
  90. }
  91. $container=$this->getContainer(dirname($path));
  92. if (is_null($container)) {
  93. return null;
  94. } else {
  95. if ($path=="/" or $path=='') {
  96. return null;
  97. }
  98. try {
  99. $obj=$container->get_object(basename($path));
  100. $this->objects[$path]=$obj;
  101. return $obj;
  102. } catch(NoSuchObjectException $e) {
  103. return null;
  104. }
  105. }
  106. }
  107. /**
  108. * get the names of all objects in a container
  109. * @param CF_Container
  110. * @return array
  111. */
  112. private function getObjects($container) {
  113. if (is_null($container)) {
  114. return array();
  115. } else {
  116. $files=$container->get_objects();
  117. foreach ($files as &$file) {
  118. $file=$file->name;
  119. }
  120. return $files;
  121. }
  122. }
  123. /**
  124. * create object
  125. * @param string path
  126. * @return CF_Object
  127. */
  128. private function createObject($path) {
  129. $container=$this->getContainer(dirname($path));
  130. if ( ! is_null($container)) {
  131. $container=$this->createContainer(dirname($path));
  132. }
  133. return $container->create_object(basename($path));
  134. }
  135. /**
  136. * check if an object exists
  137. * @param string
  138. * @return bool
  139. */
  140. private function objectExists($path) {
  141. return !is_null($this->getObject($path));
  142. }
  143. /**
  144. * check if container for path exists
  145. * @param string path
  146. * @return bool
  147. */
  148. private function containerExists($path) {
  149. return !is_null($this->getContainer($path));
  150. }
  151. /**
  152. * get the list of emulated sub containers
  153. * @param CF_Container container
  154. * @return array
  155. */
  156. private function getSubContainers($container) {
  157. $tmpFile=OCP\Files::tmpFile();
  158. $obj=$this->getSubContainerFile($container);
  159. try {
  160. $obj->save_to_filename($tmpFile);
  161. } catch(Exception $e) {
  162. return array();
  163. }
  164. $obj->save_to_filename($tmpFile);
  165. $containers=file($tmpFile);
  166. unlink($tmpFile);
  167. foreach ($containers as &$sub) {
  168. $sub=trim($sub);
  169. }
  170. return $containers;
  171. }
  172. /**
  173. * add an emulated sub container
  174. * @param CF_Container container
  175. * @param string name
  176. * @return bool
  177. */
  178. private function addSubContainer($container, $name) {
  179. if ( ! $name) {
  180. return false;
  181. }
  182. $tmpFile=OCP\Files::tmpFile();
  183. $obj=$this->getSubContainerFile($container);
  184. try {
  185. $obj->save_to_filename($tmpFile);
  186. $containers=file($tmpFile);
  187. foreach ($containers as &$sub) {
  188. $sub=trim($sub);
  189. }
  190. if (array_search($name, $containers)!==false) {
  191. unlink($tmpFile);
  192. return false;
  193. } else {
  194. $fh=fopen($tmpFile, 'a');
  195. fwrite($fh, $name."\n");
  196. }
  197. } catch(Exception $e) {
  198. $containers=array();
  199. file_put_contents($tmpFile, $name."\n");
  200. }
  201. $obj->load_from_filename($tmpFile);
  202. unlink($tmpFile);
  203. return true;
  204. }
  205. /**
  206. * remove an emulated sub container
  207. * @param CF_Container container
  208. * @param string name
  209. * @return bool
  210. */
  211. private function removeSubContainer($container, $name) {
  212. if ( ! $name) {
  213. return false;
  214. }
  215. $tmpFile=OCP\Files::tmpFile();
  216. $obj=$this->getSubContainerFile($container);
  217. try {
  218. $obj->save_to_filename($tmpFile);
  219. $containers=file($tmpFile);
  220. } catch (Exception $e) {
  221. return false;
  222. }
  223. foreach ($containers as &$sub) {
  224. $sub=trim($sub);
  225. }
  226. $i=array_search($name, $containers);
  227. if ($i===false) {
  228. unlink($tmpFile);
  229. return false;
  230. } else {
  231. unset($containers[$i]);
  232. file_put_contents($tmpFile, implode("\n", $containers)."\n");
  233. }
  234. $obj->load_from_filename($tmpFile);
  235. unlink($tmpFile);
  236. return true;
  237. }
  238. /**
  239. * ensure a subcontainer file exists and return it's object
  240. * @param CF_Container container
  241. * @return CF_Object
  242. */
  243. private function getSubContainerFile($container) {
  244. try {
  245. return $container->get_object(self::SUBCONTAINER_FILE);
  246. } catch(NoSuchObjectException $e) {
  247. return $container->create_object(self::SUBCONTAINER_FILE);
  248. }
  249. }
  250. public function __construct($params) {
  251. $this->token=$params['token'];
  252. $this->host=$params['host'];
  253. $this->user=$params['user'];
  254. $this->root=isset($params['root'])?$params['root']:'/';
  255. if (isset($params['secure'])) {
  256. if (is_string($params['secure'])) {
  257. $this->secure = ($params['secure'] === 'true');
  258. } else {
  259. $this->secure = (bool)$params['secure'];
  260. }
  261. } else {
  262. $this->secure = false;
  263. }
  264. if ( ! $this->root || $this->root[0]!='/') {
  265. $this->root='/'.$this->root;
  266. }
  267. $this->auth = new CF_Authentication($this->user, $this->token, null, $this->host);
  268. $this->auth->authenticate();
  269. $this->conn = new CF_Connection($this->auth);
  270. if ( ! $this->containerExists('/')) {
  271. $this->rootContainer=$this->createContainer('/');
  272. } else {
  273. $this->rootContainer=$this->getContainer('/');
  274. }
  275. }
  276. public function mkdir($path) {
  277. if ($this->containerExists($path)) {
  278. return false;
  279. } else {
  280. $this->createContainer($path);
  281. return true;
  282. }
  283. }
  284. public function rmdir($path) {
  285. if ( ! $this->containerExists($path)) {
  286. return false;
  287. } else {
  288. $this->emptyContainer($path);
  289. if ($path!='' and $path!='/') {
  290. $parentContainer=$this->getContainer(dirname($path));
  291. $this->removeSubContainer($parentContainer, basename($path));
  292. }
  293. $this->conn->delete_container($this->getContainerName($path));
  294. unset($this->containers[$path]);
  295. return true;
  296. }
  297. }
  298. private function emptyContainer($path) {
  299. $container=$this->getContainer($path);
  300. if (is_null($container)) {
  301. return;
  302. }
  303. $subContainers=$this->getSubContainers($container);
  304. foreach ($subContainers as $sub) {
  305. if ($sub) {
  306. $this->emptyContainer($path.'/'.$sub);
  307. $this->conn->delete_container($this->getContainerName($path.'/'.$sub));
  308. unset($this->containers[$path.'/'.$sub]);
  309. }
  310. }
  311. $objects=$this->getObjects($container);
  312. foreach ($objects as $object) {
  313. $container->delete_object($object);
  314. unset($this->objects[$path.'/'.$object]);
  315. }
  316. }
  317. public function opendir($path) {
  318. $container=$this->getContainer($path);
  319. $files=$this->getObjects($container);
  320. $i=array_search(self::SUBCONTAINER_FILE, $files);
  321. if ($i!==false) {
  322. unset($files[$i]);
  323. }
  324. $subContainers=$this->getSubContainers($container);
  325. $files=array_merge($files, $subContainers);
  326. $id=$this->getContainerName($path);
  327. OC_FakeDirStream::$dirs[$id]=$files;
  328. return opendir('fakedir://'.$id);
  329. }
  330. public function filetype($path) {
  331. if ($this->containerExists($path)) {
  332. return 'dir';
  333. } else {
  334. return 'file';
  335. }
  336. }
  337. public function isReadable($path) {
  338. return true;
  339. }
  340. public function isUpdatable($path) {
  341. return true;
  342. }
  343. public function file_exists($path) {
  344. if ($this->is_dir($path)) {
  345. return true;
  346. } else {
  347. return $this->objectExists($path);
  348. }
  349. }
  350. public function file_get_contents($path) {
  351. $obj=$this->getObject($path);
  352. if (is_null($obj)) {
  353. return false;
  354. }
  355. return $obj->read();
  356. }
  357. public function file_put_contents($path, $content) {
  358. $obj=$this->getObject($path);
  359. if (is_null($obj)) {
  360. $container=$this->getContainer(dirname($path));
  361. if (is_null($container)) {
  362. return false;
  363. }
  364. $obj=$container->create_object(basename($path));
  365. }
  366. $this->resetMTime($obj);
  367. return $obj->write($content);
  368. }
  369. public function unlink($path) {
  370. if ($this->containerExists($path)) {
  371. return $this->rmdir($path);
  372. }
  373. if ($this->objectExists($path)) {
  374. $container=$this->getContainer(dirname($path));
  375. $container->delete_object(basename($path));
  376. unset($this->objects[$path]);
  377. } else {
  378. return false;
  379. }
  380. }
  381. public function fopen($path, $mode) {
  382. switch($mode) {
  383. case 'r':
  384. case 'rb':
  385. $obj=$this->getObject($path);
  386. if (is_null($obj)) {
  387. return false;
  388. }
  389. $fp = fopen('php://temp', 'r+');
  390. $obj->stream($fp);
  391. rewind($fp);
  392. return $fp;
  393. case 'w':
  394. case 'wb':
  395. case 'a':
  396. case 'ab':
  397. case 'r+':
  398. case 'w+':
  399. case 'wb+':
  400. case 'a+':
  401. case 'x':
  402. case 'x+':
  403. case 'c':
  404. case 'c+':
  405. $tmpFile=$this->getTmpFile($path);
  406. OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this, 'writeBack');
  407. self::$tempFiles[$tmpFile]=$path;
  408. return fopen('close://'.$tmpFile, $mode);
  409. }
  410. }
  411. public function writeBack($tmpFile) {
  412. if (isset(self::$tempFiles[$tmpFile])) {
  413. $this->fromTmpFile($tmpFile, self::$tempFiles[$tmpFile]);
  414. unlink($tmpFile);
  415. }
  416. }
  417. public function free_space($path) {
  418. return 1024*1024*1024*8;
  419. }
  420. public function touch($path, $mtime=null) {
  421. $obj=$this->getObject($path);
  422. if (is_null($obj)) {
  423. return false;
  424. }
  425. if (is_null($mtime)) {
  426. $mtime=time();
  427. }
  428. //emulate setting mtime with metadata
  429. $obj->metadata['Mtime']=$mtime;
  430. $obj->sync_metadata();
  431. }
  432. public function rename($path1, $path2) {
  433. $sourceContainer=$this->getContainer(dirname($path1));
  434. $targetContainer=$this->getContainer(dirname($path2));
  435. $result=$sourceContainer->move_object_to(basename($path1), $targetContainer, basename($path2));
  436. unset($this->objects[$path1]);
  437. if ($result) {
  438. $targetObj=$this->getObject($path2);
  439. $this->resetMTime($targetObj);
  440. }
  441. return $result;
  442. }
  443. public function copy($path1, $path2) {
  444. $sourceContainer=$this->getContainer(dirname($path1));
  445. $targetContainer=$this->getContainer(dirname($path2));
  446. $result=$sourceContainer->copy_object_to(basename($path1), $targetContainer, basename($path2));
  447. if ($result) {
  448. $targetObj=$this->getObject($path2);
  449. $this->resetMTime($targetObj);
  450. }
  451. return $result;
  452. }
  453. public function stat($path) {
  454. $container=$this->getContainer($path);
  455. if ( ! is_null($container)) {
  456. return array(
  457. 'mtime'=>-1,
  458. 'size'=>$container->bytes_used,
  459. 'ctime'=>-1
  460. );
  461. }
  462. $obj=$this->getObject($path);
  463. if (is_null($obj)) {
  464. return false;
  465. }
  466. if (isset($obj->metadata['Mtime']) and $obj->metadata['Mtime']>-1) {
  467. $mtime=$obj->metadata['Mtime'];
  468. } else {
  469. $mtime=strtotime($obj->last_modified);
  470. }
  471. return array(
  472. 'mtime'=>$mtime,
  473. 'size'=>$obj->content_length,
  474. 'ctime'=>-1,
  475. );
  476. }
  477. private function getTmpFile($path) {
  478. $obj=$this->getObject($path);
  479. if ( ! is_null($obj)) {
  480. $tmpFile=OCP\Files::tmpFile();
  481. $obj->save_to_filename($tmpFile);
  482. return $tmpFile;
  483. } else {
  484. return OCP\Files::tmpFile();
  485. }
  486. }
  487. private function fromTmpFile($tmpFile, $path) {
  488. $obj=$this->getObject($path);
  489. if (is_null($obj)) {
  490. $obj=$this->createObject($path);
  491. }
  492. $obj->load_from_filename($tmpFile);
  493. $this->resetMTime($obj);
  494. }
  495. /**
  496. * remove custom mtime metadata
  497. * @param CF_Object obj
  498. */
  499. private function resetMTime($obj) {
  500. if (isset($obj->metadata['Mtime'])) {
  501. $obj->metadata['Mtime']=-1;
  502. $obj->sync_metadata();
  503. }
  504. }
  505. }