view.php 32 KB

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