AppData.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
  5. *
  6. * @author Roeland Jago Douma <roeland@famdouma.nl>
  7. *
  8. * @license GNU AGPL version 3 or any later version
  9. *
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU Affero General Public License as
  12. * published by the Free Software Foundation, either version 3 of the
  13. * License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Affero General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Affero General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. *
  23. */
  24. namespace OC\Files\AppData;
  25. use OC\Cache\CappedMemoryCache;
  26. use OC\Files\SimpleFS\SimpleFolder;
  27. use OCP\Files\IAppData;
  28. use OCP\Files\IRootFolder;
  29. use OCP\Files\Folder;
  30. use OC\SystemConfig;
  31. use OCP\Files\Node;
  32. use OCP\Files\NotFoundException;
  33. use OCP\Files\NotPermittedException;
  34. use OCP\Files\SimpleFS\ISimpleFolder;
  35. class AppData implements IAppData {
  36. /** @var IRootFolder */
  37. private $rootFolder;
  38. /** @var SystemConfig */
  39. private $config;
  40. /** @var string */
  41. private $appId;
  42. /** @var Folder */
  43. private $folder;
  44. /** @var (ISimpleFolder|NotFoundException)[]|CappedMemoryCache */
  45. private $folders;
  46. /**
  47. * AppData constructor.
  48. *
  49. * @param IRootFolder $rootFolder
  50. * @param SystemConfig $systemConfig
  51. * @param string $appId
  52. */
  53. public function __construct(IRootFolder $rootFolder,
  54. SystemConfig $systemConfig,
  55. string $appId) {
  56. $this->rootFolder = $rootFolder;
  57. $this->config = $systemConfig;
  58. $this->appId = $appId;
  59. $this->folders = new CappedMemoryCache();
  60. }
  61. private function getAppDataFolderName() {
  62. $instanceId = $this->config->getValue('instanceid', null);
  63. if ($instanceId === null) {
  64. throw new \RuntimeException('no instance id!');
  65. }
  66. return 'appdata_' . $instanceId;
  67. }
  68. private function getAppDataRootFolder(): Folder {
  69. $name = $this->getAppDataFolderName();
  70. try {
  71. /** @var Folder $node */
  72. $node = $this->rootFolder->get($name);
  73. return $node;
  74. } catch (NotFoundException $e) {
  75. try {
  76. return $this->rootFolder->newFolder($name);
  77. } catch (NotPermittedException $e) {
  78. throw new \RuntimeException('Could not get appdata folder');
  79. }
  80. }
  81. }
  82. /**
  83. * @return Folder
  84. * @throws \RuntimeException
  85. */
  86. private function getAppDataFolder(): Folder {
  87. if ($this->folder === null) {
  88. $name = $this->getAppDataFolderName();
  89. try {
  90. $this->folder = $this->rootFolder->get($name . '/' . $this->appId);
  91. } catch (NotFoundException $e) {
  92. $appDataRootFolder = $this->getAppDataRootFolder();
  93. try {
  94. $this->folder = $appDataRootFolder->get($this->appId);
  95. } catch (NotFoundException $e) {
  96. try {
  97. $this->folder = $appDataRootFolder->newFolder($this->appId);
  98. } catch (NotPermittedException $e) {
  99. throw new \RuntimeException('Could not get appdata folder for ' . $this->appId);
  100. }
  101. }
  102. }
  103. }
  104. return $this->folder;
  105. }
  106. public function getFolder(string $name): ISimpleFolder {
  107. $key = $this->appId . '/' . $name;
  108. if ($cachedFolder = $this->folders->get($key)) {
  109. if ($cachedFolder instanceof \Exception) {
  110. throw $cachedFolder;
  111. } else {
  112. return $cachedFolder;
  113. }
  114. }
  115. try {
  116. // Hardening if somebody wants to retrieve '/'
  117. if ($name === '/') {
  118. $node = $this->getAppDataFolder();
  119. } else {
  120. $path = $this->getAppDataFolderName() . '/' . $this->appId . '/' . $name;
  121. $node = $this->rootFolder->get($path);
  122. }
  123. } catch (NotFoundException $e) {
  124. $this->folders->set($key, $e);
  125. throw $e;
  126. }
  127. /** @var Folder $node */
  128. $folder = new SimpleFolder($node);
  129. $this->folders->set($key, $folder);
  130. return $folder;
  131. }
  132. public function newFolder(string $name): ISimpleFolder {
  133. $key = $this->appId . '/' . $name;
  134. $folder = $this->getAppDataFolder()->newFolder($name);
  135. $simpleFolder = new SimpleFolder($folder);
  136. $this->folders->set($key, $simpleFolder);
  137. return $simpleFolder;
  138. }
  139. public function getDirectoryListing(): array {
  140. $listing = $this->getAppDataFolder()->getDirectoryListing();
  141. $fileListing = array_map(function (Node $folder) {
  142. if ($folder instanceof Folder) {
  143. return new SimpleFolder($folder);
  144. }
  145. return null;
  146. }, $listing);
  147. $fileListing = array_filter($fileListing);
  148. return array_values($fileListing);
  149. }
  150. public function getId(): int {
  151. return $this->getAppDataFolder()->getId();
  152. }
  153. }