LocalTest.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. <?php
  2. /**
  3. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  4. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace Test\Files\Storage;
  8. use OC\Files\Storage\Wrapper\Jail;
  9. /**
  10. * Class LocalTest
  11. *
  12. * @group DB
  13. *
  14. * @package Test\Files\Storage
  15. */
  16. class LocalTest extends Storage {
  17. /**
  18. * @var string tmpDir
  19. */
  20. private $tmpDir;
  21. protected function setUp(): void {
  22. parent::setUp();
  23. $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder();
  24. $this->instance = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir]);
  25. }
  26. protected function tearDown(): void {
  27. \OC_Helper::rmdirr($this->tmpDir);
  28. parent::tearDown();
  29. }
  30. public function testStableEtag(): void {
  31. $this->instance->file_put_contents('test.txt', 'foobar');
  32. $etag1 = $this->instance->getETag('test.txt');
  33. $etag2 = $this->instance->getETag('test.txt');
  34. $this->assertEquals($etag1, $etag2);
  35. }
  36. public function testEtagChange(): void {
  37. $this->instance->file_put_contents('test.txt', 'foo');
  38. $this->instance->touch('test.txt', time() - 2);
  39. $etag1 = $this->instance->getETag('test.txt');
  40. $this->instance->file_put_contents('test.txt', 'bar');
  41. $etag2 = $this->instance->getETag('test.txt');
  42. $this->assertNotEquals($etag1, $etag2);
  43. }
  44. public function testInvalidArgumentsEmptyArray(): void {
  45. $this->expectException(\InvalidArgumentException::class);
  46. new \OC\Files\Storage\Local([]);
  47. }
  48. public function testInvalidArgumentsNoArray(): void {
  49. $this->expectException(\InvalidArgumentException::class);
  50. new \OC\Files\Storage\Local([]);
  51. }
  52. public function testDisallowSymlinksOutsideDatadir(): void {
  53. $this->expectException(\OCP\Files\ForbiddenException::class);
  54. $subDir1 = $this->tmpDir . 'sub1';
  55. $subDir2 = $this->tmpDir . 'sub2';
  56. $sym = $this->tmpDir . 'sub1/sym';
  57. mkdir($subDir1);
  58. mkdir($subDir2);
  59. symlink($subDir2, $sym);
  60. $storage = new \OC\Files\Storage\Local(['datadir' => $subDir1]);
  61. $storage->file_put_contents('sym/foo', 'bar');
  62. }
  63. public function testDisallowSymlinksInsideDatadir(): void {
  64. $subDir1 = $this->tmpDir . 'sub1';
  65. $subDir2 = $this->tmpDir . 'sub1/sub2';
  66. $sym = $this->tmpDir . 'sub1/sym';
  67. mkdir($subDir1);
  68. mkdir($subDir2);
  69. symlink($subDir2, $sym);
  70. $storage = new \OC\Files\Storage\Local(['datadir' => $subDir1]);
  71. $storage->file_put_contents('sym/foo', 'bar');
  72. $this->addToAssertionCount(1);
  73. }
  74. public function testWriteUmaskFilePutContents(): void {
  75. $oldMask = umask(0333);
  76. $this->instance->file_put_contents('test.txt', 'sad');
  77. umask($oldMask);
  78. $this->assertTrue($this->instance->isUpdatable('test.txt'));
  79. }
  80. public function testWriteUmaskMkdir(): void {
  81. $oldMask = umask(0333);
  82. $this->instance->mkdir('test.txt');
  83. umask($oldMask);
  84. $this->assertTrue($this->instance->isUpdatable('test.txt'));
  85. }
  86. public function testWriteUmaskFopen(): void {
  87. $oldMask = umask(0333);
  88. $handle = $this->instance->fopen('test.txt', 'w');
  89. fwrite($handle, 'foo');
  90. fclose($handle);
  91. umask($oldMask);
  92. $this->assertTrue($this->instance->isUpdatable('test.txt'));
  93. }
  94. public function testWriteUmaskCopy(): void {
  95. $this->instance->file_put_contents('source.txt', 'sad');
  96. $oldMask = umask(0333);
  97. $this->instance->copy('source.txt', 'test.txt');
  98. umask($oldMask);
  99. $this->assertTrue($this->instance->isUpdatable('test.txt'));
  100. }
  101. public function testUnavailableExternal(): void {
  102. $this->expectException(\OCP\Files\StorageNotAvailableException::class);
  103. $this->instance = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir . '/unexist', 'isExternal' => true]);
  104. }
  105. public function testUnavailableNonExternal(): void {
  106. $this->instance = new \OC\Files\Storage\Local(['datadir' => $this->tmpDir . '/unexist']);
  107. // no exception thrown
  108. $this->assertNotNull($this->instance);
  109. }
  110. public function testMoveNestedJail(): void {
  111. $this->instance->mkdir('foo');
  112. $this->instance->mkdir('foo/bar');
  113. $this->instance->mkdir('target');
  114. $this->instance->file_put_contents('foo/bar/file.txt', 'foo');
  115. $jail1 = new Jail([
  116. 'storage' => $this->instance,
  117. 'root' => 'foo'
  118. ]);
  119. $jail2 = new Jail([
  120. 'storage' => $jail1,
  121. 'root' => 'bar'
  122. ]);
  123. $jail3 = new Jail([
  124. 'storage' => $this->instance,
  125. 'root' => 'target'
  126. ]);
  127. $jail3->moveFromStorage($jail2, 'file.txt', 'file.txt');
  128. $this->assertTrue($this->instance->file_exists('target/file.txt'));
  129. }
  130. }