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.

преди 13 години
преди 7 години
преди 8 години
преди 9 години
преди 8 години
преди 9 години
преди 9 години
преди 7 години
преди 7 години
преди 9 години
преди 13 години
преди 9 години
преди 13 години
преди 9 години
преди 13 години
преди 9 години
преди 12 години
преди 9 години
преди 12 години
преди 9 години
преди 13 години
преди 8 години
преди 9 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 11 години
преди 13 години
преди 11 години
преди 13 години
преди 13 години
преди 13 години
преди 10 години
преди 13 години
преди 11 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 13 години
преди 10 години
преди 10 години
преди 8 години
преди 8 години
преди 8 години
преди 9 години
преди 13 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Bart Visscher <bartv@thisnet.nl>
  7. * @author Björn Schießle <bjoern@schiessle.org>
  8. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  9. * @author Daniel Calviño Sánchez <danxuliu@gmail.com>
  10. * @author Jakob Sack <mail@jakobsack.de>
  11. * @author Joas Schilling <coding@schilljs.com>
  12. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  13. * @author Klaas Freitag <freitag@owncloud.com>
  14. * @author Markus Goetz <markus@woboq.com>
  15. * @author Morris Jobke <hey@morrisjobke.de>
  16. * @author Robin Appelman <robin@icewind.nl>
  17. * @author Roeland Jago Douma <roeland@famdouma.nl>
  18. * @author Thomas Müller <thomas.mueller@tmit.eu>
  19. * @author Tobias Kaminsky <tobias@kaminsky.me>
  20. * @author Vincent Petry <vincent@nextcloud.com>
  21. *
  22. * @license AGPL-3.0
  23. *
  24. * This code is free software: you can redistribute it and/or modify
  25. * it under the terms of the GNU Affero General Public License, version 3,
  26. * as published by the Free Software Foundation.
  27. *
  28. * This program is distributed in the hope that it will be useful,
  29. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. * GNU Affero General Public License for more details.
  32. *
  33. * You should have received a copy of the GNU Affero General Public License, version 3,
  34. * along with this program. If not, see <http://www.gnu.org/licenses/>
  35. *
  36. */
  37. namespace OCA\DAV\Connector\Sabre;
  38. use OC\Files\Mount\MoveableMount;
  39. use OC\Files\View;
  40. use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
  41. use OCP\Files\FileInfo;
  42. use OCP\Files\StorageNotAvailableException;
  43. use OCP\Share\IShare;
  44. use OCP\Share\Exceptions\ShareNotFound;
  45. use OCP\Share\IManager;
  46. abstract class Node implements \Sabre\DAV\INode {
  47. /**
  48. * @var \OC\Files\View
  49. */
  50. protected $fileView;
  51. /**
  52. * The path to the current node
  53. *
  54. * @var string
  55. */
  56. protected $path;
  57. /**
  58. * node properties cache
  59. *
  60. * @var array
  61. */
  62. protected $property_cache = null;
  63. /**
  64. * @var \OCP\Files\FileInfo
  65. */
  66. protected $info;
  67. /**
  68. * @var IManager
  69. */
  70. protected $shareManager;
  71. /**
  72. * Sets up the node, expects a full path name
  73. *
  74. * @param \OC\Files\View $view
  75. * @param \OCP\Files\FileInfo $info
  76. * @param IManager $shareManager
  77. */
  78. public function __construct(View $view, FileInfo $info, IManager $shareManager = null) {
  79. $this->fileView = $view;
  80. $this->path = $this->fileView->getRelativePath($info->getPath());
  81. $this->info = $info;
  82. if ($shareManager) {
  83. $this->shareManager = $shareManager;
  84. } else {
  85. $this->shareManager = \OC::$server->getShareManager();
  86. }
  87. }
  88. protected function refreshInfo() {
  89. $this->info = $this->fileView->getFileInfo($this->path);
  90. }
  91. /**
  92. * Returns the name of the node
  93. *
  94. * @return string
  95. */
  96. public function getName() {
  97. return $this->info->getName();
  98. }
  99. /**
  100. * Returns the full path
  101. *
  102. * @return string
  103. */
  104. public function getPath() {
  105. return $this->path;
  106. }
  107. /**
  108. * Renames the node
  109. *
  110. * @param string $name The new name
  111. * @throws \Sabre\DAV\Exception\BadRequest
  112. * @throws \Sabre\DAV\Exception\Forbidden
  113. */
  114. public function setName($name) {
  115. // rename is only allowed if the update privilege is granted
  116. if (!$this->info->isUpdateable()) {
  117. throw new \Sabre\DAV\Exception\Forbidden();
  118. }
  119. [$parentPath,] = \Sabre\Uri\split($this->path);
  120. [, $newName] = \Sabre\Uri\split($name);
  121. // verify path of the target
  122. $this->verifyPath();
  123. $newPath = $parentPath . '/' . $newName;
  124. if (!$this->fileView->rename($this->path, $newPath)) {
  125. throw new \Sabre\DAV\Exception('Failed to rename '. $this->path . ' to ' . $newPath);
  126. }
  127. $this->path = $newPath;
  128. $this->refreshInfo();
  129. }
  130. public function setPropertyCache($property_cache) {
  131. $this->property_cache = $property_cache;
  132. }
  133. /**
  134. * Returns the last modification time, as a unix timestamp
  135. *
  136. * @return int timestamp as integer
  137. */
  138. public function getLastModified() {
  139. $timestamp = $this->info->getMtime();
  140. if (!empty($timestamp)) {
  141. return (int)$timestamp;
  142. }
  143. return $timestamp;
  144. }
  145. /**
  146. * sets the last modification time of the file (mtime) to the value given
  147. * in the second parameter or to now if the second param is empty.
  148. * Even if the modification time is set to a custom value the access time is set to now.
  149. */
  150. public function touch($mtime) {
  151. $mtime = $this->sanitizeMtime($mtime);
  152. $this->fileView->touch($this->path, $mtime);
  153. $this->refreshInfo();
  154. }
  155. /**
  156. * Returns the ETag for a file
  157. *
  158. * An ETag is a unique identifier representing the current version of the
  159. * file. If the file changes, the ETag MUST change. The ETag is an
  160. * arbitrary string, but MUST be surrounded by double-quotes.
  161. *
  162. * Return null if the ETag can not effectively be determined
  163. *
  164. * @return string
  165. */
  166. public function getETag() {
  167. return '"' . $this->info->getEtag() . '"';
  168. }
  169. /**
  170. * Sets the ETag
  171. *
  172. * @param string $etag
  173. *
  174. * @return int file id of updated file or -1 on failure
  175. */
  176. public function setETag($etag) {
  177. return $this->fileView->putFileInfo($this->path, ['etag' => $etag]);
  178. }
  179. public function setCreationTime(int $time) {
  180. return $this->fileView->putFileInfo($this->path, ['creation_time' => $time]);
  181. }
  182. public function setUploadTime(int $time) {
  183. return $this->fileView->putFileInfo($this->path, ['upload_time' => $time]);
  184. }
  185. /**
  186. * Returns the size of the node, in bytes
  187. *
  188. * @return integer
  189. */
  190. public function getSize() {
  191. return $this->info->getSize();
  192. }
  193. /**
  194. * Returns the cache's file id
  195. *
  196. * @return int
  197. */
  198. public function getId() {
  199. return $this->info->getId();
  200. }
  201. /**
  202. * @return string|null
  203. */
  204. public function getFileId() {
  205. if ($this->info->getId()) {
  206. $instanceId = \OC_Util::getInstanceId();
  207. $id = sprintf('%08d', $this->info->getId());
  208. return $id . $instanceId;
  209. }
  210. return null;
  211. }
  212. /**
  213. * @return integer
  214. */
  215. public function getInternalFileId() {
  216. return $this->info->getId();
  217. }
  218. /**
  219. * @param string $user
  220. * @return int
  221. */
  222. public function getSharePermissions($user) {
  223. // check of we access a federated share
  224. if ($user !== null) {
  225. try {
  226. $share = $this->shareManager->getShareByToken($user);
  227. return $share->getPermissions();
  228. } catch (ShareNotFound $e) {
  229. // ignore
  230. }
  231. }
  232. try {
  233. $storage = $this->info->getStorage();
  234. } catch (StorageNotAvailableException $e) {
  235. $storage = null;
  236. }
  237. if ($storage && $storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
  238. /** @var \OCA\Files_Sharing\SharedStorage $storage */
  239. $permissions = (int)$storage->getShare()->getPermissions();
  240. } else {
  241. $permissions = $this->info->getPermissions();
  242. }
  243. /*
  244. * We can always share non moveable mount points with DELETE and UPDATE
  245. * Eventually we need to do this properly
  246. */
  247. $mountpoint = $this->info->getMountPoint();
  248. if (!($mountpoint instanceof MoveableMount)) {
  249. $mountpointpath = $mountpoint->getMountPoint();
  250. if (substr($mountpointpath, -1) === '/') {
  251. $mountpointpath = substr($mountpointpath, 0, -1);
  252. }
  253. if (!$mountpoint->getOption('readonly', false) && $mountpointpath === $this->info->getPath()) {
  254. $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
  255. }
  256. }
  257. /*
  258. * Files can't have create or delete permissions
  259. */
  260. if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
  261. $permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE);
  262. }
  263. return $permissions;
  264. }
  265. /**
  266. * @param string $user
  267. * @return string
  268. */
  269. public function getNoteFromShare($user) {
  270. if ($user === null) {
  271. return '';
  272. }
  273. $types = [
  274. IShare::TYPE_USER,
  275. IShare::TYPE_GROUP,
  276. IShare::TYPE_CIRCLE,
  277. IShare::TYPE_ROOM
  278. ];
  279. foreach ($types as $shareType) {
  280. $shares = $this->shareManager->getSharedWith($user, $shareType, $this, -1);
  281. foreach ($shares as $share) {
  282. $note = $share->getNote();
  283. if ($share->getShareOwner() !== $user && !empty($note)) {
  284. return $note;
  285. }
  286. }
  287. }
  288. return '';
  289. }
  290. /**
  291. * @return string
  292. */
  293. public function getDavPermissions() {
  294. $p = '';
  295. if ($this->info->isShared()) {
  296. $p .= 'S';
  297. }
  298. if ($this->info->isShareable()) {
  299. $p .= 'R';
  300. }
  301. if ($this->info->isMounted()) {
  302. $p .= 'M';
  303. }
  304. if ($this->info->isReadable()) {
  305. $p .= 'G';
  306. }
  307. if ($this->info->isDeletable()) {
  308. $p .= 'D';
  309. }
  310. if ($this->info->isUpdateable()) {
  311. $p .= 'NV'; // Renameable, Moveable
  312. }
  313. if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
  314. if ($this->info->isUpdateable()) {
  315. $p .= 'W';
  316. }
  317. } else {
  318. if ($this->info->isCreatable()) {
  319. $p .= 'CK';
  320. }
  321. }
  322. return $p;
  323. }
  324. public function getOwner() {
  325. return $this->info->getOwner();
  326. }
  327. protected function verifyPath() {
  328. try {
  329. $fileName = basename($this->info->getPath());
  330. $this->fileView->verifyPath($this->path, $fileName);
  331. } catch (\OCP\Files\InvalidPathException $ex) {
  332. throw new InvalidPath($ex->getMessage());
  333. }
  334. }
  335. /**
  336. * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
  337. */
  338. public function acquireLock($type) {
  339. $this->fileView->lockFile($this->path, $type);
  340. }
  341. /**
  342. * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
  343. */
  344. public function releaseLock($type) {
  345. $this->fileView->unlockFile($this->path, $type);
  346. }
  347. /**
  348. * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
  349. */
  350. public function changeLock($type) {
  351. $this->fileView->changeLock($this->path, $type);
  352. }
  353. public function getFileInfo() {
  354. return $this->info;
  355. }
  356. protected function sanitizeMtime($mtimeFromRequest) {
  357. // In PHP 5.X "is_numeric" returns true for strings in hexadecimal
  358. // notation. This is no longer the case in PHP 7.X, so this check
  359. // ensures that strings with hexadecimal notations fail too in PHP 5.X.
  360. $isHexadecimal = is_string($mtimeFromRequest) && preg_match('/^\s*0[xX]/', $mtimeFromRequest);
  361. if ($isHexadecimal || !is_numeric($mtimeFromRequest)) {
  362. throw new \InvalidArgumentException('X-OC-MTime header must be an integer (unix timestamp).');
  363. }
  364. return (int)$mtimeFromRequest;
  365. }
  366. }