Passed
Push — master ( f4135c...dd736f )
by Joas
15:44 queued 12s
created
apps/files_sharing/lib/SharedStorage.php 1 patch
Indentation   +500 added lines, -500 removed lines patch added patch discarded remove patch
@@ -60,504 +60,504 @@
 block discarded – undo
60 60
  */
61 61
 class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage, IDisableEncryptionStorage {
62 62
 
63
-	/** @var \OCP\Share\IShare */
64
-	private $superShare;
65
-
66
-	/** @var \OCP\Share\IShare[] */
67
-	private $groupedShares;
68
-
69
-	/**
70
-	 * @var \OC\Files\View
71
-	 */
72
-	private $ownerView;
73
-
74
-	private $initialized = false;
75
-
76
-	/**
77
-	 * @var ICacheEntry
78
-	 */
79
-	private $sourceRootInfo;
80
-
81
-	/** @var string */
82
-	private $user;
83
-
84
-	/**
85
-	 * @var \OCP\ILogger
86
-	 */
87
-	private $logger;
88
-
89
-	/** @var  IStorage */
90
-	private $nonMaskedStorage;
91
-
92
-	private $options;
93
-
94
-	/** @var boolean */
95
-	private $sharingDisabledForUser;
96
-
97
-	/** @var ?Folder $ownerUserFolder */
98
-	private $ownerUserFolder = null;
99
-
100
-	private string $sourcePath = '';
101
-
102
-	public function __construct($arguments) {
103
-		$this->ownerView = $arguments['ownerView'];
104
-		$this->logger = \OC::$server->getLogger();
105
-
106
-		$this->superShare = $arguments['superShare'];
107
-		$this->groupedShares = $arguments['groupedShares'];
108
-
109
-		$this->user = $arguments['user'];
110
-		if (isset($arguments['sharingDisabledForUser'])) {
111
-			$this->sharingDisabledForUser = $arguments['sharingDisabledForUser'];
112
-		} else {
113
-			$this->sharingDisabledForUser = false;
114
-		}
115
-
116
-		parent::__construct([
117
-			'storage' => null,
118
-			'root' => null,
119
-		]);
120
-	}
121
-
122
-	/**
123
-	 * @return ICacheEntry
124
-	 */
125
-	private function getSourceRootInfo() {
126
-		if (is_null($this->sourceRootInfo)) {
127
-			if (is_null($this->superShare->getNodeCacheEntry())) {
128
-				$this->init();
129
-				$this->sourceRootInfo = $this->nonMaskedStorage->getCache()->get($this->rootPath);
130
-			} else {
131
-				$this->sourceRootInfo = $this->superShare->getNodeCacheEntry();
132
-			}
133
-		}
134
-		return $this->sourceRootInfo;
135
-	}
136
-
137
-	private function init() {
138
-		if ($this->initialized) {
139
-			return;
140
-		}
141
-		$this->initialized = true;
142
-		try {
143
-			/** @var IRootFolder $rootFolder */
144
-			$rootFolder = \OC::$server->get(IRootFolder::class);
145
-			$this->ownerUserFolder = $rootFolder->getUserFolder($this->superShare->getShareOwner());
146
-			$sourceId = $this->superShare->getNodeId();
147
-			$ownerNodes = $this->ownerUserFolder->getById($sourceId);
148
-			/** @var Node|false $ownerNode */
149
-			$ownerNode = current($ownerNodes);
150
-			if (!$ownerNode) {
151
-				$this->storage = new FailedStorage(['exception' => new NotFoundException("File by id $sourceId not found")]);
152
-				$this->cache = new FailedCache();
153
-				$this->rootPath = '';
154
-			} else {
155
-				$this->nonMaskedStorage = $ownerNode->getStorage();
156
-				$this->sourcePath = $ownerNode->getPath();
157
-				$this->rootPath = $ownerNode->getInternalPath();
158
-				$this->storage = new PermissionsMask([
159
-					'storage' => $this->nonMaskedStorage,
160
-					'mask' => $this->superShare->getPermissions(),
161
-				]);
162
-			}
163
-		} catch (NotFoundException $e) {
164
-			// original file not accessible or deleted, set FailedStorage
165
-			$this->storage = new FailedStorage(['exception' => $e]);
166
-			$this->cache = new FailedCache();
167
-			$this->rootPath = '';
168
-		} catch (NoUserException $e) {
169
-			// sharer user deleted, set FailedStorage
170
-			$this->storage = new FailedStorage(['exception' => $e]);
171
-			$this->cache = new FailedCache();
172
-			$this->rootPath = '';
173
-		} catch (\Exception $e) {
174
-			$this->storage = new FailedStorage(['exception' => $e]);
175
-			$this->cache = new FailedCache();
176
-			$this->rootPath = '';
177
-			$this->logger->logException($e);
178
-		}
179
-
180
-		if (!$this->nonMaskedStorage) {
181
-			$this->nonMaskedStorage = $this->storage;
182
-		}
183
-	}
184
-
185
-	/**
186
-	 * @inheritdoc
187
-	 */
188
-	public function instanceOfStorage($class): bool {
189
-		if ($class === '\OC\Files\Storage\Common' || $class == Common::class) {
190
-			return true;
191
-		}
192
-		if (in_array($class, [
193
-			'\OC\Files\Storage\Home',
194
-			'\OC\Files\ObjectStore\HomeObjectStoreStorage',
195
-			'\OCP\Files\IHomeStorage',
196
-			Home::class,
197
-			HomeObjectStoreStorage::class,
198
-			IHomeStorage::class
199
-		])) {
200
-			return false;
201
-		}
202
-		return parent::instanceOfStorage($class);
203
-	}
204
-
205
-	/**
206
-	 * @return string
207
-	 */
208
-	public function getShareId() {
209
-		return $this->superShare->getId();
210
-	}
211
-
212
-	private function isValid(): bool {
213
-		return $this->getSourceRootInfo() && ($this->getSourceRootInfo()->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
214
-	}
215
-
216
-	/**
217
-	 * get id of the mount point
218
-	 *
219
-	 * @return string
220
-	 */
221
-	public function getId(): string {
222
-		return 'shared::' . $this->getMountPoint();
223
-	}
224
-
225
-	/**
226
-	 * Get the permissions granted for a shared file
227
-	 *
228
-	 * @param string $target Shared target file path
229
-	 * @return int CRUDS permissions granted
230
-	 */
231
-	public function getPermissions($target = ''): int {
232
-		if (!$this->isValid()) {
233
-			return 0;
234
-		}
235
-		$permissions = parent::getPermissions($target) & $this->superShare->getPermissions();
236
-
237
-		// part files and the mount point always have delete permissions
238
-		if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
239
-			$permissions |= \OCP\Constants::PERMISSION_DELETE;
240
-		}
241
-
242
-		if ($this->sharingDisabledForUser) {
243
-			$permissions &= ~\OCP\Constants::PERMISSION_SHARE;
244
-		}
245
-
246
-		return $permissions;
247
-	}
248
-
249
-	public function isCreatable($path): bool {
250
-		return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_CREATE);
251
-	}
252
-
253
-	public function isReadable($path): bool {
254
-		if (!$this->isValid()) {
255
-			return false;
256
-		}
257
-		if (!$this->file_exists($path)) {
258
-			return false;
259
-		}
260
-		/** @var IStorage $storage */
261
-		/** @var string $internalPath */
262
-		[$storage, $internalPath] = $this->resolvePath($path);
263
-		return $storage->isReadable($internalPath);
264
-	}
265
-
266
-	public function isUpdatable($path): bool {
267
-		return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_UPDATE);
268
-	}
269
-
270
-	public function isDeletable($path): bool {
271
-		return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_DELETE);
272
-	}
273
-
274
-	public function isSharable($path): bool {
275
-		if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
276
-			return false;
277
-		}
278
-		return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
279
-	}
280
-
281
-	public function fopen($path, $mode) {
282
-		$source = $this->getUnjailedPath($path);
283
-		switch ($mode) {
284
-			case 'r+':
285
-			case 'rb+':
286
-			case 'w+':
287
-			case 'wb+':
288
-			case 'x+':
289
-			case 'xb+':
290
-			case 'a+':
291
-			case 'ab+':
292
-			case 'w':
293
-			case 'wb':
294
-			case 'x':
295
-			case 'xb':
296
-			case 'a':
297
-			case 'ab':
298
-				$creatable = $this->isCreatable(dirname($path));
299
-				$updatable = $this->isUpdatable($path);
300
-				// if neither permissions given, no need to continue
301
-				if (!$creatable && !$updatable) {
302
-					if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
303
-						$updatable = $this->isUpdatable(dirname($path));
304
-					}
305
-
306
-					if (!$updatable) {
307
-						return false;
308
-					}
309
-				}
310
-
311
-				$exists = $this->file_exists($path);
312
-				// if a file exists, updatable permissions are required
313
-				if ($exists && !$updatable) {
314
-					return false;
315
-				}
316
-
317
-				// part file is allowed if !$creatable but the final file is $updatable
318
-				if (pathinfo($path, PATHINFO_EXTENSION) !== 'part') {
319
-					if (!$exists && !$creatable) {
320
-						return false;
321
-					}
322
-				}
323
-		}
324
-		$info = [
325
-			'target' => $this->getMountPoint() . '/' . $path,
326
-			'source' => $source,
327
-			'mode' => $mode,
328
-		];
329
-		\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info);
330
-		return $this->nonMaskedStorage->fopen($this->getUnjailedPath($path), $mode);
331
-	}
332
-
333
-	/**
334
-	 * see https://www.php.net/manual/en/function.rename.php
335
-	 *
336
-	 * @param string $path1
337
-	 * @param string $path2
338
-	 * @return bool
339
-	 */
340
-	public function rename($path1, $path2): bool {
341
-		$this->init();
342
-		$isPartFile = pathinfo($path1, PATHINFO_EXTENSION) === 'part';
343
-		$targetExists = $this->file_exists($path2);
344
-		$sameFolder = dirname($path1) === dirname($path2);
345
-
346
-		if ($targetExists || ($sameFolder && !$isPartFile)) {
347
-			if (!$this->isUpdatable('')) {
348
-				return false;
349
-			}
350
-		} else {
351
-			if (!$this->isCreatable('')) {
352
-				return false;
353
-			}
354
-		}
355
-
356
-		return $this->nonMaskedStorage->rename($this->getUnjailedPath($path1), $this->getUnjailedPath($path2));
357
-	}
358
-
359
-	/**
360
-	 * return mount point of share, relative to data/user/files
361
-	 *
362
-	 * @return string
363
-	 */
364
-	public function getMountPoint(): string {
365
-		return $this->superShare->getTarget();
366
-	}
367
-
368
-	/**
369
-	 * @param string $path
370
-	 */
371
-	public function setMountPoint($path): void {
372
-		$this->superShare->setTarget($path);
373
-
374
-		foreach ($this->groupedShares as $share) {
375
-			$share->setTarget($path);
376
-		}
377
-	}
378
-
379
-	/**
380
-	 * get the user who shared the file
381
-	 *
382
-	 * @return string
383
-	 */
384
-	public function getSharedFrom(): string {
385
-		return $this->superShare->getShareOwner();
386
-	}
387
-
388
-	/**
389
-	 * @return \OCP\Share\IShare
390
-	 */
391
-	public function getShare(): IShare {
392
-		return $this->superShare;
393
-	}
394
-
395
-	/**
396
-	 * return share type, can be "file" or "folder"
397
-	 *
398
-	 * @return string
399
-	 */
400
-	public function getItemType(): string {
401
-		return $this->superShare->getNodeType();
402
-	}
403
-
404
-	public function getCache($path = '', $storage = null) {
405
-		if ($this->cache) {
406
-			return $this->cache;
407
-		}
408
-		if (!$storage) {
409
-			$storage = $this;
410
-		}
411
-		$sourceRoot = $this->getSourceRootInfo();
412
-		if ($this->storage instanceof FailedStorage) {
413
-			return new FailedCache();
414
-		}
415
-
416
-		$this->cache = new \OCA\Files_Sharing\Cache(
417
-			$storage,
418
-			$sourceRoot,
419
-			\OC::$server->get(IUserManager::class)
420
-		);
421
-		return $this->cache;
422
-	}
423
-
424
-	public function getScanner($path = '', $storage = null) {
425
-		if (!$storage) {
426
-			$storage = $this;
427
-		}
428
-		return new \OCA\Files_Sharing\Scanner($storage);
429
-	}
430
-
431
-	public function getOwner($path): string {
432
-		return $this->superShare->getShareOwner();
433
-	}
434
-
435
-	public function getWatcher($path = '', $storage = null): Watcher {
436
-		$mountManager = \OC::$server->getMountManager();
437
-
438
-		// Get node informations
439
-		$node = $this->getShare()->getNodeCacheEntry();
440
-		if ($node) {
441
-			$mount = $mountManager->findByNumericId($node->getStorageId());
442
-			// If the share is originating from an external storage
443
-			if (count($mount) > 0 && $mount[0] instanceof ExternalMountPoint) {
444
-				// Propagate original storage scan
445
-				return parent::getWatcher($path, $storage);
446
-			}
447
-		}
448
-
449
-		// cache updating is handled by the share source
450
-		return new NullWatcher();
451
-	}
452
-
453
-	/**
454
-	 * unshare complete storage, also the grouped shares
455
-	 *
456
-	 * @return bool
457
-	 */
458
-	public function unshareStorage(): bool {
459
-		foreach ($this->groupedShares as $share) {
460
-			\OC::$server->getShareManager()->deleteFromSelf($share, $this->user);
461
-		}
462
-		return true;
463
-	}
464
-
465
-	/**
466
-	 * @param string $path
467
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
468
-	 * @param \OCP\Lock\ILockingProvider $provider
469
-	 * @throws \OCP\Lock\LockedException
470
-	 */
471
-	public function acquireLock($path, $type, ILockingProvider $provider) {
472
-		/** @var \OCP\Files\Storage $targetStorage */
473
-		[$targetStorage, $targetInternalPath] = $this->resolvePath($path);
474
-		$targetStorage->acquireLock($targetInternalPath, $type, $provider);
475
-		// lock the parent folders of the owner when locking the share as recipient
476
-		if ($path === '') {
477
-			$sourcePath = $this->ownerUserFolder->getRelativePath($this->sourcePath);
478
-			$this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
479
-		}
480
-	}
481
-
482
-	/**
483
-	 * @param string $path
484
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
485
-	 * @param \OCP\Lock\ILockingProvider $provider
486
-	 */
487
-	public function releaseLock($path, $type, ILockingProvider $provider) {
488
-		/** @var \OCP\Files\Storage $targetStorage */
489
-		[$targetStorage, $targetInternalPath] = $this->resolvePath($path);
490
-		$targetStorage->releaseLock($targetInternalPath, $type, $provider);
491
-		// unlock the parent folders of the owner when unlocking the share as recipient
492
-		if ($path === '') {
493
-			$sourcePath = $this->ownerUserFolder->getRelativePath($this->sourcePath);
494
-			$this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
495
-		}
496
-	}
497
-
498
-	/**
499
-	 * @param string $path
500
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
501
-	 * @param \OCP\Lock\ILockingProvider $provider
502
-	 */
503
-	public function changeLock($path, $type, ILockingProvider $provider) {
504
-		/** @var \OCP\Files\Storage $targetStorage */
505
-		[$targetStorage, $targetInternalPath] = $this->resolvePath($path);
506
-		$targetStorage->changeLock($targetInternalPath, $type, $provider);
507
-	}
508
-
509
-	/**
510
-	 * @return array [ available, last_checked ]
511
-	 */
512
-	public function getAvailability() {
513
-		// shares do not participate in availability logic
514
-		return [
515
-			'available' => true,
516
-			'last_checked' => 0,
517
-		];
518
-	}
519
-
520
-	/**
521
-	 * @param bool $available
522
-	 */
523
-	public function setAvailability($available) {
524
-		// shares do not participate in availability logic
525
-	}
526
-
527
-	public function getSourceStorage() {
528
-		$this->init();
529
-		return $this->nonMaskedStorage;
530
-	}
531
-
532
-	public function getWrapperStorage() {
533
-		$this->init();
534
-		return $this->storage;
535
-	}
536
-
537
-	public function file_get_contents($path) {
538
-		$info = [
539
-			'target' => $this->getMountPoint() . '/' . $path,
540
-			'source' => $this->getUnjailedPath($path),
541
-		];
542
-		\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
543
-		return parent::file_get_contents($path);
544
-	}
545
-
546
-	public function file_put_contents($path, $data) {
547
-		$info = [
548
-			'target' => $this->getMountPoint() . '/' . $path,
549
-			'source' => $this->getUnjailedPath($path),
550
-		];
551
-		\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
552
-		return parent::file_put_contents($path, $data);
553
-	}
554
-
555
-	public function setMountOptions(array $options) {
556
-		$this->mountOptions = $options;
557
-	}
558
-
559
-	public function getUnjailedPath($path) {
560
-		$this->init();
561
-		return parent::getUnjailedPath($path);
562
-	}
63
+    /** @var \OCP\Share\IShare */
64
+    private $superShare;
65
+
66
+    /** @var \OCP\Share\IShare[] */
67
+    private $groupedShares;
68
+
69
+    /**
70
+     * @var \OC\Files\View
71
+     */
72
+    private $ownerView;
73
+
74
+    private $initialized = false;
75
+
76
+    /**
77
+     * @var ICacheEntry
78
+     */
79
+    private $sourceRootInfo;
80
+
81
+    /** @var string */
82
+    private $user;
83
+
84
+    /**
85
+     * @var \OCP\ILogger
86
+     */
87
+    private $logger;
88
+
89
+    /** @var  IStorage */
90
+    private $nonMaskedStorage;
91
+
92
+    private $options;
93
+
94
+    /** @var boolean */
95
+    private $sharingDisabledForUser;
96
+
97
+    /** @var ?Folder $ownerUserFolder */
98
+    private $ownerUserFolder = null;
99
+
100
+    private string $sourcePath = '';
101
+
102
+    public function __construct($arguments) {
103
+        $this->ownerView = $arguments['ownerView'];
104
+        $this->logger = \OC::$server->getLogger();
105
+
106
+        $this->superShare = $arguments['superShare'];
107
+        $this->groupedShares = $arguments['groupedShares'];
108
+
109
+        $this->user = $arguments['user'];
110
+        if (isset($arguments['sharingDisabledForUser'])) {
111
+            $this->sharingDisabledForUser = $arguments['sharingDisabledForUser'];
112
+        } else {
113
+            $this->sharingDisabledForUser = false;
114
+        }
115
+
116
+        parent::__construct([
117
+            'storage' => null,
118
+            'root' => null,
119
+        ]);
120
+    }
121
+
122
+    /**
123
+     * @return ICacheEntry
124
+     */
125
+    private function getSourceRootInfo() {
126
+        if (is_null($this->sourceRootInfo)) {
127
+            if (is_null($this->superShare->getNodeCacheEntry())) {
128
+                $this->init();
129
+                $this->sourceRootInfo = $this->nonMaskedStorage->getCache()->get($this->rootPath);
130
+            } else {
131
+                $this->sourceRootInfo = $this->superShare->getNodeCacheEntry();
132
+            }
133
+        }
134
+        return $this->sourceRootInfo;
135
+    }
136
+
137
+    private function init() {
138
+        if ($this->initialized) {
139
+            return;
140
+        }
141
+        $this->initialized = true;
142
+        try {
143
+            /** @var IRootFolder $rootFolder */
144
+            $rootFolder = \OC::$server->get(IRootFolder::class);
145
+            $this->ownerUserFolder = $rootFolder->getUserFolder($this->superShare->getShareOwner());
146
+            $sourceId = $this->superShare->getNodeId();
147
+            $ownerNodes = $this->ownerUserFolder->getById($sourceId);
148
+            /** @var Node|false $ownerNode */
149
+            $ownerNode = current($ownerNodes);
150
+            if (!$ownerNode) {
151
+                $this->storage = new FailedStorage(['exception' => new NotFoundException("File by id $sourceId not found")]);
152
+                $this->cache = new FailedCache();
153
+                $this->rootPath = '';
154
+            } else {
155
+                $this->nonMaskedStorage = $ownerNode->getStorage();
156
+                $this->sourcePath = $ownerNode->getPath();
157
+                $this->rootPath = $ownerNode->getInternalPath();
158
+                $this->storage = new PermissionsMask([
159
+                    'storage' => $this->nonMaskedStorage,
160
+                    'mask' => $this->superShare->getPermissions(),
161
+                ]);
162
+            }
163
+        } catch (NotFoundException $e) {
164
+            // original file not accessible or deleted, set FailedStorage
165
+            $this->storage = new FailedStorage(['exception' => $e]);
166
+            $this->cache = new FailedCache();
167
+            $this->rootPath = '';
168
+        } catch (NoUserException $e) {
169
+            // sharer user deleted, set FailedStorage
170
+            $this->storage = new FailedStorage(['exception' => $e]);
171
+            $this->cache = new FailedCache();
172
+            $this->rootPath = '';
173
+        } catch (\Exception $e) {
174
+            $this->storage = new FailedStorage(['exception' => $e]);
175
+            $this->cache = new FailedCache();
176
+            $this->rootPath = '';
177
+            $this->logger->logException($e);
178
+        }
179
+
180
+        if (!$this->nonMaskedStorage) {
181
+            $this->nonMaskedStorage = $this->storage;
182
+        }
183
+    }
184
+
185
+    /**
186
+     * @inheritdoc
187
+     */
188
+    public function instanceOfStorage($class): bool {
189
+        if ($class === '\OC\Files\Storage\Common' || $class == Common::class) {
190
+            return true;
191
+        }
192
+        if (in_array($class, [
193
+            '\OC\Files\Storage\Home',
194
+            '\OC\Files\ObjectStore\HomeObjectStoreStorage',
195
+            '\OCP\Files\IHomeStorage',
196
+            Home::class,
197
+            HomeObjectStoreStorage::class,
198
+            IHomeStorage::class
199
+        ])) {
200
+            return false;
201
+        }
202
+        return parent::instanceOfStorage($class);
203
+    }
204
+
205
+    /**
206
+     * @return string
207
+     */
208
+    public function getShareId() {
209
+        return $this->superShare->getId();
210
+    }
211
+
212
+    private function isValid(): bool {
213
+        return $this->getSourceRootInfo() && ($this->getSourceRootInfo()->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
214
+    }
215
+
216
+    /**
217
+     * get id of the mount point
218
+     *
219
+     * @return string
220
+     */
221
+    public function getId(): string {
222
+        return 'shared::' . $this->getMountPoint();
223
+    }
224
+
225
+    /**
226
+     * Get the permissions granted for a shared file
227
+     *
228
+     * @param string $target Shared target file path
229
+     * @return int CRUDS permissions granted
230
+     */
231
+    public function getPermissions($target = ''): int {
232
+        if (!$this->isValid()) {
233
+            return 0;
234
+        }
235
+        $permissions = parent::getPermissions($target) & $this->superShare->getPermissions();
236
+
237
+        // part files and the mount point always have delete permissions
238
+        if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
239
+            $permissions |= \OCP\Constants::PERMISSION_DELETE;
240
+        }
241
+
242
+        if ($this->sharingDisabledForUser) {
243
+            $permissions &= ~\OCP\Constants::PERMISSION_SHARE;
244
+        }
245
+
246
+        return $permissions;
247
+    }
248
+
249
+    public function isCreatable($path): bool {
250
+        return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_CREATE);
251
+    }
252
+
253
+    public function isReadable($path): bool {
254
+        if (!$this->isValid()) {
255
+            return false;
256
+        }
257
+        if (!$this->file_exists($path)) {
258
+            return false;
259
+        }
260
+        /** @var IStorage $storage */
261
+        /** @var string $internalPath */
262
+        [$storage, $internalPath] = $this->resolvePath($path);
263
+        return $storage->isReadable($internalPath);
264
+    }
265
+
266
+    public function isUpdatable($path): bool {
267
+        return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_UPDATE);
268
+    }
269
+
270
+    public function isDeletable($path): bool {
271
+        return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_DELETE);
272
+    }
273
+
274
+    public function isSharable($path): bool {
275
+        if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
276
+            return false;
277
+        }
278
+        return (bool)($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
279
+    }
280
+
281
+    public function fopen($path, $mode) {
282
+        $source = $this->getUnjailedPath($path);
283
+        switch ($mode) {
284
+            case 'r+':
285
+            case 'rb+':
286
+            case 'w+':
287
+            case 'wb+':
288
+            case 'x+':
289
+            case 'xb+':
290
+            case 'a+':
291
+            case 'ab+':
292
+            case 'w':
293
+            case 'wb':
294
+            case 'x':
295
+            case 'xb':
296
+            case 'a':
297
+            case 'ab':
298
+                $creatable = $this->isCreatable(dirname($path));
299
+                $updatable = $this->isUpdatable($path);
300
+                // if neither permissions given, no need to continue
301
+                if (!$creatable && !$updatable) {
302
+                    if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
303
+                        $updatable = $this->isUpdatable(dirname($path));
304
+                    }
305
+
306
+                    if (!$updatable) {
307
+                        return false;
308
+                    }
309
+                }
310
+
311
+                $exists = $this->file_exists($path);
312
+                // if a file exists, updatable permissions are required
313
+                if ($exists && !$updatable) {
314
+                    return false;
315
+                }
316
+
317
+                // part file is allowed if !$creatable but the final file is $updatable
318
+                if (pathinfo($path, PATHINFO_EXTENSION) !== 'part') {
319
+                    if (!$exists && !$creatable) {
320
+                        return false;
321
+                    }
322
+                }
323
+        }
324
+        $info = [
325
+            'target' => $this->getMountPoint() . '/' . $path,
326
+            'source' => $source,
327
+            'mode' => $mode,
328
+        ];
329
+        \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info);
330
+        return $this->nonMaskedStorage->fopen($this->getUnjailedPath($path), $mode);
331
+    }
332
+
333
+    /**
334
+     * see https://www.php.net/manual/en/function.rename.php
335
+     *
336
+     * @param string $path1
337
+     * @param string $path2
338
+     * @return bool
339
+     */
340
+    public function rename($path1, $path2): bool {
341
+        $this->init();
342
+        $isPartFile = pathinfo($path1, PATHINFO_EXTENSION) === 'part';
343
+        $targetExists = $this->file_exists($path2);
344
+        $sameFolder = dirname($path1) === dirname($path2);
345
+
346
+        if ($targetExists || ($sameFolder && !$isPartFile)) {
347
+            if (!$this->isUpdatable('')) {
348
+                return false;
349
+            }
350
+        } else {
351
+            if (!$this->isCreatable('')) {
352
+                return false;
353
+            }
354
+        }
355
+
356
+        return $this->nonMaskedStorage->rename($this->getUnjailedPath($path1), $this->getUnjailedPath($path2));
357
+    }
358
+
359
+    /**
360
+     * return mount point of share, relative to data/user/files
361
+     *
362
+     * @return string
363
+     */
364
+    public function getMountPoint(): string {
365
+        return $this->superShare->getTarget();
366
+    }
367
+
368
+    /**
369
+     * @param string $path
370
+     */
371
+    public function setMountPoint($path): void {
372
+        $this->superShare->setTarget($path);
373
+
374
+        foreach ($this->groupedShares as $share) {
375
+            $share->setTarget($path);
376
+        }
377
+    }
378
+
379
+    /**
380
+     * get the user who shared the file
381
+     *
382
+     * @return string
383
+     */
384
+    public function getSharedFrom(): string {
385
+        return $this->superShare->getShareOwner();
386
+    }
387
+
388
+    /**
389
+     * @return \OCP\Share\IShare
390
+     */
391
+    public function getShare(): IShare {
392
+        return $this->superShare;
393
+    }
394
+
395
+    /**
396
+     * return share type, can be "file" or "folder"
397
+     *
398
+     * @return string
399
+     */
400
+    public function getItemType(): string {
401
+        return $this->superShare->getNodeType();
402
+    }
403
+
404
+    public function getCache($path = '', $storage = null) {
405
+        if ($this->cache) {
406
+            return $this->cache;
407
+        }
408
+        if (!$storage) {
409
+            $storage = $this;
410
+        }
411
+        $sourceRoot = $this->getSourceRootInfo();
412
+        if ($this->storage instanceof FailedStorage) {
413
+            return new FailedCache();
414
+        }
415
+
416
+        $this->cache = new \OCA\Files_Sharing\Cache(
417
+            $storage,
418
+            $sourceRoot,
419
+            \OC::$server->get(IUserManager::class)
420
+        );
421
+        return $this->cache;
422
+    }
423
+
424
+    public function getScanner($path = '', $storage = null) {
425
+        if (!$storage) {
426
+            $storage = $this;
427
+        }
428
+        return new \OCA\Files_Sharing\Scanner($storage);
429
+    }
430
+
431
+    public function getOwner($path): string {
432
+        return $this->superShare->getShareOwner();
433
+    }
434
+
435
+    public function getWatcher($path = '', $storage = null): Watcher {
436
+        $mountManager = \OC::$server->getMountManager();
437
+
438
+        // Get node informations
439
+        $node = $this->getShare()->getNodeCacheEntry();
440
+        if ($node) {
441
+            $mount = $mountManager->findByNumericId($node->getStorageId());
442
+            // If the share is originating from an external storage
443
+            if (count($mount) > 0 && $mount[0] instanceof ExternalMountPoint) {
444
+                // Propagate original storage scan
445
+                return parent::getWatcher($path, $storage);
446
+            }
447
+        }
448
+
449
+        // cache updating is handled by the share source
450
+        return new NullWatcher();
451
+    }
452
+
453
+    /**
454
+     * unshare complete storage, also the grouped shares
455
+     *
456
+     * @return bool
457
+     */
458
+    public function unshareStorage(): bool {
459
+        foreach ($this->groupedShares as $share) {
460
+            \OC::$server->getShareManager()->deleteFromSelf($share, $this->user);
461
+        }
462
+        return true;
463
+    }
464
+
465
+    /**
466
+     * @param string $path
467
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
468
+     * @param \OCP\Lock\ILockingProvider $provider
469
+     * @throws \OCP\Lock\LockedException
470
+     */
471
+    public function acquireLock($path, $type, ILockingProvider $provider) {
472
+        /** @var \OCP\Files\Storage $targetStorage */
473
+        [$targetStorage, $targetInternalPath] = $this->resolvePath($path);
474
+        $targetStorage->acquireLock($targetInternalPath, $type, $provider);
475
+        // lock the parent folders of the owner when locking the share as recipient
476
+        if ($path === '') {
477
+            $sourcePath = $this->ownerUserFolder->getRelativePath($this->sourcePath);
478
+            $this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
479
+        }
480
+    }
481
+
482
+    /**
483
+     * @param string $path
484
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
485
+     * @param \OCP\Lock\ILockingProvider $provider
486
+     */
487
+    public function releaseLock($path, $type, ILockingProvider $provider) {
488
+        /** @var \OCP\Files\Storage $targetStorage */
489
+        [$targetStorage, $targetInternalPath] = $this->resolvePath($path);
490
+        $targetStorage->releaseLock($targetInternalPath, $type, $provider);
491
+        // unlock the parent folders of the owner when unlocking the share as recipient
492
+        if ($path === '') {
493
+            $sourcePath = $this->ownerUserFolder->getRelativePath($this->sourcePath);
494
+            $this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
495
+        }
496
+    }
497
+
498
+    /**
499
+     * @param string $path
500
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
501
+     * @param \OCP\Lock\ILockingProvider $provider
502
+     */
503
+    public function changeLock($path, $type, ILockingProvider $provider) {
504
+        /** @var \OCP\Files\Storage $targetStorage */
505
+        [$targetStorage, $targetInternalPath] = $this->resolvePath($path);
506
+        $targetStorage->changeLock($targetInternalPath, $type, $provider);
507
+    }
508
+
509
+    /**
510
+     * @return array [ available, last_checked ]
511
+     */
512
+    public function getAvailability() {
513
+        // shares do not participate in availability logic
514
+        return [
515
+            'available' => true,
516
+            'last_checked' => 0,
517
+        ];
518
+    }
519
+
520
+    /**
521
+     * @param bool $available
522
+     */
523
+    public function setAvailability($available) {
524
+        // shares do not participate in availability logic
525
+    }
526
+
527
+    public function getSourceStorage() {
528
+        $this->init();
529
+        return $this->nonMaskedStorage;
530
+    }
531
+
532
+    public function getWrapperStorage() {
533
+        $this->init();
534
+        return $this->storage;
535
+    }
536
+
537
+    public function file_get_contents($path) {
538
+        $info = [
539
+            'target' => $this->getMountPoint() . '/' . $path,
540
+            'source' => $this->getUnjailedPath($path),
541
+        ];
542
+        \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
543
+        return parent::file_get_contents($path);
544
+    }
545
+
546
+    public function file_put_contents($path, $data) {
547
+        $info = [
548
+            'target' => $this->getMountPoint() . '/' . $path,
549
+            'source' => $this->getUnjailedPath($path),
550
+        ];
551
+        \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
552
+        return parent::file_put_contents($path, $data);
553
+    }
554
+
555
+    public function setMountOptions(array $options) {
556
+        $this->mountOptions = $options;
557
+    }
558
+
559
+    public function getUnjailedPath($path) {
560
+        $this->init();
561
+        return parent::getUnjailedPath($path);
562
+    }
563 563
 }
Please login to merge, or discard this patch.