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.

996 lines
32 KiB

12 years ago
12 years ago
12 years ago
11 years ago
12 years ago
12 years ago
12 years ago
12 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  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. namespace Test\Files;
  8. use OC\Files\Cache\Watcher;
  9. use OC\Files\Mount\MountPoint;
  10. use OC\Files\Storage\Temporary;
  11. class TemporaryNoTouch extends \OC\Files\Storage\Temporary {
  12. public function touch($path, $mtime = null) {
  13. return false;
  14. }
  15. }
  16. class View extends \Test\TestCase {
  17. /**
  18. * @var \OC\Files\Storage\Storage[] $storages
  19. */
  20. private $storages = array();
  21. private $user;
  22. /** @var \OC\Files\Storage\Storage */
  23. private $tempStorage;
  24. /** @var \OC\Files\Storage\Storage */
  25. private $originalStorage;
  26. protected function setUp() {
  27. parent::setUp();
  28. \OC_User::clearBackends();
  29. \OC_User::useBackend(new \OC_User_Dummy());
  30. //login
  31. \OC_User::createUser('test', 'test');
  32. $this->user = \OC_User::getUser();
  33. \OC_User::setUserId('test');
  34. $this->originalStorage = \OC\Files\Filesystem::getStorage('/');
  35. \OC\Files\Filesystem::clearMounts();
  36. $this->tempStorage = null;
  37. }
  38. protected function tearDown() {
  39. \OC_User::setUserId($this->user);
  40. foreach ($this->storages as $storage) {
  41. $cache = $storage->getCache();
  42. $ids = $cache->getAll();
  43. $cache->clear();
  44. }
  45. if ($this->tempStorage && !\OC_Util::runningOnWindows()) {
  46. system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir()));
  47. }
  48. \OC\Files\Filesystem::clearMounts();
  49. \OC\Files\Filesystem::mount($this->originalStorage, array(), '/');
  50. parent::tearDown();
  51. }
  52. /**
  53. * @medium
  54. */
  55. public function testCacheAPI() {
  56. $storage1 = $this->getTestStorage();
  57. $storage2 = $this->getTestStorage();
  58. $storage3 = $this->getTestStorage();
  59. $root = $this->getUniqueID('/');
  60. \OC\Files\Filesystem::mount($storage1, array(), $root . '/');
  61. \OC\Files\Filesystem::mount($storage2, array(), $root . '/substorage');
  62. \OC\Files\Filesystem::mount($storage3, array(), $root . '/folder/anotherstorage');
  63. $textSize = strlen("dummy file data\n");
  64. $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png');
  65. $storageSize = $textSize * 2 + $imageSize;
  66. $storageInfo = $storage3->getCache()->get('');
  67. $this->assertEquals($storageSize, $storageInfo['size']);
  68. $rootView = new \OC\Files\View($root);
  69. $cachedData = $rootView->getFileInfo('/foo.txt');
  70. $this->assertEquals($textSize, $cachedData['size']);
  71. $this->assertEquals('text/plain', $cachedData['mimetype']);
  72. $this->assertNotEquals(-1, $cachedData['permissions']);
  73. $cachedData = $rootView->getFileInfo('/');
  74. $this->assertEquals($storageSize * 3, $cachedData['size']);
  75. $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
  76. // get cached data excluding mount points
  77. $cachedData = $rootView->getFileInfo('/', false);
  78. $this->assertEquals($storageSize, $cachedData['size']);
  79. $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
  80. $cachedData = $rootView->getFileInfo('/folder');
  81. $this->assertEquals($storageSize + $textSize, $cachedData['size']);
  82. $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
  83. $folderData = $rootView->getDirectoryContent('/');
  84. /**
  85. * expected entries:
  86. * folder
  87. * foo.png
  88. * foo.txt
  89. * substorage
  90. */
  91. $this->assertEquals(4, count($folderData));
  92. $this->assertEquals('folder', $folderData[0]['name']);
  93. $this->assertEquals('foo.png', $folderData[1]['name']);
  94. $this->assertEquals('foo.txt', $folderData[2]['name']);
  95. $this->assertEquals('substorage', $folderData[3]['name']);
  96. $this->assertEquals($storageSize + $textSize, $folderData[0]['size']);
  97. $this->assertEquals($imageSize, $folderData[1]['size']);
  98. $this->assertEquals($textSize, $folderData[2]['size']);
  99. $this->assertEquals($storageSize, $folderData[3]['size']);
  100. $folderData = $rootView->getDirectoryContent('/substorage');
  101. /**
  102. * expected entries:
  103. * folder
  104. * foo.png
  105. * foo.txt
  106. */
  107. $this->assertEquals(3, count($folderData));
  108. $this->assertEquals('folder', $folderData[0]['name']);
  109. $this->assertEquals('foo.png', $folderData[1]['name']);
  110. $this->assertEquals('foo.txt', $folderData[2]['name']);
  111. $folderView = new \OC\Files\View($root . '/folder');
  112. $this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/'));
  113. $cachedData = $rootView->getFileInfo('/foo.txt');
  114. $this->assertFalse($cachedData['encrypted']);
  115. $id = $rootView->putFileInfo('/foo.txt', array('encrypted' => true));
  116. $cachedData = $rootView->getFileInfo('/foo.txt');
  117. $this->assertTrue($cachedData['encrypted']);
  118. $this->assertEquals($cachedData['fileid'], $id);
  119. $this->assertFalse($rootView->getFileInfo('/non/existing'));
  120. $this->assertEquals(array(), $rootView->getDirectoryContent('/non/existing'));
  121. }
  122. /**
  123. * @medium
  124. */
  125. function testGetPath() {
  126. $storage1 = $this->getTestStorage();
  127. $storage2 = $this->getTestStorage();
  128. $storage3 = $this->getTestStorage();
  129. \OC\Files\Filesystem::mount($storage1, array(), '/');
  130. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  131. \OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage');
  132. $rootView = new \OC\Files\View('');
  133. $cachedData = $rootView->getFileInfo('/foo.txt');
  134. $id1 = $cachedData['fileid'];
  135. $this->assertEquals('/foo.txt', $rootView->getPath($id1));
  136. $cachedData = $rootView->getFileInfo('/substorage/foo.txt');
  137. $id2 = $cachedData['fileid'];
  138. $this->assertEquals('/substorage/foo.txt', $rootView->getPath($id2));
  139. $folderView = new \OC\Files\View('/substorage');
  140. $this->assertEquals('/foo.txt', $folderView->getPath($id2));
  141. $this->assertNull($folderView->getPath($id1));
  142. }
  143. /**
  144. * @medium
  145. */
  146. function testMountPointOverwrite() {
  147. $storage1 = $this->getTestStorage(false);
  148. $storage2 = $this->getTestStorage();
  149. $storage1->mkdir('substorage');
  150. \OC\Files\Filesystem::mount($storage1, array(), '/');
  151. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  152. $rootView = new \OC\Files\View('');
  153. $folderContent = $rootView->getDirectoryContent('/');
  154. $this->assertEquals(4, count($folderContent));
  155. }
  156. function testCacheIncompleteFolder() {
  157. $storage1 = $this->getTestStorage(false);
  158. \OC\Files\Filesystem::clearMounts();
  159. \OC\Files\Filesystem::mount($storage1, array(), '/incomplete');
  160. $rootView = new \OC\Files\View('/incomplete');
  161. $entries = $rootView->getDirectoryContent('/');
  162. $this->assertEquals(3, count($entries));
  163. // /folder will already be in the cache but not scanned
  164. $entries = $rootView->getDirectoryContent('/folder');
  165. $this->assertEquals(1, count($entries));
  166. }
  167. public function testAutoScan() {
  168. $storage1 = $this->getTestStorage(false);
  169. $storage2 = $this->getTestStorage(false);
  170. \OC\Files\Filesystem::mount($storage1, array(), '/');
  171. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  172. $textSize = strlen("dummy file data\n");
  173. $rootView = new \OC\Files\View('');
  174. $cachedData = $rootView->getFileInfo('/');
  175. $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']);
  176. $this->assertEquals(-1, $cachedData['size']);
  177. $folderData = $rootView->getDirectoryContent('/substorage/folder');
  178. $this->assertEquals('text/plain', $folderData[0]['mimetype']);
  179. $this->assertEquals($textSize, $folderData[0]['size']);
  180. }
  181. /**
  182. * @medium
  183. */
  184. function testSearch() {
  185. $storage1 = $this->getTestStorage();
  186. $storage2 = $this->getTestStorage();
  187. $storage3 = $this->getTestStorage();
  188. \OC\Files\Filesystem::mount($storage1, array(), '/');
  189. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  190. \OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage');
  191. $rootView = new \OC\Files\View('');
  192. $results = $rootView->search('foo');
  193. $this->assertEquals(6, count($results));
  194. $paths = array();
  195. foreach ($results as $result) {
  196. $this->assertEquals($result['path'], \OC\Files\Filesystem::normalizePath($result['path']));
  197. $paths[] = $result['path'];
  198. }
  199. $this->assertContains('/foo.txt', $paths);
  200. $this->assertContains('/foo.png', $paths);
  201. $this->assertContains('/substorage/foo.txt', $paths);
  202. $this->assertContains('/substorage/foo.png', $paths);
  203. $this->assertContains('/folder/anotherstorage/foo.txt', $paths);
  204. $this->assertContains('/folder/anotherstorage/foo.png', $paths);
  205. $folderView = new \OC\Files\View('/folder');
  206. $results = $folderView->search('bar');
  207. $this->assertEquals(2, count($results));
  208. $paths = array();
  209. foreach ($results as $result) {
  210. $paths[] = $result['path'];
  211. }
  212. $this->assertContains('/anotherstorage/folder/bar.txt', $paths);
  213. $this->assertContains('/bar.txt', $paths);
  214. $results = $folderView->search('foo');
  215. $this->assertEquals(2, count($results));
  216. $paths = array();
  217. foreach ($results as $result) {
  218. $paths[] = $result['path'];
  219. }
  220. $this->assertContains('/anotherstorage/foo.txt', $paths);
  221. $this->assertContains('/anotherstorage/foo.png', $paths);
  222. $this->assertEquals(6, count($rootView->searchByMime('text')));
  223. $this->assertEquals(3, count($folderView->searchByMime('text')));
  224. }
  225. /**
  226. * @medium
  227. */
  228. function testWatcher() {
  229. $storage1 = $this->getTestStorage();
  230. \OC\Files\Filesystem::mount($storage1, array(), '/');
  231. $storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS);
  232. $rootView = new \OC\Files\View('');
  233. $cachedData = $rootView->getFileInfo('foo.txt');
  234. $this->assertEquals(16, $cachedData['size']);
  235. $rootView->putFileInfo('foo.txt', array('storage_mtime' => 10));
  236. $storage1->file_put_contents('foo.txt', 'foo');
  237. clearstatcache();
  238. $cachedData = $rootView->getFileInfo('foo.txt');
  239. $this->assertEquals(3, $cachedData['size']);
  240. }
  241. /**
  242. * @medium
  243. */
  244. function testCopyBetweenStorages() {
  245. $storage1 = $this->getTestStorage();
  246. $storage2 = $this->getTestStorage();
  247. \OC\Files\Filesystem::mount($storage1, array(), '/');
  248. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  249. $rootView = new \OC\Files\View('');
  250. $rootView->mkdir('substorage/emptyfolder');
  251. $rootView->copy('substorage', 'anotherfolder');
  252. $this->assertTrue($rootView->is_dir('/anotherfolder'));
  253. $this->assertTrue($rootView->is_dir('/substorage'));
  254. $this->assertTrue($rootView->is_dir('/anotherfolder/emptyfolder'));
  255. $this->assertTrue($rootView->is_dir('/substorage/emptyfolder'));
  256. $this->assertTrue($rootView->file_exists('/anotherfolder/foo.txt'));
  257. $this->assertTrue($rootView->file_exists('/anotherfolder/foo.png'));
  258. $this->assertTrue($rootView->file_exists('/anotherfolder/folder/bar.txt'));
  259. $this->assertTrue($rootView->file_exists('/substorage/foo.txt'));
  260. $this->assertTrue($rootView->file_exists('/substorage/foo.png'));
  261. $this->assertTrue($rootView->file_exists('/substorage/folder/bar.txt'));
  262. }
  263. /**
  264. * @medium
  265. */
  266. function testMoveBetweenStorages() {
  267. $storage1 = $this->getTestStorage();
  268. $storage2 = $this->getTestStorage();
  269. \OC\Files\Filesystem::mount($storage1, array(), '/');
  270. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  271. $rootView = new \OC\Files\View('');
  272. $rootView->rename('foo.txt', 'substorage/folder/foo.txt');
  273. $this->assertFalse($rootView->file_exists('foo.txt'));
  274. $this->assertTrue($rootView->file_exists('substorage/folder/foo.txt'));
  275. $rootView->rename('substorage/folder', 'anotherfolder');
  276. $this->assertFalse($rootView->is_dir('substorage/folder'));
  277. $this->assertTrue($rootView->file_exists('anotherfolder/foo.txt'));
  278. $this->assertTrue($rootView->file_exists('anotherfolder/bar.txt'));
  279. }
  280. /**
  281. * @medium
  282. */
  283. function testUnlink() {
  284. $storage1 = $this->getTestStorage();
  285. $storage2 = $this->getTestStorage();
  286. \OC\Files\Filesystem::mount($storage1, array(), '/');
  287. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  288. $rootView = new \OC\Files\View('');
  289. $rootView->file_put_contents('/foo.txt', 'asd');
  290. $rootView->file_put_contents('/substorage/bar.txt', 'asd');
  291. $this->assertTrue($rootView->file_exists('foo.txt'));
  292. $this->assertTrue($rootView->file_exists('substorage/bar.txt'));
  293. $this->assertTrue($rootView->unlink('foo.txt'));
  294. $this->assertTrue($rootView->unlink('substorage/bar.txt'));
  295. $this->assertFalse($rootView->file_exists('foo.txt'));
  296. $this->assertFalse($rootView->file_exists('substorage/bar.txt'));
  297. }
  298. /**
  299. * @medium
  300. */
  301. function testUnlinkRootMustFail() {
  302. $storage1 = $this->getTestStorage();
  303. $storage2 = $this->getTestStorage();
  304. \OC\Files\Filesystem::mount($storage1, array(), '/');
  305. \OC\Files\Filesystem::mount($storage2, array(), '/substorage');
  306. $rootView = new \OC\Files\View('');
  307. $rootView->file_put_contents('/foo.txt', 'asd');
  308. $rootView->file_put_contents('/substorage/bar.txt', 'asd');
  309. $this->assertFalse($rootView->unlink(''));
  310. $this->assertFalse($rootView->unlink('/'));
  311. $this->assertFalse($rootView->unlink('substorage'));
  312. $this->assertFalse($rootView->unlink('/substorage'));
  313. }
  314. /**
  315. * @medium
  316. */
  317. function testTouch() {
  318. $storage = $this->getTestStorage(true, '\Test\Files\TemporaryNoTouch');
  319. \OC\Files\Filesystem::mount($storage, array(), '/');
  320. $rootView = new \OC\Files\View('');
  321. $oldCachedData = $rootView->getFileInfo('foo.txt');
  322. $rootView->touch('foo.txt', 500);
  323. $cachedData = $rootView->getFileInfo('foo.txt');
  324. $this->assertEquals(500, $cachedData['mtime']);
  325. $this->assertEquals($oldCachedData['storage_mtime'], $cachedData['storage_mtime']);
  326. $rootView->putFileInfo('foo.txt', array('storage_mtime' => 1000)); //make sure the watcher detects the change
  327. $rootView->file_put_contents('foo.txt', 'asd');
  328. $cachedData = $rootView->getFileInfo('foo.txt');
  329. $this->assertGreaterThanOrEqual($oldCachedData['mtime'], $cachedData['mtime']);
  330. $this->assertEquals($cachedData['storage_mtime'], $cachedData['mtime']);
  331. }
  332. /**
  333. * @medium
  334. */
  335. function testViewHooks() {
  336. $storage1 = $this->getTestStorage();
  337. $storage2 = $this->getTestStorage();
  338. $defaultRoot = \OC\Files\Filesystem::getRoot();
  339. \OC\Files\Filesystem::mount($storage1, array(), '/');
  340. \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '/substorage');
  341. \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
  342. $rootView = new \OC\Files\View('');
  343. $subView = new \OC\Files\View($defaultRoot . '/substorage');
  344. $this->hookPath = null;
  345. $rootView->file_put_contents('/foo.txt', 'asd');
  346. $this->assertNull($this->hookPath);
  347. $subView->file_put_contents('/foo.txt', 'asd');
  348. $this->assertEquals('/substorage/foo.txt', $this->hookPath);
  349. }
  350. private $hookPath;
  351. public function dummyHook($params) {
  352. $this->hookPath = $params['path'];
  353. }
  354. public function testSearchNotOutsideView() {
  355. $storage1 = $this->getTestStorage();
  356. \OC\Files\Filesystem::mount($storage1, array(), '/');
  357. $storage1->rename('folder', 'foo');
  358. $scanner = $storage1->getScanner();
  359. $scanner->scan('');
  360. $view = new \OC\Files\View('/foo');
  361. $result = $view->search('.txt');
  362. $this->assertCount(1, $result);
  363. }
  364. /**
  365. * @param bool $scan
  366. * @param string $class
  367. * @return \OC\Files\Storage\Storage
  368. */
  369. private function getTestStorage($scan = true, $class = '\OC\Files\Storage\Temporary') {
  370. /**
  371. * @var \OC\Files\Storage\Storage $storage
  372. */
  373. $storage = new $class(array());
  374. $textData = "dummy file data\n";
  375. $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png');
  376. $storage->mkdir('folder');
  377. $storage->file_put_contents('foo.txt', $textData);
  378. $storage->file_put_contents('foo.png', $imgData);
  379. $storage->file_put_contents('folder/bar.txt', $textData);
  380. if ($scan) {
  381. $scanner = $storage->getScanner();
  382. $scanner->scan('');
  383. }
  384. $this->storages[] = $storage;
  385. return $storage;
  386. }
  387. /**
  388. * @medium
  389. */
  390. function testViewHooksIfRootStartsTheSame() {
  391. $storage1 = $this->getTestStorage();
  392. $storage2 = $this->getTestStorage();
  393. $defaultRoot = \OC\Files\Filesystem::getRoot();
  394. \OC\Files\Filesystem::mount($storage1, array(), '/');
  395. \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '_substorage');
  396. \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
  397. $subView = new \OC\Files\View($defaultRoot . '_substorage');
  398. $this->hookPath = null;
  399. $subView->file_put_contents('/foo.txt', 'asd');
  400. $this->assertNull($this->hookPath);
  401. }
  402. private $hookWritePath;
  403. private $hookCreatePath;
  404. private $hookUpdatePath;
  405. public function dummyHookWrite($params) {
  406. $this->hookWritePath = $params['path'];
  407. }
  408. public function dummyHookUpdate($params) {
  409. $this->hookUpdatePath = $params['path'];
  410. }
  411. public function dummyHookCreate($params) {
  412. $this->hookCreatePath = $params['path'];
  413. }
  414. public function testEditNoCreateHook() {
  415. $storage1 = $this->getTestStorage();
  416. $storage2 = $this->getTestStorage();
  417. $defaultRoot = \OC\Files\Filesystem::getRoot();
  418. \OC\Files\Filesystem::mount($storage1, array(), '/');
  419. \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot);
  420. \OC_Hook::connect('OC_Filesystem', 'post_create', $this, 'dummyHookCreate');
  421. \OC_Hook::connect('OC_Filesystem', 'post_update', $this, 'dummyHookUpdate');
  422. \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHookWrite');
  423. $view = new \OC\Files\View($defaultRoot);
  424. $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
  425. $view->file_put_contents('/asd.txt', 'foo');
  426. $this->assertEquals('/asd.txt', $this->hookCreatePath);
  427. $this->assertNull($this->hookUpdatePath);
  428. $this->assertEquals('/asd.txt', $this->hookWritePath);
  429. $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null;
  430. $view->file_put_contents('/asd.txt', 'foo');
  431. $this->assertNull($this->hookCreatePath);
  432. $this->assertEquals('/asd.txt', $this->hookUpdatePath);
  433. $this->assertEquals('/asd.txt', $this->hookWritePath);
  434. \OC_Hook::clear('OC_Filesystem', 'post_create');
  435. \OC_Hook::clear('OC_Filesystem', 'post_update');
  436. \OC_Hook::clear('OC_Filesystem', 'post_write');
  437. }
  438. /**
  439. * @dataProvider resolvePathTestProvider
  440. */
  441. public function testResolvePath($expected, $pathToTest) {
  442. $storage1 = $this->getTestStorage();
  443. \OC\Files\Filesystem::mount($storage1, array(), '/');
  444. $view = new \OC\Files\View('');
  445. $result = $view->resolvePath($pathToTest);
  446. $this->assertEquals($expected, $result[1]);
  447. $exists = $view->file_exists($pathToTest);
  448. $this->assertTrue($exists);
  449. $exists = $view->file_exists($result[1]);
  450. $this->assertTrue($exists);
  451. }
  452. function resolvePathTestProvider() {
  453. return array(
  454. array('foo.txt', 'foo.txt'),
  455. array('foo.txt', '/foo.txt'),
  456. array('folder', 'folder'),
  457. array('folder', '/folder'),
  458. array('folder', 'folder/'),
  459. array('folder', '/folder/'),
  460. array('folder/bar.txt', 'folder/bar.txt'),
  461. array('folder/bar.txt', '/folder/bar.txt'),
  462. array('', ''),
  463. array('', '/'),
  464. );
  465. }
  466. public function testUTF8Names() {
  467. $names = array('虚', '和知しゃ和で', 'regular ascii', 'sɨˈrɪlɪk', 'ѨѬ', 'أنا أحب القراءة كثيرا');
  468. $storage = new \OC\Files\Storage\Temporary(array());
  469. \OC\Files\Filesystem::mount($storage, array(), '/');
  470. $rootView = new \OC\Files\View('');
  471. foreach ($names as $name) {
  472. $rootView->file_put_contents('/' . $name, 'dummy content');
  473. }
  474. $list = $rootView->getDirectoryContent('/');
  475. $this->assertCount(count($names), $list);
  476. foreach ($list as $item) {
  477. $this->assertContains($item['name'], $names);
  478. }
  479. $cache = $storage->getCache();
  480. $scanner = $storage->getScanner();
  481. $scanner->scan('');
  482. $list = $cache->getFolderContents('');
  483. $this->assertCount(count($names), $list);
  484. foreach ($list as $item) {
  485. $this->assertContains($item['name'], $names);
  486. }
  487. }
  488. public function xtestLongPath() {
  489. $storage = new \OC\Files\Storage\Temporary(array());
  490. \OC\Files\Filesystem::mount($storage, array(), '/');
  491. $rootView = new \OC\Files\View('');
  492. $longPath = '';
  493. $ds = DIRECTORY_SEPARATOR;
  494. /*
  495. * 4096 is the maximum path length in file_cache.path in *nix
  496. * 1024 is the max path length in mac
  497. * 228 is the max path length in windows
  498. */
  499. $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
  500. $tmpdirLength = strlen(\OC_Helper::tmpFolder());
  501. if (\OC_Util::runningOnWindows()) {
  502. $this->markTestSkipped('[Windows] ');
  503. $depth = ((260 - $tmpdirLength) / 57);
  504. } elseif (\OC_Util::runningOnMac()) {
  505. $depth = ((1024 - $tmpdirLength) / 57);
  506. } else {
  507. $depth = ((4000 - $tmpdirLength) / 57);
  508. }
  509. foreach (range(0, $depth - 1) as $i) {
  510. $longPath .= $ds . $folderName;
  511. $result = $rootView->mkdir($longPath);
  512. $this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath));
  513. $result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem');
  514. $this->assertEquals(5, $result, "file_put_contents failed on $i");
  515. $this->assertTrue($rootView->file_exists($longPath));
  516. $this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt"));
  517. }
  518. $cache = $storage->getCache();
  519. $scanner = $storage->getScanner();
  520. $scanner->scan('');
  521. $longPath = $folderName;
  522. foreach (range(0, $depth - 1) as $i) {
  523. $cachedFolder = $cache->get($longPath);
  524. $this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i");
  525. $this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i");
  526. $cachedFile = $cache->get($longPath . '/test.txt');
  527. $this->assertTrue(is_array($cachedFile), "No cache entry for file at $i");
  528. $this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i");
  529. $longPath .= $ds . $folderName;
  530. }
  531. }
  532. public function testTouchNotSupported() {
  533. $storage = new TemporaryNoTouch(array());
  534. $scanner = $storage->getScanner();
  535. \OC\Files\Filesystem::mount($storage, array(), '/test/');
  536. $past = time() - 100;
  537. $storage->file_put_contents('test', 'foobar');
  538. $scanner->scan('');
  539. $view = new \OC\Files\View('');
  540. $info = $view->getFileInfo('/test/test');
  541. $view->touch('/test/test', $past);
  542. $scanner->scanFile('test', \OC\Files\Cache\Scanner::REUSE_ETAG);
  543. $info2 = $view->getFileInfo('/test/test');
  544. $this->assertSame($info['etag'], $info2['etag']);
  545. }
  546. public function testWatcherEtagCrossStorage() {
  547. $storage1 = new Temporary(array());
  548. $storage2 = new Temporary(array());
  549. $scanner1 = $storage1->getScanner();
  550. $scanner2 = $storage2->getScanner();
  551. $storage1->mkdir('sub');
  552. \OC\Files\Filesystem::mount($storage1, array(), '/test/');
  553. \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage');
  554. $past = time() - 100;
  555. $storage2->file_put_contents('test.txt', 'foobar');
  556. $scanner1->scan('');
  557. $scanner2->scan('');
  558. $view = new \OC\Files\View('');
  559. $storage2->getWatcher('')->setPolicy(Watcher::CHECK_ALWAYS);
  560. $oldFileInfo = $view->getFileInfo('/test/sub/storage/test.txt');
  561. $oldFolderInfo = $view->getFileInfo('/test');
  562. $storage2->getCache()->update($oldFileInfo->getId(), array(
  563. 'storage_mtime' => $past
  564. ));
  565. $view->getFileInfo('/test/sub/storage/test.txt');
  566. $newFolderInfo = $view->getFileInfo('/test');
  567. $this->assertNotEquals($newFolderInfo->getEtag(), $oldFolderInfo->getEtag());
  568. }
  569. /**
  570. * @dataProvider absolutePathProvider
  571. */
  572. public function testGetAbsolutePath($expectedPath, $relativePath) {
  573. $view = new \OC\Files\View('/files');
  574. $this->assertEquals($expectedPath, $view->getAbsolutePath($relativePath));
  575. }
  576. public function testPartFileInfo() {
  577. $storage = new Temporary(array());
  578. $scanner = $storage->getScanner();
  579. \OC\Files\Filesystem::mount($storage, array(), '/test/');
  580. $storage->file_put_contents('test.part', 'foobar');
  581. $scanner->scan('');
  582. $view = new \OC\Files\View('/test');
  583. $info = $view->getFileInfo('test.part');
  584. $this->assertInstanceOf('\OCP\Files\FileInfo', $info);
  585. $this->assertNull($info->getId());
  586. $this->assertEquals(6, $info->getSize());
  587. }
  588. function absolutePathProvider() {
  589. return array(
  590. array('/files/', ''),
  591. array('/files/0', '0'),
  592. array('/files/false', 'false'),
  593. array('/files/true', 'true'),
  594. array('/files/', '/'),
  595. array('/files/test', 'test'),
  596. array('/files/test', '/test'),
  597. );
  598. }
  599. /**
  600. * @dataProvider relativePathProvider
  601. */
  602. function testGetRelativePath($absolutePath, $expectedPath) {
  603. $view = new \OC\Files\View('/files');
  604. // simulate a external storage mount point which has a trailing slash
  605. $view->chroot('/files/');
  606. $this->assertEquals($expectedPath, $view->getRelativePath($absolutePath));
  607. }
  608. function relativePathProvider() {
  609. return array(
  610. array('/files/', '/'),
  611. array('/files', '/'),
  612. array('/files/0', '0'),
  613. array('/files/false', 'false'),
  614. array('/files/true', 'true'),
  615. array('/files/test', 'test'),
  616. array('/files/test/foo', 'test/foo'),
  617. );
  618. }
  619. public function testFileView() {
  620. $storage = new Temporary(array());
  621. $scanner = $storage->getScanner();
  622. $storage->file_put_contents('foo.txt', 'bar');
  623. \OC\Files\Filesystem::mount($storage, array(), '/test/');
  624. $scanner->scan('');
  625. $view = new \OC\Files\View('/test/foo.txt');
  626. $this->assertEquals('bar', $view->file_get_contents(''));
  627. $fh = tmpfile();
  628. fwrite($fh, 'foo');
  629. rewind($fh);
  630. $view->file_put_contents('', $fh);
  631. $this->assertEquals('foo', $view->file_get_contents(''));
  632. }
  633. /**
  634. * @dataProvider tooLongPathDataProvider
  635. * @expectedException \OCP\Files\InvalidPathException
  636. */
  637. public function testTooLongPath($operation, $param0 = null) {
  638. $longPath = '';
  639. // 4000 is the maximum path length in file_cache.path
  640. $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789';
  641. $depth = (4000 / 57);
  642. foreach (range(0, $depth + 1) as $i) {
  643. $longPath .= '/' . $folderName;
  644. }
  645. $storage = new \OC\Files\Storage\Temporary(array());
  646. $this->tempStorage = $storage; // for later hard cleanup
  647. \OC\Files\Filesystem::mount($storage, array(), '/');
  648. $rootView = new \OC\Files\View('');
  649. if ($param0 === '@0') {
  650. $param0 = $longPath;
  651. }
  652. if ($operation === 'hash') {
  653. $param0 = $longPath;
  654. $longPath = 'md5';
  655. }
  656. call_user_func(array($rootView, $operation), $longPath, $param0);
  657. }
  658. public function tooLongPathDataProvider() {
  659. return array(
  660. array('getAbsolutePath'),
  661. array('getRelativePath'),
  662. array('getMountPoint'),
  663. array('resolvePath'),
  664. array('getLocalFile'),
  665. array('getLocalFolder'),
  666. array('mkdir'),
  667. array('rmdir'),
  668. array('opendir'),
  669. array('is_dir'),
  670. array('is_file'),
  671. array('stat'),
  672. array('filetype'),
  673. array('filesize'),
  674. array('readfile'),
  675. array('isCreatable'),
  676. array('isReadable'),
  677. array('isUpdatable'),
  678. array('isDeletable'),
  679. array('isSharable'),
  680. array('file_exists'),
  681. array('filemtime'),
  682. array('touch'),
  683. array('file_get_contents'),
  684. array('unlink'),
  685. array('deleteAll'),
  686. array('toTmpFile'),
  687. array('getMimeType'),
  688. array('free_space'),
  689. array('getFileInfo'),
  690. array('getDirectoryContent'),
  691. array('getOwner'),
  692. array('getETag'),
  693. array('file_put_contents', 'ipsum'),
  694. array('rename', '@0'),
  695. array('copy', '@0'),
  696. array('fopen', 'r'),
  697. array('fromTmpFile', '@0'),
  698. array('hash'),
  699. array('hasUpdated', 0),
  700. array('putFileInfo', array()),
  701. );
  702. }
  703. public function testRenameCrossStoragePreserveMtime() {
  704. $storage1 = new Temporary(array());
  705. $storage2 = new Temporary(array());
  706. $scanner1 = $storage1->getScanner();
  707. $scanner2 = $storage2->getScanner();
  708. $storage1->mkdir('sub');
  709. $storage1->mkdir('foo');
  710. $storage1->file_put_contents('foo.txt', 'asd');
  711. $storage1->file_put_contents('foo/bar.txt', 'asd');
  712. \OC\Files\Filesystem::mount($storage1, array(), '/test/');
  713. \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage');
  714. $view = new \OC\Files\View('');
  715. $time = time() - 200;
  716. $view->touch('/test/foo.txt', $time);
  717. $view->touch('/test/foo', $time);
  718. $view->touch('/test/foo/bar.txt', $time);
  719. $view->rename('/test/foo.txt', '/test/sub/storage/foo.txt');
  720. $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo.txt'));
  721. $view->rename('/test/foo', '/test/sub/storage/foo');
  722. $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo/bar.txt'));
  723. }
  724. public function testRenameFailDeleteTargetKeepSource() {
  725. $this->doTestCopyRenameFail('rename');
  726. }
  727. public function testCopyFailDeleteTargetKeepSource() {
  728. $this->doTestCopyRenameFail('copy');
  729. }
  730. private function doTestCopyRenameFail($operation) {
  731. $storage1 = new Temporary(array());
  732. $storage2 = new Temporary(array());
  733. $storage2 = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage2, 'quota' => 9));
  734. $storage1->mkdir('sub');
  735. $storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH');
  736. $storage1->mkdir('dirtomove');
  737. $storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits
  738. $storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit
  739. $storage2->file_put_contents('existing.txt', '0123');
  740. $storage1->getScanner()->scan('');
  741. $storage2->getScanner()->scan('');
  742. \OC\Files\Filesystem::mount($storage1, array(), '/test/');
  743. \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage');
  744. // move file
  745. $view = new \OC\Files\View('');
  746. $this->assertTrue($storage1->file_exists('foo.txt'));
  747. $this->assertFalse($storage2->file_exists('foo.txt'));
  748. $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/foo.txt'));
  749. $this->assertFalse($storage2->file_exists('foo.txt'));
  750. $this->assertFalse($storage2->getCache()->get('foo.txt'));
  751. $this->assertTrue($storage1->file_exists('foo.txt'));
  752. // if target exists, it will be deleted too
  753. $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/existing.txt'));
  754. $this->assertFalse($storage2->file_exists('existing.txt'));
  755. $this->assertFalse($storage2->getCache()->get('existing.txt'));
  756. $this->assertTrue($storage1->file_exists('foo.txt'));
  757. // move folder
  758. $this->assertFalse($view->$operation('/test/dirtomove/', '/test/sub/storage/dirtomove/'));
  759. // since the move failed, the full source tree is kept
  760. $this->assertTrue($storage1->file_exists('dirtomove/indir1.txt'));
  761. // but the target file stays
  762. $this->assertTrue($storage2->file_exists('dirtomove/indir1.txt'));
  763. // second file not moved/copied
  764. $this->assertTrue($storage1->file_exists('dirtomove/indir2.txt'));
  765. $this->assertFalse($storage2->file_exists('dirtomove/indir2.txt'));
  766. $this->assertFalse($storage2->getCache()->get('dirtomove/indir2.txt'));
  767. }
  768. public function testDeleteFailKeepCache() {
  769. /**
  770. * @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage
  771. */
  772. $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary')
  773. ->setConstructorArgs(array(array()))
  774. ->setMethods(array('unlink'))
  775. ->getMock();
  776. $storage->expects($this->once())
  777. ->method('unlink')
  778. ->will($this->returnValue(false));
  779. $scanner = $storage->getScanner();
  780. $cache = $storage->getCache();
  781. $storage->file_put_contents('foo.txt', 'asd');
  782. $scanner->scan('');
  783. \OC\Files\Filesystem::mount($storage, array(), '/test/');
  784. $view = new \OC\Files\View('/test');
  785. $this->assertFalse($view->unlink('foo.txt'));
  786. $this->assertTrue($cache->inCache('foo.txt'));
  787. }
  788. function directoryTraversalProvider() {
  789. return [
  790. ['../test/'],
  791. ['..\\test\\my/../folder'],
  792. ['/test/my/../foo\\'],
  793. ];
  794. }
  795. /**
  796. * @dataProvider directoryTraversalProvider
  797. * @expectedException \Exception
  798. * @param string $root
  799. */
  800. public function testConstructDirectoryTraversalException($root) {
  801. new \OC\Files\View($root);
  802. }
  803. public function testRenameOverWrite() {
  804. $storage = new Temporary(array());
  805. $scanner = $storage->getScanner();
  806. $storage->mkdir('sub');
  807. $storage->mkdir('foo');
  808. $storage->file_put_contents('foo.txt', 'asd');
  809. $storage->file_put_contents('foo/bar.txt', 'asd');
  810. $scanner->scan('');
  811. \OC\Files\Filesystem::mount($storage, array(), '/test/');
  812. $view = new \OC\Files\View('');
  813. $this->assertTrue($view->rename('/test/foo.txt', '/test/foo/bar.txt'));
  814. }
  815. public function testSetMountOptionsInStorage() {
  816. $mount = new MountPoint('\OC\Files\Storage\Temporary', '/asd/', [[]], \OC\Files\Filesystem::getLoader(), ['foo' => 'bar']);
  817. \OC\Files\Filesystem::getMountManager()->addMount($mount);
  818. /** @var \OC\Files\Storage\Common $storage */
  819. $storage = $mount->getStorage();
  820. $this->assertEquals($storage->getMountOption('foo'), 'bar');
  821. }
  822. public function testSetMountOptionsWatcherPolicy() {
  823. $mount = new MountPoint('\OC\Files\Storage\Temporary', '/asd/', [[]], \OC\Files\Filesystem::getLoader(), ['filesystem_check_changes' => Watcher::CHECK_NEVER]);
  824. \OC\Files\Filesystem::getMountManager()->addMount($mount);
  825. /** @var \OC\Files\Storage\Common $storage */
  826. $storage = $mount->getStorage();
  827. $watcher = $storage->getWatcher();
  828. $this->assertEquals(Watcher::CHECK_NEVER, $watcher->getPolicy());
  829. }
  830. }