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.

Storage.php 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Joas Schilling <coding@schilljs.com>
  7. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  8. * @author Morris Jobke <hey@morrisjobke.de>
  9. * @author Robin Appelman <robin@icewind.nl>
  10. * @author Robin McCorkell <robin@mccorkell.me.uk>
  11. * @author Thomas Müller <thomas.mueller@tmit.eu>
  12. * @author Vincent Petry <vincent@nextcloud.com>
  13. *
  14. * @license AGPL-3.0
  15. *
  16. * This code is free software: you can redistribute it and/or modify
  17. * it under the terms of the GNU Affero General Public License, version 3,
  18. * as published by the Free Software Foundation.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU Affero General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Affero General Public License, version 3,
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>
  27. *
  28. */
  29. namespace OC\Files\Cache;
  30. use OCP\Files\Storage\IStorage;
  31. /**
  32. * Handle the mapping between the string and numeric storage ids
  33. *
  34. * Each storage has 2 different ids
  35. * a string id which is generated by the storage backend and reflects the configuration of the storage (e.g. 'smb://user@host/share')
  36. * and a numeric storage id which is referenced in the file cache
  37. *
  38. * A mapping between the two storage ids is stored in the database and accessible trough this class
  39. *
  40. * @package OC\Files\Cache
  41. */
  42. class Storage {
  43. /** @var StorageGlobal|null */
  44. private static $globalCache = null;
  45. private $storageId;
  46. private $numericId;
  47. /**
  48. * @return StorageGlobal
  49. */
  50. public static function getGlobalCache() {
  51. if (is_null(self::$globalCache)) {
  52. self::$globalCache = new StorageGlobal(\OC::$server->getDatabaseConnection());
  53. }
  54. return self::$globalCache;
  55. }
  56. /**
  57. * @param \OC\Files\Storage\Storage|string $storage
  58. * @param bool $isAvailable
  59. * @throws \RuntimeException
  60. */
  61. public function __construct($storage, $isAvailable = true) {
  62. if ($storage instanceof IStorage) {
  63. $this->storageId = $storage->getId();
  64. } else {
  65. $this->storageId = $storage;
  66. }
  67. $this->storageId = self::adjustStorageId($this->storageId);
  68. if ($row = self::getStorageById($this->storageId)) {
  69. $this->numericId = (int)$row['numeric_id'];
  70. } else {
  71. $connection = \OC::$server->getDatabaseConnection();
  72. $available = $isAvailable ? 1 : 0;
  73. if ($connection->insertIfNotExist('*PREFIX*storages', ['id' => $this->storageId, 'available' => $available])) {
  74. $this->numericId = (int)$connection->lastInsertId('*PREFIX*storages');
  75. } else {
  76. if ($row = self::getStorageById($this->storageId)) {
  77. $this->numericId = (int)$row['numeric_id'];
  78. } else {
  79. throw new \RuntimeException('Storage could neither be inserted nor be selected from the database: ' . $this->storageId);
  80. }
  81. }
  82. }
  83. }
  84. /**
  85. * @param string $storageId
  86. * @return array
  87. */
  88. public static function getStorageById($storageId) {
  89. return self::getGlobalCache()->getStorageInfo($storageId);
  90. }
  91. /**
  92. * Adjusts the storage id to use md5 if too long
  93. * @param string $storageId storage id
  94. * @return string unchanged $storageId if its length is less than 64 characters,
  95. * else returns the md5 of $storageId
  96. */
  97. public static function adjustStorageId($storageId) {
  98. if (strlen($storageId) > 64) {
  99. return md5($storageId);
  100. }
  101. return $storageId;
  102. }
  103. /**
  104. * Get the numeric id for the storage
  105. *
  106. * @return int
  107. */
  108. public function getNumericId() {
  109. return $this->numericId;
  110. }
  111. /**
  112. * Get the string id for the storage
  113. *
  114. * @param int $numericId
  115. * @return string|null either the storage id string or null if the numeric id is not known
  116. */
  117. public static function getStorageId($numericId) {
  118. $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  119. $query->select('id')
  120. ->from('storages')
  121. ->where($query->expr()->eq('numeric_id', $query->createNamedParameter($numericId)));
  122. $result = $query->execute();
  123. $row = $result->fetch();
  124. $result->closeCursor();
  125. if ($row) {
  126. return $row['id'];
  127. } else {
  128. return null;
  129. }
  130. }
  131. /**
  132. * Get the numeric of the storage with the provided string id
  133. *
  134. * @param $storageId
  135. * @return int|null either the numeric storage id or null if the storage id is not knwon
  136. */
  137. public static function getNumericStorageId($storageId) {
  138. $storageId = self::adjustStorageId($storageId);
  139. if ($row = self::getStorageById($storageId)) {
  140. return (int)$row['numeric_id'];
  141. } else {
  142. return null;
  143. }
  144. }
  145. /**
  146. * @return array|null [ available, last_checked ]
  147. */
  148. public function getAvailability() {
  149. if ($row = self::getStorageById($this->storageId)) {
  150. return [
  151. 'available' => (int)$row['available'] === 1,
  152. 'last_checked' => $row['last_checked']
  153. ];
  154. } else {
  155. return null;
  156. }
  157. }
  158. /**
  159. * @param bool $isAvailable
  160. * @param int $delay amount of seconds to delay reconsidering that storage further
  161. */
  162. public function setAvailability($isAvailable, int $delay = 0) {
  163. $available = $isAvailable ? 1 : 0;
  164. $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  165. $query->update('storages')
  166. ->set('available', $query->createNamedParameter($available))
  167. ->set('last_checked', $query->createNamedParameter(time() + $delay))
  168. ->where($query->expr()->eq('id', $query->createNamedParameter($this->storageId)));
  169. $query->execute();
  170. }
  171. /**
  172. * Check if a string storage id is known
  173. *
  174. * @param string $storageId
  175. * @return bool
  176. */
  177. public static function exists($storageId) {
  178. return !is_null(self::getNumericStorageId($storageId));
  179. }
  180. /**
  181. * remove the entry for the storage
  182. *
  183. * @param string $storageId
  184. */
  185. public static function remove($storageId) {
  186. $storageId = self::adjustStorageId($storageId);
  187. $numericId = self::getNumericStorageId($storageId);
  188. $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  189. $query->delete('storages')
  190. ->where($query->expr()->eq('id', $query->createNamedParameter($storageId)));
  191. $query->execute();
  192. if (!is_null($numericId)) {
  193. $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
  194. $query->delete('filecache')
  195. ->where($query->expr()->eq('storage', $query->createNamedParameter($numericId)));
  196. $query->execute();
  197. }
  198. }
  199. }