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.

226 lines
4.6 KiB

3 years ago
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2020 Robin Appelman <robin@icewind.nl>
  5. *
  6. * @author Robin Appelman <robin@icewind.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\SimpleFS;
  25. use Icewind\Streams\CallbackWrapper;
  26. use OCP\Files\File;
  27. use OCP\Files\Folder;
  28. use OCP\Files\NotFoundException;
  29. use OCP\Files\NotPermittedException;
  30. use OCP\Files\SimpleFS\ISimpleFile;
  31. class NewSimpleFile implements ISimpleFile {
  32. private $parentFolder;
  33. private $name;
  34. /** @var File|null */
  35. private $file = null;
  36. /**
  37. * File constructor.
  38. *
  39. * @param File $file
  40. */
  41. public function __construct(Folder $parentFolder, string $name) {
  42. $this->parentFolder = $parentFolder;
  43. $this->name = $name;
  44. }
  45. /**
  46. * Get the name
  47. *
  48. * @return string
  49. */
  50. public function getName() {
  51. return $this->name;
  52. }
  53. /**
  54. * Get the size in bytes
  55. *
  56. * @return int
  57. */
  58. public function getSize() {
  59. if ($this->file) {
  60. return $this->file->getSize();
  61. } else {
  62. return 0;
  63. }
  64. }
  65. /**
  66. * Get the ETag
  67. *
  68. * @return string
  69. */
  70. public function getETag() {
  71. if ($this->file) {
  72. return $this->file->getEtag();
  73. } else {
  74. return '';
  75. }
  76. }
  77. /**
  78. * Get the last modification time
  79. *
  80. * @return int
  81. */
  82. public function getMTime() {
  83. if ($this->file) {
  84. return $this->file->getMTime();
  85. } else {
  86. return time();
  87. }
  88. }
  89. /**
  90. * Get the content
  91. *
  92. * @return string
  93. * @throws NotFoundException
  94. * @throws NotPermittedException
  95. */
  96. public function getContent() {
  97. if ($this->file) {
  98. $result = $this->file->getContent();
  99. if ($result === false) {
  100. $this->checkFile();
  101. }
  102. return $result;
  103. } else {
  104. return '';
  105. }
  106. }
  107. /**
  108. * Overwrite the file
  109. *
  110. * @param string|resource $data
  111. * @throws NotPermittedException
  112. * @throws NotFoundException
  113. */
  114. public function putContent($data) {
  115. try {
  116. if ($this->file) {
  117. $this->file->putContent($data);
  118. } else {
  119. $this->file = $this->parentFolder->newFile($this->name, $data);
  120. }
  121. } catch (NotFoundException $e) {
  122. $this->checkFile();
  123. }
  124. }
  125. /**
  126. * Sometimes there are some issues with the AppData. Most of them are from
  127. * user error. But we should handle them gracefull anyway.
  128. *
  129. * If for some reason the current file can't be found. We remove it.
  130. * Then traverse up and check all folders if they exists. This so that the
  131. * next request will have a valid appdata structure again.
  132. *
  133. * @throws NotFoundException
  134. */
  135. private function checkFile() {
  136. $cur = $this->file;
  137. while ($cur->stat() === false) {
  138. $parent = $cur->getParent();
  139. try {
  140. $cur->delete();
  141. } catch (NotFoundException $e) {
  142. // Just continue then
  143. }
  144. $cur = $parent;
  145. }
  146. if ($cur !== $this->file) {
  147. throw new NotFoundException('File does not exist');
  148. }
  149. }
  150. /**
  151. * Delete the file
  152. *
  153. * @throws NotPermittedException
  154. */
  155. public function delete() {
  156. if ($this->file) {
  157. $this->file->delete();
  158. }
  159. }
  160. /**
  161. * Get the MimeType
  162. *
  163. * @return string
  164. */
  165. public function getMimeType() {
  166. if ($this->file) {
  167. return $this->file->getMimeType();
  168. } else {
  169. return 'text/plain';
  170. }
  171. }
  172. /**
  173. * Open the file as stream for reading, resulting resource can be operated as stream like the result from php's own fopen
  174. *
  175. * @return resource
  176. * @throws \OCP\Files\NotPermittedException
  177. * @since 14.0.0
  178. */
  179. public function read() {
  180. if ($this->file) {
  181. return $this->file->fopen('r');
  182. } else {
  183. return fopen('php://temp', 'r');
  184. }
  185. }
  186. /**
  187. * Open the file as stream for writing, resulting resource can be operated as stream like the result from php's own fopen
  188. *
  189. * @return resource
  190. * @throws \OCP\Files\NotPermittedException
  191. * @since 14.0.0
  192. */
  193. public function write() {
  194. if ($this->file) {
  195. return $this->file->fopen('w');
  196. } else {
  197. $source = fopen('php://temp', 'w+');
  198. return CallbackWrapper::wrap($source, null, null, null, null, function () use ($source) {
  199. rewind($source);
  200. $this->putContent($source);
  201. });
  202. }
  203. }
  204. }