filesystem.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. <?php
  2. /**
  3. * ownCloud
  4. *
  5. * @author Robin Appelman
  6. * @copyright 2012 Robin Appelman icewind@owncloud.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. namespace Test\Files;
  23. class Filesystem extends \Test\TestCase {
  24. /**
  25. * @var array tmpDirs
  26. */
  27. private $tmpDirs = array();
  28. /**
  29. * @return array
  30. */
  31. private function getStorageData() {
  32. $dir = \OC_Helper::tmpFolder();
  33. $this->tmpDirs[] = $dir;
  34. return array('datadir' => $dir);
  35. }
  36. protected function setUp() {
  37. parent::setUp();
  38. $this->loginAsUser();
  39. }
  40. protected function tearDown() {
  41. foreach ($this->tmpDirs as $dir) {
  42. \OC_Helper::rmdirr($dir);
  43. }
  44. $this->logout();
  45. parent::tearDown();
  46. }
  47. public function testMount() {
  48. \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', self::getStorageData(), '/');
  49. $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/'));
  50. $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/some/folder'));
  51. list(, $internalPath) = \OC\Files\Filesystem::resolvePath('/');
  52. $this->assertEquals('', $internalPath);
  53. list(, $internalPath) = \OC\Files\Filesystem::resolvePath('/some/folder');
  54. $this->assertEquals('some/folder', $internalPath);
  55. \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', self::getStorageData(), '/some');
  56. $this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/'));
  57. $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/folder'));
  58. $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some/'));
  59. $this->assertEquals('/some/', \OC\Files\Filesystem::getMountPoint('/some'));
  60. list(, $internalPath) = \OC\Files\Filesystem::resolvePath('/some/folder');
  61. $this->assertEquals('folder', $internalPath);
  62. }
  63. public function normalizePathData() {
  64. return array(
  65. array('/', ''),
  66. array('/', '/'),
  67. array('/', '//'),
  68. array('/', '/', false),
  69. array('/', '//', false),
  70. array('/path', '/path/'),
  71. array('/path/', '/path/', false),
  72. array('/path', 'path'),
  73. array('/foo/bar', '/foo//bar/'),
  74. array('/foo/bar/', '/foo//bar/', false),
  75. array('/foo/bar', '/foo////bar'),
  76. array('/foo/bar', '/foo/////bar'),
  77. array('/foo/bar', '/foo/bar/.'),
  78. array('/foo/bar', '/foo/bar/./'),
  79. array('/foo/bar/', '/foo/bar/./', false),
  80. array('/foo/bar', '/foo/bar/./.'),
  81. array('/foo/bar', '/foo/bar/././'),
  82. array('/foo/bar/', '/foo/bar/././', false),
  83. array('/foo/bar', '/foo/./bar/'),
  84. array('/foo/bar/', '/foo/./bar/', false),
  85. array('/foo/.bar', '/foo/.bar/'),
  86. array('/foo/.bar/', '/foo/.bar/', false),
  87. array('/foo/.bar/tee', '/foo/.bar/tee'),
  88. // Windows paths
  89. array('/', ''),
  90. array('/', '\\'),
  91. array('/', '\\', false),
  92. array('/', '\\\\'),
  93. array('/', '\\\\', false),
  94. array('/path', '\\path'),
  95. array('/path', '\\path', false),
  96. array('/path', '\\path\\'),
  97. array('/path/', '\\path\\', false),
  98. array('/foo/bar', '\\foo\\\\bar\\'),
  99. array('/foo/bar/', '\\foo\\\\bar\\', false),
  100. array('/foo/bar', '\\foo\\\\\\\\bar'),
  101. array('/foo/bar', '\\foo\\\\\\\\\\bar'),
  102. array('/foo/bar', '\\foo\\bar\\.'),
  103. array('/foo/bar', '\\foo\\bar\\.\\'),
  104. array('/foo/bar/', '\\foo\\bar\\.\\', false),
  105. array('/foo/bar', '\\foo\\bar\\.\\.'),
  106. array('/foo/bar', '\\foo\\bar\\.\\.\\'),
  107. array('/foo/bar/', '\\foo\\bar\\.\\.\\', false),
  108. array('/foo/bar', '\\foo\\.\\bar\\'),
  109. array('/foo/bar/', '\\foo\\.\\bar\\', false),
  110. array('/foo/.bar', '\\foo\\.bar\\'),
  111. array('/foo/.bar/', '\\foo\\.bar\\', false),
  112. array('/foo/.bar/tee', '\\foo\\.bar\\tee'),
  113. // Absolute windows paths NOT marked as absolute
  114. array('/C:', 'C:\\'),
  115. array('/C:/', 'C:\\', false),
  116. array('/C:/tests', 'C:\\tests'),
  117. array('/C:/tests', 'C:\\tests', false),
  118. array('/C:/tests', 'C:\\tests\\'),
  119. array('/C:/tests/', 'C:\\tests\\', false),
  120. // normalize does not resolve '..' (by design)
  121. array('/foo/..', '/foo/../'),
  122. array('/foo/..', '\\foo\\..\\'),
  123. );
  124. }
  125. /**
  126. * @dataProvider normalizePathData
  127. */
  128. public function testNormalizePath($expected, $path, $stripTrailingSlash = true) {
  129. $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash));
  130. }
  131. public function isValidPathData() {
  132. return array(
  133. array('/', true),
  134. array('/path', true),
  135. array('/foo/bar', true),
  136. array('/foo//bar/', true),
  137. array('/foo////bar', true),
  138. array('/foo//\///bar', true),
  139. array('/foo/bar/.', true),
  140. array('/foo/bar/./', true),
  141. array('/foo/bar/./.', true),
  142. array('/foo/bar/././', true),
  143. array('/foo/bar/././..bar', true),
  144. array('/foo/bar/././..bar/a', true),
  145. array('/foo/bar/././..', false),
  146. array('/foo/bar/././../', false),
  147. array('/foo/bar/.././', false),
  148. array('/foo/bar/../../', false),
  149. array('/foo/bar/../..\\', false),
  150. array('..', false),
  151. array('../', false),
  152. array('../foo/bar', false),
  153. array('..\foo/bar', false),
  154. );
  155. }
  156. /**
  157. * @dataProvider isValidPathData
  158. */
  159. public function testIsValidPath($path, $expected) {
  160. $this->assertSame($expected, \OC\Files\Filesystem::isValidPath($path));
  161. }
  162. public function isFileBlacklistedData() {
  163. return array(
  164. array('/etc/foo/bar/foo.txt', false),
  165. array('\etc\foo/bar\foo.txt', false),
  166. array('.htaccess', true),
  167. array('.htaccess/', true),
  168. array('.htaccess\\', true),
  169. array('/etc/foo\bar/.htaccess\\', true),
  170. array('/etc/foo\bar/.htaccess/', true),
  171. array('/etc/foo\bar/.htaccess/foo', false),
  172. array('//foo//bar/\.htaccess/', true),
  173. array('\foo\bar\.HTAccess', true),
  174. );
  175. }
  176. /**
  177. * @dataProvider isFileBlacklistedData
  178. */
  179. public function testIsFileBlacklisted($path, $expected) {
  180. $this->assertSame($expected, \OC\Files\Filesystem::isFileBlacklisted($path));
  181. }
  182. public function normalizePathWindowsAbsolutePathData() {
  183. return array(
  184. array('C:/', 'C:\\'),
  185. array('C:/', 'C:\\', false),
  186. array('C:/tests', 'C:\\tests'),
  187. array('C:/tests', 'C:\\tests', false),
  188. array('C:/tests', 'C:\\tests\\'),
  189. array('C:/tests/', 'C:\\tests\\', false),
  190. );
  191. }
  192. /**
  193. * @dataProvider normalizePathWindowsAbsolutePathData
  194. */
  195. public function testNormalizePathWindowsAbsolutePath($expected, $path, $stripTrailingSlash = true) {
  196. if (!\OC_Util::runningOnWindows()) {
  197. $this->markTestSkipped('This test is Windows only');
  198. }
  199. $this->assertEquals($expected, \OC\Files\Filesystem::normalizePath($path, $stripTrailingSlash, true));
  200. }
  201. public function testNormalizePathUTF8() {
  202. if (!class_exists('Patchwork\PHP\Shim\Normalizer')) {
  203. $this->markTestSkipped('UTF8 normalizer Patchwork was not found');
  204. }
  205. $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("/foo/baru\xCC\x88"));
  206. $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("\\foo\\baru\xCC\x88"));
  207. }
  208. public function testHooks() {
  209. if (\OC\Files\Filesystem::getView()) {
  210. $user = \OC_User::getUser();
  211. } else {
  212. $user = $this->getUniqueID();
  213. \OC\Files\Filesystem::init($user, '/' . $user . '/files');
  214. }
  215. \OC_Hook::clear('OC_Filesystem');
  216. \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook');
  217. \OC\Files\Filesystem::mount('OC\Files\Storage\Temporary', array(), '/');
  218. $rootView = new \OC\Files\View('');
  219. $rootView->mkdir('/' . $user);
  220. $rootView->mkdir('/' . $user . '/files');
  221. // \OC\Files\Filesystem::file_put_contents('/foo', 'foo');
  222. \OC\Files\Filesystem::mkdir('/bar');
  223. // \OC\Files\Filesystem::file_put_contents('/bar//foo', 'foo');
  224. $tmpFile = \OC_Helper::tmpFile();
  225. file_put_contents($tmpFile, 'foo');
  226. $fh = fopen($tmpFile, 'r');
  227. // \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh);
  228. }
  229. /**
  230. * Tests that a local storage mount is used when passed user
  231. * does not exist.
  232. */
  233. public function testLocalMountWhenUserDoesNotExist() {
  234. $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
  235. $userId = $this->getUniqueID('user_');
  236. \OC\Files\Filesystem::initMountPoints($userId);
  237. $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
  238. $this->assertTrue($homeMount->instanceOfStorage('\OC\Files\Storage\Local'));
  239. $this->assertEquals('local::' . $datadir . '/' . $userId . '/', $homeMount->getId());
  240. }
  241. /**
  242. * Tests that the home storage is used for the user's mount point
  243. */
  244. public function testHomeMount() {
  245. $userId = $this->getUniqueID('user_');
  246. \OC_User::createUser($userId, $userId);
  247. \OC\Files\Filesystem::initMountPoints($userId);
  248. $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
  249. $this->assertTrue($homeMount->instanceOfStorage('\OC\Files\Storage\Home'));
  250. $this->assertEquals('home::' . $userId, $homeMount->getId());
  251. \OC_User::deleteUser($userId);
  252. }
  253. /**
  254. * Tests that the home storage is used in legacy mode
  255. * for the user's mount point
  256. */
  257. public function testLegacyHomeMount() {
  258. $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
  259. $userId = $this->getUniqueID('user_');
  260. // insert storage into DB by constructing it
  261. // to make initMountsPoint find its existence
  262. $localStorage = new \OC\Files\Storage\Local(array('datadir' => $datadir . '/' . $userId . '/'));
  263. // this will trigger the insert
  264. $cache = $localStorage->getCache();
  265. \OC_User::createUser($userId, $userId);
  266. \OC\Files\Filesystem::initMountPoints($userId);
  267. $homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
  268. $this->assertTrue($homeMount->instanceOfStorage('\OC\Files\Storage\Home'));
  269. $this->assertEquals('local::' . $datadir . '/' . $userId . '/', $homeMount->getId());
  270. \OC_User::deleteUser($userId);
  271. // delete storage entry
  272. $cache->clear();
  273. }
  274. public function dummyHook($arguments) {
  275. $path = $arguments['path'];
  276. $this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized
  277. }
  278. /**
  279. * Test that the default cache dir is part of the user's home
  280. */
  281. public function testMountDefaultCacheDir() {
  282. $userId = $this->getUniqueID('user_');
  283. $oldCachePath = \OC_Config::getValue('cache_path', '');
  284. // no cache path configured
  285. \OC_Config::setValue('cache_path', '');
  286. \OC_User::createUser($userId, $userId);
  287. \OC\Files\Filesystem::initMountPoints($userId);
  288. $this->assertEquals(
  289. '/' . $userId . '/',
  290. \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache')
  291. );
  292. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache');
  293. $this->assertTrue($storage->instanceOfStorage('\OC\Files\Storage\Home'));
  294. $this->assertEquals('cache', $internalPath);
  295. \OC_User::deleteUser($userId);
  296. \OC_Config::setValue('cache_path', $oldCachePath);
  297. }
  298. /**
  299. * Test that an external cache is mounted into
  300. * the user's home
  301. */
  302. public function testMountExternalCacheDir() {
  303. $userId = $this->getUniqueID('user_');
  304. $oldCachePath = \OC_Config::getValue('cache_path', '');
  305. // set cache path to temp dir
  306. $cachePath = \OC_Helper::tmpFolder() . '/extcache';
  307. \OC_Config::setValue('cache_path', $cachePath);
  308. \OC_User::createUser($userId, $userId);
  309. \OC\Files\Filesystem::initMountPoints($userId);
  310. $this->assertEquals(
  311. '/' . $userId . '/cache/',
  312. \OC\Files\Filesystem::getMountPoint('/' . $userId . '/cache')
  313. );
  314. list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath('/' . $userId . '/cache');
  315. $this->assertTrue($storage->instanceOfStorage('\OC\Files\Storage\Local'));
  316. $this->assertEquals('', $internalPath);
  317. \OC_User::deleteUser($userId);
  318. \OC_Config::setValue('cache_path', $oldCachePath);
  319. }
  320. }