Completed
Push — stable13 ( 9c0a9a...065ec7 )
by Morris
19:50 queued 05:17
created
apps/files_sharing/lib/SharedStorage.php 1 patch
Indentation   +446 added lines, -446 removed lines patch added patch discarded remove patch
@@ -48,450 +48,450 @@
 block discarded – undo
48 48
  */
49 49
 class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedStorage {
50 50
 
51
-	/** @var \OCP\Share\IShare */
52
-	private $superShare;
53
-
54
-	/** @var \OCP\Share\IShare[] */
55
-	private $groupedShares;
56
-
57
-	/**
58
-	 * @var \OC\Files\View
59
-	 */
60
-	private $ownerView;
61
-
62
-	private $initialized = false;
63
-
64
-	/**
65
-	 * @var ICacheEntry
66
-	 */
67
-	private $sourceRootInfo;
68
-
69
-	/** @var string */
70
-	private $user;
71
-
72
-	/**
73
-	 * @var \OCP\ILogger
74
-	 */
75
-	private $logger;
76
-
77
-	/** @var  IStorage */
78
-	private $nonMaskedStorage;
79
-
80
-	private $options;
81
-
82
-	/** @var boolean */
83
-	private $sharingDisabledForUser;
84
-
85
-	public function __construct($arguments) {
86
-		$this->ownerView = $arguments['ownerView'];
87
-		$this->logger = \OC::$server->getLogger();
88
-
89
-		$this->superShare = $arguments['superShare'];
90
-		$this->groupedShares = $arguments['groupedShares'];
91
-
92
-		$this->user = $arguments['user'];
93
-		if (isset($arguments['sharingDisabledForUser'])) {
94
-			$this->sharingDisabledForUser = $arguments['sharingDisabledForUser'];
95
-		} else {
96
-			$this->sharingDisabledForUser = false;
97
-		}
98
-
99
-		parent::__construct([
100
-			'storage' => null,
101
-			'root' => null,
102
-		]);
103
-	}
104
-
105
-	/**
106
-	 * @return ICacheEntry
107
-	 */
108
-	private function getSourceRootInfo() {
109
-		if (is_null($this->sourceRootInfo)) {
110
-			if (is_null($this->superShare->getNodeCacheEntry())) {
111
-				$this->init();
112
-				$this->sourceRootInfo = $this->nonMaskedStorage->getCache()->get($this->rootPath);
113
-			} else {
114
-				$this->sourceRootInfo = $this->superShare->getNodeCacheEntry();
115
-			}
116
-		}
117
-		return $this->sourceRootInfo;
118
-	}
119
-
120
-	private function init() {
121
-		if ($this->initialized) {
122
-			return;
123
-		}
124
-		$this->initialized = true;
125
-		try {
126
-			Filesystem::initMountPoints($this->superShare->getShareOwner());
127
-			$sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
128
-			list($this->nonMaskedStorage, $this->rootPath) = $this->ownerView->resolvePath($sourcePath);
129
-			$this->storage = new PermissionsMask([
130
-				'storage' => $this->nonMaskedStorage,
131
-				'mask' => $this->superShare->getPermissions()
132
-			]);
133
-		} catch (NotFoundException $e) {
134
-			// original file not accessible or deleted, set FailedStorage
135
-			$this->storage = new FailedStorage(['exception' => $e]);
136
-			$this->cache = new FailedCache();
137
-			$this->rootPath = '';
138
-		} catch (NoUserException $e) {
139
-			// sharer user deleted, set FailedStorage
140
-			$this->storage = new FailedStorage(['exception' => $e]);
141
-			$this->cache = new FailedCache();
142
-			$this->rootPath = '';
143
-		} catch (\Exception $e) {
144
-			$this->storage = new FailedStorage(['exception' => $e]);
145
-			$this->cache = new FailedCache();
146
-			$this->rootPath = '';
147
-			$this->logger->logException($e);
148
-		}
149
-
150
-		if (!$this->nonMaskedStorage) {
151
-			$this->nonMaskedStorage = $this->storage;
152
-		}
153
-	}
154
-
155
-	/**
156
-	 * @inheritdoc
157
-	 */
158
-	public function instanceOfStorage($class) {
159
-		if ($class === '\OC\Files\Storage\Common') {
160
-			return true;
161
-		}
162
-		if (in_array($class, ['\OC\Files\Storage\Home', '\OC\Files\ObjectStore\HomeObjectStoreStorage'])) {
163
-			return false;
164
-		}
165
-		return parent::instanceOfStorage($class);
166
-	}
167
-
168
-	/**
169
-	 * @return string
170
-	 */
171
-	public function getShareId() {
172
-		return $this->superShare->getId();
173
-	}
174
-
175
-	private function isValid() {
176
-		return $this->getSourceRootInfo() && ($this->getSourceRootInfo()->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
177
-	}
178
-
179
-	/**
180
-	 * get id of the mount point
181
-	 *
182
-	 * @return string
183
-	 */
184
-	public function getId() {
185
-		return 'shared::' . $this->getMountPoint();
186
-	}
187
-
188
-	/**
189
-	 * Get the permissions granted for a shared file
190
-	 *
191
-	 * @param string $target Shared target file path
192
-	 * @return int CRUDS permissions granted
193
-	 */
194
-	public function getPermissions($target = '') {
195
-		if (!$this->isValid()) {
196
-			return 0;
197
-		}
198
-		$permissions = $this->superShare->getPermissions();
199
-		// part files and the mount point always have delete permissions
200
-		if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
201
-			$permissions |= \OCP\Constants::PERMISSION_DELETE;
202
-		}
203
-
204
-		if ($this->sharingDisabledForUser) {
205
-			$permissions &= ~\OCP\Constants::PERMISSION_SHARE;
206
-		}
207
-
208
-		return $permissions;
209
-	}
210
-
211
-	public function isCreatable($path) {
212
-		return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_CREATE);
213
-	}
214
-
215
-	public function isReadable($path) {
216
-		if (!$this->isValid()) {
217
-			return false;
218
-		}
219
-		if (!$this->file_exists($path)) {
220
-			return false;
221
-		}
222
-		/** @var IStorage $storage */
223
-		/** @var string $internalPath */
224
-		list($storage, $internalPath) = $this->resolvePath($path);
225
-		return $storage->isReadable($internalPath);
226
-	}
227
-
228
-	public function isUpdatable($path) {
229
-		return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_UPDATE);
230
-	}
231
-
232
-	public function isDeletable($path) {
233
-		return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_DELETE);
234
-	}
235
-
236
-	public function isSharable($path) {
237
-		if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
238
-			return false;
239
-		}
240
-		return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
241
-	}
242
-
243
-	public function fopen($path, $mode) {
244
-		if ($source = $this->getUnjailedPath($path)) {
245
-			switch ($mode) {
246
-				case 'r+':
247
-				case 'rb+':
248
-				case 'w+':
249
-				case 'wb+':
250
-				case 'x+':
251
-				case 'xb+':
252
-				case 'a+':
253
-				case 'ab+':
254
-				case 'w':
255
-				case 'wb':
256
-				case 'x':
257
-				case 'xb':
258
-				case 'a':
259
-				case 'ab':
260
-					$creatable = $this->isCreatable($path);
261
-					$updatable = $this->isUpdatable($path);
262
-					// if neither permissions given, no need to continue
263
-					if (!$creatable && !$updatable) {
264
-						return false;
265
-					}
266
-
267
-					$exists = $this->file_exists($path);
268
-					// if a file exists, updatable permissions are required
269
-					if ($exists && !$updatable) {
270
-						return false;
271
-					}
272
-
273
-					// part file is allowed if !$creatable but the final file is $updatable
274
-					if (pathinfo($path, PATHINFO_EXTENSION) !== 'part') {
275
-						if (!$exists && !$creatable) {
276
-							return false;
277
-						}
278
-					}
279
-			}
280
-			$info = array(
281
-				'target' => $this->getMountPoint() . $path,
282
-				'source' => $source,
283
-				'mode' => $mode,
284
-			);
285
-			\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info);
286
-			return $this->nonMaskedStorage->fopen($this->getUnjailedPath($path), $mode);
287
-		}
288
-		return false;
289
-	}
290
-
291
-	/**
292
-	 * see http://php.net/manual/en/function.rename.php
293
-	 *
294
-	 * @param string $path1
295
-	 * @param string $path2
296
-	 * @return bool
297
-	 */
298
-	public function rename($path1, $path2) {
299
-		$this->init();
300
-		$isPartFile = pathinfo($path1, PATHINFO_EXTENSION) === 'part';
301
-		$targetExists = $this->file_exists($path2);
302
-		$sameFodler = dirname($path1) === dirname($path2);
303
-
304
-		if ($targetExists || ($sameFodler && !$isPartFile)) {
305
-			if (!$this->isUpdatable('')) {
306
-				return false;
307
-			}
308
-		} else {
309
-			if (!$this->isCreatable('')) {
310
-				return false;
311
-			}
312
-		}
313
-
314
-		return $this->nonMaskedStorage->rename($this->getUnjailedPath($path1), $this->getUnjailedPath($path2));
315
-	}
316
-
317
-	/**
318
-	 * return mount point of share, relative to data/user/files
319
-	 *
320
-	 * @return string
321
-	 */
322
-	public function getMountPoint() {
323
-		return $this->superShare->getTarget();
324
-	}
325
-
326
-	/**
327
-	 * @param string $path
328
-	 */
329
-	public function setMountPoint($path) {
330
-		$this->superShare->setTarget($path);
331
-
332
-		foreach ($this->groupedShares as $share) {
333
-			$share->setTarget($path);
334
-		}
335
-	}
336
-
337
-	/**
338
-	 * get the user who shared the file
339
-	 *
340
-	 * @return string
341
-	 */
342
-	public function getSharedFrom() {
343
-		return $this->superShare->getShareOwner();
344
-	}
345
-
346
-	/**
347
-	 * @return \OCP\Share\IShare
348
-	 */
349
-	public function getShare() {
350
-		return $this->superShare;
351
-	}
352
-
353
-	/**
354
-	 * return share type, can be "file" or "folder"
355
-	 *
356
-	 * @return string
357
-	 */
358
-	public function getItemType() {
359
-		return $this->superShare->getNodeType();
360
-	}
361
-
362
-	/**
363
-	 * @param string $path
364
-	 * @param null $storage
365
-	 * @return Cache
366
-	 */
367
-	public function getCache($path = '', $storage = null) {
368
-		if ($this->cache) {
369
-			return $this->cache;
370
-		}
371
-		if (!$storage) {
372
-			$storage = $this;
373
-		}
374
-		if ($this->storage instanceof FailedStorage) {
375
-			return new FailedCache();
376
-		}
377
-		$this->cache = new \OCA\Files_Sharing\Cache($storage, $this->getSourceRootInfo(), $this->superShare);
378
-		return $this->cache;
379
-	}
380
-
381
-	public function getScanner($path = '', $storage = null) {
382
-		if (!$storage) {
383
-			$storage = $this;
384
-		}
385
-		return new \OCA\Files_Sharing\Scanner($storage);
386
-	}
387
-
388
-	public function getOwner($path) {
389
-		return $this->superShare->getShareOwner();
390
-	}
391
-
392
-	/**
393
-	 * unshare complete storage, also the grouped shares
394
-	 *
395
-	 * @return bool
396
-	 */
397
-	public function unshareStorage() {
398
-		foreach ($this->groupedShares as $share) {
399
-			\OC::$server->getShareManager()->deleteFromSelf($share, $this->user);
400
-		}
401
-		return true;
402
-	}
403
-
404
-	/**
405
-	 * @param string $path
406
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
407
-	 * @param \OCP\Lock\ILockingProvider $provider
408
-	 * @throws \OCP\Lock\LockedException
409
-	 */
410
-	public function acquireLock($path, $type, ILockingProvider $provider) {
411
-		/** @var \OCP\Files\Storage $targetStorage */
412
-		list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
413
-		$targetStorage->acquireLock($targetInternalPath, $type, $provider);
414
-		// lock the parent folders of the owner when locking the share as recipient
415
-		if ($path === '') {
416
-			$sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
417
-			$this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
418
-		}
419
-	}
420
-
421
-	/**
422
-	 * @param string $path
423
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
424
-	 * @param \OCP\Lock\ILockingProvider $provider
425
-	 */
426
-	public function releaseLock($path, $type, ILockingProvider $provider) {
427
-		/** @var \OCP\Files\Storage $targetStorage */
428
-		list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
429
-		$targetStorage->releaseLock($targetInternalPath, $type, $provider);
430
-		// unlock the parent folders of the owner when unlocking the share as recipient
431
-		if ($path === '') {
432
-			$sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
433
-			$this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
434
-		}
435
-	}
436
-
437
-	/**
438
-	 * @param string $path
439
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
440
-	 * @param \OCP\Lock\ILockingProvider $provider
441
-	 */
442
-	public function changeLock($path, $type, ILockingProvider $provider) {
443
-		/** @var \OCP\Files\Storage $targetStorage */
444
-		list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
445
-		$targetStorage->changeLock($targetInternalPath, $type, $provider);
446
-	}
447
-
448
-	/**
449
-	 * @return array [ available, last_checked ]
450
-	 */
451
-	public function getAvailability() {
452
-		// shares do not participate in availability logic
453
-		return [
454
-			'available' => true,
455
-			'last_checked' => 0
456
-		];
457
-	}
458
-
459
-	/**
460
-	 * @param bool $available
461
-	 */
462
-	public function setAvailability($available) {
463
-		// shares do not participate in availability logic
464
-	}
465
-
466
-	public function getSourceStorage() {
467
-		$this->init();
468
-		return $this->nonMaskedStorage;
469
-	}
470
-
471
-	public function getWrapperStorage() {
472
-		$this->init();
473
-		return $this->storage;
474
-	}
475
-
476
-	public function file_get_contents($path) {
477
-		$info = [
478
-			'target' => $this->getMountPoint() . '/' . $path,
479
-			'source' => $this->getUnjailedPath($path),
480
-		];
481
-		\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
482
-		return parent::file_get_contents($path);
483
-	}
484
-
485
-	public function file_put_contents($path, $data) {
486
-		$info = [
487
-			'target' => $this->getMountPoint() . '/' . $path,
488
-			'source' => $this->getUnjailedPath($path),
489
-		];
490
-		\OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
491
-		return parent::file_put_contents($path, $data);
492
-	}
493
-
494
-	public function setMountOptions(array $options) {
495
-		$this->mountOptions = $options;
496
-	}
51
+    /** @var \OCP\Share\IShare */
52
+    private $superShare;
53
+
54
+    /** @var \OCP\Share\IShare[] */
55
+    private $groupedShares;
56
+
57
+    /**
58
+     * @var \OC\Files\View
59
+     */
60
+    private $ownerView;
61
+
62
+    private $initialized = false;
63
+
64
+    /**
65
+     * @var ICacheEntry
66
+     */
67
+    private $sourceRootInfo;
68
+
69
+    /** @var string */
70
+    private $user;
71
+
72
+    /**
73
+     * @var \OCP\ILogger
74
+     */
75
+    private $logger;
76
+
77
+    /** @var  IStorage */
78
+    private $nonMaskedStorage;
79
+
80
+    private $options;
81
+
82
+    /** @var boolean */
83
+    private $sharingDisabledForUser;
84
+
85
+    public function __construct($arguments) {
86
+        $this->ownerView = $arguments['ownerView'];
87
+        $this->logger = \OC::$server->getLogger();
88
+
89
+        $this->superShare = $arguments['superShare'];
90
+        $this->groupedShares = $arguments['groupedShares'];
91
+
92
+        $this->user = $arguments['user'];
93
+        if (isset($arguments['sharingDisabledForUser'])) {
94
+            $this->sharingDisabledForUser = $arguments['sharingDisabledForUser'];
95
+        } else {
96
+            $this->sharingDisabledForUser = false;
97
+        }
98
+
99
+        parent::__construct([
100
+            'storage' => null,
101
+            'root' => null,
102
+        ]);
103
+    }
104
+
105
+    /**
106
+     * @return ICacheEntry
107
+     */
108
+    private function getSourceRootInfo() {
109
+        if (is_null($this->sourceRootInfo)) {
110
+            if (is_null($this->superShare->getNodeCacheEntry())) {
111
+                $this->init();
112
+                $this->sourceRootInfo = $this->nonMaskedStorage->getCache()->get($this->rootPath);
113
+            } else {
114
+                $this->sourceRootInfo = $this->superShare->getNodeCacheEntry();
115
+            }
116
+        }
117
+        return $this->sourceRootInfo;
118
+    }
119
+
120
+    private function init() {
121
+        if ($this->initialized) {
122
+            return;
123
+        }
124
+        $this->initialized = true;
125
+        try {
126
+            Filesystem::initMountPoints($this->superShare->getShareOwner());
127
+            $sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
128
+            list($this->nonMaskedStorage, $this->rootPath) = $this->ownerView->resolvePath($sourcePath);
129
+            $this->storage = new PermissionsMask([
130
+                'storage' => $this->nonMaskedStorage,
131
+                'mask' => $this->superShare->getPermissions()
132
+            ]);
133
+        } catch (NotFoundException $e) {
134
+            // original file not accessible or deleted, set FailedStorage
135
+            $this->storage = new FailedStorage(['exception' => $e]);
136
+            $this->cache = new FailedCache();
137
+            $this->rootPath = '';
138
+        } catch (NoUserException $e) {
139
+            // sharer user deleted, set FailedStorage
140
+            $this->storage = new FailedStorage(['exception' => $e]);
141
+            $this->cache = new FailedCache();
142
+            $this->rootPath = '';
143
+        } catch (\Exception $e) {
144
+            $this->storage = new FailedStorage(['exception' => $e]);
145
+            $this->cache = new FailedCache();
146
+            $this->rootPath = '';
147
+            $this->logger->logException($e);
148
+        }
149
+
150
+        if (!$this->nonMaskedStorage) {
151
+            $this->nonMaskedStorage = $this->storage;
152
+        }
153
+    }
154
+
155
+    /**
156
+     * @inheritdoc
157
+     */
158
+    public function instanceOfStorage($class) {
159
+        if ($class === '\OC\Files\Storage\Common') {
160
+            return true;
161
+        }
162
+        if (in_array($class, ['\OC\Files\Storage\Home', '\OC\Files\ObjectStore\HomeObjectStoreStorage'])) {
163
+            return false;
164
+        }
165
+        return parent::instanceOfStorage($class);
166
+    }
167
+
168
+    /**
169
+     * @return string
170
+     */
171
+    public function getShareId() {
172
+        return $this->superShare->getId();
173
+    }
174
+
175
+    private function isValid() {
176
+        return $this->getSourceRootInfo() && ($this->getSourceRootInfo()->getPermissions() & Constants::PERMISSION_SHARE) === Constants::PERMISSION_SHARE;
177
+    }
178
+
179
+    /**
180
+     * get id of the mount point
181
+     *
182
+     * @return string
183
+     */
184
+    public function getId() {
185
+        return 'shared::' . $this->getMountPoint();
186
+    }
187
+
188
+    /**
189
+     * Get the permissions granted for a shared file
190
+     *
191
+     * @param string $target Shared target file path
192
+     * @return int CRUDS permissions granted
193
+     */
194
+    public function getPermissions($target = '') {
195
+        if (!$this->isValid()) {
196
+            return 0;
197
+        }
198
+        $permissions = $this->superShare->getPermissions();
199
+        // part files and the mount point always have delete permissions
200
+        if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
201
+            $permissions |= \OCP\Constants::PERMISSION_DELETE;
202
+        }
203
+
204
+        if ($this->sharingDisabledForUser) {
205
+            $permissions &= ~\OCP\Constants::PERMISSION_SHARE;
206
+        }
207
+
208
+        return $permissions;
209
+    }
210
+
211
+    public function isCreatable($path) {
212
+        return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_CREATE);
213
+    }
214
+
215
+    public function isReadable($path) {
216
+        if (!$this->isValid()) {
217
+            return false;
218
+        }
219
+        if (!$this->file_exists($path)) {
220
+            return false;
221
+        }
222
+        /** @var IStorage $storage */
223
+        /** @var string $internalPath */
224
+        list($storage, $internalPath) = $this->resolvePath($path);
225
+        return $storage->isReadable($internalPath);
226
+    }
227
+
228
+    public function isUpdatable($path) {
229
+        return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_UPDATE);
230
+    }
231
+
232
+    public function isDeletable($path) {
233
+        return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_DELETE);
234
+    }
235
+
236
+    public function isSharable($path) {
237
+        if (\OCP\Util::isSharingDisabledForUser() || !\OC\Share\Share::isResharingAllowed()) {
238
+            return false;
239
+        }
240
+        return ($this->getPermissions($path) & \OCP\Constants::PERMISSION_SHARE);
241
+    }
242
+
243
+    public function fopen($path, $mode) {
244
+        if ($source = $this->getUnjailedPath($path)) {
245
+            switch ($mode) {
246
+                case 'r+':
247
+                case 'rb+':
248
+                case 'w+':
249
+                case 'wb+':
250
+                case 'x+':
251
+                case 'xb+':
252
+                case 'a+':
253
+                case 'ab+':
254
+                case 'w':
255
+                case 'wb':
256
+                case 'x':
257
+                case 'xb':
258
+                case 'a':
259
+                case 'ab':
260
+                    $creatable = $this->isCreatable($path);
261
+                    $updatable = $this->isUpdatable($path);
262
+                    // if neither permissions given, no need to continue
263
+                    if (!$creatable && !$updatable) {
264
+                        return false;
265
+                    }
266
+
267
+                    $exists = $this->file_exists($path);
268
+                    // if a file exists, updatable permissions are required
269
+                    if ($exists && !$updatable) {
270
+                        return false;
271
+                    }
272
+
273
+                    // part file is allowed if !$creatable but the final file is $updatable
274
+                    if (pathinfo($path, PATHINFO_EXTENSION) !== 'part') {
275
+                        if (!$exists && !$creatable) {
276
+                            return false;
277
+                        }
278
+                    }
279
+            }
280
+            $info = array(
281
+                'target' => $this->getMountPoint() . $path,
282
+                'source' => $source,
283
+                'mode' => $mode,
284
+            );
285
+            \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'fopen', $info);
286
+            return $this->nonMaskedStorage->fopen($this->getUnjailedPath($path), $mode);
287
+        }
288
+        return false;
289
+    }
290
+
291
+    /**
292
+     * see http://php.net/manual/en/function.rename.php
293
+     *
294
+     * @param string $path1
295
+     * @param string $path2
296
+     * @return bool
297
+     */
298
+    public function rename($path1, $path2) {
299
+        $this->init();
300
+        $isPartFile = pathinfo($path1, PATHINFO_EXTENSION) === 'part';
301
+        $targetExists = $this->file_exists($path2);
302
+        $sameFodler = dirname($path1) === dirname($path2);
303
+
304
+        if ($targetExists || ($sameFodler && !$isPartFile)) {
305
+            if (!$this->isUpdatable('')) {
306
+                return false;
307
+            }
308
+        } else {
309
+            if (!$this->isCreatable('')) {
310
+                return false;
311
+            }
312
+        }
313
+
314
+        return $this->nonMaskedStorage->rename($this->getUnjailedPath($path1), $this->getUnjailedPath($path2));
315
+    }
316
+
317
+    /**
318
+     * return mount point of share, relative to data/user/files
319
+     *
320
+     * @return string
321
+     */
322
+    public function getMountPoint() {
323
+        return $this->superShare->getTarget();
324
+    }
325
+
326
+    /**
327
+     * @param string $path
328
+     */
329
+    public function setMountPoint($path) {
330
+        $this->superShare->setTarget($path);
331
+
332
+        foreach ($this->groupedShares as $share) {
333
+            $share->setTarget($path);
334
+        }
335
+    }
336
+
337
+    /**
338
+     * get the user who shared the file
339
+     *
340
+     * @return string
341
+     */
342
+    public function getSharedFrom() {
343
+        return $this->superShare->getShareOwner();
344
+    }
345
+
346
+    /**
347
+     * @return \OCP\Share\IShare
348
+     */
349
+    public function getShare() {
350
+        return $this->superShare;
351
+    }
352
+
353
+    /**
354
+     * return share type, can be "file" or "folder"
355
+     *
356
+     * @return string
357
+     */
358
+    public function getItemType() {
359
+        return $this->superShare->getNodeType();
360
+    }
361
+
362
+    /**
363
+     * @param string $path
364
+     * @param null $storage
365
+     * @return Cache
366
+     */
367
+    public function getCache($path = '', $storage = null) {
368
+        if ($this->cache) {
369
+            return $this->cache;
370
+        }
371
+        if (!$storage) {
372
+            $storage = $this;
373
+        }
374
+        if ($this->storage instanceof FailedStorage) {
375
+            return new FailedCache();
376
+        }
377
+        $this->cache = new \OCA\Files_Sharing\Cache($storage, $this->getSourceRootInfo(), $this->superShare);
378
+        return $this->cache;
379
+    }
380
+
381
+    public function getScanner($path = '', $storage = null) {
382
+        if (!$storage) {
383
+            $storage = $this;
384
+        }
385
+        return new \OCA\Files_Sharing\Scanner($storage);
386
+    }
387
+
388
+    public function getOwner($path) {
389
+        return $this->superShare->getShareOwner();
390
+    }
391
+
392
+    /**
393
+     * unshare complete storage, also the grouped shares
394
+     *
395
+     * @return bool
396
+     */
397
+    public function unshareStorage() {
398
+        foreach ($this->groupedShares as $share) {
399
+            \OC::$server->getShareManager()->deleteFromSelf($share, $this->user);
400
+        }
401
+        return true;
402
+    }
403
+
404
+    /**
405
+     * @param string $path
406
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
407
+     * @param \OCP\Lock\ILockingProvider $provider
408
+     * @throws \OCP\Lock\LockedException
409
+     */
410
+    public function acquireLock($path, $type, ILockingProvider $provider) {
411
+        /** @var \OCP\Files\Storage $targetStorage */
412
+        list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
413
+        $targetStorage->acquireLock($targetInternalPath, $type, $provider);
414
+        // lock the parent folders of the owner when locking the share as recipient
415
+        if ($path === '') {
416
+            $sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
417
+            $this->ownerView->lockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
418
+        }
419
+    }
420
+
421
+    /**
422
+     * @param string $path
423
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
424
+     * @param \OCP\Lock\ILockingProvider $provider
425
+     */
426
+    public function releaseLock($path, $type, ILockingProvider $provider) {
427
+        /** @var \OCP\Files\Storage $targetStorage */
428
+        list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
429
+        $targetStorage->releaseLock($targetInternalPath, $type, $provider);
430
+        // unlock the parent folders of the owner when unlocking the share as recipient
431
+        if ($path === '') {
432
+            $sourcePath = $this->ownerView->getPath($this->superShare->getNodeId());
433
+            $this->ownerView->unlockFile(dirname($sourcePath), ILockingProvider::LOCK_SHARED, true);
434
+        }
435
+    }
436
+
437
+    /**
438
+     * @param string $path
439
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
440
+     * @param \OCP\Lock\ILockingProvider $provider
441
+     */
442
+    public function changeLock($path, $type, ILockingProvider $provider) {
443
+        /** @var \OCP\Files\Storage $targetStorage */
444
+        list($targetStorage, $targetInternalPath) = $this->resolvePath($path);
445
+        $targetStorage->changeLock($targetInternalPath, $type, $provider);
446
+    }
447
+
448
+    /**
449
+     * @return array [ available, last_checked ]
450
+     */
451
+    public function getAvailability() {
452
+        // shares do not participate in availability logic
453
+        return [
454
+            'available' => true,
455
+            'last_checked' => 0
456
+        ];
457
+    }
458
+
459
+    /**
460
+     * @param bool $available
461
+     */
462
+    public function setAvailability($available) {
463
+        // shares do not participate in availability logic
464
+    }
465
+
466
+    public function getSourceStorage() {
467
+        $this->init();
468
+        return $this->nonMaskedStorage;
469
+    }
470
+
471
+    public function getWrapperStorage() {
472
+        $this->init();
473
+        return $this->storage;
474
+    }
475
+
476
+    public function file_get_contents($path) {
477
+        $info = [
478
+            'target' => $this->getMountPoint() . '/' . $path,
479
+            'source' => $this->getUnjailedPath($path),
480
+        ];
481
+        \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_get_contents', $info);
482
+        return parent::file_get_contents($path);
483
+    }
484
+
485
+    public function file_put_contents($path, $data) {
486
+        $info = [
487
+            'target' => $this->getMountPoint() . '/' . $path,
488
+            'source' => $this->getUnjailedPath($path),
489
+        ];
490
+        \OCP\Util::emitHook('\OC\Files\Storage\Shared', 'file_put_contents', $info);
491
+        return parent::file_put_contents($path, $data);
492
+    }
493
+
494
+    public function setMountOptions(array $options) {
495
+        $this->mountOptions = $options;
496
+    }
497 497
 }
Please login to merge, or discard this patch.
lib/private/Files/Mount/Manager.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -95,7 +95,7 @@
 block discarded – undo
95 95
 
96 96
 		$current = $path;
97 97
 		while (true) {
98
-			$mountPoint = $current . '/';
98
+			$mountPoint = $current.'/';
99 99
 			if (isset($this->mounts[$mountPoint])) {
100 100
 				$this->pathCache[$path] = $this->mounts[$mountPoint];
101 101
 				return $this->mounts[$mountPoint];
Please login to merge, or discard this patch.
Indentation   +145 added lines, -145 removed lines patch added patch discarded remove patch
@@ -31,149 +31,149 @@
 block discarded – undo
31 31
 use OCP\Files\Mount\IMountPoint;
32 32
 
33 33
 class Manager implements IMountManager {
34
-	/** @var MountPoint[] */
35
-	private $mounts = [];
36
-
37
-	/** @var CappedMemoryCache */
38
-	private $inPathCache;
39
-
40
-	public function __construct() {
41
-		$this->inPathCache = new CappedMemoryCache();
42
-	}
43
-
44
-	/**
45
-	 * @param IMountPoint $mount
46
-	 */
47
-	public function addMount(IMountPoint $mount) {
48
-		$this->mounts[$mount->getMountPoint()] = $mount;
49
-		$this->inPathCache->clear();
50
-	}
51
-
52
-	/**
53
-	 * @param string $mountPoint
54
-	 */
55
-	public function removeMount($mountPoint) {
56
-		$mountPoint = Filesystem::normalizePath($mountPoint);
57
-		if (strlen($mountPoint) > 1) {
58
-			$mountPoint .= '/';
59
-		}
60
-		unset($this->mounts[$mountPoint]);
61
-		$this->inPathCache->clear();
62
-	}
63
-
64
-	/**
65
-	 * @param string $mountPoint
66
-	 * @param string $target
67
-	 */
68
-	public function moveMount($mountPoint, $target) {
69
-		$this->mounts[$target] = $this->mounts[$mountPoint];
70
-		unset($this->mounts[$mountPoint]);
71
-		$this->inPathCache->clear();
72
-	}
73
-
74
-	/**
75
-	 * Find the mount for $path
76
-	 *
77
-	 * @param string $path
78
-	 * @return MountPoint
79
-	 */
80
-	public function find($path) {
81
-		\OC_Util::setupFS();
82
-		$path = Filesystem::normalizePath($path);
83
-
84
-		$current = $path;
85
-		while (true) {
86
-			$mountPoint = $current . '/';
87
-			if (isset($this->mounts[$mountPoint])) {
88
-				$this->pathCache[$path] = $this->mounts[$mountPoint];
89
-				return $this->mounts[$mountPoint];
90
-			}
91
-
92
-			if ($current === '') {
93
-				return null;
94
-			}
95
-
96
-			$current = dirname($current);
97
-			if ($current === '.' || $current === '/') {
98
-				$current = '';
99
-			}
100
-		}
101
-	}
102
-
103
-	/**
104
-	 * Find all mounts in $path
105
-	 *
106
-	 * @param string $path
107
-	 * @return MountPoint[]
108
-	 */
109
-	public function findIn($path) {
110
-		\OC_Util::setupFS();
111
-		$path = $this->formatPath($path);
112
-		$result = array();
113
-		$pathLength = strlen($path);
114
-		$mountPoints = array_keys($this->mounts);
115
-		foreach ($mountPoints as $mountPoint) {
116
-			if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) {
117
-				$result[] = $this->mounts[$mountPoint];
118
-			}
119
-		}
120
-
121
-		$this->inPathCache[$path] = $result;
122
-		return $result;
123
-	}
124
-
125
-	public function clear() {
126
-		$this->mounts = [];
127
-		$this->inPathCache->clear();
128
-	}
129
-
130
-	/**
131
-	 * Find mounts by storage id
132
-	 *
133
-	 * @param string $id
134
-	 * @return MountPoint[]
135
-	 */
136
-	public function findByStorageId($id) {
137
-		\OC_Util::setupFS();
138
-		if (strlen($id) > 64) {
139
-			$id = md5($id);
140
-		}
141
-		$result = array();
142
-		foreach ($this->mounts as $mount) {
143
-			if ($mount->getStorageId() === $id) {
144
-				$result[] = $mount;
145
-			}
146
-		}
147
-		return $result;
148
-	}
149
-
150
-	/**
151
-	 * @return MountPoint[]
152
-	 */
153
-	public function getAll() {
154
-		return $this->mounts;
155
-	}
156
-
157
-	/**
158
-	 * Find mounts by numeric storage id
159
-	 *
160
-	 * @param int $id
161
-	 * @return MountPoint[]
162
-	 */
163
-	public function findByNumericId($id) {
164
-		$storageId = \OC\Files\Cache\Storage::getStorageId($id);
165
-		return $this->findByStorageId($storageId);
166
-	}
167
-
168
-	/**
169
-	 * @param string $path
170
-	 * @return string
171
-	 */
172
-	private function formatPath($path) {
173
-		$path = Filesystem::normalizePath($path);
174
-		if (strlen($path) > 1) {
175
-			$path .= '/';
176
-		}
177
-		return $path;
178
-	}
34
+    /** @var MountPoint[] */
35
+    private $mounts = [];
36
+
37
+    /** @var CappedMemoryCache */
38
+    private $inPathCache;
39
+
40
+    public function __construct() {
41
+        $this->inPathCache = new CappedMemoryCache();
42
+    }
43
+
44
+    /**
45
+     * @param IMountPoint $mount
46
+     */
47
+    public function addMount(IMountPoint $mount) {
48
+        $this->mounts[$mount->getMountPoint()] = $mount;
49
+        $this->inPathCache->clear();
50
+    }
51
+
52
+    /**
53
+     * @param string $mountPoint
54
+     */
55
+    public function removeMount($mountPoint) {
56
+        $mountPoint = Filesystem::normalizePath($mountPoint);
57
+        if (strlen($mountPoint) > 1) {
58
+            $mountPoint .= '/';
59
+        }
60
+        unset($this->mounts[$mountPoint]);
61
+        $this->inPathCache->clear();
62
+    }
63
+
64
+    /**
65
+     * @param string $mountPoint
66
+     * @param string $target
67
+     */
68
+    public function moveMount($mountPoint, $target) {
69
+        $this->mounts[$target] = $this->mounts[$mountPoint];
70
+        unset($this->mounts[$mountPoint]);
71
+        $this->inPathCache->clear();
72
+    }
73
+
74
+    /**
75
+     * Find the mount for $path
76
+     *
77
+     * @param string $path
78
+     * @return MountPoint
79
+     */
80
+    public function find($path) {
81
+        \OC_Util::setupFS();
82
+        $path = Filesystem::normalizePath($path);
83
+
84
+        $current = $path;
85
+        while (true) {
86
+            $mountPoint = $current . '/';
87
+            if (isset($this->mounts[$mountPoint])) {
88
+                $this->pathCache[$path] = $this->mounts[$mountPoint];
89
+                return $this->mounts[$mountPoint];
90
+            }
91
+
92
+            if ($current === '') {
93
+                return null;
94
+            }
95
+
96
+            $current = dirname($current);
97
+            if ($current === '.' || $current === '/') {
98
+                $current = '';
99
+            }
100
+        }
101
+    }
102
+
103
+    /**
104
+     * Find all mounts in $path
105
+     *
106
+     * @param string $path
107
+     * @return MountPoint[]
108
+     */
109
+    public function findIn($path) {
110
+        \OC_Util::setupFS();
111
+        $path = $this->formatPath($path);
112
+        $result = array();
113
+        $pathLength = strlen($path);
114
+        $mountPoints = array_keys($this->mounts);
115
+        foreach ($mountPoints as $mountPoint) {
116
+            if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) {
117
+                $result[] = $this->mounts[$mountPoint];
118
+            }
119
+        }
120
+
121
+        $this->inPathCache[$path] = $result;
122
+        return $result;
123
+    }
124
+
125
+    public function clear() {
126
+        $this->mounts = [];
127
+        $this->inPathCache->clear();
128
+    }
129
+
130
+    /**
131
+     * Find mounts by storage id
132
+     *
133
+     * @param string $id
134
+     * @return MountPoint[]
135
+     */
136
+    public function findByStorageId($id) {
137
+        \OC_Util::setupFS();
138
+        if (strlen($id) > 64) {
139
+            $id = md5($id);
140
+        }
141
+        $result = array();
142
+        foreach ($this->mounts as $mount) {
143
+            if ($mount->getStorageId() === $id) {
144
+                $result[] = $mount;
145
+            }
146
+        }
147
+        return $result;
148
+    }
149
+
150
+    /**
151
+     * @return MountPoint[]
152
+     */
153
+    public function getAll() {
154
+        return $this->mounts;
155
+    }
156
+
157
+    /**
158
+     * Find mounts by numeric storage id
159
+     *
160
+     * @param int $id
161
+     * @return MountPoint[]
162
+     */
163
+    public function findByNumericId($id) {
164
+        $storageId = \OC\Files\Cache\Storage::getStorageId($id);
165
+        return $this->findByStorageId($storageId);
166
+    }
167
+
168
+    /**
169
+     * @param string $path
170
+     * @return string
171
+     */
172
+    private function formatPath($path) {
173
+        $path = Filesystem::normalizePath($path);
174
+        if (strlen($path) > 1) {
175
+            $path .= '/';
176
+        }
177
+        return $path;
178
+    }
179 179
 }
Please login to merge, or discard this patch.
lib/private/Files/Config/UserMountCache.php 2 patches
Indentation   +363 added lines, -363 removed lines patch added patch discarded remove patch
@@ -43,367 +43,367 @@
 block discarded – undo
43 43
  * Cache mounts points per user in the cache so we can easilly look them up
44 44
  */
45 45
 class UserMountCache implements IUserMountCache {
46
-	/**
47
-	 * @var IDBConnection
48
-	 */
49
-	private $connection;
50
-
51
-	/**
52
-	 * @var IUserManager
53
-	 */
54
-	private $userManager;
55
-
56
-	/**
57
-	 * Cached mount info.
58
-	 * Map of $userId to ICachedMountInfo.
59
-	 *
60
-	 * @var ICache
61
-	 **/
62
-	private $mountsForUsers;
63
-
64
-	/**
65
-	 * @var ILogger
66
-	 */
67
-	private $logger;
68
-
69
-	/**
70
-	 * @var ICache
71
-	 */
72
-	private $cacheInfoCache;
73
-
74
-	/**
75
-	 * UserMountCache constructor.
76
-	 *
77
-	 * @param IDBConnection $connection
78
-	 * @param IUserManager $userManager
79
-	 * @param ILogger $logger
80
-	 */
81
-	public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
82
-		$this->connection = $connection;
83
-		$this->userManager = $userManager;
84
-		$this->logger = $logger;
85
-		$this->cacheInfoCache = new CappedMemoryCache();
86
-		$this->mountsForUsers = new CappedMemoryCache();
87
-	}
88
-
89
-	public function registerMounts(IUser $user, array $mounts) {
90
-		// filter out non-proper storages coming from unit tests
91
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
92
-			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93
-		});
94
-		/** @var ICachedMountInfo[] $newMounts */
95
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
96
-			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97
-			if ($mount->getStorageRootId() === -1) {
98
-				return null;
99
-			} else {
100
-				return new LazyStorageMountInfo($user, $mount);
101
-			}
102
-		}, $mounts);
103
-		$newMounts = array_values(array_filter($newMounts));
104
-		$newMountRootIds = array_map(function (ICachedMountInfo $mount) {
105
-			return $mount->getRootId();
106
-		}, $newMounts);
107
-		$newMounts = array_combine($newMountRootIds, $newMounts);
108
-
109
-		$cachedMounts = $this->getMountsForUser($user);
110
-		$cachedMountRootIds = array_map(function (ICachedMountInfo $mount) {
111
-			return $mount->getRootId();
112
-		}, $cachedMounts);
113
-		$cachedMounts = array_combine($cachedMountRootIds, $cachedMounts);
114
-
115
-		$addedMounts = [];
116
-		$removedMounts = [];
117
-
118
-		foreach ($newMounts as $rootId => $newMount) {
119
-			if (!isset($cachedMounts[$rootId])) {
120
-				$addedMounts[] = $newMount;
121
-			}
122
-		}
123
-
124
-		foreach ($cachedMounts as $rootId => $cachedMount) {
125
-			if (!isset($newMounts[$rootId])) {
126
-				$removedMounts[] = $cachedMount;
127
-			}
128
-		}
129
-
130
-		$changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
131
-
132
-		foreach ($addedMounts as $mount) {
133
-			$this->addToCache($mount);
134
-			$this->mountsForUsers[$user->getUID()][] = $mount;
135
-		}
136
-		foreach ($removedMounts as $mount) {
137
-			$this->removeFromCache($mount);
138
-			$index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
139
-			unset($this->mountsForUsers[$user->getUID()][$index]);
140
-		}
141
-		foreach ($changedMounts as $mount) {
142
-			$this->updateCachedMount($mount);
143
-		}
144
-	}
145
-
146
-	/**
147
-	 * @param ICachedMountInfo[] $newMounts
148
-	 * @param ICachedMountInfo[] $cachedMounts
149
-	 * @return ICachedMountInfo[]
150
-	 */
151
-	private function findChangedMounts(array $newMounts, array $cachedMounts) {
152
-		$new = [];
153
-		foreach ($newMounts as $mount) {
154
-			$new[$mount->getRootId()] = $mount;
155
-		}
156
-		$changed = [];
157
-		foreach ($cachedMounts as $cachedMount) {
158
-			$rootId = $cachedMount->getRootId();
159
-			if (isset($new[$rootId])) {
160
-				$newMount = $new[$rootId];
161
-				if (
162
-					$newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
163
-					$newMount->getStorageId() !== $cachedMount->getStorageId() ||
164
-					$newMount->getMountId() !== $cachedMount->getMountId()
165
-				) {
166
-					$changed[] = $newMount;
167
-				}
168
-			}
169
-		}
170
-		return $changed;
171
-	}
172
-
173
-	private function addToCache(ICachedMountInfo $mount) {
174
-		if ($mount->getStorageId() !== -1) {
175
-			$this->connection->insertIfNotExist('*PREFIX*mounts', [
176
-				'storage_id' => $mount->getStorageId(),
177
-				'root_id' => $mount->getRootId(),
178
-				'user_id' => $mount->getUser()->getUID(),
179
-				'mount_point' => $mount->getMountPoint(),
180
-				'mount_id' => $mount->getMountId()
181
-			], ['root_id', 'user_id']);
182
-		} else {
183
-			// in some cases this is legitimate, like orphaned shares
184
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
185
-		}
186
-	}
187
-
188
-	private function updateCachedMount(ICachedMountInfo $mount) {
189
-		$builder = $this->connection->getQueryBuilder();
190
-
191
-		$query = $builder->update('mounts')
192
-			->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
193
-			->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
194
-			->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
195
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
196
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
197
-
198
-		$query->execute();
199
-	}
200
-
201
-	private function removeFromCache(ICachedMountInfo $mount) {
202
-		$builder = $this->connection->getQueryBuilder();
203
-
204
-		$query = $builder->delete('mounts')
205
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
206
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
207
-		$query->execute();
208
-	}
209
-
210
-	private function dbRowToMountInfo(array $row) {
211
-		$user = $this->userManager->get($row['user_id']);
212
-		if (is_null($user)) {
213
-			return null;
214
-		}
215
-		$mount_id = $row['mount_id'];
216
-		if (!is_null($mount_id)) {
217
-			$mount_id = (int)$mount_id;
218
-		}
219
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
220
-	}
221
-
222
-	/**
223
-	 * @param IUser $user
224
-	 * @return ICachedMountInfo[]
225
-	 */
226
-	public function getMountsForUser(IUser $user) {
227
-		if (!isset($this->mountsForUsers[$user->getUID()])) {
228
-			$builder = $this->connection->getQueryBuilder();
229
-			$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
230
-				->from('mounts', 'm')
231
-				->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
232
-				->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
233
-
234
-			$rows = $query->execute()->fetchAll();
235
-
236
-			$this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
237
-		}
238
-		return $this->mountsForUsers[$user->getUID()];
239
-	}
240
-
241
-	/**
242
-	 * @param int $numericStorageId
243
-	 * @param string|null $user limit the results to a single user
244
-	 * @return CachedMountInfo[]
245
-	 */
246
-	public function getMountsForStorageId($numericStorageId, $user = null) {
247
-		$builder = $this->connection->getQueryBuilder();
248
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
249
-			->from('mounts', 'm')
250
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
251
-			->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
252
-
253
-		if ($user) {
254
-			$query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
255
-		}
256
-
257
-		$rows = $query->execute()->fetchAll();
258
-
259
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
260
-	}
261
-
262
-	/**
263
-	 * @param int $rootFileId
264
-	 * @return CachedMountInfo[]
265
-	 */
266
-	public function getMountsForRootId($rootFileId) {
267
-		$builder = $this->connection->getQueryBuilder();
268
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
269
-			->from('mounts', 'm')
270
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
271
-			->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
272
-
273
-		$rows = $query->execute()->fetchAll();
274
-
275
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
276
-	}
277
-
278
-	/**
279
-	 * @param $fileId
280
-	 * @return array
281
-	 * @throws \OCP\Files\NotFoundException
282
-	 */
283
-	private function getCacheInfoFromFileId($fileId) {
284
-		if (!isset($this->cacheInfoCache[$fileId])) {
285
-			$builder = $this->connection->getQueryBuilder();
286
-			$query = $builder->select('storage', 'path', 'mimetype')
287
-				->from('filecache')
288
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
289
-
290
-			$row = $query->execute()->fetch();
291
-			if (is_array($row)) {
292
-				$this->cacheInfoCache[$fileId] = [
293
-					(int)$row['storage'],
294
-					$row['path'],
295
-					(int)$row['mimetype']
296
-				];
297
-			} else {
298
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
299
-			}
300
-		}
301
-		return $this->cacheInfoCache[$fileId];
302
-	}
303
-
304
-	/**
305
-	 * @param int $fileId
306
-	 * @param string|null $user optionally restrict the results to a single user
307
-	 * @return ICachedMountFileInfo[]
308
-	 * @since 9.0.0
309
-	 */
310
-	public function getMountsForFileId($fileId, $user = null) {
311
-		try {
312
-			list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
313
-		} catch (NotFoundException $e) {
314
-			return [];
315
-		}
316
-		$mountsForStorage = $this->getMountsForStorageId($storageId, $user);
317
-
318
-		// filter mounts that are from the same storage but a different directory
319
-		$filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
320
-			if ($fileId === $mount->getRootId()) {
321
-				return true;
322
-			}
323
-			$internalMountPath = $mount->getRootInternalPath();
324
-
325
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
326
-		});
327
-
328
-		return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
329
-			return new CachedMountFileInfo(
330
-				$mount->getUser(),
331
-				$mount->getStorageId(),
332
-				$mount->getRootId(),
333
-				$mount->getMountPoint(),
334
-				$mount->getMountId(),
335
-				$mount->getRootInternalPath(),
336
-				$internalPath
337
-			);
338
-		}, $filteredMounts);
339
-	}
340
-
341
-	/**
342
-	 * Remove all cached mounts for a user
343
-	 *
344
-	 * @param IUser $user
345
-	 */
346
-	public function removeUserMounts(IUser $user) {
347
-		$builder = $this->connection->getQueryBuilder();
348
-
349
-		$query = $builder->delete('mounts')
350
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
351
-		$query->execute();
352
-	}
353
-
354
-	public function removeUserStorageMount($storageId, $userId) {
355
-		$builder = $this->connection->getQueryBuilder();
356
-
357
-		$query = $builder->delete('mounts')
358
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
359
-			->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
360
-		$query->execute();
361
-	}
362
-
363
-	public function remoteStorageMounts($storageId) {
364
-		$builder = $this->connection->getQueryBuilder();
365
-
366
-		$query = $builder->delete('mounts')
367
-			->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
368
-		$query->execute();
369
-	}
370
-
371
-	/**
372
-	 * @param array $users
373
-	 * @return array
374
-	 * @suppress SqlInjectionChecker
375
-	 */
376
-	public function getUsedSpaceForUsers(array $users) {
377
-		$builder = $this->connection->getQueryBuilder();
378
-
379
-		$slash = $builder->createNamedParameter('/');
380
-
381
-		$mountPoint = $builder->func()->concat(
382
-			$builder->func()->concat($slash, 'user_id'),
383
-			$slash
384
-		);
385
-
386
-		$userIds = array_map(function (IUser $user) {
387
-			return $user->getUID();
388
-		}, $users);
389
-
390
-		$query = $builder->select('m.user_id', 'f.size')
391
-			->from('mounts', 'm')
392
-			->innerJoin('m', 'filecache', 'f',
393
-				$builder->expr()->andX(
394
-					$builder->expr()->eq('m.storage_id', 'f.storage'),
395
-					$builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
396
-				))
397
-			->where($builder->expr()->eq('m.mount_point', $mountPoint))
398
-			->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
399
-
400
-		$result = $query->execute();
401
-
402
-		$results = [];
403
-		while ($row = $result->fetch()) {
404
-			$results[$row['user_id']] = $row['size'];
405
-		}
406
-		$result->closeCursor();
407
-		return $results;
408
-	}
46
+    /**
47
+     * @var IDBConnection
48
+     */
49
+    private $connection;
50
+
51
+    /**
52
+     * @var IUserManager
53
+     */
54
+    private $userManager;
55
+
56
+    /**
57
+     * Cached mount info.
58
+     * Map of $userId to ICachedMountInfo.
59
+     *
60
+     * @var ICache
61
+     **/
62
+    private $mountsForUsers;
63
+
64
+    /**
65
+     * @var ILogger
66
+     */
67
+    private $logger;
68
+
69
+    /**
70
+     * @var ICache
71
+     */
72
+    private $cacheInfoCache;
73
+
74
+    /**
75
+     * UserMountCache constructor.
76
+     *
77
+     * @param IDBConnection $connection
78
+     * @param IUserManager $userManager
79
+     * @param ILogger $logger
80
+     */
81
+    public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
82
+        $this->connection = $connection;
83
+        $this->userManager = $userManager;
84
+        $this->logger = $logger;
85
+        $this->cacheInfoCache = new CappedMemoryCache();
86
+        $this->mountsForUsers = new CappedMemoryCache();
87
+    }
88
+
89
+    public function registerMounts(IUser $user, array $mounts) {
90
+        // filter out non-proper storages coming from unit tests
91
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
92
+            return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93
+        });
94
+        /** @var ICachedMountInfo[] $newMounts */
95
+        $newMounts = array_map(function (IMountPoint $mount) use ($user) {
96
+            // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97
+            if ($mount->getStorageRootId() === -1) {
98
+                return null;
99
+            } else {
100
+                return new LazyStorageMountInfo($user, $mount);
101
+            }
102
+        }, $mounts);
103
+        $newMounts = array_values(array_filter($newMounts));
104
+        $newMountRootIds = array_map(function (ICachedMountInfo $mount) {
105
+            return $mount->getRootId();
106
+        }, $newMounts);
107
+        $newMounts = array_combine($newMountRootIds, $newMounts);
108
+
109
+        $cachedMounts = $this->getMountsForUser($user);
110
+        $cachedMountRootIds = array_map(function (ICachedMountInfo $mount) {
111
+            return $mount->getRootId();
112
+        }, $cachedMounts);
113
+        $cachedMounts = array_combine($cachedMountRootIds, $cachedMounts);
114
+
115
+        $addedMounts = [];
116
+        $removedMounts = [];
117
+
118
+        foreach ($newMounts as $rootId => $newMount) {
119
+            if (!isset($cachedMounts[$rootId])) {
120
+                $addedMounts[] = $newMount;
121
+            }
122
+        }
123
+
124
+        foreach ($cachedMounts as $rootId => $cachedMount) {
125
+            if (!isset($newMounts[$rootId])) {
126
+                $removedMounts[] = $cachedMount;
127
+            }
128
+        }
129
+
130
+        $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
131
+
132
+        foreach ($addedMounts as $mount) {
133
+            $this->addToCache($mount);
134
+            $this->mountsForUsers[$user->getUID()][] = $mount;
135
+        }
136
+        foreach ($removedMounts as $mount) {
137
+            $this->removeFromCache($mount);
138
+            $index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
139
+            unset($this->mountsForUsers[$user->getUID()][$index]);
140
+        }
141
+        foreach ($changedMounts as $mount) {
142
+            $this->updateCachedMount($mount);
143
+        }
144
+    }
145
+
146
+    /**
147
+     * @param ICachedMountInfo[] $newMounts
148
+     * @param ICachedMountInfo[] $cachedMounts
149
+     * @return ICachedMountInfo[]
150
+     */
151
+    private function findChangedMounts(array $newMounts, array $cachedMounts) {
152
+        $new = [];
153
+        foreach ($newMounts as $mount) {
154
+            $new[$mount->getRootId()] = $mount;
155
+        }
156
+        $changed = [];
157
+        foreach ($cachedMounts as $cachedMount) {
158
+            $rootId = $cachedMount->getRootId();
159
+            if (isset($new[$rootId])) {
160
+                $newMount = $new[$rootId];
161
+                if (
162
+                    $newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
163
+                    $newMount->getStorageId() !== $cachedMount->getStorageId() ||
164
+                    $newMount->getMountId() !== $cachedMount->getMountId()
165
+                ) {
166
+                    $changed[] = $newMount;
167
+                }
168
+            }
169
+        }
170
+        return $changed;
171
+    }
172
+
173
+    private function addToCache(ICachedMountInfo $mount) {
174
+        if ($mount->getStorageId() !== -1) {
175
+            $this->connection->insertIfNotExist('*PREFIX*mounts', [
176
+                'storage_id' => $mount->getStorageId(),
177
+                'root_id' => $mount->getRootId(),
178
+                'user_id' => $mount->getUser()->getUID(),
179
+                'mount_point' => $mount->getMountPoint(),
180
+                'mount_id' => $mount->getMountId()
181
+            ], ['root_id', 'user_id']);
182
+        } else {
183
+            // in some cases this is legitimate, like orphaned shares
184
+            $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
185
+        }
186
+    }
187
+
188
+    private function updateCachedMount(ICachedMountInfo $mount) {
189
+        $builder = $this->connection->getQueryBuilder();
190
+
191
+        $query = $builder->update('mounts')
192
+            ->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
193
+            ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
194
+            ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
195
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
196
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
197
+
198
+        $query->execute();
199
+    }
200
+
201
+    private function removeFromCache(ICachedMountInfo $mount) {
202
+        $builder = $this->connection->getQueryBuilder();
203
+
204
+        $query = $builder->delete('mounts')
205
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
206
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
207
+        $query->execute();
208
+    }
209
+
210
+    private function dbRowToMountInfo(array $row) {
211
+        $user = $this->userManager->get($row['user_id']);
212
+        if (is_null($user)) {
213
+            return null;
214
+        }
215
+        $mount_id = $row['mount_id'];
216
+        if (!is_null($mount_id)) {
217
+            $mount_id = (int)$mount_id;
218
+        }
219
+        return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
220
+    }
221
+
222
+    /**
223
+     * @param IUser $user
224
+     * @return ICachedMountInfo[]
225
+     */
226
+    public function getMountsForUser(IUser $user) {
227
+        if (!isset($this->mountsForUsers[$user->getUID()])) {
228
+            $builder = $this->connection->getQueryBuilder();
229
+            $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
230
+                ->from('mounts', 'm')
231
+                ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
232
+                ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
233
+
234
+            $rows = $query->execute()->fetchAll();
235
+
236
+            $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
237
+        }
238
+        return $this->mountsForUsers[$user->getUID()];
239
+    }
240
+
241
+    /**
242
+     * @param int $numericStorageId
243
+     * @param string|null $user limit the results to a single user
244
+     * @return CachedMountInfo[]
245
+     */
246
+    public function getMountsForStorageId($numericStorageId, $user = null) {
247
+        $builder = $this->connection->getQueryBuilder();
248
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
249
+            ->from('mounts', 'm')
250
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
251
+            ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
252
+
253
+        if ($user) {
254
+            $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
255
+        }
256
+
257
+        $rows = $query->execute()->fetchAll();
258
+
259
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
260
+    }
261
+
262
+    /**
263
+     * @param int $rootFileId
264
+     * @return CachedMountInfo[]
265
+     */
266
+    public function getMountsForRootId($rootFileId) {
267
+        $builder = $this->connection->getQueryBuilder();
268
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
269
+            ->from('mounts', 'm')
270
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
271
+            ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
272
+
273
+        $rows = $query->execute()->fetchAll();
274
+
275
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
276
+    }
277
+
278
+    /**
279
+     * @param $fileId
280
+     * @return array
281
+     * @throws \OCP\Files\NotFoundException
282
+     */
283
+    private function getCacheInfoFromFileId($fileId) {
284
+        if (!isset($this->cacheInfoCache[$fileId])) {
285
+            $builder = $this->connection->getQueryBuilder();
286
+            $query = $builder->select('storage', 'path', 'mimetype')
287
+                ->from('filecache')
288
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
289
+
290
+            $row = $query->execute()->fetch();
291
+            if (is_array($row)) {
292
+                $this->cacheInfoCache[$fileId] = [
293
+                    (int)$row['storage'],
294
+                    $row['path'],
295
+                    (int)$row['mimetype']
296
+                ];
297
+            } else {
298
+                throw new NotFoundException('File with id "' . $fileId . '" not found');
299
+            }
300
+        }
301
+        return $this->cacheInfoCache[$fileId];
302
+    }
303
+
304
+    /**
305
+     * @param int $fileId
306
+     * @param string|null $user optionally restrict the results to a single user
307
+     * @return ICachedMountFileInfo[]
308
+     * @since 9.0.0
309
+     */
310
+    public function getMountsForFileId($fileId, $user = null) {
311
+        try {
312
+            list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
313
+        } catch (NotFoundException $e) {
314
+            return [];
315
+        }
316
+        $mountsForStorage = $this->getMountsForStorageId($storageId, $user);
317
+
318
+        // filter mounts that are from the same storage but a different directory
319
+        $filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
320
+            if ($fileId === $mount->getRootId()) {
321
+                return true;
322
+            }
323
+            $internalMountPath = $mount->getRootInternalPath();
324
+
325
+            return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
326
+        });
327
+
328
+        return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
329
+            return new CachedMountFileInfo(
330
+                $mount->getUser(),
331
+                $mount->getStorageId(),
332
+                $mount->getRootId(),
333
+                $mount->getMountPoint(),
334
+                $mount->getMountId(),
335
+                $mount->getRootInternalPath(),
336
+                $internalPath
337
+            );
338
+        }, $filteredMounts);
339
+    }
340
+
341
+    /**
342
+     * Remove all cached mounts for a user
343
+     *
344
+     * @param IUser $user
345
+     */
346
+    public function removeUserMounts(IUser $user) {
347
+        $builder = $this->connection->getQueryBuilder();
348
+
349
+        $query = $builder->delete('mounts')
350
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
351
+        $query->execute();
352
+    }
353
+
354
+    public function removeUserStorageMount($storageId, $userId) {
355
+        $builder = $this->connection->getQueryBuilder();
356
+
357
+        $query = $builder->delete('mounts')
358
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
359
+            ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
360
+        $query->execute();
361
+    }
362
+
363
+    public function remoteStorageMounts($storageId) {
364
+        $builder = $this->connection->getQueryBuilder();
365
+
366
+        $query = $builder->delete('mounts')
367
+            ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
368
+        $query->execute();
369
+    }
370
+
371
+    /**
372
+     * @param array $users
373
+     * @return array
374
+     * @suppress SqlInjectionChecker
375
+     */
376
+    public function getUsedSpaceForUsers(array $users) {
377
+        $builder = $this->connection->getQueryBuilder();
378
+
379
+        $slash = $builder->createNamedParameter('/');
380
+
381
+        $mountPoint = $builder->func()->concat(
382
+            $builder->func()->concat($slash, 'user_id'),
383
+            $slash
384
+        );
385
+
386
+        $userIds = array_map(function (IUser $user) {
387
+            return $user->getUID();
388
+        }, $users);
389
+
390
+        $query = $builder->select('m.user_id', 'f.size')
391
+            ->from('mounts', 'm')
392
+            ->innerJoin('m', 'filecache', 'f',
393
+                $builder->expr()->andX(
394
+                    $builder->expr()->eq('m.storage_id', 'f.storage'),
395
+                    $builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
396
+                ))
397
+            ->where($builder->expr()->eq('m.mount_point', $mountPoint))
398
+            ->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
399
+
400
+        $result = $query->execute();
401
+
402
+        $results = [];
403
+        while ($row = $result->fetch()) {
404
+            $results[$row['user_id']] = $row['size'];
405
+        }
406
+        $result->closeCursor();
407
+        return $results;
408
+    }
409 409
 }
Please login to merge, or discard this patch.
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -88,11 +88,11 @@  discard block
 block discarded – undo
88 88
 
89 89
 	public function registerMounts(IUser $user, array $mounts) {
90 90
 		// filter out non-proper storages coming from unit tests
91
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
91
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
92 92
 			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93 93
 		});
94 94
 		/** @var ICachedMountInfo[] $newMounts */
95
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
95
+		$newMounts = array_map(function(IMountPoint $mount) use ($user) {
96 96
 			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97 97
 			if ($mount->getStorageRootId() === -1) {
98 98
 				return null;
@@ -101,13 +101,13 @@  discard block
 block discarded – undo
101 101
 			}
102 102
 		}, $mounts);
103 103
 		$newMounts = array_values(array_filter($newMounts));
104
-		$newMountRootIds = array_map(function (ICachedMountInfo $mount) {
104
+		$newMountRootIds = array_map(function(ICachedMountInfo $mount) {
105 105
 			return $mount->getRootId();
106 106
 		}, $newMounts);
107 107
 		$newMounts = array_combine($newMountRootIds, $newMounts);
108 108
 
109 109
 		$cachedMounts = $this->getMountsForUser($user);
110
-		$cachedMountRootIds = array_map(function (ICachedMountInfo $mount) {
110
+		$cachedMountRootIds = array_map(function(ICachedMountInfo $mount) {
111 111
 			return $mount->getRootId();
112 112
 		}, $cachedMounts);
113 113
 		$cachedMounts = array_combine($cachedMountRootIds, $cachedMounts);
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
 			], ['root_id', 'user_id']);
182 182
 		} else {
183 183
 			// in some cases this is legitimate, like orphaned shares
184
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
184
+			$this->logger->debug('Could not get storage info for mount at '.$mount->getMountPoint());
185 185
 		}
186 186
 	}
187 187
 
@@ -214,9 +214,9 @@  discard block
 block discarded – undo
214 214
 		}
215 215
 		$mount_id = $row['mount_id'];
216 216
 		if (!is_null($mount_id)) {
217
-			$mount_id = (int)$mount_id;
217
+			$mount_id = (int) $mount_id;
218 218
 		}
219
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
219
+		return new CachedMountInfo($user, (int) $row['storage_id'], (int) $row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
220 220
 	}
221 221
 
222 222
 	/**
@@ -290,12 +290,12 @@  discard block
 block discarded – undo
290 290
 			$row = $query->execute()->fetch();
291 291
 			if (is_array($row)) {
292 292
 				$this->cacheInfoCache[$fileId] = [
293
-					(int)$row['storage'],
293
+					(int) $row['storage'],
294 294
 					$row['path'],
295
-					(int)$row['mimetype']
295
+					(int) $row['mimetype']
296 296
 				];
297 297
 			} else {
298
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
298
+				throw new NotFoundException('File with id "'.$fileId.'" not found');
299 299
 			}
300 300
 		}
301 301
 		return $this->cacheInfoCache[$fileId];
@@ -316,16 +316,16 @@  discard block
 block discarded – undo
316 316
 		$mountsForStorage = $this->getMountsForStorageId($storageId, $user);
317 317
 
318 318
 		// filter mounts that are from the same storage but a different directory
319
-		$filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
319
+		$filteredMounts = array_filter($mountsForStorage, function(ICachedMountInfo $mount) use ($internalPath, $fileId) {
320 320
 			if ($fileId === $mount->getRootId()) {
321 321
 				return true;
322 322
 			}
323 323
 			$internalMountPath = $mount->getRootInternalPath();
324 324
 
325
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
325
+			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath.'/';
326 326
 		});
327 327
 
328
-		return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
328
+		return array_map(function(ICachedMountInfo $mount) use ($internalPath) {
329 329
 			return new CachedMountFileInfo(
330 330
 				$mount->getUser(),
331 331
 				$mount->getStorageId(),
@@ -383,7 +383,7 @@  discard block
 block discarded – undo
383 383
 			$slash
384 384
 		);
385 385
 
386
-		$userIds = array_map(function (IUser $user) {
386
+		$userIds = array_map(function(IUser $user) {
387 387
 			return $user->getUID();
388 388
 		}, $users);
389 389
 
Please login to merge, or discard this patch.
apps/files_sharing/lib/SharedMount.php 2 patches
Indentation   +224 added lines, -224 removed lines patch added patch discarded remove patch
@@ -38,228 +38,228 @@
 block discarded – undo
38 38
  * Shared mount points can be moved by the user
39 39
  */
40 40
 class SharedMount extends MountPoint implements MoveableMount {
41
-	/**
42
-	 * @var \OCA\Files_Sharing\SharedStorage $storage
43
-	 */
44
-	protected $storage = null;
45
-
46
-	/**
47
-	 * @var \OC\Files\View
48
-	 */
49
-	private $recipientView;
50
-
51
-	/**
52
-	 * @var string
53
-	 */
54
-	private $user;
55
-
56
-	/** @var \OCP\Share\IShare */
57
-	private $superShare;
58
-
59
-	/** @var \OCP\Share\IShare[] */
60
-	private $groupedShares;
61
-
62
-	/**
63
-	 * @param string $storage
64
-	 * @param SharedMount[] $mountpoints
65
-	 * @param array $arguments
66
-	 * @param IStorageFactory $loader
67
-	 * @param View $recipientView
68
-	 */
69
-	public function __construct($storage, array $mountpoints, $arguments, IStorageFactory $loader, View $recipientView, CappedMemoryCache $folderExistCache) {
70
-		$this->user = $arguments['user'];
71
-		$this->recipientView = $recipientView;
72
-
73
-		$this->superShare = $arguments['superShare'];
74
-		$this->groupedShares = $arguments['groupedShares'];
75
-
76
-		$newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints, $folderExistCache);
77
-		$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
78
-		parent::__construct($storage, $absMountPoint, $arguments, $loader);
79
-	}
80
-
81
-	/**
82
-	 * check if the parent folder exists otherwise move the mount point up
83
-	 *
84
-	 * @param \OCP\Share\IShare $share
85
-	 * @param SharedMount[] $mountpoints
86
-	 * @return string
87
-	 */
88
-	private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints, CappedMemoryCache $folderExistCache) {
89
-
90
-		$mountPoint = basename($share->getTarget());
91
-		$parent = dirname($share->getTarget());
92
-
93
-		if ($folderExistCache->hasKey($parent)) {
94
-			$parentExists = $folderExistCache->get($parent);
95
-		} else {
96
-			$parentExists = $this->recipientView->is_dir($parent);
97
-			$folderExistCache->set($parent, $parentExists);
98
-		}
99
-		if (!$parentExists) {
100
-			$parent = Helper::getShareFolder($this->recipientView);
101
-		}
102
-
103
-		$newMountPoint = $this->generateUniqueTarget(
104
-			\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
105
-			$this->recipientView,
106
-			$mountpoints
107
-		);
108
-
109
-		if ($newMountPoint !== $share->getTarget()) {
110
-			$this->updateFileTarget($newMountPoint, $share);
111
-		}
112
-
113
-		return $newMountPoint;
114
-	}
115
-
116
-	/**
117
-	 * update fileTarget in the database if the mount point changed
118
-	 *
119
-	 * @param string $newPath
120
-	 * @param \OCP\Share\IShare $share
121
-	 * @return bool
122
-	 */
123
-	private function updateFileTarget($newPath, &$share) {
124
-		$share->setTarget($newPath);
125
-
126
-		foreach ($this->groupedShares as $tmpShare) {
127
-			$tmpShare->setTarget($newPath);
128
-			\OC::$server->getShareManager()->moveShare($tmpShare, $this->user);
129
-		}
130
-	}
131
-
132
-
133
-	/**
134
-	 * @param string $path
135
-	 * @param View $view
136
-	 * @param SharedMount[] $mountpoints
137
-	 * @return mixed
138
-	 */
139
-	private function generateUniqueTarget($path, $view, array $mountpoints) {
140
-		$pathinfo = pathinfo($path);
141
-		$ext = (isset($pathinfo['extension'])) ? '.' . $pathinfo['extension'] : '';
142
-		$name = $pathinfo['filename'];
143
-		$dir = $pathinfo['dirname'];
144
-
145
-		$i = 2;
146
-		$absolutePath = $this->recipientView->getAbsolutePath($path) . '/';
147
-		while ($view->file_exists($path) || isset($mountpoints[$absolutePath])) {
148
-			$path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
149
-			$absolutePath = $this->recipientView->getAbsolutePath($path) . '/';
150
-			$i++;
151
-		}
152
-
153
-		return $path;
154
-	}
155
-
156
-	/**
157
-	 * Format a path to be relative to the /user/files/ directory
158
-	 *
159
-	 * @param string $path the absolute path
160
-	 * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
161
-	 * @throws \OCA\Files_Sharing\Exceptions\BrokenPath
162
-	 */
163
-	protected function stripUserFilesPath($path) {
164
-		$trimmed = ltrim($path, '/');
165
-		$split = explode('/', $trimmed);
166
-
167
-		// it is not a file relative to data/user/files
168
-		if (count($split) < 3 || $split[1] !== 'files') {
169
-			\OCP\Util::writeLog('file sharing',
170
-				'Can not strip userid and "files/" from path: ' . $path,
171
-				\OCP\Util::ERROR);
172
-			throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
173
-		}
174
-
175
-		// skip 'user' and 'files'
176
-		$sliced = array_slice($split, 2);
177
-		$relPath = implode('/', $sliced);
178
-
179
-		return '/' . $relPath;
180
-	}
181
-
182
-	/**
183
-	 * Move the mount point to $target
184
-	 *
185
-	 * @param string $target the target mount point
186
-	 * @return bool
187
-	 */
188
-	public function moveMount($target) {
189
-
190
-		$relTargetPath = $this->stripUserFilesPath($target);
191
-		$share = $this->storage->getShare();
192
-
193
-		$result = true;
194
-
195
-		try {
196
-			$this->updateFileTarget($relTargetPath, $share);
197
-			$this->setMountPoint($target);
198
-			$this->storage->setMountPoint($relTargetPath);
199
-		} catch (\Exception $e) {
200
-			\OCP\Util::writeLog('file sharing',
201
-				'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
202
-				\OCP\Util::ERROR);
203
-		}
204
-
205
-		return $result;
206
-	}
207
-
208
-	/**
209
-	 * Remove the mount points
210
-	 *
211
-	 * @return bool
212
-	 */
213
-	public function removeMount() {
214
-		$mountManager = \OC\Files\Filesystem::getMountManager();
215
-		/** @var $storage \OCA\Files_Sharing\SharedStorage */
216
-		$storage = $this->getStorage();
217
-		$result = $storage->unshareStorage();
218
-		$mountManager->removeMount($this->mountPoint);
219
-
220
-		return $result;
221
-	}
222
-
223
-	/**
224
-	 * @return \OCP\Share\IShare
225
-	 */
226
-	public function getShare() {
227
-		return $this->superShare;
228
-	}
229
-
230
-	/**
231
-	 * Get the file id of the root of the storage
232
-	 *
233
-	 * @return int
234
-	 */
235
-	public function getStorageRootId() {
236
-		return $this->getShare()->getNodeId();
237
-	}
238
-
239
-	/**
240
-	 * @return int
241
-	 */
242
-	public function getNumericStorageId() {
243
-		if (!is_null($this->getShare()->getNodeCacheEntry())) {
244
-			return $this->getShare()->getNodeCacheEntry()->getStorageId();
245
-		} else {
246
-			$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
247
-
248
-			$query = $builder->select('storage')
249
-				->from('filecache')
250
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($this->getStorageRootId())));
251
-
252
-			$result = $query->execute();
253
-			$row = $result->fetch();
254
-			$result->closeCursor();
255
-			if ($row) {
256
-				return (int)$row['storage'];
257
-			}
258
-			return -1;
259
-		}
260
-	}
261
-
262
-	public function getMountType() {
263
-		return 'shared';
264
-	}
41
+    /**
42
+     * @var \OCA\Files_Sharing\SharedStorage $storage
43
+     */
44
+    protected $storage = null;
45
+
46
+    /**
47
+     * @var \OC\Files\View
48
+     */
49
+    private $recipientView;
50
+
51
+    /**
52
+     * @var string
53
+     */
54
+    private $user;
55
+
56
+    /** @var \OCP\Share\IShare */
57
+    private $superShare;
58
+
59
+    /** @var \OCP\Share\IShare[] */
60
+    private $groupedShares;
61
+
62
+    /**
63
+     * @param string $storage
64
+     * @param SharedMount[] $mountpoints
65
+     * @param array $arguments
66
+     * @param IStorageFactory $loader
67
+     * @param View $recipientView
68
+     */
69
+    public function __construct($storage, array $mountpoints, $arguments, IStorageFactory $loader, View $recipientView, CappedMemoryCache $folderExistCache) {
70
+        $this->user = $arguments['user'];
71
+        $this->recipientView = $recipientView;
72
+
73
+        $this->superShare = $arguments['superShare'];
74
+        $this->groupedShares = $arguments['groupedShares'];
75
+
76
+        $newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints, $folderExistCache);
77
+        $absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
78
+        parent::__construct($storage, $absMountPoint, $arguments, $loader);
79
+    }
80
+
81
+    /**
82
+     * check if the parent folder exists otherwise move the mount point up
83
+     *
84
+     * @param \OCP\Share\IShare $share
85
+     * @param SharedMount[] $mountpoints
86
+     * @return string
87
+     */
88
+    private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints, CappedMemoryCache $folderExistCache) {
89
+
90
+        $mountPoint = basename($share->getTarget());
91
+        $parent = dirname($share->getTarget());
92
+
93
+        if ($folderExistCache->hasKey($parent)) {
94
+            $parentExists = $folderExistCache->get($parent);
95
+        } else {
96
+            $parentExists = $this->recipientView->is_dir($parent);
97
+            $folderExistCache->set($parent, $parentExists);
98
+        }
99
+        if (!$parentExists) {
100
+            $parent = Helper::getShareFolder($this->recipientView);
101
+        }
102
+
103
+        $newMountPoint = $this->generateUniqueTarget(
104
+            \OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
105
+            $this->recipientView,
106
+            $mountpoints
107
+        );
108
+
109
+        if ($newMountPoint !== $share->getTarget()) {
110
+            $this->updateFileTarget($newMountPoint, $share);
111
+        }
112
+
113
+        return $newMountPoint;
114
+    }
115
+
116
+    /**
117
+     * update fileTarget in the database if the mount point changed
118
+     *
119
+     * @param string $newPath
120
+     * @param \OCP\Share\IShare $share
121
+     * @return bool
122
+     */
123
+    private function updateFileTarget($newPath, &$share) {
124
+        $share->setTarget($newPath);
125
+
126
+        foreach ($this->groupedShares as $tmpShare) {
127
+            $tmpShare->setTarget($newPath);
128
+            \OC::$server->getShareManager()->moveShare($tmpShare, $this->user);
129
+        }
130
+    }
131
+
132
+
133
+    /**
134
+     * @param string $path
135
+     * @param View $view
136
+     * @param SharedMount[] $mountpoints
137
+     * @return mixed
138
+     */
139
+    private function generateUniqueTarget($path, $view, array $mountpoints) {
140
+        $pathinfo = pathinfo($path);
141
+        $ext = (isset($pathinfo['extension'])) ? '.' . $pathinfo['extension'] : '';
142
+        $name = $pathinfo['filename'];
143
+        $dir = $pathinfo['dirname'];
144
+
145
+        $i = 2;
146
+        $absolutePath = $this->recipientView->getAbsolutePath($path) . '/';
147
+        while ($view->file_exists($path) || isset($mountpoints[$absolutePath])) {
148
+            $path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
149
+            $absolutePath = $this->recipientView->getAbsolutePath($path) . '/';
150
+            $i++;
151
+        }
152
+
153
+        return $path;
154
+    }
155
+
156
+    /**
157
+     * Format a path to be relative to the /user/files/ directory
158
+     *
159
+     * @param string $path the absolute path
160
+     * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
161
+     * @throws \OCA\Files_Sharing\Exceptions\BrokenPath
162
+     */
163
+    protected function stripUserFilesPath($path) {
164
+        $trimmed = ltrim($path, '/');
165
+        $split = explode('/', $trimmed);
166
+
167
+        // it is not a file relative to data/user/files
168
+        if (count($split) < 3 || $split[1] !== 'files') {
169
+            \OCP\Util::writeLog('file sharing',
170
+                'Can not strip userid and "files/" from path: ' . $path,
171
+                \OCP\Util::ERROR);
172
+            throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
173
+        }
174
+
175
+        // skip 'user' and 'files'
176
+        $sliced = array_slice($split, 2);
177
+        $relPath = implode('/', $sliced);
178
+
179
+        return '/' . $relPath;
180
+    }
181
+
182
+    /**
183
+     * Move the mount point to $target
184
+     *
185
+     * @param string $target the target mount point
186
+     * @return bool
187
+     */
188
+    public function moveMount($target) {
189
+
190
+        $relTargetPath = $this->stripUserFilesPath($target);
191
+        $share = $this->storage->getShare();
192
+
193
+        $result = true;
194
+
195
+        try {
196
+            $this->updateFileTarget($relTargetPath, $share);
197
+            $this->setMountPoint($target);
198
+            $this->storage->setMountPoint($relTargetPath);
199
+        } catch (\Exception $e) {
200
+            \OCP\Util::writeLog('file sharing',
201
+                'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
202
+                \OCP\Util::ERROR);
203
+        }
204
+
205
+        return $result;
206
+    }
207
+
208
+    /**
209
+     * Remove the mount points
210
+     *
211
+     * @return bool
212
+     */
213
+    public function removeMount() {
214
+        $mountManager = \OC\Files\Filesystem::getMountManager();
215
+        /** @var $storage \OCA\Files_Sharing\SharedStorage */
216
+        $storage = $this->getStorage();
217
+        $result = $storage->unshareStorage();
218
+        $mountManager->removeMount($this->mountPoint);
219
+
220
+        return $result;
221
+    }
222
+
223
+    /**
224
+     * @return \OCP\Share\IShare
225
+     */
226
+    public function getShare() {
227
+        return $this->superShare;
228
+    }
229
+
230
+    /**
231
+     * Get the file id of the root of the storage
232
+     *
233
+     * @return int
234
+     */
235
+    public function getStorageRootId() {
236
+        return $this->getShare()->getNodeId();
237
+    }
238
+
239
+    /**
240
+     * @return int
241
+     */
242
+    public function getNumericStorageId() {
243
+        if (!is_null($this->getShare()->getNodeCacheEntry())) {
244
+            return $this->getShare()->getNodeCacheEntry()->getStorageId();
245
+        } else {
246
+            $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
247
+
248
+            $query = $builder->select('storage')
249
+                ->from('filecache')
250
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($this->getStorageRootId())));
251
+
252
+            $result = $query->execute();
253
+            $row = $result->fetch();
254
+            $result->closeCursor();
255
+            if ($row) {
256
+                return (int)$row['storage'];
257
+            }
258
+            return -1;
259
+        }
260
+    }
261
+
262
+    public function getMountType() {
263
+        return 'shared';
264
+    }
265 265
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
 		$this->groupedShares = $arguments['groupedShares'];
75 75
 
76 76
 		$newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints, $folderExistCache);
77
-		$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
77
+		$absMountPoint = '/'.$this->user.'/files'.$newMountPoint;
78 78
 		parent::__construct($storage, $absMountPoint, $arguments, $loader);
79 79
 	}
80 80
 
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 		}
102 102
 
103 103
 		$newMountPoint = $this->generateUniqueTarget(
104
-			\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
104
+			\OC\Files\Filesystem::normalizePath($parent.'/'.$mountPoint),
105 105
 			$this->recipientView,
106 106
 			$mountpoints
107 107
 		);
@@ -138,15 +138,15 @@  discard block
 block discarded – undo
138 138
 	 */
139 139
 	private function generateUniqueTarget($path, $view, array $mountpoints) {
140 140
 		$pathinfo = pathinfo($path);
141
-		$ext = (isset($pathinfo['extension'])) ? '.' . $pathinfo['extension'] : '';
141
+		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
142 142
 		$name = $pathinfo['filename'];
143 143
 		$dir = $pathinfo['dirname'];
144 144
 
145 145
 		$i = 2;
146
-		$absolutePath = $this->recipientView->getAbsolutePath($path) . '/';
146
+		$absolutePath = $this->recipientView->getAbsolutePath($path).'/';
147 147
 		while ($view->file_exists($path) || isset($mountpoints[$absolutePath])) {
148
-			$path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
149
-			$absolutePath = $this->recipientView->getAbsolutePath($path) . '/';
148
+			$path = Filesystem::normalizePath($dir.'/'.$name.' ('.$i.')'.$ext);
149
+			$absolutePath = $this->recipientView->getAbsolutePath($path).'/';
150 150
 			$i++;
151 151
 		}
152 152
 
@@ -167,7 +167,7 @@  discard block
 block discarded – undo
167 167
 		// it is not a file relative to data/user/files
168 168
 		if (count($split) < 3 || $split[1] !== 'files') {
169 169
 			\OCP\Util::writeLog('file sharing',
170
-				'Can not strip userid and "files/" from path: ' . $path,
170
+				'Can not strip userid and "files/" from path: '.$path,
171 171
 				\OCP\Util::ERROR);
172 172
 			throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
173 173
 		}
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
 		$sliced = array_slice($split, 2);
177 177
 		$relPath = implode('/', $sliced);
178 178
 
179
-		return '/' . $relPath;
179
+		return '/'.$relPath;
180 180
 	}
181 181
 
182 182
 	/**
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
 			$this->storage->setMountPoint($relTargetPath);
199 199
 		} catch (\Exception $e) {
200 200
 			\OCP\Util::writeLog('file sharing',
201
-				'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
201
+				'Could not rename mount point for shared folder "'.$this->getMountPoint().'" to "'.$target.'"',
202 202
 				\OCP\Util::ERROR);
203 203
 		}
204 204
 
@@ -253,7 +253,7 @@  discard block
 block discarded – undo
253 253
 			$row = $result->fetch();
254 254
 			$result->closeCursor();
255 255
 			if ($row) {
256
-				return (int)$row['storage'];
256
+				return (int) $row['storage'];
257 257
 			}
258 258
 			return -1;
259 259
 		}
Please login to merge, or discard this patch.
apps/files_sharing/lib/MountProvider.php 2 patches
Indentation   +185 added lines, -185 removed lines patch added patch discarded remove patch
@@ -35,189 +35,189 @@
 block discarded – undo
35 35
 use OCP\Share\IManager;
36 36
 
37 37
 class MountProvider implements IMountProvider {
38
-	/**
39
-	 * @var \OCP\IConfig
40
-	 */
41
-	protected $config;
42
-
43
-	/**
44
-	 * @var IManager
45
-	 */
46
-	protected $shareManager;
47
-
48
-	/**
49
-	 * @var ILogger
50
-	 */
51
-	protected $logger;
52
-
53
-	/**
54
-	 * @param \OCP\IConfig $config
55
-	 * @param IManager $shareManager
56
-	 * @param ILogger $logger
57
-	 */
58
-	public function __construct(IConfig $config, IManager $shareManager, ILogger $logger) {
59
-		$this->config = $config;
60
-		$this->shareManager = $shareManager;
61
-		$this->logger = $logger;
62
-	}
63
-
64
-
65
-	/**
66
-	 * Get all mountpoints applicable for the user and check for shares where we need to update the etags
67
-	 *
68
-	 * @param \OCP\IUser $user
69
-	 * @param \OCP\Files\Storage\IStorageFactory $storageFactory
70
-	 * @return \OCP\Files\Mount\IMountPoint[]
71
-	 */
72
-	public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
73
-
74
-		$shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1);
75
-		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1));
76
-		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_CIRCLE, null, -1));
77
-
78
-		// filter out excluded shares and group shares that includes self
79
-		$shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
80
-			return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
81
-		});
82
-
83
-		$superShares = $this->buildSuperShares($shares, $user);
84
-
85
-		$mounts = [];
86
-		$view = new View('/' . $user->getUID() . '/files');
87
-		$ownerViews = [];
88
-		$sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($user->getUID());
89
-		$foldersExistCache = new CappedMemoryCache();
90
-		foreach ($superShares as $share) {
91
-			try {
92
-				/** @var \OCP\Share\IShare $parentShare */
93
-				$parentShare = $share[0];
94
-				$owner = $parentShare->getShareOwner();
95
-				if (!isset($ownerViews[$owner])) {
96
-					$ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files');
97
-				}
98
-				$mount = new SharedMount(
99
-					'\OCA\Files_Sharing\SharedStorage',
100
-					$mounts,
101
-					[
102
-						'user' => $user->getUID(),
103
-						// parent share
104
-						'superShare' => $parentShare,
105
-						// children/component of the superShare
106
-						'groupedShares' => $share[1],
107
-						'ownerView' => $ownerViews[$owner],
108
-						'sharingDisabledForUser' => $sharingDisabledForUser
109
-					],
110
-					$storageFactory,
111
-					$view,
112
-					$foldersExistCache
113
-				);
114
-				$mounts[$mount->getMountPoint()] = $mount;
115
-			} catch (\Exception $e) {
116
-				$this->logger->logException($e);
117
-				$this->logger->error('Error while trying to create shared mount');
118
-			}
119
-		}
120
-
121
-		// array_filter removes the null values from the array
122
-		return array_values(array_filter($mounts));
123
-	}
124
-
125
-	/**
126
-	 * Groups shares by path (nodeId) and target path
127
-	 *
128
-	 * @param \OCP\Share\IShare[] $shares
129
-	 * @return \OCP\Share\IShare[][] array of grouped shares, each element in the
130
-	 * array is a group which itself is an array of shares
131
-	 */
132
-	private function groupShares(array $shares) {
133
-		$tmp = [];
134
-
135
-		foreach ($shares as $share) {
136
-			if (!isset($tmp[$share->getNodeId()])) {
137
-				$tmp[$share->getNodeId()] = [];
138
-			}
139
-			$tmp[$share->getNodeId()][] = $share;
140
-		}
141
-
142
-		$result = [];
143
-		// sort by stime, the super share will be based on the least recent share
144
-		foreach ($tmp as &$tmp2) {
145
-			@usort($tmp2, function($a, $b) {
146
-				if ($a->getShareTime() <= $b->getShareTime()) {
147
-					return -1;
148
-				}
149
-				return 1;
150
-			});
151
-			$result[] = $tmp2;
152
-		}
153
-
154
-		return array_values($result);
155
-	}
156
-
157
-	/**
158
-	 * Build super shares (virtual share) by grouping them by node id and target,
159
-	 * then for each group compute the super share and return it along with the matching
160
-	 * grouped shares. The most permissive permissions are used based on the permissions
161
-	 * of all shares within the group.
162
-	 *
163
-	 * @param \OCP\Share\IShare[] $allShares
164
-	 * @param \OCP\IUser $user user
165
-	 * @return array Tuple of [superShare, groupedShares]
166
-	 */
167
-	private function buildSuperShares(array $allShares, \OCP\IUser $user) {
168
-		$result = [];
169
-
170
-		$groupedShares = $this->groupShares($allShares);
171
-
172
-		/** @var \OCP\Share\IShare[] $shares */
173
-		foreach ($groupedShares as $shares) {
174
-			if (count($shares) === 0) {
175
-				continue;
176
-			}
177
-
178
-			$superShare = $this->shareManager->newShare();
179
-
180
-			// compute super share based on first entry of the group
181
-			$superShare->setId($shares[0]->getId())
182
-				->setShareOwner($shares[0]->getShareOwner())
183
-				->setNodeId($shares[0]->getNodeId())
184
-				->setTarget($shares[0]->getTarget());
185
-
186
-			// use most permissive permissions
187
-			$permissions = 0;
188
-			foreach ($shares as $share) {
189
-				$permissions |= $share->getPermissions();
190
-				if ($share->getTarget() !== $superShare->getTarget()) {
191
-					// adjust target, for database consistency
192
-					$share->setTarget($superShare->getTarget());
193
-					try {
194
-						$this->shareManager->moveShare($share, $user->getUID());
195
-					} catch (\InvalidArgumentException $e) {
196
-						// ignore as it is not important and we don't want to
197
-						// block FS setup
198
-
199
-						// the subsequent code anyway only uses the target of the
200
-						// super share
201
-
202
-						// such issue can usually happen when dealing with
203
-						// null groups which usually appear with group backend
204
-						// caching inconsistencies
205
-						$this->logger->debug(
206
-							'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
207
-							['app' => 'files_sharing']
208
-						);
209
-					}
210
-				}
211
-				if (!is_null($share->getNodeCacheEntry())) {
212
-					$superShare->setNodeCacheEntry($share->getNodeCacheEntry());
213
-				}
214
-			}
215
-
216
-			$superShare->setPermissions($permissions);
217
-
218
-			$result[] = [$superShare, $shares];
219
-		}
220
-
221
-		return $result;
222
-	}
38
+    /**
39
+     * @var \OCP\IConfig
40
+     */
41
+    protected $config;
42
+
43
+    /**
44
+     * @var IManager
45
+     */
46
+    protected $shareManager;
47
+
48
+    /**
49
+     * @var ILogger
50
+     */
51
+    protected $logger;
52
+
53
+    /**
54
+     * @param \OCP\IConfig $config
55
+     * @param IManager $shareManager
56
+     * @param ILogger $logger
57
+     */
58
+    public function __construct(IConfig $config, IManager $shareManager, ILogger $logger) {
59
+        $this->config = $config;
60
+        $this->shareManager = $shareManager;
61
+        $this->logger = $logger;
62
+    }
63
+
64
+
65
+    /**
66
+     * Get all mountpoints applicable for the user and check for shares where we need to update the etags
67
+     *
68
+     * @param \OCP\IUser $user
69
+     * @param \OCP\Files\Storage\IStorageFactory $storageFactory
70
+     * @return \OCP\Files\Mount\IMountPoint[]
71
+     */
72
+    public function getMountsForUser(IUser $user, IStorageFactory $storageFactory) {
73
+
74
+        $shares = $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_USER, null, -1);
75
+        $shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_GROUP, null, -1));
76
+        $shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_CIRCLE, null, -1));
77
+
78
+        // filter out excluded shares and group shares that includes self
79
+        $shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
80
+            return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
81
+        });
82
+
83
+        $superShares = $this->buildSuperShares($shares, $user);
84
+
85
+        $mounts = [];
86
+        $view = new View('/' . $user->getUID() . '/files');
87
+        $ownerViews = [];
88
+        $sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($user->getUID());
89
+        $foldersExistCache = new CappedMemoryCache();
90
+        foreach ($superShares as $share) {
91
+            try {
92
+                /** @var \OCP\Share\IShare $parentShare */
93
+                $parentShare = $share[0];
94
+                $owner = $parentShare->getShareOwner();
95
+                if (!isset($ownerViews[$owner])) {
96
+                    $ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files');
97
+                }
98
+                $mount = new SharedMount(
99
+                    '\OCA\Files_Sharing\SharedStorage',
100
+                    $mounts,
101
+                    [
102
+                        'user' => $user->getUID(),
103
+                        // parent share
104
+                        'superShare' => $parentShare,
105
+                        // children/component of the superShare
106
+                        'groupedShares' => $share[1],
107
+                        'ownerView' => $ownerViews[$owner],
108
+                        'sharingDisabledForUser' => $sharingDisabledForUser
109
+                    ],
110
+                    $storageFactory,
111
+                    $view,
112
+                    $foldersExistCache
113
+                );
114
+                $mounts[$mount->getMountPoint()] = $mount;
115
+            } catch (\Exception $e) {
116
+                $this->logger->logException($e);
117
+                $this->logger->error('Error while trying to create shared mount');
118
+            }
119
+        }
120
+
121
+        // array_filter removes the null values from the array
122
+        return array_values(array_filter($mounts));
123
+    }
124
+
125
+    /**
126
+     * Groups shares by path (nodeId) and target path
127
+     *
128
+     * @param \OCP\Share\IShare[] $shares
129
+     * @return \OCP\Share\IShare[][] array of grouped shares, each element in the
130
+     * array is a group which itself is an array of shares
131
+     */
132
+    private function groupShares(array $shares) {
133
+        $tmp = [];
134
+
135
+        foreach ($shares as $share) {
136
+            if (!isset($tmp[$share->getNodeId()])) {
137
+                $tmp[$share->getNodeId()] = [];
138
+            }
139
+            $tmp[$share->getNodeId()][] = $share;
140
+        }
141
+
142
+        $result = [];
143
+        // sort by stime, the super share will be based on the least recent share
144
+        foreach ($tmp as &$tmp2) {
145
+            @usort($tmp2, function($a, $b) {
146
+                if ($a->getShareTime() <= $b->getShareTime()) {
147
+                    return -1;
148
+                }
149
+                return 1;
150
+            });
151
+            $result[] = $tmp2;
152
+        }
153
+
154
+        return array_values($result);
155
+    }
156
+
157
+    /**
158
+     * Build super shares (virtual share) by grouping them by node id and target,
159
+     * then for each group compute the super share and return it along with the matching
160
+     * grouped shares. The most permissive permissions are used based on the permissions
161
+     * of all shares within the group.
162
+     *
163
+     * @param \OCP\Share\IShare[] $allShares
164
+     * @param \OCP\IUser $user user
165
+     * @return array Tuple of [superShare, groupedShares]
166
+     */
167
+    private function buildSuperShares(array $allShares, \OCP\IUser $user) {
168
+        $result = [];
169
+
170
+        $groupedShares = $this->groupShares($allShares);
171
+
172
+        /** @var \OCP\Share\IShare[] $shares */
173
+        foreach ($groupedShares as $shares) {
174
+            if (count($shares) === 0) {
175
+                continue;
176
+            }
177
+
178
+            $superShare = $this->shareManager->newShare();
179
+
180
+            // compute super share based on first entry of the group
181
+            $superShare->setId($shares[0]->getId())
182
+                ->setShareOwner($shares[0]->getShareOwner())
183
+                ->setNodeId($shares[0]->getNodeId())
184
+                ->setTarget($shares[0]->getTarget());
185
+
186
+            // use most permissive permissions
187
+            $permissions = 0;
188
+            foreach ($shares as $share) {
189
+                $permissions |= $share->getPermissions();
190
+                if ($share->getTarget() !== $superShare->getTarget()) {
191
+                    // adjust target, for database consistency
192
+                    $share->setTarget($superShare->getTarget());
193
+                    try {
194
+                        $this->shareManager->moveShare($share, $user->getUID());
195
+                    } catch (\InvalidArgumentException $e) {
196
+                        // ignore as it is not important and we don't want to
197
+                        // block FS setup
198
+
199
+                        // the subsequent code anyway only uses the target of the
200
+                        // super share
201
+
202
+                        // such issue can usually happen when dealing with
203
+                        // null groups which usually appear with group backend
204
+                        // caching inconsistencies
205
+                        $this->logger->debug(
206
+                            'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
207
+                            ['app' => 'files_sharing']
208
+                        );
209
+                    }
210
+                }
211
+                if (!is_null($share->getNodeCacheEntry())) {
212
+                    $superShare->setNodeCacheEntry($share->getNodeCacheEntry());
213
+                }
214
+            }
215
+
216
+            $superShare->setPermissions($permissions);
217
+
218
+            $result[] = [$superShare, $shares];
219
+        }
220
+
221
+        return $result;
222
+    }
223 223
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -76,14 +76,14 @@  discard block
 block discarded – undo
76 76
 		$shares = array_merge($shares, $this->shareManager->getSharedWith($user->getUID(), \OCP\Share::SHARE_TYPE_CIRCLE, null, -1));
77 77
 
78 78
 		// filter out excluded shares and group shares that includes self
79
-		$shares = array_filter($shares, function (\OCP\Share\IShare $share) use ($user) {
79
+		$shares = array_filter($shares, function(\OCP\Share\IShare $share) use ($user) {
80 80
 			return $share->getPermissions() > 0 && $share->getShareOwner() !== $user->getUID();
81 81
 		});
82 82
 
83 83
 		$superShares = $this->buildSuperShares($shares, $user);
84 84
 
85 85
 		$mounts = [];
86
-		$view = new View('/' . $user->getUID() . '/files');
86
+		$view = new View('/'.$user->getUID().'/files');
87 87
 		$ownerViews = [];
88 88
 		$sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($user->getUID());
89 89
 		$foldersExistCache = new CappedMemoryCache();
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
 				$parentShare = $share[0];
94 94
 				$owner = $parentShare->getShareOwner();
95 95
 				if (!isset($ownerViews[$owner])) {
96
-					$ownerViews[$owner] = new View('/' . $parentShare->getShareOwner() . '/files');
96
+					$ownerViews[$owner] = new View('/'.$parentShare->getShareOwner().'/files');
97 97
 				}
98 98
 				$mount = new SharedMount(
99 99
 					'\OCA\Files_Sharing\SharedStorage',
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
 						// null groups which usually appear with group backend
204 204
 						// caching inconsistencies
205 205
 						$this->logger->debug(
206
-							'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
206
+							'Could not adjust share target for share '.$share->getId().' to make it consistent: '.$e->getMessage(),
207 207
 							['app' => 'files_sharing']
208 208
 						);
209 209
 					}
Please login to merge, or discard this patch.
lib/private/Files/View.php 2 patches
Indentation   +2080 added lines, -2080 removed lines patch added patch discarded remove patch
@@ -80,2084 +80,2084 @@
 block discarded – undo
80 80
  * \OC\Files\Storage\Storage object
81 81
  */
82 82
 class View {
83
-	/** @var string */
84
-	private $fakeRoot = '';
85
-
86
-	/**
87
-	 * @var \OCP\Lock\ILockingProvider
88
-	 */
89
-	protected $lockingProvider;
90
-
91
-	private $lockingEnabled;
92
-
93
-	private $updaterEnabled = true;
94
-
95
-	/** @var \OC\User\Manager */
96
-	private $userManager;
97
-
98
-	/** @var \OCP\ILogger */
99
-	private $logger;
100
-
101
-	/**
102
-	 * @param string $root
103
-	 * @throws \Exception If $root contains an invalid path
104
-	 */
105
-	public function __construct($root = '') {
106
-		if (is_null($root)) {
107
-			throw new \InvalidArgumentException('Root can\'t be null');
108
-		}
109
-		if (!Filesystem::isValidPath($root)) {
110
-			throw new \Exception();
111
-		}
112
-
113
-		$this->fakeRoot = $root;
114
-		$this->lockingProvider = \OC::$server->getLockingProvider();
115
-		$this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
116
-		$this->userManager = \OC::$server->getUserManager();
117
-		$this->logger = \OC::$server->getLogger();
118
-	}
119
-
120
-	public function getAbsolutePath($path = '/') {
121
-		if ($path === null) {
122
-			return null;
123
-		}
124
-		$this->assertPathLength($path);
125
-		if ($path === '') {
126
-			$path = '/';
127
-		}
128
-		if ($path[0] !== '/') {
129
-			$path = '/' . $path;
130
-		}
131
-		return $this->fakeRoot . $path;
132
-	}
133
-
134
-	/**
135
-	 * change the root to a fake root
136
-	 *
137
-	 * @param string $fakeRoot
138
-	 * @return boolean|null
139
-	 */
140
-	public function chroot($fakeRoot) {
141
-		if (!$fakeRoot == '') {
142
-			if ($fakeRoot[0] !== '/') {
143
-				$fakeRoot = '/' . $fakeRoot;
144
-			}
145
-		}
146
-		$this->fakeRoot = $fakeRoot;
147
-	}
148
-
149
-	/**
150
-	 * get the fake root
151
-	 *
152
-	 * @return string
153
-	 */
154
-	public function getRoot() {
155
-		return $this->fakeRoot;
156
-	}
157
-
158
-	/**
159
-	 * get path relative to the root of the view
160
-	 *
161
-	 * @param string $path
162
-	 * @return string
163
-	 */
164
-	public function getRelativePath($path) {
165
-		$this->assertPathLength($path);
166
-		if ($this->fakeRoot == '') {
167
-			return $path;
168
-		}
169
-
170
-		if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) {
171
-			return '/';
172
-		}
173
-
174
-		// missing slashes can cause wrong matches!
175
-		$root = rtrim($this->fakeRoot, '/') . '/';
176
-
177
-		if (strpos($path, $root) !== 0) {
178
-			return null;
179
-		} else {
180
-			$path = substr($path, strlen($this->fakeRoot));
181
-			if (strlen($path) === 0) {
182
-				return '/';
183
-			} else {
184
-				return $path;
185
-			}
186
-		}
187
-	}
188
-
189
-	/**
190
-	 * get the mountpoint of the storage object for a path
191
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
192
-	 * returned mountpoint is relative to the absolute root of the filesystem
193
-	 * and does not take the chroot into account )
194
-	 *
195
-	 * @param string $path
196
-	 * @return string
197
-	 */
198
-	public function getMountPoint($path) {
199
-		return Filesystem::getMountPoint($this->getAbsolutePath($path));
200
-	}
201
-
202
-	/**
203
-	 * get the mountpoint of the storage object for a path
204
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
205
-	 * returned mountpoint is relative to the absolute root of the filesystem
206
-	 * and does not take the chroot into account )
207
-	 *
208
-	 * @param string $path
209
-	 * @return \OCP\Files\Mount\IMountPoint
210
-	 */
211
-	public function getMount($path) {
212
-		return Filesystem::getMountManager()->find($this->getAbsolutePath($path));
213
-	}
214
-
215
-	/**
216
-	 * resolve a path to a storage and internal path
217
-	 *
218
-	 * @param string $path
219
-	 * @return array an array consisting of the storage and the internal path
220
-	 */
221
-	public function resolvePath($path) {
222
-		$a = $this->getAbsolutePath($path);
223
-		$p = Filesystem::normalizePath($a);
224
-		return Filesystem::resolvePath($p);
225
-	}
226
-
227
-	/**
228
-	 * return the path to a local version of the file
229
-	 * we need this because we can't know if a file is stored local or not from
230
-	 * outside the filestorage and for some purposes a local file is needed
231
-	 *
232
-	 * @param string $path
233
-	 * @return string
234
-	 */
235
-	public function getLocalFile($path) {
236
-		$parent = substr($path, 0, strrpos($path, '/'));
237
-		$path = $this->getAbsolutePath($path);
238
-		list($storage, $internalPath) = Filesystem::resolvePath($path);
239
-		if (Filesystem::isValidPath($parent) and $storage) {
240
-			return $storage->getLocalFile($internalPath);
241
-		} else {
242
-			return null;
243
-		}
244
-	}
245
-
246
-	/**
247
-	 * @param string $path
248
-	 * @return string
249
-	 */
250
-	public function getLocalFolder($path) {
251
-		$parent = substr($path, 0, strrpos($path, '/'));
252
-		$path = $this->getAbsolutePath($path);
253
-		list($storage, $internalPath) = Filesystem::resolvePath($path);
254
-		if (Filesystem::isValidPath($parent) and $storage) {
255
-			return $storage->getLocalFolder($internalPath);
256
-		} else {
257
-			return null;
258
-		}
259
-	}
260
-
261
-	/**
262
-	 * the following functions operate with arguments and return values identical
263
-	 * to those of their PHP built-in equivalents. Mostly they are merely wrappers
264
-	 * for \OC\Files\Storage\Storage via basicOperation().
265
-	 */
266
-	public function mkdir($path) {
267
-		return $this->basicOperation('mkdir', $path, array('create', 'write'));
268
-	}
269
-
270
-	/**
271
-	 * remove mount point
272
-	 *
273
-	 * @param \OC\Files\Mount\MoveableMount $mount
274
-	 * @param string $path relative to data/
275
-	 * @return boolean
276
-	 */
277
-	protected function removeMount($mount, $path) {
278
-		if ($mount instanceof MoveableMount) {
279
-			// cut of /user/files to get the relative path to data/user/files
280
-			$pathParts = explode('/', $path, 4);
281
-			$relPath = '/' . $pathParts[3];
282
-			$this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
283
-			\OC_Hook::emit(
284
-				Filesystem::CLASSNAME, "umount",
285
-				array(Filesystem::signal_param_path => $relPath)
286
-			);
287
-			$this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true);
288
-			$result = $mount->removeMount();
289
-			$this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true);
290
-			if ($result) {
291
-				\OC_Hook::emit(
292
-					Filesystem::CLASSNAME, "post_umount",
293
-					array(Filesystem::signal_param_path => $relPath)
294
-				);
295
-			}
296
-			$this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true);
297
-			return $result;
298
-		} else {
299
-			// do not allow deleting the storage's root / the mount point
300
-			// because for some storages it might delete the whole contents
301
-			// but isn't supposed to work that way
302
-			return false;
303
-		}
304
-	}
305
-
306
-	public function disableCacheUpdate() {
307
-		$this->updaterEnabled = false;
308
-	}
309
-
310
-	public function enableCacheUpdate() {
311
-		$this->updaterEnabled = true;
312
-	}
313
-
314
-	protected function writeUpdate(Storage $storage, $internalPath, $time = null) {
315
-		if ($this->updaterEnabled) {
316
-			if (is_null($time)) {
317
-				$time = time();
318
-			}
319
-			$storage->getUpdater()->update($internalPath, $time);
320
-		}
321
-	}
322
-
323
-	protected function removeUpdate(Storage $storage, $internalPath) {
324
-		if ($this->updaterEnabled) {
325
-			$storage->getUpdater()->remove($internalPath);
326
-		}
327
-	}
328
-
329
-	protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) {
330
-		if ($this->updaterEnabled) {
331
-			$targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
332
-		}
333
-	}
334
-
335
-	/**
336
-	 * @param string $path
337
-	 * @return bool|mixed
338
-	 */
339
-	public function rmdir($path) {
340
-		$absolutePath = $this->getAbsolutePath($path);
341
-		$mount = Filesystem::getMountManager()->find($absolutePath);
342
-		if ($mount->getInternalPath($absolutePath) === '') {
343
-			return $this->removeMount($mount, $absolutePath);
344
-		}
345
-		if ($this->is_dir($path)) {
346
-			$result = $this->basicOperation('rmdir', $path, array('delete'));
347
-		} else {
348
-			$result = false;
349
-		}
350
-
351
-		if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
352
-			$storage = $mount->getStorage();
353
-			$internalPath = $mount->getInternalPath($absolutePath);
354
-			$storage->getUpdater()->remove($internalPath);
355
-		}
356
-		return $result;
357
-	}
358
-
359
-	/**
360
-	 * @param string $path
361
-	 * @return resource
362
-	 */
363
-	public function opendir($path) {
364
-		return $this->basicOperation('opendir', $path, array('read'));
365
-	}
366
-
367
-	/**
368
-	 * @param string $path
369
-	 * @return bool|mixed
370
-	 */
371
-	public function is_dir($path) {
372
-		if ($path == '/') {
373
-			return true;
374
-		}
375
-		return $this->basicOperation('is_dir', $path);
376
-	}
377
-
378
-	/**
379
-	 * @param string $path
380
-	 * @return bool|mixed
381
-	 */
382
-	public function is_file($path) {
383
-		if ($path == '/') {
384
-			return false;
385
-		}
386
-		return $this->basicOperation('is_file', $path);
387
-	}
388
-
389
-	/**
390
-	 * @param string $path
391
-	 * @return mixed
392
-	 */
393
-	public function stat($path) {
394
-		return $this->basicOperation('stat', $path);
395
-	}
396
-
397
-	/**
398
-	 * @param string $path
399
-	 * @return mixed
400
-	 */
401
-	public function filetype($path) {
402
-		return $this->basicOperation('filetype', $path);
403
-	}
404
-
405
-	/**
406
-	 * @param string $path
407
-	 * @return mixed
408
-	 */
409
-	public function filesize($path) {
410
-		return $this->basicOperation('filesize', $path);
411
-	}
412
-
413
-	/**
414
-	 * @param string $path
415
-	 * @return bool|mixed
416
-	 * @throws \OCP\Files\InvalidPathException
417
-	 */
418
-	public function readfile($path) {
419
-		$this->assertPathLength($path);
420
-		@ob_end_clean();
421
-		$handle = $this->fopen($path, 'rb');
422
-		if ($handle) {
423
-			$chunkSize = 8192; // 8 kB chunks
424
-			while (!feof($handle)) {
425
-				echo fread($handle, $chunkSize);
426
-				flush();
427
-			}
428
-			fclose($handle);
429
-			$size = $this->filesize($path);
430
-			return $size;
431
-		}
432
-		return false;
433
-	}
434
-
435
-	/**
436
-	 * @param string $path
437
-	 * @param int $from
438
-	 * @param int $to
439
-	 * @return bool|mixed
440
-	 * @throws \OCP\Files\InvalidPathException
441
-	 * @throws \OCP\Files\UnseekableException
442
-	 */
443
-	public function readfilePart($path, $from, $to) {
444
-		$this->assertPathLength($path);
445
-		@ob_end_clean();
446
-		$handle = $this->fopen($path, 'rb');
447
-		if ($handle) {
448
-			$chunkSize = 8192; // 8 kB chunks
449
-			$startReading = true;
450
-
451
-			if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) {
452
-				// forward file handle via chunked fread because fseek seem to have failed
453
-
454
-				$end = $from + 1;
455
-				while (!feof($handle) && ftell($handle) < $end) {
456
-					$len = $from - ftell($handle);
457
-					if ($len > $chunkSize) {
458
-						$len = $chunkSize;
459
-					}
460
-					$result = fread($handle, $len);
461
-
462
-					if ($result === false) {
463
-						$startReading = false;
464
-						break;
465
-					}
466
-				}
467
-			}
468
-
469
-			if ($startReading) {
470
-				$end = $to + 1;
471
-				while (!feof($handle) && ftell($handle) < $end) {
472
-					$len = $end - ftell($handle);
473
-					if ($len > $chunkSize) {
474
-						$len = $chunkSize;
475
-					}
476
-					echo fread($handle, $len);
477
-					flush();
478
-				}
479
-				$size = ftell($handle) - $from;
480
-				return $size;
481
-			}
482
-
483
-			throw new \OCP\Files\UnseekableException('fseek error');
484
-		}
485
-		return false;
486
-	}
487
-
488
-	/**
489
-	 * @param string $path
490
-	 * @return mixed
491
-	 */
492
-	public function isCreatable($path) {
493
-		return $this->basicOperation('isCreatable', $path);
494
-	}
495
-
496
-	/**
497
-	 * @param string $path
498
-	 * @return mixed
499
-	 */
500
-	public function isReadable($path) {
501
-		return $this->basicOperation('isReadable', $path);
502
-	}
503
-
504
-	/**
505
-	 * @param string $path
506
-	 * @return mixed
507
-	 */
508
-	public function isUpdatable($path) {
509
-		return $this->basicOperation('isUpdatable', $path);
510
-	}
511
-
512
-	/**
513
-	 * @param string $path
514
-	 * @return bool|mixed
515
-	 */
516
-	public function isDeletable($path) {
517
-		$absolutePath = $this->getAbsolutePath($path);
518
-		$mount = Filesystem::getMountManager()->find($absolutePath);
519
-		if ($mount->getInternalPath($absolutePath) === '') {
520
-			return $mount instanceof MoveableMount;
521
-		}
522
-		return $this->basicOperation('isDeletable', $path);
523
-	}
524
-
525
-	/**
526
-	 * @param string $path
527
-	 * @return mixed
528
-	 */
529
-	public function isSharable($path) {
530
-		return $this->basicOperation('isSharable', $path);
531
-	}
532
-
533
-	/**
534
-	 * @param string $path
535
-	 * @return bool|mixed
536
-	 */
537
-	public function file_exists($path) {
538
-		if ($path == '/') {
539
-			return true;
540
-		}
541
-		return $this->basicOperation('file_exists', $path);
542
-	}
543
-
544
-	/**
545
-	 * @param string $path
546
-	 * @return mixed
547
-	 */
548
-	public function filemtime($path) {
549
-		return $this->basicOperation('filemtime', $path);
550
-	}
551
-
552
-	/**
553
-	 * @param string $path
554
-	 * @param int|string $mtime
555
-	 * @return bool
556
-	 */
557
-	public function touch($path, $mtime = null) {
558
-		if (!is_null($mtime) and !is_numeric($mtime)) {
559
-			$mtime = strtotime($mtime);
560
-		}
561
-
562
-		$hooks = array('touch');
563
-
564
-		if (!$this->file_exists($path)) {
565
-			$hooks[] = 'create';
566
-			$hooks[] = 'write';
567
-		}
568
-		$result = $this->basicOperation('touch', $path, $hooks, $mtime);
569
-		if (!$result) {
570
-			// If create file fails because of permissions on external storage like SMB folders,
571
-			// check file exists and return false if not.
572
-			if (!$this->file_exists($path)) {
573
-				return false;
574
-			}
575
-			if (is_null($mtime)) {
576
-				$mtime = time();
577
-			}
578
-			//if native touch fails, we emulate it by changing the mtime in the cache
579
-			$this->putFileInfo($path, array('mtime' => floor($mtime)));
580
-		}
581
-		return true;
582
-	}
583
-
584
-	/**
585
-	 * @param string $path
586
-	 * @return mixed
587
-	 */
588
-	public function file_get_contents($path) {
589
-		return $this->basicOperation('file_get_contents', $path, array('read'));
590
-	}
591
-
592
-	/**
593
-	 * @param bool $exists
594
-	 * @param string $path
595
-	 * @param bool $run
596
-	 */
597
-	protected function emit_file_hooks_pre($exists, $path, &$run) {
598
-		if (!$exists) {
599
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, array(
600
-				Filesystem::signal_param_path => $this->getHookPath($path),
601
-				Filesystem::signal_param_run => &$run,
602
-			));
603
-		} else {
604
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, array(
605
-				Filesystem::signal_param_path => $this->getHookPath($path),
606
-				Filesystem::signal_param_run => &$run,
607
-			));
608
-		}
609
-		\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, array(
610
-			Filesystem::signal_param_path => $this->getHookPath($path),
611
-			Filesystem::signal_param_run => &$run,
612
-		));
613
-	}
614
-
615
-	/**
616
-	 * @param bool $exists
617
-	 * @param string $path
618
-	 */
619
-	protected function emit_file_hooks_post($exists, $path) {
620
-		if (!$exists) {
621
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, array(
622
-				Filesystem::signal_param_path => $this->getHookPath($path),
623
-			));
624
-		} else {
625
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, array(
626
-				Filesystem::signal_param_path => $this->getHookPath($path),
627
-			));
628
-		}
629
-		\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, array(
630
-			Filesystem::signal_param_path => $this->getHookPath($path),
631
-		));
632
-	}
633
-
634
-	/**
635
-	 * @param string $path
636
-	 * @param mixed $data
637
-	 * @return bool|mixed
638
-	 * @throws \Exception
639
-	 */
640
-	public function file_put_contents($path, $data) {
641
-		if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
642
-			$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
643
-			if (Filesystem::isValidPath($path)
644
-				and !Filesystem::isFileBlacklisted($path)
645
-			) {
646
-				$path = $this->getRelativePath($absolutePath);
647
-
648
-				$this->lockFile($path, ILockingProvider::LOCK_SHARED);
649
-
650
-				$exists = $this->file_exists($path);
651
-				$run = true;
652
-				if ($this->shouldEmitHooks($path)) {
653
-					$this->emit_file_hooks_pre($exists, $path, $run);
654
-				}
655
-				if (!$run) {
656
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
657
-					return false;
658
-				}
659
-
660
-				$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
661
-
662
-				/** @var \OC\Files\Storage\Storage $storage */
663
-				list($storage, $internalPath) = $this->resolvePath($path);
664
-				$target = $storage->fopen($internalPath, 'w');
665
-				if ($target) {
666
-					list (, $result) = \OC_Helper::streamCopy($data, $target);
667
-					fclose($target);
668
-					fclose($data);
669
-
670
-					$this->writeUpdate($storage, $internalPath);
671
-
672
-					$this->changeLock($path, ILockingProvider::LOCK_SHARED);
673
-
674
-					if ($this->shouldEmitHooks($path) && $result !== false) {
675
-						$this->emit_file_hooks_post($exists, $path);
676
-					}
677
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
678
-					return $result;
679
-				} else {
680
-					$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
681
-					return false;
682
-				}
683
-			} else {
684
-				return false;
685
-			}
686
-		} else {
687
-			$hooks = ($this->file_exists($path)) ? array('update', 'write') : array('create', 'write');
688
-			return $this->basicOperation('file_put_contents', $path, $hooks, $data);
689
-		}
690
-	}
691
-
692
-	/**
693
-	 * @param string $path
694
-	 * @return bool|mixed
695
-	 */
696
-	public function unlink($path) {
697
-		if ($path === '' || $path === '/') {
698
-			// do not allow deleting the root
699
-			return false;
700
-		}
701
-		$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
702
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
703
-		$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
704
-		if ($mount and $mount->getInternalPath($absolutePath) === '') {
705
-			return $this->removeMount($mount, $absolutePath);
706
-		}
707
-		if ($this->is_dir($path)) {
708
-			$result = $this->basicOperation('rmdir', $path, ['delete']);
709
-		} else {
710
-			$result = $this->basicOperation('unlink', $path, ['delete']);
711
-		}
712
-		if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
713
-			$storage = $mount->getStorage();
714
-			$internalPath = $mount->getInternalPath($absolutePath);
715
-			$storage->getUpdater()->remove($internalPath);
716
-			return true;
717
-		} else {
718
-			return $result;
719
-		}
720
-	}
721
-
722
-	/**
723
-	 * @param string $directory
724
-	 * @return bool|mixed
725
-	 */
726
-	public function deleteAll($directory) {
727
-		return $this->rmdir($directory);
728
-	}
729
-
730
-	/**
731
-	 * Rename/move a file or folder from the source path to target path.
732
-	 *
733
-	 * @param string $path1 source path
734
-	 * @param string $path2 target path
735
-	 *
736
-	 * @return bool|mixed
737
-	 */
738
-	public function rename($path1, $path2) {
739
-		$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
740
-		$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
741
-		$result = false;
742
-		if (
743
-			Filesystem::isValidPath($path2)
744
-			and Filesystem::isValidPath($path1)
745
-			and !Filesystem::isFileBlacklisted($path2)
746
-		) {
747
-			$path1 = $this->getRelativePath($absolutePath1);
748
-			$path2 = $this->getRelativePath($absolutePath2);
749
-			$exists = $this->file_exists($path2);
750
-
751
-			if ($path1 == null or $path2 == null) {
752
-				return false;
753
-			}
754
-
755
-			$this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
756
-			try {
757
-				$this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
758
-
759
-				$run = true;
760
-				if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
761
-					// if it was a rename from a part file to a regular file it was a write and not a rename operation
762
-					$this->emit_file_hooks_pre($exists, $path2, $run);
763
-				} elseif ($this->shouldEmitHooks($path1)) {
764
-					\OC_Hook::emit(
765
-						Filesystem::CLASSNAME, Filesystem::signal_rename,
766
-						array(
767
-							Filesystem::signal_param_oldpath => $this->getHookPath($path1),
768
-							Filesystem::signal_param_newpath => $this->getHookPath($path2),
769
-							Filesystem::signal_param_run => &$run
770
-						)
771
-					);
772
-				}
773
-				if ($run) {
774
-					$this->verifyPath(dirname($path2), basename($path2));
775
-
776
-					$manager = Filesystem::getMountManager();
777
-					$mount1 = $this->getMount($path1);
778
-					$mount2 = $this->getMount($path2);
779
-					$storage1 = $mount1->getStorage();
780
-					$storage2 = $mount2->getStorage();
781
-					$internalPath1 = $mount1->getInternalPath($absolutePath1);
782
-					$internalPath2 = $mount2->getInternalPath($absolutePath2);
783
-
784
-					$this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
785
-					try {
786
-						$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
787
-
788
-						if ($internalPath1 === '') {
789
-							if ($mount1 instanceof MoveableMount) {
790
-								if ($this->isTargetAllowed($absolutePath2)) {
791
-									/**
792
-									 * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
793
-									 */
794
-									$sourceMountPoint = $mount1->getMountPoint();
795
-									$result = $mount1->moveMount($absolutePath2);
796
-									$manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
797
-								} else {
798
-									$result = false;
799
-								}
800
-							} else {
801
-								$result = false;
802
-							}
803
-							// moving a file/folder within the same mount point
804
-						} elseif ($storage1 === $storage2) {
805
-							if ($storage1) {
806
-								$result = $storage1->rename($internalPath1, $internalPath2);
807
-							} else {
808
-								$result = false;
809
-							}
810
-							// moving a file/folder between storages (from $storage1 to $storage2)
811
-						} else {
812
-							$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
813
-						}
814
-
815
-						if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
816
-							// if it was a rename from a part file to a regular file it was a write and not a rename operation
817
-							$this->writeUpdate($storage2, $internalPath2);
818
-						} else if ($result) {
819
-							if ($internalPath1 !== '') { // don't do a cache update for moved mounts
820
-								$this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
821
-							}
822
-						}
823
-					} catch(\Exception $e) {
824
-						throw $e;
825
-					} finally {
826
-						$this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
827
-						$this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
828
-					}
829
-
830
-					if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
831
-						if ($this->shouldEmitHooks()) {
832
-							$this->emit_file_hooks_post($exists, $path2);
833
-						}
834
-					} elseif ($result) {
835
-						if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) {
836
-							\OC_Hook::emit(
837
-								Filesystem::CLASSNAME,
838
-								Filesystem::signal_post_rename,
839
-								array(
840
-									Filesystem::signal_param_oldpath => $this->getHookPath($path1),
841
-									Filesystem::signal_param_newpath => $this->getHookPath($path2)
842
-								)
843
-							);
844
-						}
845
-					}
846
-				}
847
-			} catch(\Exception $e) {
848
-				throw $e;
849
-			} finally {
850
-				$this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
851
-				$this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
852
-			}
853
-		}
854
-		return $result;
855
-	}
856
-
857
-	/**
858
-	 * Copy a file/folder from the source path to target path
859
-	 *
860
-	 * @param string $path1 source path
861
-	 * @param string $path2 target path
862
-	 * @param bool $preserveMtime whether to preserve mtime on the copy
863
-	 *
864
-	 * @return bool|mixed
865
-	 */
866
-	public function copy($path1, $path2, $preserveMtime = false) {
867
-		$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
868
-		$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
869
-		$result = false;
870
-		if (
871
-			Filesystem::isValidPath($path2)
872
-			and Filesystem::isValidPath($path1)
873
-			and !Filesystem::isFileBlacklisted($path2)
874
-		) {
875
-			$path1 = $this->getRelativePath($absolutePath1);
876
-			$path2 = $this->getRelativePath($absolutePath2);
877
-
878
-			if ($path1 == null or $path2 == null) {
879
-				return false;
880
-			}
881
-			$run = true;
882
-
883
-			$this->lockFile($path2, ILockingProvider::LOCK_SHARED);
884
-			$this->lockFile($path1, ILockingProvider::LOCK_SHARED);
885
-			$lockTypePath1 = ILockingProvider::LOCK_SHARED;
886
-			$lockTypePath2 = ILockingProvider::LOCK_SHARED;
887
-
888
-			try {
889
-
890
-				$exists = $this->file_exists($path2);
891
-				if ($this->shouldEmitHooks()) {
892
-					\OC_Hook::emit(
893
-						Filesystem::CLASSNAME,
894
-						Filesystem::signal_copy,
895
-						array(
896
-							Filesystem::signal_param_oldpath => $this->getHookPath($path1),
897
-							Filesystem::signal_param_newpath => $this->getHookPath($path2),
898
-							Filesystem::signal_param_run => &$run
899
-						)
900
-					);
901
-					$this->emit_file_hooks_pre($exists, $path2, $run);
902
-				}
903
-				if ($run) {
904
-					$mount1 = $this->getMount($path1);
905
-					$mount2 = $this->getMount($path2);
906
-					$storage1 = $mount1->getStorage();
907
-					$internalPath1 = $mount1->getInternalPath($absolutePath1);
908
-					$storage2 = $mount2->getStorage();
909
-					$internalPath2 = $mount2->getInternalPath($absolutePath2);
910
-
911
-					$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE);
912
-					$lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE;
913
-
914
-					if ($mount1->getMountPoint() == $mount2->getMountPoint()) {
915
-						if ($storage1) {
916
-							$result = $storage1->copy($internalPath1, $internalPath2);
917
-						} else {
918
-							$result = false;
919
-						}
920
-					} else {
921
-						$result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
922
-					}
923
-
924
-					$this->writeUpdate($storage2, $internalPath2);
925
-
926
-					$this->changeLock($path2, ILockingProvider::LOCK_SHARED);
927
-					$lockTypePath2 = ILockingProvider::LOCK_SHARED;
928
-
929
-					if ($this->shouldEmitHooks() && $result !== false) {
930
-						\OC_Hook::emit(
931
-							Filesystem::CLASSNAME,
932
-							Filesystem::signal_post_copy,
933
-							array(
934
-								Filesystem::signal_param_oldpath => $this->getHookPath($path1),
935
-								Filesystem::signal_param_newpath => $this->getHookPath($path2)
936
-							)
937
-						);
938
-						$this->emit_file_hooks_post($exists, $path2);
939
-					}
940
-
941
-				}
942
-			} catch (\Exception $e) {
943
-				$this->unlockFile($path2, $lockTypePath2);
944
-				$this->unlockFile($path1, $lockTypePath1);
945
-				throw $e;
946
-			}
947
-
948
-			$this->unlockFile($path2, $lockTypePath2);
949
-			$this->unlockFile($path1, $lockTypePath1);
950
-
951
-		}
952
-		return $result;
953
-	}
954
-
955
-	/**
956
-	 * @param string $path
957
-	 * @param string $mode 'r' or 'w'
958
-	 * @return resource
959
-	 */
960
-	public function fopen($path, $mode) {
961
-		$mode = str_replace('b', '', $mode); // the binary flag is a windows only feature which we do not support
962
-		$hooks = array();
963
-		switch ($mode) {
964
-			case 'r':
965
-				$hooks[] = 'read';
966
-				break;
967
-			case 'r+':
968
-			case 'w+':
969
-			case 'x+':
970
-			case 'a+':
971
-				$hooks[] = 'read';
972
-				$hooks[] = 'write';
973
-				break;
974
-			case 'w':
975
-			case 'x':
976
-			case 'a':
977
-				$hooks[] = 'write';
978
-				break;
979
-			default:
980
-				\OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR);
981
-		}
982
-
983
-		if ($mode !== 'r' && $mode !== 'w') {
984
-			\OC::$server->getLogger()->info('Trying to open a file with a mode other than "r" or "w" can cause severe performance issues with some backends');
985
-		}
986
-
987
-		return $this->basicOperation('fopen', $path, $hooks, $mode);
988
-	}
989
-
990
-	/**
991
-	 * @param string $path
992
-	 * @return bool|string
993
-	 * @throws \OCP\Files\InvalidPathException
994
-	 */
995
-	public function toTmpFile($path) {
996
-		$this->assertPathLength($path);
997
-		if (Filesystem::isValidPath($path)) {
998
-			$source = $this->fopen($path, 'r');
999
-			if ($source) {
1000
-				$extension = pathinfo($path, PATHINFO_EXTENSION);
1001
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
1002
-				file_put_contents($tmpFile, $source);
1003
-				return $tmpFile;
1004
-			} else {
1005
-				return false;
1006
-			}
1007
-		} else {
1008
-			return false;
1009
-		}
1010
-	}
1011
-
1012
-	/**
1013
-	 * @param string $tmpFile
1014
-	 * @param string $path
1015
-	 * @return bool|mixed
1016
-	 * @throws \OCP\Files\InvalidPathException
1017
-	 */
1018
-	public function fromTmpFile($tmpFile, $path) {
1019
-		$this->assertPathLength($path);
1020
-		if (Filesystem::isValidPath($path)) {
1021
-
1022
-			// Get directory that the file is going into
1023
-			$filePath = dirname($path);
1024
-
1025
-			// Create the directories if any
1026
-			if (!$this->file_exists($filePath)) {
1027
-				$result = $this->createParentDirectories($filePath);
1028
-				if ($result === false) {
1029
-					return false;
1030
-				}
1031
-			}
1032
-
1033
-			$source = fopen($tmpFile, 'r');
1034
-			if ($source) {
1035
-				$result = $this->file_put_contents($path, $source);
1036
-				// $this->file_put_contents() might have already closed
1037
-				// the resource, so we check it, before trying to close it
1038
-				// to avoid messages in the error log.
1039
-				if (is_resource($source)) {
1040
-					fclose($source);
1041
-				}
1042
-				unlink($tmpFile);
1043
-				return $result;
1044
-			} else {
1045
-				return false;
1046
-			}
1047
-		} else {
1048
-			return false;
1049
-		}
1050
-	}
1051
-
1052
-
1053
-	/**
1054
-	 * @param string $path
1055
-	 * @return mixed
1056
-	 * @throws \OCP\Files\InvalidPathException
1057
-	 */
1058
-	public function getMimeType($path) {
1059
-		$this->assertPathLength($path);
1060
-		return $this->basicOperation('getMimeType', $path);
1061
-	}
1062
-
1063
-	/**
1064
-	 * @param string $type
1065
-	 * @param string $path
1066
-	 * @param bool $raw
1067
-	 * @return bool|null|string
1068
-	 */
1069
-	public function hash($type, $path, $raw = false) {
1070
-		$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
1071
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1072
-		if (Filesystem::isValidPath($path)) {
1073
-			$path = $this->getRelativePath($absolutePath);
1074
-			if ($path == null) {
1075
-				return false;
1076
-			}
1077
-			if ($this->shouldEmitHooks($path)) {
1078
-				\OC_Hook::emit(
1079
-					Filesystem::CLASSNAME,
1080
-					Filesystem::signal_read,
1081
-					array(Filesystem::signal_param_path => $this->getHookPath($path))
1082
-				);
1083
-			}
1084
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1085
-			if ($storage) {
1086
-				$result = $storage->hash($type, $internalPath, $raw);
1087
-				return $result;
1088
-			}
1089
-		}
1090
-		return null;
1091
-	}
1092
-
1093
-	/**
1094
-	 * @param string $path
1095
-	 * @return mixed
1096
-	 * @throws \OCP\Files\InvalidPathException
1097
-	 */
1098
-	public function free_space($path = '/') {
1099
-		$this->assertPathLength($path);
1100
-		$result = $this->basicOperation('free_space', $path);
1101
-		if ($result === null) {
1102
-			throw new InvalidPathException();
1103
-		}
1104
-		return $result;
1105
-	}
1106
-
1107
-	/**
1108
-	 * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage
1109
-	 *
1110
-	 * @param string $operation
1111
-	 * @param string $path
1112
-	 * @param array $hooks (optional)
1113
-	 * @param mixed $extraParam (optional)
1114
-	 * @return mixed
1115
-	 * @throws \Exception
1116
-	 *
1117
-	 * This method takes requests for basic filesystem functions (e.g. reading & writing
1118
-	 * files), processes hooks and proxies, sanitises paths, and finally passes them on to
1119
-	 * \OC\Files\Storage\Storage for delegation to a storage backend for execution
1120
-	 */
1121
-	private function basicOperation($operation, $path, $hooks = [], $extraParam = null) {
1122
-		$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
1123
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1124
-		if (Filesystem::isValidPath($path)
1125
-			and !Filesystem::isFileBlacklisted($path)
1126
-		) {
1127
-			$path = $this->getRelativePath($absolutePath);
1128
-			if ($path == null) {
1129
-				return false;
1130
-			}
1131
-
1132
-			if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) {
1133
-				// always a shared lock during pre-hooks so the hook can read the file
1134
-				$this->lockFile($path, ILockingProvider::LOCK_SHARED);
1135
-			}
1136
-
1137
-			$run = $this->runHooks($hooks, $path);
1138
-			/** @var \OC\Files\Storage\Storage $storage */
1139
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1140
-			if ($run and $storage) {
1141
-				if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1142
-					$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
1143
-				}
1144
-				try {
1145
-					if (!is_null($extraParam)) {
1146
-						$result = $storage->$operation($internalPath, $extraParam);
1147
-					} else {
1148
-						$result = $storage->$operation($internalPath);
1149
-					}
1150
-				} catch (\Exception $e) {
1151
-					if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1152
-						$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1153
-					} else if (in_array('read', $hooks)) {
1154
-						$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1155
-					}
1156
-					throw $e;
1157
-				}
1158
-
1159
-				if ($result && in_array('delete', $hooks) and $result) {
1160
-					$this->removeUpdate($storage, $internalPath);
1161
-				}
1162
-				if ($result && in_array('write', $hooks) and $operation !== 'fopen') {
1163
-					$this->writeUpdate($storage, $internalPath);
1164
-				}
1165
-				if ($result && in_array('touch', $hooks)) {
1166
-					$this->writeUpdate($storage, $internalPath, $extraParam);
1167
-				}
1168
-
1169
-				if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
1170
-					$this->changeLock($path, ILockingProvider::LOCK_SHARED);
1171
-				}
1172
-
1173
-				$unlockLater = false;
1174
-				if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) {
1175
-					$unlockLater = true;
1176
-					// make sure our unlocking callback will still be called if connection is aborted
1177
-					ignore_user_abort(true);
1178
-					$result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1179
-						if (in_array('write', $hooks)) {
1180
-							$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1181
-						} else if (in_array('read', $hooks)) {
1182
-							$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1183
-						}
1184
-					});
1185
-				}
1186
-
1187
-				if ($this->shouldEmitHooks($path) && $result !== false) {
1188
-					if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
1189
-						$this->runHooks($hooks, $path, true);
1190
-					}
1191
-				}
1192
-
1193
-				if (!$unlockLater
1194
-					&& (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks))
1195
-				) {
1196
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1197
-				}
1198
-				return $result;
1199
-			} else {
1200
-				$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1201
-			}
1202
-		}
1203
-		return null;
1204
-	}
1205
-
1206
-	/**
1207
-	 * get the path relative to the default root for hook usage
1208
-	 *
1209
-	 * @param string $path
1210
-	 * @return string
1211
-	 */
1212
-	private function getHookPath($path) {
1213
-		if (!Filesystem::getView()) {
1214
-			return $path;
1215
-		}
1216
-		return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path));
1217
-	}
1218
-
1219
-	private function shouldEmitHooks($path = '') {
1220
-		if ($path && Cache\Scanner::isPartialFile($path)) {
1221
-			return false;
1222
-		}
1223
-		if (!Filesystem::$loaded) {
1224
-			return false;
1225
-		}
1226
-		$defaultRoot = Filesystem::getRoot();
1227
-		if ($defaultRoot === null) {
1228
-			return false;
1229
-		}
1230
-		if ($this->fakeRoot === $defaultRoot) {
1231
-			return true;
1232
-		}
1233
-		$fullPath = $this->getAbsolutePath($path);
1234
-
1235
-		if ($fullPath === $defaultRoot) {
1236
-			return true;
1237
-		}
1238
-
1239
-		return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1240
-	}
1241
-
1242
-	/**
1243
-	 * @param string[] $hooks
1244
-	 * @param string $path
1245
-	 * @param bool $post
1246
-	 * @return bool
1247
-	 */
1248
-	private function runHooks($hooks, $path, $post = false) {
1249
-		$relativePath = $path;
1250
-		$path = $this->getHookPath($path);
1251
-		$prefix = ($post) ? 'post_' : '';
1252
-		$run = true;
1253
-		if ($this->shouldEmitHooks($relativePath)) {
1254
-			foreach ($hooks as $hook) {
1255
-				if ($hook != 'read') {
1256
-					\OC_Hook::emit(
1257
-						Filesystem::CLASSNAME,
1258
-						$prefix . $hook,
1259
-						array(
1260
-							Filesystem::signal_param_run => &$run,
1261
-							Filesystem::signal_param_path => $path
1262
-						)
1263
-					);
1264
-				} elseif (!$post) {
1265
-					\OC_Hook::emit(
1266
-						Filesystem::CLASSNAME,
1267
-						$prefix . $hook,
1268
-						array(
1269
-							Filesystem::signal_param_path => $path
1270
-						)
1271
-					);
1272
-				}
1273
-			}
1274
-		}
1275
-		return $run;
1276
-	}
1277
-
1278
-	/**
1279
-	 * check if a file or folder has been updated since $time
1280
-	 *
1281
-	 * @param string $path
1282
-	 * @param int $time
1283
-	 * @return bool
1284
-	 */
1285
-	public function hasUpdated($path, $time) {
1286
-		return $this->basicOperation('hasUpdated', $path, array(), $time);
1287
-	}
1288
-
1289
-	/**
1290
-	 * @param string $ownerId
1291
-	 * @return \OC\User\User
1292
-	 */
1293
-	private function getUserObjectForOwner($ownerId) {
1294
-		$owner = $this->userManager->get($ownerId);
1295
-		if ($owner instanceof IUser) {
1296
-			return $owner;
1297
-		} else {
1298
-			return new User($ownerId, null);
1299
-		}
1300
-	}
1301
-
1302
-	/**
1303
-	 * Get file info from cache
1304
-	 *
1305
-	 * If the file is not in cached it will be scanned
1306
-	 * If the file has changed on storage the cache will be updated
1307
-	 *
1308
-	 * @param \OC\Files\Storage\Storage $storage
1309
-	 * @param string $internalPath
1310
-	 * @param string $relativePath
1311
-	 * @return ICacheEntry|bool
1312
-	 */
1313
-	private function getCacheEntry($storage, $internalPath, $relativePath) {
1314
-		$cache = $storage->getCache($internalPath);
1315
-		$data = $cache->get($internalPath);
1316
-		$watcher = $storage->getWatcher($internalPath);
1317
-
1318
-		try {
1319
-			// if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
1320
-			if (!$data || $data['size'] === -1) {
1321
-				if (!$storage->file_exists($internalPath)) {
1322
-					return false;
1323
-				}
1324
-				// don't need to get a lock here since the scanner does it's own locking
1325
-				$scanner = $storage->getScanner($internalPath);
1326
-				$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1327
-				$data = $cache->get($internalPath);
1328
-			} else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
1329
-				$this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1330
-				$watcher->update($internalPath, $data);
1331
-				$storage->getPropagator()->propagateChange($internalPath, time());
1332
-				$data = $cache->get($internalPath);
1333
-				$this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1334
-			}
1335
-		} catch (LockedException $e) {
1336
-			// if the file is locked we just use the old cache info
1337
-		}
1338
-
1339
-		return $data;
1340
-	}
1341
-
1342
-	/**
1343
-	 * get the filesystem info
1344
-	 *
1345
-	 * @param string $path
1346
-	 * @param boolean|string $includeMountPoints true to add mountpoint sizes,
1347
-	 * 'ext' to add only ext storage mount point sizes. Defaults to true.
1348
-	 * defaults to true
1349
-	 * @return \OC\Files\FileInfo|false False if file does not exist
1350
-	 */
1351
-	public function getFileInfo($path, $includeMountPoints = true) {
1352
-		$this->assertPathLength($path);
1353
-		if (!Filesystem::isValidPath($path)) {
1354
-			return false;
1355
-		}
1356
-		if (Cache\Scanner::isPartialFile($path)) {
1357
-			return $this->getPartFileInfo($path);
1358
-		}
1359
-		$relativePath = $path;
1360
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1361
-
1362
-		$mount = Filesystem::getMountManager()->find($path);
1363
-		if (!$mount) {
1364
-			return false;
1365
-		}
1366
-		$storage = $mount->getStorage();
1367
-		$internalPath = $mount->getInternalPath($path);
1368
-		if ($storage) {
1369
-			$data = $this->getCacheEntry($storage, $internalPath, $relativePath);
1370
-
1371
-			if (!$data instanceof ICacheEntry) {
1372
-				return false;
1373
-			}
1374
-
1375
-			if ($mount instanceof MoveableMount && $internalPath === '') {
1376
-				$data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
1377
-			}
1378
-
1379
-			$owner = $this->getUserObjectForOwner($storage->getOwner($internalPath));
1380
-			$info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
1381
-
1382
-			if ($data and isset($data['fileid'])) {
1383
-				if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
1384
-					//add the sizes of other mount points to the folder
1385
-					$extOnly = ($includeMountPoints === 'ext');
1386
-					$mounts = Filesystem::getMountManager()->findIn($path);
1387
-					$info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1388
-						$subStorage = $mount->getStorage();
1389
-						return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1390
-					}));
1391
-				}
1392
-			}
1393
-
1394
-			return $info;
1395
-		}
1396
-
1397
-		return false;
1398
-	}
1399
-
1400
-	/**
1401
-	 * get the content of a directory
1402
-	 *
1403
-	 * @param string $directory path under datadirectory
1404
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
1405
-	 * @return FileInfo[]
1406
-	 */
1407
-	public function getDirectoryContent($directory, $mimetype_filter = '') {
1408
-		$this->assertPathLength($directory);
1409
-		if (!Filesystem::isValidPath($directory)) {
1410
-			return [];
1411
-		}
1412
-		$path = $this->getAbsolutePath($directory);
1413
-		$path = Filesystem::normalizePath($path);
1414
-		$mount = $this->getMount($directory);
1415
-		if (!$mount) {
1416
-			return [];
1417
-		}
1418
-		$storage = $mount->getStorage();
1419
-		$internalPath = $mount->getInternalPath($path);
1420
-		if ($storage) {
1421
-			$cache = $storage->getCache($internalPath);
1422
-			$user = \OC_User::getUser();
1423
-
1424
-			$data = $this->getCacheEntry($storage, $internalPath, $directory);
1425
-
1426
-			if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
1427
-				return [];
1428
-			}
1429
-
1430
-			$folderId = $data['fileid'];
1431
-			$contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
1432
-
1433
-			$sharingDisabled = \OCP\Util::isSharingDisabledForUser();
1434
-
1435
-			$fileNames = array_map(function(ICacheEntry $content) {
1436
-				return $content->getName();
1437
-			}, $contents);
1438
-			/**
1439
-			 * @var \OC\Files\FileInfo[] $fileInfos
1440
-			 */
1441
-			$fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1442
-				if ($sharingDisabled) {
1443
-					$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1444
-				}
1445
-				$owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1446
-				return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1447
-			}, $contents);
1448
-			$files = array_combine($fileNames, $fileInfos);
1449
-
1450
-			//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
1451
-			$mounts = Filesystem::getMountManager()->findIn($path);
1452
-			$dirLength = strlen($path);
1453
-			foreach ($mounts as $mount) {
1454
-				$mountPoint = $mount->getMountPoint();
1455
-				$subStorage = $mount->getStorage();
1456
-				if ($subStorage) {
1457
-					$subCache = $subStorage->getCache('');
1458
-
1459
-					$rootEntry = $subCache->get('');
1460
-					if (!$rootEntry) {
1461
-						$subScanner = $subStorage->getScanner('');
1462
-						try {
1463
-							$subScanner->scanFile('');
1464
-						} catch (\OCP\Files\StorageNotAvailableException $e) {
1465
-							continue;
1466
-						} catch (\OCP\Files\StorageInvalidException $e) {
1467
-							continue;
1468
-						} catch (\Exception $e) {
1469
-							// sometimes when the storage is not available it can be any exception
1470
-							\OCP\Util::writeLog(
1471
-								'core',
1472
-								'Exception while scanning storage "' . $subStorage->getId() . '": ' .
1473
-								get_class($e) . ': ' . $e->getMessage(),
1474
-								\OCP\Util::ERROR
1475
-							);
1476
-							continue;
1477
-						}
1478
-						$rootEntry = $subCache->get('');
1479
-					}
1480
-
1481
-					if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
1482
-						$relativePath = trim(substr($mountPoint, $dirLength), '/');
1483
-						if ($pos = strpos($relativePath, '/')) {
1484
-							//mountpoint inside subfolder add size to the correct folder
1485
-							$entryName = substr($relativePath, 0, $pos);
1486
-							foreach ($files as &$entry) {
1487
-								if ($entry->getName() === $entryName) {
1488
-									$entry->addSubEntry($rootEntry, $mountPoint);
1489
-								}
1490
-							}
1491
-						} else { //mountpoint in this folder, add an entry for it
1492
-							$rootEntry['name'] = $relativePath;
1493
-							$rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
1494
-							$permissions = $rootEntry['permissions'];
1495
-							// do not allow renaming/deleting the mount point if they are not shared files/folders
1496
-							// for shared files/folders we use the permissions given by the owner
1497
-							if ($mount instanceof MoveableMount) {
1498
-								$rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
1499
-							} else {
1500
-								$rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
1501
-							}
1502
-
1503
-							$rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1504
-
1505
-							// if sharing was disabled for the user we remove the share permissions
1506
-							if (\OCP\Util::isSharingDisabledForUser()) {
1507
-								$rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1508
-							}
1509
-
1510
-							$owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1511
-							$files[$rootEntry->getName()] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1512
-						}
1513
-					}
1514
-				}
1515
-			}
1516
-
1517
-			if ($mimetype_filter) {
1518
-				$files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1519
-					if (strpos($mimetype_filter, '/')) {
1520
-						return $file->getMimetype() === $mimetype_filter;
1521
-					} else {
1522
-						return $file->getMimePart() === $mimetype_filter;
1523
-					}
1524
-				});
1525
-			}
1526
-
1527
-			return array_values($files);
1528
-		} else {
1529
-			return [];
1530
-		}
1531
-	}
1532
-
1533
-	/**
1534
-	 * change file metadata
1535
-	 *
1536
-	 * @param string $path
1537
-	 * @param array|\OCP\Files\FileInfo $data
1538
-	 * @return int
1539
-	 *
1540
-	 * returns the fileid of the updated file
1541
-	 */
1542
-	public function putFileInfo($path, $data) {
1543
-		$this->assertPathLength($path);
1544
-		if ($data instanceof FileInfo) {
1545
-			$data = $data->getData();
1546
-		}
1547
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1548
-		/**
1549
-		 * @var \OC\Files\Storage\Storage $storage
1550
-		 * @var string $internalPath
1551
-		 */
1552
-		list($storage, $internalPath) = Filesystem::resolvePath($path);
1553
-		if ($storage) {
1554
-			$cache = $storage->getCache($path);
1555
-
1556
-			if (!$cache->inCache($internalPath)) {
1557
-				$scanner = $storage->getScanner($internalPath);
1558
-				$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1559
-			}
1560
-
1561
-			return $cache->put($internalPath, $data);
1562
-		} else {
1563
-			return -1;
1564
-		}
1565
-	}
1566
-
1567
-	/**
1568
-	 * search for files with the name matching $query
1569
-	 *
1570
-	 * @param string $query
1571
-	 * @return FileInfo[]
1572
-	 */
1573
-	public function search($query) {
1574
-		return $this->searchCommon('search', array('%' . $query . '%'));
1575
-	}
1576
-
1577
-	/**
1578
-	 * search for files with the name matching $query
1579
-	 *
1580
-	 * @param string $query
1581
-	 * @return FileInfo[]
1582
-	 */
1583
-	public function searchRaw($query) {
1584
-		return $this->searchCommon('search', array($query));
1585
-	}
1586
-
1587
-	/**
1588
-	 * search for files by mimetype
1589
-	 *
1590
-	 * @param string $mimetype
1591
-	 * @return FileInfo[]
1592
-	 */
1593
-	public function searchByMime($mimetype) {
1594
-		return $this->searchCommon('searchByMime', array($mimetype));
1595
-	}
1596
-
1597
-	/**
1598
-	 * search for files by tag
1599
-	 *
1600
-	 * @param string|int $tag name or tag id
1601
-	 * @param string $userId owner of the tags
1602
-	 * @return FileInfo[]
1603
-	 */
1604
-	public function searchByTag($tag, $userId) {
1605
-		return $this->searchCommon('searchByTag', array($tag, $userId));
1606
-	}
1607
-
1608
-	/**
1609
-	 * @param string $method cache method
1610
-	 * @param array $args
1611
-	 * @return FileInfo[]
1612
-	 */
1613
-	private function searchCommon($method, $args) {
1614
-		$files = array();
1615
-		$rootLength = strlen($this->fakeRoot);
1616
-
1617
-		$mount = $this->getMount('');
1618
-		$mountPoint = $mount->getMountPoint();
1619
-		$storage = $mount->getStorage();
1620
-		if ($storage) {
1621
-			$cache = $storage->getCache('');
1622
-
1623
-			$results = call_user_func_array(array($cache, $method), $args);
1624
-			foreach ($results as $result) {
1625
-				if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1626
-					$internalPath = $result['path'];
1627
-					$path = $mountPoint . $result['path'];
1628
-					$result['path'] = substr($mountPoint . $result['path'], $rootLength);
1629
-					$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1630
-					$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1631
-				}
1632
-			}
1633
-
1634
-			$mounts = Filesystem::getMountManager()->findIn($this->fakeRoot);
1635
-			foreach ($mounts as $mount) {
1636
-				$mountPoint = $mount->getMountPoint();
1637
-				$storage = $mount->getStorage();
1638
-				if ($storage) {
1639
-					$cache = $storage->getCache('');
1640
-
1641
-					$relativeMountPoint = substr($mountPoint, $rootLength);
1642
-					$results = call_user_func_array(array($cache, $method), $args);
1643
-					if ($results) {
1644
-						foreach ($results as $result) {
1645
-							$internalPath = $result['path'];
1646
-							$result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1647
-							$path = rtrim($mountPoint . $internalPath, '/');
1648
-							$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1649
-							$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1650
-						}
1651
-					}
1652
-				}
1653
-			}
1654
-		}
1655
-		return $files;
1656
-	}
1657
-
1658
-	/**
1659
-	 * Get the owner for a file or folder
1660
-	 *
1661
-	 * @param string $path
1662
-	 * @return string the user id of the owner
1663
-	 * @throws NotFoundException
1664
-	 */
1665
-	public function getOwner($path) {
1666
-		$info = $this->getFileInfo($path);
1667
-		if (!$info) {
1668
-			throw new NotFoundException($path . ' not found while trying to get owner');
1669
-		}
1670
-		return $info->getOwner()->getUID();
1671
-	}
1672
-
1673
-	/**
1674
-	 * get the ETag for a file or folder
1675
-	 *
1676
-	 * @param string $path
1677
-	 * @return string
1678
-	 */
1679
-	public function getETag($path) {
1680
-		/**
1681
-		 * @var Storage\Storage $storage
1682
-		 * @var string $internalPath
1683
-		 */
1684
-		list($storage, $internalPath) = $this->resolvePath($path);
1685
-		if ($storage) {
1686
-			return $storage->getETag($internalPath);
1687
-		} else {
1688
-			return null;
1689
-		}
1690
-	}
1691
-
1692
-	/**
1693
-	 * Get the path of a file by id, relative to the view
1694
-	 *
1695
-	 * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
1696
-	 *
1697
-	 * @param int $id
1698
-	 * @throws NotFoundException
1699
-	 * @return string
1700
-	 */
1701
-	public function getPath($id) {
1702
-		$id = (int)$id;
1703
-		$manager = Filesystem::getMountManager();
1704
-		$mounts = $manager->findIn($this->fakeRoot);
1705
-		$mounts[] = $manager->find($this->fakeRoot);
1706
-		// reverse the array so we start with the storage this view is in
1707
-		// which is the most likely to contain the file we're looking for
1708
-		$mounts = array_reverse($mounts);
1709
-		foreach ($mounts as $mount) {
1710
-			/**
1711
-			 * @var \OC\Files\Mount\MountPoint $mount
1712
-			 */
1713
-			if ($mount->getStorage()) {
1714
-				$cache = $mount->getStorage()->getCache();
1715
-				$internalPath = $cache->getPathById($id);
1716
-				if (is_string($internalPath)) {
1717
-					$fullPath = $mount->getMountPoint() . $internalPath;
1718
-					if (!is_null($path = $this->getRelativePath($fullPath))) {
1719
-						return $path;
1720
-					}
1721
-				}
1722
-			}
1723
-		}
1724
-		throw new NotFoundException(sprintf('File with id "%s" has not been found.', $id));
1725
-	}
1726
-
1727
-	/**
1728
-	 * @param string $path
1729
-	 * @throws InvalidPathException
1730
-	 */
1731
-	private function assertPathLength($path) {
1732
-		$maxLen = min(PHP_MAXPATHLEN, 4000);
1733
-		// Check for the string length - performed using isset() instead of strlen()
1734
-		// because isset() is about 5x-40x faster.
1735
-		if (isset($path[$maxLen])) {
1736
-			$pathLen = strlen($path);
1737
-			throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path");
1738
-		}
1739
-	}
1740
-
1741
-	/**
1742
-	 * check if it is allowed to move a mount point to a given target.
1743
-	 * It is not allowed to move a mount point into a different mount point or
1744
-	 * into an already shared folder
1745
-	 *
1746
-	 * @param string $target path
1747
-	 * @return boolean
1748
-	 */
1749
-	private function isTargetAllowed($target) {
1750
-
1751
-		list($targetStorage, $targetInternalPath) = \OC\Files\Filesystem::resolvePath($target);
1752
-		if (!$targetStorage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
1753
-			\OCP\Util::writeLog('files',
1754
-				'It is not allowed to move one mount point into another one',
1755
-				\OCP\Util::DEBUG);
1756
-			return false;
1757
-		}
1758
-
1759
-		// note: cannot use the view because the target is already locked
1760
-		$fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1761
-		if ($fileId === -1) {
1762
-			// target might not exist, need to check parent instead
1763
-			$fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1764
-		}
1765
-
1766
-		// check if any of the parents were shared by the current owner (include collections)
1767
-		$shares = \OCP\Share::getItemShared(
1768
-			'folder',
1769
-			$fileId,
1770
-			\OCP\Share::FORMAT_NONE,
1771
-			null,
1772
-			true
1773
-		);
1774
-
1775
-		if (count($shares) > 0) {
1776
-			\OCP\Util::writeLog('files',
1777
-				'It is not allowed to move one mount point into a shared folder',
1778
-				\OCP\Util::DEBUG);
1779
-			return false;
1780
-		}
1781
-
1782
-		return true;
1783
-	}
1784
-
1785
-	/**
1786
-	 * Get a fileinfo object for files that are ignored in the cache (part files)
1787
-	 *
1788
-	 * @param string $path
1789
-	 * @return \OCP\Files\FileInfo
1790
-	 */
1791
-	private function getPartFileInfo($path) {
1792
-		$mount = $this->getMount($path);
1793
-		$storage = $mount->getStorage();
1794
-		$internalPath = $mount->getInternalPath($this->getAbsolutePath($path));
1795
-		$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1796
-		return new FileInfo(
1797
-			$this->getAbsolutePath($path),
1798
-			$storage,
1799
-			$internalPath,
1800
-			[
1801
-				'fileid' => null,
1802
-				'mimetype' => $storage->getMimeType($internalPath),
1803
-				'name' => basename($path),
1804
-				'etag' => null,
1805
-				'size' => $storage->filesize($internalPath),
1806
-				'mtime' => $storage->filemtime($internalPath),
1807
-				'encrypted' => false,
1808
-				'permissions' => \OCP\Constants::PERMISSION_ALL
1809
-			],
1810
-			$mount,
1811
-			$owner
1812
-		);
1813
-	}
1814
-
1815
-	/**
1816
-	 * @param string $path
1817
-	 * @param string $fileName
1818
-	 * @throws InvalidPathException
1819
-	 */
1820
-	public function verifyPath($path, $fileName) {
1821
-		try {
1822
-			/** @type \OCP\Files\Storage $storage */
1823
-			list($storage, $internalPath) = $this->resolvePath($path);
1824
-			$storage->verifyPath($internalPath, $fileName);
1825
-		} catch (ReservedWordException $ex) {
1826
-			$l = \OC::$server->getL10N('lib');
1827
-			throw new InvalidPathException($l->t('File name is a reserved word'));
1828
-		} catch (InvalidCharacterInPathException $ex) {
1829
-			$l = \OC::$server->getL10N('lib');
1830
-			throw new InvalidPathException($l->t('File name contains at least one invalid character'));
1831
-		} catch (FileNameTooLongException $ex) {
1832
-			$l = \OC::$server->getL10N('lib');
1833
-			throw new InvalidPathException($l->t('File name is too long'));
1834
-		} catch (InvalidDirectoryException $ex) {
1835
-			$l = \OC::$server->getL10N('lib');
1836
-			throw new InvalidPathException($l->t('Dot files are not allowed'));
1837
-		} catch (EmptyFileNameException $ex) {
1838
-			$l = \OC::$server->getL10N('lib');
1839
-			throw new InvalidPathException($l->t('Empty filename is not allowed'));
1840
-		}
1841
-	}
1842
-
1843
-	/**
1844
-	 * get all parent folders of $path
1845
-	 *
1846
-	 * @param string $path
1847
-	 * @return string[]
1848
-	 */
1849
-	private function getParents($path) {
1850
-		$path = trim($path, '/');
1851
-		if (!$path) {
1852
-			return [];
1853
-		}
1854
-
1855
-		$parts = explode('/', $path);
1856
-
1857
-		// remove the single file
1858
-		array_pop($parts);
1859
-		$result = array('/');
1860
-		$resultPath = '';
1861
-		foreach ($parts as $part) {
1862
-			if ($part) {
1863
-				$resultPath .= '/' . $part;
1864
-				$result[] = $resultPath;
1865
-			}
1866
-		}
1867
-		return $result;
1868
-	}
1869
-
1870
-	/**
1871
-	 * Returns the mount point for which to lock
1872
-	 *
1873
-	 * @param string $absolutePath absolute path
1874
-	 * @param bool $useParentMount true to return parent mount instead of whatever
1875
-	 * is mounted directly on the given path, false otherwise
1876
-	 * @return \OC\Files\Mount\MountPoint mount point for which to apply locks
1877
-	 */
1878
-	private function getMountForLock($absolutePath, $useParentMount = false) {
1879
-		$results = [];
1880
-		$mount = Filesystem::getMountManager()->find($absolutePath);
1881
-		if (!$mount) {
1882
-			return $results;
1883
-		}
1884
-
1885
-		if ($useParentMount) {
1886
-			// find out if something is mounted directly on the path
1887
-			$internalPath = $mount->getInternalPath($absolutePath);
1888
-			if ($internalPath === '') {
1889
-				// resolve the parent mount instead
1890
-				$mount = Filesystem::getMountManager()->find(dirname($absolutePath));
1891
-			}
1892
-		}
1893
-
1894
-		return $mount;
1895
-	}
1896
-
1897
-	/**
1898
-	 * Lock the given path
1899
-	 *
1900
-	 * @param string $path the path of the file to lock, relative to the view
1901
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1902
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1903
-	 *
1904
-	 * @return bool False if the path is excluded from locking, true otherwise
1905
-	 * @throws \OCP\Lock\LockedException if the path is already locked
1906
-	 */
1907
-	private function lockPath($path, $type, $lockMountPoint = false) {
1908
-		$absolutePath = $this->getAbsolutePath($path);
1909
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1910
-		if (!$this->shouldLockFile($absolutePath)) {
1911
-			return false;
1912
-		}
1913
-
1914
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1915
-		if ($mount) {
1916
-			try {
1917
-				$storage = $mount->getStorage();
1918
-				if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1919
-					$storage->acquireLock(
1920
-						$mount->getInternalPath($absolutePath),
1921
-						$type,
1922
-						$this->lockingProvider
1923
-					);
1924
-				}
1925
-			} catch (\OCP\Lock\LockedException $e) {
1926
-				// rethrow with the a human-readable path
1927
-				throw new \OCP\Lock\LockedException(
1928
-					$this->getPathRelativeToFiles($absolutePath),
1929
-					$e
1930
-				);
1931
-			}
1932
-		}
1933
-
1934
-		return true;
1935
-	}
1936
-
1937
-	/**
1938
-	 * Change the lock type
1939
-	 *
1940
-	 * @param string $path the path of the file to lock, relative to the view
1941
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1942
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1943
-	 *
1944
-	 * @return bool False if the path is excluded from locking, true otherwise
1945
-	 * @throws \OCP\Lock\LockedException if the path is already locked
1946
-	 */
1947
-	public function changeLock($path, $type, $lockMountPoint = false) {
1948
-		$path = Filesystem::normalizePath($path);
1949
-		$absolutePath = $this->getAbsolutePath($path);
1950
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1951
-		if (!$this->shouldLockFile($absolutePath)) {
1952
-			return false;
1953
-		}
1954
-
1955
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1956
-		if ($mount) {
1957
-			try {
1958
-				$storage = $mount->getStorage();
1959
-				if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1960
-					$storage->changeLock(
1961
-						$mount->getInternalPath($absolutePath),
1962
-						$type,
1963
-						$this->lockingProvider
1964
-					);
1965
-				}
1966
-			} catch (\OCP\Lock\LockedException $e) {
1967
-				try {
1968
-					// rethrow with the a human-readable path
1969
-					throw new \OCP\Lock\LockedException(
1970
-						$this->getPathRelativeToFiles($absolutePath),
1971
-						$e
1972
-					);
1973
-				} catch (\InvalidArgumentException $e) {
1974
-					throw new \OCP\Lock\LockedException(
1975
-						$absolutePath,
1976
-						$e
1977
-					);
1978
-				}
1979
-			}
1980
-		}
1981
-
1982
-		return true;
1983
-	}
1984
-
1985
-	/**
1986
-	 * Unlock the given path
1987
-	 *
1988
-	 * @param string $path the path of the file to unlock, relative to the view
1989
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1990
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1991
-	 *
1992
-	 * @return bool False if the path is excluded from locking, true otherwise
1993
-	 */
1994
-	private function unlockPath($path, $type, $lockMountPoint = false) {
1995
-		$absolutePath = $this->getAbsolutePath($path);
1996
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1997
-		if (!$this->shouldLockFile($absolutePath)) {
1998
-			return false;
1999
-		}
2000
-
2001
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
2002
-		if ($mount) {
2003
-			$storage = $mount->getStorage();
2004
-			if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2005
-				$storage->releaseLock(
2006
-					$mount->getInternalPath($absolutePath),
2007
-					$type,
2008
-					$this->lockingProvider
2009
-				);
2010
-			}
2011
-		}
2012
-
2013
-		return true;
2014
-	}
2015
-
2016
-	/**
2017
-	 * Lock a path and all its parents up to the root of the view
2018
-	 *
2019
-	 * @param string $path the path of the file to lock relative to the view
2020
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2021
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2022
-	 *
2023
-	 * @return bool False if the path is excluded from locking, true otherwise
2024
-	 */
2025
-	public function lockFile($path, $type, $lockMountPoint = false) {
2026
-		$absolutePath = $this->getAbsolutePath($path);
2027
-		$absolutePath = Filesystem::normalizePath($absolutePath);
2028
-		if (!$this->shouldLockFile($absolutePath)) {
2029
-			return false;
2030
-		}
2031
-
2032
-		$this->lockPath($path, $type, $lockMountPoint);
2033
-
2034
-		$parents = $this->getParents($path);
2035
-		foreach ($parents as $parent) {
2036
-			$this->lockPath($parent, ILockingProvider::LOCK_SHARED);
2037
-		}
2038
-
2039
-		return true;
2040
-	}
2041
-
2042
-	/**
2043
-	 * Unlock a path and all its parents up to the root of the view
2044
-	 *
2045
-	 * @param string $path the path of the file to lock relative to the view
2046
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2047
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2048
-	 *
2049
-	 * @return bool False if the path is excluded from locking, true otherwise
2050
-	 */
2051
-	public function unlockFile($path, $type, $lockMountPoint = false) {
2052
-		$absolutePath = $this->getAbsolutePath($path);
2053
-		$absolutePath = Filesystem::normalizePath($absolutePath);
2054
-		if (!$this->shouldLockFile($absolutePath)) {
2055
-			return false;
2056
-		}
2057
-
2058
-		$this->unlockPath($path, $type, $lockMountPoint);
2059
-
2060
-		$parents = $this->getParents($path);
2061
-		foreach ($parents as $parent) {
2062
-			$this->unlockPath($parent, ILockingProvider::LOCK_SHARED);
2063
-		}
2064
-
2065
-		return true;
2066
-	}
2067
-
2068
-	/**
2069
-	 * Only lock files in data/user/files/
2070
-	 *
2071
-	 * @param string $path Absolute path to the file/folder we try to (un)lock
2072
-	 * @return bool
2073
-	 */
2074
-	protected function shouldLockFile($path) {
2075
-		$path = Filesystem::normalizePath($path);
2076
-
2077
-		$pathSegments = explode('/', $path);
2078
-		if (isset($pathSegments[2])) {
2079
-			// E.g.: /username/files/path-to-file
2080
-			return ($pathSegments[2] === 'files') && (count($pathSegments) > 3);
2081
-		}
2082
-
2083
-		return strpos($path, '/appdata_') !== 0;
2084
-	}
2085
-
2086
-	/**
2087
-	 * Shortens the given absolute path to be relative to
2088
-	 * "$user/files".
2089
-	 *
2090
-	 * @param string $absolutePath absolute path which is under "files"
2091
-	 *
2092
-	 * @return string path relative to "files" with trimmed slashes or null
2093
-	 * if the path was NOT relative to files
2094
-	 *
2095
-	 * @throws \InvalidArgumentException if the given path was not under "files"
2096
-	 * @since 8.1.0
2097
-	 */
2098
-	public function getPathRelativeToFiles($absolutePath) {
2099
-		$path = Filesystem::normalizePath($absolutePath);
2100
-		$parts = explode('/', trim($path, '/'), 3);
2101
-		// "$user", "files", "path/to/dir"
2102
-		if (!isset($parts[1]) || $parts[1] !== 'files') {
2103
-			$this->logger->error(
2104
-				'$absolutePath must be relative to "files", value is "%s"',
2105
-				[
2106
-					$absolutePath
2107
-				]
2108
-			);
2109
-			throw new \InvalidArgumentException('$absolutePath must be relative to "files"');
2110
-		}
2111
-		if (isset($parts[2])) {
2112
-			return $parts[2];
2113
-		}
2114
-		return '';
2115
-	}
2116
-
2117
-	/**
2118
-	 * @param string $filename
2119
-	 * @return array
2120
-	 * @throws \OC\User\NoUserException
2121
-	 * @throws NotFoundException
2122
-	 */
2123
-	public function getUidAndFilename($filename) {
2124
-		$info = $this->getFileInfo($filename);
2125
-		if (!$info instanceof \OCP\Files\FileInfo) {
2126
-			throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2127
-		}
2128
-		$uid = $info->getOwner()->getUID();
2129
-		if ($uid != \OCP\User::getUser()) {
2130
-			Filesystem::initMountPoints($uid);
2131
-			$ownerView = new View('/' . $uid . '/files');
2132
-			try {
2133
-				$filename = $ownerView->getPath($info['fileid']);
2134
-			} catch (NotFoundException $e) {
2135
-				throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2136
-			}
2137
-		}
2138
-		return [$uid, $filename];
2139
-	}
2140
-
2141
-	/**
2142
-	 * Creates parent non-existing folders
2143
-	 *
2144
-	 * @param string $filePath
2145
-	 * @return bool
2146
-	 */
2147
-	private function createParentDirectories($filePath) {
2148
-		$directoryParts = explode('/', $filePath);
2149
-		$directoryParts = array_filter($directoryParts);
2150
-		foreach ($directoryParts as $key => $part) {
2151
-			$currentPathElements = array_slice($directoryParts, 0, $key);
2152
-			$currentPath = '/' . implode('/', $currentPathElements);
2153
-			if ($this->is_file($currentPath)) {
2154
-				return false;
2155
-			}
2156
-			if (!$this->file_exists($currentPath)) {
2157
-				$this->mkdir($currentPath);
2158
-			}
2159
-		}
2160
-
2161
-		return true;
2162
-	}
83
+    /** @var string */
84
+    private $fakeRoot = '';
85
+
86
+    /**
87
+     * @var \OCP\Lock\ILockingProvider
88
+     */
89
+    protected $lockingProvider;
90
+
91
+    private $lockingEnabled;
92
+
93
+    private $updaterEnabled = true;
94
+
95
+    /** @var \OC\User\Manager */
96
+    private $userManager;
97
+
98
+    /** @var \OCP\ILogger */
99
+    private $logger;
100
+
101
+    /**
102
+     * @param string $root
103
+     * @throws \Exception If $root contains an invalid path
104
+     */
105
+    public function __construct($root = '') {
106
+        if (is_null($root)) {
107
+            throw new \InvalidArgumentException('Root can\'t be null');
108
+        }
109
+        if (!Filesystem::isValidPath($root)) {
110
+            throw new \Exception();
111
+        }
112
+
113
+        $this->fakeRoot = $root;
114
+        $this->lockingProvider = \OC::$server->getLockingProvider();
115
+        $this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
116
+        $this->userManager = \OC::$server->getUserManager();
117
+        $this->logger = \OC::$server->getLogger();
118
+    }
119
+
120
+    public function getAbsolutePath($path = '/') {
121
+        if ($path === null) {
122
+            return null;
123
+        }
124
+        $this->assertPathLength($path);
125
+        if ($path === '') {
126
+            $path = '/';
127
+        }
128
+        if ($path[0] !== '/') {
129
+            $path = '/' . $path;
130
+        }
131
+        return $this->fakeRoot . $path;
132
+    }
133
+
134
+    /**
135
+     * change the root to a fake root
136
+     *
137
+     * @param string $fakeRoot
138
+     * @return boolean|null
139
+     */
140
+    public function chroot($fakeRoot) {
141
+        if (!$fakeRoot == '') {
142
+            if ($fakeRoot[0] !== '/') {
143
+                $fakeRoot = '/' . $fakeRoot;
144
+            }
145
+        }
146
+        $this->fakeRoot = $fakeRoot;
147
+    }
148
+
149
+    /**
150
+     * get the fake root
151
+     *
152
+     * @return string
153
+     */
154
+    public function getRoot() {
155
+        return $this->fakeRoot;
156
+    }
157
+
158
+    /**
159
+     * get path relative to the root of the view
160
+     *
161
+     * @param string $path
162
+     * @return string
163
+     */
164
+    public function getRelativePath($path) {
165
+        $this->assertPathLength($path);
166
+        if ($this->fakeRoot == '') {
167
+            return $path;
168
+        }
169
+
170
+        if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) {
171
+            return '/';
172
+        }
173
+
174
+        // missing slashes can cause wrong matches!
175
+        $root = rtrim($this->fakeRoot, '/') . '/';
176
+
177
+        if (strpos($path, $root) !== 0) {
178
+            return null;
179
+        } else {
180
+            $path = substr($path, strlen($this->fakeRoot));
181
+            if (strlen($path) === 0) {
182
+                return '/';
183
+            } else {
184
+                return $path;
185
+            }
186
+        }
187
+    }
188
+
189
+    /**
190
+     * get the mountpoint of the storage object for a path
191
+     * ( note: because a storage is not always mounted inside the fakeroot, the
192
+     * returned mountpoint is relative to the absolute root of the filesystem
193
+     * and does not take the chroot into account )
194
+     *
195
+     * @param string $path
196
+     * @return string
197
+     */
198
+    public function getMountPoint($path) {
199
+        return Filesystem::getMountPoint($this->getAbsolutePath($path));
200
+    }
201
+
202
+    /**
203
+     * get the mountpoint of the storage object for a path
204
+     * ( note: because a storage is not always mounted inside the fakeroot, the
205
+     * returned mountpoint is relative to the absolute root of the filesystem
206
+     * and does not take the chroot into account )
207
+     *
208
+     * @param string $path
209
+     * @return \OCP\Files\Mount\IMountPoint
210
+     */
211
+    public function getMount($path) {
212
+        return Filesystem::getMountManager()->find($this->getAbsolutePath($path));
213
+    }
214
+
215
+    /**
216
+     * resolve a path to a storage and internal path
217
+     *
218
+     * @param string $path
219
+     * @return array an array consisting of the storage and the internal path
220
+     */
221
+    public function resolvePath($path) {
222
+        $a = $this->getAbsolutePath($path);
223
+        $p = Filesystem::normalizePath($a);
224
+        return Filesystem::resolvePath($p);
225
+    }
226
+
227
+    /**
228
+     * return the path to a local version of the file
229
+     * we need this because we can't know if a file is stored local or not from
230
+     * outside the filestorage and for some purposes a local file is needed
231
+     *
232
+     * @param string $path
233
+     * @return string
234
+     */
235
+    public function getLocalFile($path) {
236
+        $parent = substr($path, 0, strrpos($path, '/'));
237
+        $path = $this->getAbsolutePath($path);
238
+        list($storage, $internalPath) = Filesystem::resolvePath($path);
239
+        if (Filesystem::isValidPath($parent) and $storage) {
240
+            return $storage->getLocalFile($internalPath);
241
+        } else {
242
+            return null;
243
+        }
244
+    }
245
+
246
+    /**
247
+     * @param string $path
248
+     * @return string
249
+     */
250
+    public function getLocalFolder($path) {
251
+        $parent = substr($path, 0, strrpos($path, '/'));
252
+        $path = $this->getAbsolutePath($path);
253
+        list($storage, $internalPath) = Filesystem::resolvePath($path);
254
+        if (Filesystem::isValidPath($parent) and $storage) {
255
+            return $storage->getLocalFolder($internalPath);
256
+        } else {
257
+            return null;
258
+        }
259
+    }
260
+
261
+    /**
262
+     * the following functions operate with arguments and return values identical
263
+     * to those of their PHP built-in equivalents. Mostly they are merely wrappers
264
+     * for \OC\Files\Storage\Storage via basicOperation().
265
+     */
266
+    public function mkdir($path) {
267
+        return $this->basicOperation('mkdir', $path, array('create', 'write'));
268
+    }
269
+
270
+    /**
271
+     * remove mount point
272
+     *
273
+     * @param \OC\Files\Mount\MoveableMount $mount
274
+     * @param string $path relative to data/
275
+     * @return boolean
276
+     */
277
+    protected function removeMount($mount, $path) {
278
+        if ($mount instanceof MoveableMount) {
279
+            // cut of /user/files to get the relative path to data/user/files
280
+            $pathParts = explode('/', $path, 4);
281
+            $relPath = '/' . $pathParts[3];
282
+            $this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
283
+            \OC_Hook::emit(
284
+                Filesystem::CLASSNAME, "umount",
285
+                array(Filesystem::signal_param_path => $relPath)
286
+            );
287
+            $this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true);
288
+            $result = $mount->removeMount();
289
+            $this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true);
290
+            if ($result) {
291
+                \OC_Hook::emit(
292
+                    Filesystem::CLASSNAME, "post_umount",
293
+                    array(Filesystem::signal_param_path => $relPath)
294
+                );
295
+            }
296
+            $this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true);
297
+            return $result;
298
+        } else {
299
+            // do not allow deleting the storage's root / the mount point
300
+            // because for some storages it might delete the whole contents
301
+            // but isn't supposed to work that way
302
+            return false;
303
+        }
304
+    }
305
+
306
+    public function disableCacheUpdate() {
307
+        $this->updaterEnabled = false;
308
+    }
309
+
310
+    public function enableCacheUpdate() {
311
+        $this->updaterEnabled = true;
312
+    }
313
+
314
+    protected function writeUpdate(Storage $storage, $internalPath, $time = null) {
315
+        if ($this->updaterEnabled) {
316
+            if (is_null($time)) {
317
+                $time = time();
318
+            }
319
+            $storage->getUpdater()->update($internalPath, $time);
320
+        }
321
+    }
322
+
323
+    protected function removeUpdate(Storage $storage, $internalPath) {
324
+        if ($this->updaterEnabled) {
325
+            $storage->getUpdater()->remove($internalPath);
326
+        }
327
+    }
328
+
329
+    protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) {
330
+        if ($this->updaterEnabled) {
331
+            $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
332
+        }
333
+    }
334
+
335
+    /**
336
+     * @param string $path
337
+     * @return bool|mixed
338
+     */
339
+    public function rmdir($path) {
340
+        $absolutePath = $this->getAbsolutePath($path);
341
+        $mount = Filesystem::getMountManager()->find($absolutePath);
342
+        if ($mount->getInternalPath($absolutePath) === '') {
343
+            return $this->removeMount($mount, $absolutePath);
344
+        }
345
+        if ($this->is_dir($path)) {
346
+            $result = $this->basicOperation('rmdir', $path, array('delete'));
347
+        } else {
348
+            $result = false;
349
+        }
350
+
351
+        if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
352
+            $storage = $mount->getStorage();
353
+            $internalPath = $mount->getInternalPath($absolutePath);
354
+            $storage->getUpdater()->remove($internalPath);
355
+        }
356
+        return $result;
357
+    }
358
+
359
+    /**
360
+     * @param string $path
361
+     * @return resource
362
+     */
363
+    public function opendir($path) {
364
+        return $this->basicOperation('opendir', $path, array('read'));
365
+    }
366
+
367
+    /**
368
+     * @param string $path
369
+     * @return bool|mixed
370
+     */
371
+    public function is_dir($path) {
372
+        if ($path == '/') {
373
+            return true;
374
+        }
375
+        return $this->basicOperation('is_dir', $path);
376
+    }
377
+
378
+    /**
379
+     * @param string $path
380
+     * @return bool|mixed
381
+     */
382
+    public function is_file($path) {
383
+        if ($path == '/') {
384
+            return false;
385
+        }
386
+        return $this->basicOperation('is_file', $path);
387
+    }
388
+
389
+    /**
390
+     * @param string $path
391
+     * @return mixed
392
+     */
393
+    public function stat($path) {
394
+        return $this->basicOperation('stat', $path);
395
+    }
396
+
397
+    /**
398
+     * @param string $path
399
+     * @return mixed
400
+     */
401
+    public function filetype($path) {
402
+        return $this->basicOperation('filetype', $path);
403
+    }
404
+
405
+    /**
406
+     * @param string $path
407
+     * @return mixed
408
+     */
409
+    public function filesize($path) {
410
+        return $this->basicOperation('filesize', $path);
411
+    }
412
+
413
+    /**
414
+     * @param string $path
415
+     * @return bool|mixed
416
+     * @throws \OCP\Files\InvalidPathException
417
+     */
418
+    public function readfile($path) {
419
+        $this->assertPathLength($path);
420
+        @ob_end_clean();
421
+        $handle = $this->fopen($path, 'rb');
422
+        if ($handle) {
423
+            $chunkSize = 8192; // 8 kB chunks
424
+            while (!feof($handle)) {
425
+                echo fread($handle, $chunkSize);
426
+                flush();
427
+            }
428
+            fclose($handle);
429
+            $size = $this->filesize($path);
430
+            return $size;
431
+        }
432
+        return false;
433
+    }
434
+
435
+    /**
436
+     * @param string $path
437
+     * @param int $from
438
+     * @param int $to
439
+     * @return bool|mixed
440
+     * @throws \OCP\Files\InvalidPathException
441
+     * @throws \OCP\Files\UnseekableException
442
+     */
443
+    public function readfilePart($path, $from, $to) {
444
+        $this->assertPathLength($path);
445
+        @ob_end_clean();
446
+        $handle = $this->fopen($path, 'rb');
447
+        if ($handle) {
448
+            $chunkSize = 8192; // 8 kB chunks
449
+            $startReading = true;
450
+
451
+            if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) {
452
+                // forward file handle via chunked fread because fseek seem to have failed
453
+
454
+                $end = $from + 1;
455
+                while (!feof($handle) && ftell($handle) < $end) {
456
+                    $len = $from - ftell($handle);
457
+                    if ($len > $chunkSize) {
458
+                        $len = $chunkSize;
459
+                    }
460
+                    $result = fread($handle, $len);
461
+
462
+                    if ($result === false) {
463
+                        $startReading = false;
464
+                        break;
465
+                    }
466
+                }
467
+            }
468
+
469
+            if ($startReading) {
470
+                $end = $to + 1;
471
+                while (!feof($handle) && ftell($handle) < $end) {
472
+                    $len = $end - ftell($handle);
473
+                    if ($len > $chunkSize) {
474
+                        $len = $chunkSize;
475
+                    }
476
+                    echo fread($handle, $len);
477
+                    flush();
478
+                }
479
+                $size = ftell($handle) - $from;
480
+                return $size;
481
+            }
482
+
483
+            throw new \OCP\Files\UnseekableException('fseek error');
484
+        }
485
+        return false;
486
+    }
487
+
488
+    /**
489
+     * @param string $path
490
+     * @return mixed
491
+     */
492
+    public function isCreatable($path) {
493
+        return $this->basicOperation('isCreatable', $path);
494
+    }
495
+
496
+    /**
497
+     * @param string $path
498
+     * @return mixed
499
+     */
500
+    public function isReadable($path) {
501
+        return $this->basicOperation('isReadable', $path);
502
+    }
503
+
504
+    /**
505
+     * @param string $path
506
+     * @return mixed
507
+     */
508
+    public function isUpdatable($path) {
509
+        return $this->basicOperation('isUpdatable', $path);
510
+    }
511
+
512
+    /**
513
+     * @param string $path
514
+     * @return bool|mixed
515
+     */
516
+    public function isDeletable($path) {
517
+        $absolutePath = $this->getAbsolutePath($path);
518
+        $mount = Filesystem::getMountManager()->find($absolutePath);
519
+        if ($mount->getInternalPath($absolutePath) === '') {
520
+            return $mount instanceof MoveableMount;
521
+        }
522
+        return $this->basicOperation('isDeletable', $path);
523
+    }
524
+
525
+    /**
526
+     * @param string $path
527
+     * @return mixed
528
+     */
529
+    public function isSharable($path) {
530
+        return $this->basicOperation('isSharable', $path);
531
+    }
532
+
533
+    /**
534
+     * @param string $path
535
+     * @return bool|mixed
536
+     */
537
+    public function file_exists($path) {
538
+        if ($path == '/') {
539
+            return true;
540
+        }
541
+        return $this->basicOperation('file_exists', $path);
542
+    }
543
+
544
+    /**
545
+     * @param string $path
546
+     * @return mixed
547
+     */
548
+    public function filemtime($path) {
549
+        return $this->basicOperation('filemtime', $path);
550
+    }
551
+
552
+    /**
553
+     * @param string $path
554
+     * @param int|string $mtime
555
+     * @return bool
556
+     */
557
+    public function touch($path, $mtime = null) {
558
+        if (!is_null($mtime) and !is_numeric($mtime)) {
559
+            $mtime = strtotime($mtime);
560
+        }
561
+
562
+        $hooks = array('touch');
563
+
564
+        if (!$this->file_exists($path)) {
565
+            $hooks[] = 'create';
566
+            $hooks[] = 'write';
567
+        }
568
+        $result = $this->basicOperation('touch', $path, $hooks, $mtime);
569
+        if (!$result) {
570
+            // If create file fails because of permissions on external storage like SMB folders,
571
+            // check file exists and return false if not.
572
+            if (!$this->file_exists($path)) {
573
+                return false;
574
+            }
575
+            if (is_null($mtime)) {
576
+                $mtime = time();
577
+            }
578
+            //if native touch fails, we emulate it by changing the mtime in the cache
579
+            $this->putFileInfo($path, array('mtime' => floor($mtime)));
580
+        }
581
+        return true;
582
+    }
583
+
584
+    /**
585
+     * @param string $path
586
+     * @return mixed
587
+     */
588
+    public function file_get_contents($path) {
589
+        return $this->basicOperation('file_get_contents', $path, array('read'));
590
+    }
591
+
592
+    /**
593
+     * @param bool $exists
594
+     * @param string $path
595
+     * @param bool $run
596
+     */
597
+    protected function emit_file_hooks_pre($exists, $path, &$run) {
598
+        if (!$exists) {
599
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, array(
600
+                Filesystem::signal_param_path => $this->getHookPath($path),
601
+                Filesystem::signal_param_run => &$run,
602
+            ));
603
+        } else {
604
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, array(
605
+                Filesystem::signal_param_path => $this->getHookPath($path),
606
+                Filesystem::signal_param_run => &$run,
607
+            ));
608
+        }
609
+        \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, array(
610
+            Filesystem::signal_param_path => $this->getHookPath($path),
611
+            Filesystem::signal_param_run => &$run,
612
+        ));
613
+    }
614
+
615
+    /**
616
+     * @param bool $exists
617
+     * @param string $path
618
+     */
619
+    protected function emit_file_hooks_post($exists, $path) {
620
+        if (!$exists) {
621
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, array(
622
+                Filesystem::signal_param_path => $this->getHookPath($path),
623
+            ));
624
+        } else {
625
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, array(
626
+                Filesystem::signal_param_path => $this->getHookPath($path),
627
+            ));
628
+        }
629
+        \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, array(
630
+            Filesystem::signal_param_path => $this->getHookPath($path),
631
+        ));
632
+    }
633
+
634
+    /**
635
+     * @param string $path
636
+     * @param mixed $data
637
+     * @return bool|mixed
638
+     * @throws \Exception
639
+     */
640
+    public function file_put_contents($path, $data) {
641
+        if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
642
+            $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
643
+            if (Filesystem::isValidPath($path)
644
+                and !Filesystem::isFileBlacklisted($path)
645
+            ) {
646
+                $path = $this->getRelativePath($absolutePath);
647
+
648
+                $this->lockFile($path, ILockingProvider::LOCK_SHARED);
649
+
650
+                $exists = $this->file_exists($path);
651
+                $run = true;
652
+                if ($this->shouldEmitHooks($path)) {
653
+                    $this->emit_file_hooks_pre($exists, $path, $run);
654
+                }
655
+                if (!$run) {
656
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
657
+                    return false;
658
+                }
659
+
660
+                $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
661
+
662
+                /** @var \OC\Files\Storage\Storage $storage */
663
+                list($storage, $internalPath) = $this->resolvePath($path);
664
+                $target = $storage->fopen($internalPath, 'w');
665
+                if ($target) {
666
+                    list (, $result) = \OC_Helper::streamCopy($data, $target);
667
+                    fclose($target);
668
+                    fclose($data);
669
+
670
+                    $this->writeUpdate($storage, $internalPath);
671
+
672
+                    $this->changeLock($path, ILockingProvider::LOCK_SHARED);
673
+
674
+                    if ($this->shouldEmitHooks($path) && $result !== false) {
675
+                        $this->emit_file_hooks_post($exists, $path);
676
+                    }
677
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
678
+                    return $result;
679
+                } else {
680
+                    $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
681
+                    return false;
682
+                }
683
+            } else {
684
+                return false;
685
+            }
686
+        } else {
687
+            $hooks = ($this->file_exists($path)) ? array('update', 'write') : array('create', 'write');
688
+            return $this->basicOperation('file_put_contents', $path, $hooks, $data);
689
+        }
690
+    }
691
+
692
+    /**
693
+     * @param string $path
694
+     * @return bool|mixed
695
+     */
696
+    public function unlink($path) {
697
+        if ($path === '' || $path === '/') {
698
+            // do not allow deleting the root
699
+            return false;
700
+        }
701
+        $postFix = (substr($path, -1, 1) === '/') ? '/' : '';
702
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
703
+        $mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
704
+        if ($mount and $mount->getInternalPath($absolutePath) === '') {
705
+            return $this->removeMount($mount, $absolutePath);
706
+        }
707
+        if ($this->is_dir($path)) {
708
+            $result = $this->basicOperation('rmdir', $path, ['delete']);
709
+        } else {
710
+            $result = $this->basicOperation('unlink', $path, ['delete']);
711
+        }
712
+        if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
713
+            $storage = $mount->getStorage();
714
+            $internalPath = $mount->getInternalPath($absolutePath);
715
+            $storage->getUpdater()->remove($internalPath);
716
+            return true;
717
+        } else {
718
+            return $result;
719
+        }
720
+    }
721
+
722
+    /**
723
+     * @param string $directory
724
+     * @return bool|mixed
725
+     */
726
+    public function deleteAll($directory) {
727
+        return $this->rmdir($directory);
728
+    }
729
+
730
+    /**
731
+     * Rename/move a file or folder from the source path to target path.
732
+     *
733
+     * @param string $path1 source path
734
+     * @param string $path2 target path
735
+     *
736
+     * @return bool|mixed
737
+     */
738
+    public function rename($path1, $path2) {
739
+        $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
740
+        $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
741
+        $result = false;
742
+        if (
743
+            Filesystem::isValidPath($path2)
744
+            and Filesystem::isValidPath($path1)
745
+            and !Filesystem::isFileBlacklisted($path2)
746
+        ) {
747
+            $path1 = $this->getRelativePath($absolutePath1);
748
+            $path2 = $this->getRelativePath($absolutePath2);
749
+            $exists = $this->file_exists($path2);
750
+
751
+            if ($path1 == null or $path2 == null) {
752
+                return false;
753
+            }
754
+
755
+            $this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
756
+            try {
757
+                $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
758
+
759
+                $run = true;
760
+                if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
761
+                    // if it was a rename from a part file to a regular file it was a write and not a rename operation
762
+                    $this->emit_file_hooks_pre($exists, $path2, $run);
763
+                } elseif ($this->shouldEmitHooks($path1)) {
764
+                    \OC_Hook::emit(
765
+                        Filesystem::CLASSNAME, Filesystem::signal_rename,
766
+                        array(
767
+                            Filesystem::signal_param_oldpath => $this->getHookPath($path1),
768
+                            Filesystem::signal_param_newpath => $this->getHookPath($path2),
769
+                            Filesystem::signal_param_run => &$run
770
+                        )
771
+                    );
772
+                }
773
+                if ($run) {
774
+                    $this->verifyPath(dirname($path2), basename($path2));
775
+
776
+                    $manager = Filesystem::getMountManager();
777
+                    $mount1 = $this->getMount($path1);
778
+                    $mount2 = $this->getMount($path2);
779
+                    $storage1 = $mount1->getStorage();
780
+                    $storage2 = $mount2->getStorage();
781
+                    $internalPath1 = $mount1->getInternalPath($absolutePath1);
782
+                    $internalPath2 = $mount2->getInternalPath($absolutePath2);
783
+
784
+                    $this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
785
+                    try {
786
+                        $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
787
+
788
+                        if ($internalPath1 === '') {
789
+                            if ($mount1 instanceof MoveableMount) {
790
+                                if ($this->isTargetAllowed($absolutePath2)) {
791
+                                    /**
792
+                                     * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
793
+                                     */
794
+                                    $sourceMountPoint = $mount1->getMountPoint();
795
+                                    $result = $mount1->moveMount($absolutePath2);
796
+                                    $manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
797
+                                } else {
798
+                                    $result = false;
799
+                                }
800
+                            } else {
801
+                                $result = false;
802
+                            }
803
+                            // moving a file/folder within the same mount point
804
+                        } elseif ($storage1 === $storage2) {
805
+                            if ($storage1) {
806
+                                $result = $storage1->rename($internalPath1, $internalPath2);
807
+                            } else {
808
+                                $result = false;
809
+                            }
810
+                            // moving a file/folder between storages (from $storage1 to $storage2)
811
+                        } else {
812
+                            $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
813
+                        }
814
+
815
+                        if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
816
+                            // if it was a rename from a part file to a regular file it was a write and not a rename operation
817
+                            $this->writeUpdate($storage2, $internalPath2);
818
+                        } else if ($result) {
819
+                            if ($internalPath1 !== '') { // don't do a cache update for moved mounts
820
+                                $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
821
+                            }
822
+                        }
823
+                    } catch(\Exception $e) {
824
+                        throw $e;
825
+                    } finally {
826
+                        $this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
827
+                        $this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
828
+                    }
829
+
830
+                    if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
831
+                        if ($this->shouldEmitHooks()) {
832
+                            $this->emit_file_hooks_post($exists, $path2);
833
+                        }
834
+                    } elseif ($result) {
835
+                        if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) {
836
+                            \OC_Hook::emit(
837
+                                Filesystem::CLASSNAME,
838
+                                Filesystem::signal_post_rename,
839
+                                array(
840
+                                    Filesystem::signal_param_oldpath => $this->getHookPath($path1),
841
+                                    Filesystem::signal_param_newpath => $this->getHookPath($path2)
842
+                                )
843
+                            );
844
+                        }
845
+                    }
846
+                }
847
+            } catch(\Exception $e) {
848
+                throw $e;
849
+            } finally {
850
+                $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
851
+                $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
852
+            }
853
+        }
854
+        return $result;
855
+    }
856
+
857
+    /**
858
+     * Copy a file/folder from the source path to target path
859
+     *
860
+     * @param string $path1 source path
861
+     * @param string $path2 target path
862
+     * @param bool $preserveMtime whether to preserve mtime on the copy
863
+     *
864
+     * @return bool|mixed
865
+     */
866
+    public function copy($path1, $path2, $preserveMtime = false) {
867
+        $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
868
+        $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
869
+        $result = false;
870
+        if (
871
+            Filesystem::isValidPath($path2)
872
+            and Filesystem::isValidPath($path1)
873
+            and !Filesystem::isFileBlacklisted($path2)
874
+        ) {
875
+            $path1 = $this->getRelativePath($absolutePath1);
876
+            $path2 = $this->getRelativePath($absolutePath2);
877
+
878
+            if ($path1 == null or $path2 == null) {
879
+                return false;
880
+            }
881
+            $run = true;
882
+
883
+            $this->lockFile($path2, ILockingProvider::LOCK_SHARED);
884
+            $this->lockFile($path1, ILockingProvider::LOCK_SHARED);
885
+            $lockTypePath1 = ILockingProvider::LOCK_SHARED;
886
+            $lockTypePath2 = ILockingProvider::LOCK_SHARED;
887
+
888
+            try {
889
+
890
+                $exists = $this->file_exists($path2);
891
+                if ($this->shouldEmitHooks()) {
892
+                    \OC_Hook::emit(
893
+                        Filesystem::CLASSNAME,
894
+                        Filesystem::signal_copy,
895
+                        array(
896
+                            Filesystem::signal_param_oldpath => $this->getHookPath($path1),
897
+                            Filesystem::signal_param_newpath => $this->getHookPath($path2),
898
+                            Filesystem::signal_param_run => &$run
899
+                        )
900
+                    );
901
+                    $this->emit_file_hooks_pre($exists, $path2, $run);
902
+                }
903
+                if ($run) {
904
+                    $mount1 = $this->getMount($path1);
905
+                    $mount2 = $this->getMount($path2);
906
+                    $storage1 = $mount1->getStorage();
907
+                    $internalPath1 = $mount1->getInternalPath($absolutePath1);
908
+                    $storage2 = $mount2->getStorage();
909
+                    $internalPath2 = $mount2->getInternalPath($absolutePath2);
910
+
911
+                    $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE);
912
+                    $lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE;
913
+
914
+                    if ($mount1->getMountPoint() == $mount2->getMountPoint()) {
915
+                        if ($storage1) {
916
+                            $result = $storage1->copy($internalPath1, $internalPath2);
917
+                        } else {
918
+                            $result = false;
919
+                        }
920
+                    } else {
921
+                        $result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
922
+                    }
923
+
924
+                    $this->writeUpdate($storage2, $internalPath2);
925
+
926
+                    $this->changeLock($path2, ILockingProvider::LOCK_SHARED);
927
+                    $lockTypePath2 = ILockingProvider::LOCK_SHARED;
928
+
929
+                    if ($this->shouldEmitHooks() && $result !== false) {
930
+                        \OC_Hook::emit(
931
+                            Filesystem::CLASSNAME,
932
+                            Filesystem::signal_post_copy,
933
+                            array(
934
+                                Filesystem::signal_param_oldpath => $this->getHookPath($path1),
935
+                                Filesystem::signal_param_newpath => $this->getHookPath($path2)
936
+                            )
937
+                        );
938
+                        $this->emit_file_hooks_post($exists, $path2);
939
+                    }
940
+
941
+                }
942
+            } catch (\Exception $e) {
943
+                $this->unlockFile($path2, $lockTypePath2);
944
+                $this->unlockFile($path1, $lockTypePath1);
945
+                throw $e;
946
+            }
947
+
948
+            $this->unlockFile($path2, $lockTypePath2);
949
+            $this->unlockFile($path1, $lockTypePath1);
950
+
951
+        }
952
+        return $result;
953
+    }
954
+
955
+    /**
956
+     * @param string $path
957
+     * @param string $mode 'r' or 'w'
958
+     * @return resource
959
+     */
960
+    public function fopen($path, $mode) {
961
+        $mode = str_replace('b', '', $mode); // the binary flag is a windows only feature which we do not support
962
+        $hooks = array();
963
+        switch ($mode) {
964
+            case 'r':
965
+                $hooks[] = 'read';
966
+                break;
967
+            case 'r+':
968
+            case 'w+':
969
+            case 'x+':
970
+            case 'a+':
971
+                $hooks[] = 'read';
972
+                $hooks[] = 'write';
973
+                break;
974
+            case 'w':
975
+            case 'x':
976
+            case 'a':
977
+                $hooks[] = 'write';
978
+                break;
979
+            default:
980
+                \OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR);
981
+        }
982
+
983
+        if ($mode !== 'r' && $mode !== 'w') {
984
+            \OC::$server->getLogger()->info('Trying to open a file with a mode other than "r" or "w" can cause severe performance issues with some backends');
985
+        }
986
+
987
+        return $this->basicOperation('fopen', $path, $hooks, $mode);
988
+    }
989
+
990
+    /**
991
+     * @param string $path
992
+     * @return bool|string
993
+     * @throws \OCP\Files\InvalidPathException
994
+     */
995
+    public function toTmpFile($path) {
996
+        $this->assertPathLength($path);
997
+        if (Filesystem::isValidPath($path)) {
998
+            $source = $this->fopen($path, 'r');
999
+            if ($source) {
1000
+                $extension = pathinfo($path, PATHINFO_EXTENSION);
1001
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
1002
+                file_put_contents($tmpFile, $source);
1003
+                return $tmpFile;
1004
+            } else {
1005
+                return false;
1006
+            }
1007
+        } else {
1008
+            return false;
1009
+        }
1010
+    }
1011
+
1012
+    /**
1013
+     * @param string $tmpFile
1014
+     * @param string $path
1015
+     * @return bool|mixed
1016
+     * @throws \OCP\Files\InvalidPathException
1017
+     */
1018
+    public function fromTmpFile($tmpFile, $path) {
1019
+        $this->assertPathLength($path);
1020
+        if (Filesystem::isValidPath($path)) {
1021
+
1022
+            // Get directory that the file is going into
1023
+            $filePath = dirname($path);
1024
+
1025
+            // Create the directories if any
1026
+            if (!$this->file_exists($filePath)) {
1027
+                $result = $this->createParentDirectories($filePath);
1028
+                if ($result === false) {
1029
+                    return false;
1030
+                }
1031
+            }
1032
+
1033
+            $source = fopen($tmpFile, 'r');
1034
+            if ($source) {
1035
+                $result = $this->file_put_contents($path, $source);
1036
+                // $this->file_put_contents() might have already closed
1037
+                // the resource, so we check it, before trying to close it
1038
+                // to avoid messages in the error log.
1039
+                if (is_resource($source)) {
1040
+                    fclose($source);
1041
+                }
1042
+                unlink($tmpFile);
1043
+                return $result;
1044
+            } else {
1045
+                return false;
1046
+            }
1047
+        } else {
1048
+            return false;
1049
+        }
1050
+    }
1051
+
1052
+
1053
+    /**
1054
+     * @param string $path
1055
+     * @return mixed
1056
+     * @throws \OCP\Files\InvalidPathException
1057
+     */
1058
+    public function getMimeType($path) {
1059
+        $this->assertPathLength($path);
1060
+        return $this->basicOperation('getMimeType', $path);
1061
+    }
1062
+
1063
+    /**
1064
+     * @param string $type
1065
+     * @param string $path
1066
+     * @param bool $raw
1067
+     * @return bool|null|string
1068
+     */
1069
+    public function hash($type, $path, $raw = false) {
1070
+        $postFix = (substr($path, -1, 1) === '/') ? '/' : '';
1071
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1072
+        if (Filesystem::isValidPath($path)) {
1073
+            $path = $this->getRelativePath($absolutePath);
1074
+            if ($path == null) {
1075
+                return false;
1076
+            }
1077
+            if ($this->shouldEmitHooks($path)) {
1078
+                \OC_Hook::emit(
1079
+                    Filesystem::CLASSNAME,
1080
+                    Filesystem::signal_read,
1081
+                    array(Filesystem::signal_param_path => $this->getHookPath($path))
1082
+                );
1083
+            }
1084
+            list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1085
+            if ($storage) {
1086
+                $result = $storage->hash($type, $internalPath, $raw);
1087
+                return $result;
1088
+            }
1089
+        }
1090
+        return null;
1091
+    }
1092
+
1093
+    /**
1094
+     * @param string $path
1095
+     * @return mixed
1096
+     * @throws \OCP\Files\InvalidPathException
1097
+     */
1098
+    public function free_space($path = '/') {
1099
+        $this->assertPathLength($path);
1100
+        $result = $this->basicOperation('free_space', $path);
1101
+        if ($result === null) {
1102
+            throw new InvalidPathException();
1103
+        }
1104
+        return $result;
1105
+    }
1106
+
1107
+    /**
1108
+     * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage
1109
+     *
1110
+     * @param string $operation
1111
+     * @param string $path
1112
+     * @param array $hooks (optional)
1113
+     * @param mixed $extraParam (optional)
1114
+     * @return mixed
1115
+     * @throws \Exception
1116
+     *
1117
+     * This method takes requests for basic filesystem functions (e.g. reading & writing
1118
+     * files), processes hooks and proxies, sanitises paths, and finally passes them on to
1119
+     * \OC\Files\Storage\Storage for delegation to a storage backend for execution
1120
+     */
1121
+    private function basicOperation($operation, $path, $hooks = [], $extraParam = null) {
1122
+        $postFix = (substr($path, -1, 1) === '/') ? '/' : '';
1123
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1124
+        if (Filesystem::isValidPath($path)
1125
+            and !Filesystem::isFileBlacklisted($path)
1126
+        ) {
1127
+            $path = $this->getRelativePath($absolutePath);
1128
+            if ($path == null) {
1129
+                return false;
1130
+            }
1131
+
1132
+            if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) {
1133
+                // always a shared lock during pre-hooks so the hook can read the file
1134
+                $this->lockFile($path, ILockingProvider::LOCK_SHARED);
1135
+            }
1136
+
1137
+            $run = $this->runHooks($hooks, $path);
1138
+            /** @var \OC\Files\Storage\Storage $storage */
1139
+            list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1140
+            if ($run and $storage) {
1141
+                if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1142
+                    $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
1143
+                }
1144
+                try {
1145
+                    if (!is_null($extraParam)) {
1146
+                        $result = $storage->$operation($internalPath, $extraParam);
1147
+                    } else {
1148
+                        $result = $storage->$operation($internalPath);
1149
+                    }
1150
+                } catch (\Exception $e) {
1151
+                    if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1152
+                        $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1153
+                    } else if (in_array('read', $hooks)) {
1154
+                        $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1155
+                    }
1156
+                    throw $e;
1157
+                }
1158
+
1159
+                if ($result && in_array('delete', $hooks) and $result) {
1160
+                    $this->removeUpdate($storage, $internalPath);
1161
+                }
1162
+                if ($result && in_array('write', $hooks) and $operation !== 'fopen') {
1163
+                    $this->writeUpdate($storage, $internalPath);
1164
+                }
1165
+                if ($result && in_array('touch', $hooks)) {
1166
+                    $this->writeUpdate($storage, $internalPath, $extraParam);
1167
+                }
1168
+
1169
+                if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
1170
+                    $this->changeLock($path, ILockingProvider::LOCK_SHARED);
1171
+                }
1172
+
1173
+                $unlockLater = false;
1174
+                if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) {
1175
+                    $unlockLater = true;
1176
+                    // make sure our unlocking callback will still be called if connection is aborted
1177
+                    ignore_user_abort(true);
1178
+                    $result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1179
+                        if (in_array('write', $hooks)) {
1180
+                            $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1181
+                        } else if (in_array('read', $hooks)) {
1182
+                            $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1183
+                        }
1184
+                    });
1185
+                }
1186
+
1187
+                if ($this->shouldEmitHooks($path) && $result !== false) {
1188
+                    if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
1189
+                        $this->runHooks($hooks, $path, true);
1190
+                    }
1191
+                }
1192
+
1193
+                if (!$unlockLater
1194
+                    && (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks))
1195
+                ) {
1196
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1197
+                }
1198
+                return $result;
1199
+            } else {
1200
+                $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1201
+            }
1202
+        }
1203
+        return null;
1204
+    }
1205
+
1206
+    /**
1207
+     * get the path relative to the default root for hook usage
1208
+     *
1209
+     * @param string $path
1210
+     * @return string
1211
+     */
1212
+    private function getHookPath($path) {
1213
+        if (!Filesystem::getView()) {
1214
+            return $path;
1215
+        }
1216
+        return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path));
1217
+    }
1218
+
1219
+    private function shouldEmitHooks($path = '') {
1220
+        if ($path && Cache\Scanner::isPartialFile($path)) {
1221
+            return false;
1222
+        }
1223
+        if (!Filesystem::$loaded) {
1224
+            return false;
1225
+        }
1226
+        $defaultRoot = Filesystem::getRoot();
1227
+        if ($defaultRoot === null) {
1228
+            return false;
1229
+        }
1230
+        if ($this->fakeRoot === $defaultRoot) {
1231
+            return true;
1232
+        }
1233
+        $fullPath = $this->getAbsolutePath($path);
1234
+
1235
+        if ($fullPath === $defaultRoot) {
1236
+            return true;
1237
+        }
1238
+
1239
+        return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1240
+    }
1241
+
1242
+    /**
1243
+     * @param string[] $hooks
1244
+     * @param string $path
1245
+     * @param bool $post
1246
+     * @return bool
1247
+     */
1248
+    private function runHooks($hooks, $path, $post = false) {
1249
+        $relativePath = $path;
1250
+        $path = $this->getHookPath($path);
1251
+        $prefix = ($post) ? 'post_' : '';
1252
+        $run = true;
1253
+        if ($this->shouldEmitHooks($relativePath)) {
1254
+            foreach ($hooks as $hook) {
1255
+                if ($hook != 'read') {
1256
+                    \OC_Hook::emit(
1257
+                        Filesystem::CLASSNAME,
1258
+                        $prefix . $hook,
1259
+                        array(
1260
+                            Filesystem::signal_param_run => &$run,
1261
+                            Filesystem::signal_param_path => $path
1262
+                        )
1263
+                    );
1264
+                } elseif (!$post) {
1265
+                    \OC_Hook::emit(
1266
+                        Filesystem::CLASSNAME,
1267
+                        $prefix . $hook,
1268
+                        array(
1269
+                            Filesystem::signal_param_path => $path
1270
+                        )
1271
+                    );
1272
+                }
1273
+            }
1274
+        }
1275
+        return $run;
1276
+    }
1277
+
1278
+    /**
1279
+     * check if a file or folder has been updated since $time
1280
+     *
1281
+     * @param string $path
1282
+     * @param int $time
1283
+     * @return bool
1284
+     */
1285
+    public function hasUpdated($path, $time) {
1286
+        return $this->basicOperation('hasUpdated', $path, array(), $time);
1287
+    }
1288
+
1289
+    /**
1290
+     * @param string $ownerId
1291
+     * @return \OC\User\User
1292
+     */
1293
+    private function getUserObjectForOwner($ownerId) {
1294
+        $owner = $this->userManager->get($ownerId);
1295
+        if ($owner instanceof IUser) {
1296
+            return $owner;
1297
+        } else {
1298
+            return new User($ownerId, null);
1299
+        }
1300
+    }
1301
+
1302
+    /**
1303
+     * Get file info from cache
1304
+     *
1305
+     * If the file is not in cached it will be scanned
1306
+     * If the file has changed on storage the cache will be updated
1307
+     *
1308
+     * @param \OC\Files\Storage\Storage $storage
1309
+     * @param string $internalPath
1310
+     * @param string $relativePath
1311
+     * @return ICacheEntry|bool
1312
+     */
1313
+    private function getCacheEntry($storage, $internalPath, $relativePath) {
1314
+        $cache = $storage->getCache($internalPath);
1315
+        $data = $cache->get($internalPath);
1316
+        $watcher = $storage->getWatcher($internalPath);
1317
+
1318
+        try {
1319
+            // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
1320
+            if (!$data || $data['size'] === -1) {
1321
+                if (!$storage->file_exists($internalPath)) {
1322
+                    return false;
1323
+                }
1324
+                // don't need to get a lock here since the scanner does it's own locking
1325
+                $scanner = $storage->getScanner($internalPath);
1326
+                $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1327
+                $data = $cache->get($internalPath);
1328
+            } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
1329
+                $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1330
+                $watcher->update($internalPath, $data);
1331
+                $storage->getPropagator()->propagateChange($internalPath, time());
1332
+                $data = $cache->get($internalPath);
1333
+                $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1334
+            }
1335
+        } catch (LockedException $e) {
1336
+            // if the file is locked we just use the old cache info
1337
+        }
1338
+
1339
+        return $data;
1340
+    }
1341
+
1342
+    /**
1343
+     * get the filesystem info
1344
+     *
1345
+     * @param string $path
1346
+     * @param boolean|string $includeMountPoints true to add mountpoint sizes,
1347
+     * 'ext' to add only ext storage mount point sizes. Defaults to true.
1348
+     * defaults to true
1349
+     * @return \OC\Files\FileInfo|false False if file does not exist
1350
+     */
1351
+    public function getFileInfo($path, $includeMountPoints = true) {
1352
+        $this->assertPathLength($path);
1353
+        if (!Filesystem::isValidPath($path)) {
1354
+            return false;
1355
+        }
1356
+        if (Cache\Scanner::isPartialFile($path)) {
1357
+            return $this->getPartFileInfo($path);
1358
+        }
1359
+        $relativePath = $path;
1360
+        $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1361
+
1362
+        $mount = Filesystem::getMountManager()->find($path);
1363
+        if (!$mount) {
1364
+            return false;
1365
+        }
1366
+        $storage = $mount->getStorage();
1367
+        $internalPath = $mount->getInternalPath($path);
1368
+        if ($storage) {
1369
+            $data = $this->getCacheEntry($storage, $internalPath, $relativePath);
1370
+
1371
+            if (!$data instanceof ICacheEntry) {
1372
+                return false;
1373
+            }
1374
+
1375
+            if ($mount instanceof MoveableMount && $internalPath === '') {
1376
+                $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
1377
+            }
1378
+
1379
+            $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath));
1380
+            $info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
1381
+
1382
+            if ($data and isset($data['fileid'])) {
1383
+                if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
1384
+                    //add the sizes of other mount points to the folder
1385
+                    $extOnly = ($includeMountPoints === 'ext');
1386
+                    $mounts = Filesystem::getMountManager()->findIn($path);
1387
+                    $info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1388
+                        $subStorage = $mount->getStorage();
1389
+                        return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1390
+                    }));
1391
+                }
1392
+            }
1393
+
1394
+            return $info;
1395
+        }
1396
+
1397
+        return false;
1398
+    }
1399
+
1400
+    /**
1401
+     * get the content of a directory
1402
+     *
1403
+     * @param string $directory path under datadirectory
1404
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
1405
+     * @return FileInfo[]
1406
+     */
1407
+    public function getDirectoryContent($directory, $mimetype_filter = '') {
1408
+        $this->assertPathLength($directory);
1409
+        if (!Filesystem::isValidPath($directory)) {
1410
+            return [];
1411
+        }
1412
+        $path = $this->getAbsolutePath($directory);
1413
+        $path = Filesystem::normalizePath($path);
1414
+        $mount = $this->getMount($directory);
1415
+        if (!$mount) {
1416
+            return [];
1417
+        }
1418
+        $storage = $mount->getStorage();
1419
+        $internalPath = $mount->getInternalPath($path);
1420
+        if ($storage) {
1421
+            $cache = $storage->getCache($internalPath);
1422
+            $user = \OC_User::getUser();
1423
+
1424
+            $data = $this->getCacheEntry($storage, $internalPath, $directory);
1425
+
1426
+            if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
1427
+                return [];
1428
+            }
1429
+
1430
+            $folderId = $data['fileid'];
1431
+            $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
1432
+
1433
+            $sharingDisabled = \OCP\Util::isSharingDisabledForUser();
1434
+
1435
+            $fileNames = array_map(function(ICacheEntry $content) {
1436
+                return $content->getName();
1437
+            }, $contents);
1438
+            /**
1439
+             * @var \OC\Files\FileInfo[] $fileInfos
1440
+             */
1441
+            $fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1442
+                if ($sharingDisabled) {
1443
+                    $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1444
+                }
1445
+                $owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1446
+                return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1447
+            }, $contents);
1448
+            $files = array_combine($fileNames, $fileInfos);
1449
+
1450
+            //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
1451
+            $mounts = Filesystem::getMountManager()->findIn($path);
1452
+            $dirLength = strlen($path);
1453
+            foreach ($mounts as $mount) {
1454
+                $mountPoint = $mount->getMountPoint();
1455
+                $subStorage = $mount->getStorage();
1456
+                if ($subStorage) {
1457
+                    $subCache = $subStorage->getCache('');
1458
+
1459
+                    $rootEntry = $subCache->get('');
1460
+                    if (!$rootEntry) {
1461
+                        $subScanner = $subStorage->getScanner('');
1462
+                        try {
1463
+                            $subScanner->scanFile('');
1464
+                        } catch (\OCP\Files\StorageNotAvailableException $e) {
1465
+                            continue;
1466
+                        } catch (\OCP\Files\StorageInvalidException $e) {
1467
+                            continue;
1468
+                        } catch (\Exception $e) {
1469
+                            // sometimes when the storage is not available it can be any exception
1470
+                            \OCP\Util::writeLog(
1471
+                                'core',
1472
+                                'Exception while scanning storage "' . $subStorage->getId() . '": ' .
1473
+                                get_class($e) . ': ' . $e->getMessage(),
1474
+                                \OCP\Util::ERROR
1475
+                            );
1476
+                            continue;
1477
+                        }
1478
+                        $rootEntry = $subCache->get('');
1479
+                    }
1480
+
1481
+                    if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
1482
+                        $relativePath = trim(substr($mountPoint, $dirLength), '/');
1483
+                        if ($pos = strpos($relativePath, '/')) {
1484
+                            //mountpoint inside subfolder add size to the correct folder
1485
+                            $entryName = substr($relativePath, 0, $pos);
1486
+                            foreach ($files as &$entry) {
1487
+                                if ($entry->getName() === $entryName) {
1488
+                                    $entry->addSubEntry($rootEntry, $mountPoint);
1489
+                                }
1490
+                            }
1491
+                        } else { //mountpoint in this folder, add an entry for it
1492
+                            $rootEntry['name'] = $relativePath;
1493
+                            $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
1494
+                            $permissions = $rootEntry['permissions'];
1495
+                            // do not allow renaming/deleting the mount point if they are not shared files/folders
1496
+                            // for shared files/folders we use the permissions given by the owner
1497
+                            if ($mount instanceof MoveableMount) {
1498
+                                $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
1499
+                            } else {
1500
+                                $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
1501
+                            }
1502
+
1503
+                            $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1504
+
1505
+                            // if sharing was disabled for the user we remove the share permissions
1506
+                            if (\OCP\Util::isSharingDisabledForUser()) {
1507
+                                $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1508
+                            }
1509
+
1510
+                            $owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1511
+                            $files[$rootEntry->getName()] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1512
+                        }
1513
+                    }
1514
+                }
1515
+            }
1516
+
1517
+            if ($mimetype_filter) {
1518
+                $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1519
+                    if (strpos($mimetype_filter, '/')) {
1520
+                        return $file->getMimetype() === $mimetype_filter;
1521
+                    } else {
1522
+                        return $file->getMimePart() === $mimetype_filter;
1523
+                    }
1524
+                });
1525
+            }
1526
+
1527
+            return array_values($files);
1528
+        } else {
1529
+            return [];
1530
+        }
1531
+    }
1532
+
1533
+    /**
1534
+     * change file metadata
1535
+     *
1536
+     * @param string $path
1537
+     * @param array|\OCP\Files\FileInfo $data
1538
+     * @return int
1539
+     *
1540
+     * returns the fileid of the updated file
1541
+     */
1542
+    public function putFileInfo($path, $data) {
1543
+        $this->assertPathLength($path);
1544
+        if ($data instanceof FileInfo) {
1545
+            $data = $data->getData();
1546
+        }
1547
+        $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1548
+        /**
1549
+         * @var \OC\Files\Storage\Storage $storage
1550
+         * @var string $internalPath
1551
+         */
1552
+        list($storage, $internalPath) = Filesystem::resolvePath($path);
1553
+        if ($storage) {
1554
+            $cache = $storage->getCache($path);
1555
+
1556
+            if (!$cache->inCache($internalPath)) {
1557
+                $scanner = $storage->getScanner($internalPath);
1558
+                $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1559
+            }
1560
+
1561
+            return $cache->put($internalPath, $data);
1562
+        } else {
1563
+            return -1;
1564
+        }
1565
+    }
1566
+
1567
+    /**
1568
+     * search for files with the name matching $query
1569
+     *
1570
+     * @param string $query
1571
+     * @return FileInfo[]
1572
+     */
1573
+    public function search($query) {
1574
+        return $this->searchCommon('search', array('%' . $query . '%'));
1575
+    }
1576
+
1577
+    /**
1578
+     * search for files with the name matching $query
1579
+     *
1580
+     * @param string $query
1581
+     * @return FileInfo[]
1582
+     */
1583
+    public function searchRaw($query) {
1584
+        return $this->searchCommon('search', array($query));
1585
+    }
1586
+
1587
+    /**
1588
+     * search for files by mimetype
1589
+     *
1590
+     * @param string $mimetype
1591
+     * @return FileInfo[]
1592
+     */
1593
+    public function searchByMime($mimetype) {
1594
+        return $this->searchCommon('searchByMime', array($mimetype));
1595
+    }
1596
+
1597
+    /**
1598
+     * search for files by tag
1599
+     *
1600
+     * @param string|int $tag name or tag id
1601
+     * @param string $userId owner of the tags
1602
+     * @return FileInfo[]
1603
+     */
1604
+    public function searchByTag($tag, $userId) {
1605
+        return $this->searchCommon('searchByTag', array($tag, $userId));
1606
+    }
1607
+
1608
+    /**
1609
+     * @param string $method cache method
1610
+     * @param array $args
1611
+     * @return FileInfo[]
1612
+     */
1613
+    private function searchCommon($method, $args) {
1614
+        $files = array();
1615
+        $rootLength = strlen($this->fakeRoot);
1616
+
1617
+        $mount = $this->getMount('');
1618
+        $mountPoint = $mount->getMountPoint();
1619
+        $storage = $mount->getStorage();
1620
+        if ($storage) {
1621
+            $cache = $storage->getCache('');
1622
+
1623
+            $results = call_user_func_array(array($cache, $method), $args);
1624
+            foreach ($results as $result) {
1625
+                if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1626
+                    $internalPath = $result['path'];
1627
+                    $path = $mountPoint . $result['path'];
1628
+                    $result['path'] = substr($mountPoint . $result['path'], $rootLength);
1629
+                    $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1630
+                    $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1631
+                }
1632
+            }
1633
+
1634
+            $mounts = Filesystem::getMountManager()->findIn($this->fakeRoot);
1635
+            foreach ($mounts as $mount) {
1636
+                $mountPoint = $mount->getMountPoint();
1637
+                $storage = $mount->getStorage();
1638
+                if ($storage) {
1639
+                    $cache = $storage->getCache('');
1640
+
1641
+                    $relativeMountPoint = substr($mountPoint, $rootLength);
1642
+                    $results = call_user_func_array(array($cache, $method), $args);
1643
+                    if ($results) {
1644
+                        foreach ($results as $result) {
1645
+                            $internalPath = $result['path'];
1646
+                            $result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1647
+                            $path = rtrim($mountPoint . $internalPath, '/');
1648
+                            $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1649
+                            $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1650
+                        }
1651
+                    }
1652
+                }
1653
+            }
1654
+        }
1655
+        return $files;
1656
+    }
1657
+
1658
+    /**
1659
+     * Get the owner for a file or folder
1660
+     *
1661
+     * @param string $path
1662
+     * @return string the user id of the owner
1663
+     * @throws NotFoundException
1664
+     */
1665
+    public function getOwner($path) {
1666
+        $info = $this->getFileInfo($path);
1667
+        if (!$info) {
1668
+            throw new NotFoundException($path . ' not found while trying to get owner');
1669
+        }
1670
+        return $info->getOwner()->getUID();
1671
+    }
1672
+
1673
+    /**
1674
+     * get the ETag for a file or folder
1675
+     *
1676
+     * @param string $path
1677
+     * @return string
1678
+     */
1679
+    public function getETag($path) {
1680
+        /**
1681
+         * @var Storage\Storage $storage
1682
+         * @var string $internalPath
1683
+         */
1684
+        list($storage, $internalPath) = $this->resolvePath($path);
1685
+        if ($storage) {
1686
+            return $storage->getETag($internalPath);
1687
+        } else {
1688
+            return null;
1689
+        }
1690
+    }
1691
+
1692
+    /**
1693
+     * Get the path of a file by id, relative to the view
1694
+     *
1695
+     * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
1696
+     *
1697
+     * @param int $id
1698
+     * @throws NotFoundException
1699
+     * @return string
1700
+     */
1701
+    public function getPath($id) {
1702
+        $id = (int)$id;
1703
+        $manager = Filesystem::getMountManager();
1704
+        $mounts = $manager->findIn($this->fakeRoot);
1705
+        $mounts[] = $manager->find($this->fakeRoot);
1706
+        // reverse the array so we start with the storage this view is in
1707
+        // which is the most likely to contain the file we're looking for
1708
+        $mounts = array_reverse($mounts);
1709
+        foreach ($mounts as $mount) {
1710
+            /**
1711
+             * @var \OC\Files\Mount\MountPoint $mount
1712
+             */
1713
+            if ($mount->getStorage()) {
1714
+                $cache = $mount->getStorage()->getCache();
1715
+                $internalPath = $cache->getPathById($id);
1716
+                if (is_string($internalPath)) {
1717
+                    $fullPath = $mount->getMountPoint() . $internalPath;
1718
+                    if (!is_null($path = $this->getRelativePath($fullPath))) {
1719
+                        return $path;
1720
+                    }
1721
+                }
1722
+            }
1723
+        }
1724
+        throw new NotFoundException(sprintf('File with id "%s" has not been found.', $id));
1725
+    }
1726
+
1727
+    /**
1728
+     * @param string $path
1729
+     * @throws InvalidPathException
1730
+     */
1731
+    private function assertPathLength($path) {
1732
+        $maxLen = min(PHP_MAXPATHLEN, 4000);
1733
+        // Check for the string length - performed using isset() instead of strlen()
1734
+        // because isset() is about 5x-40x faster.
1735
+        if (isset($path[$maxLen])) {
1736
+            $pathLen = strlen($path);
1737
+            throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path");
1738
+        }
1739
+    }
1740
+
1741
+    /**
1742
+     * check if it is allowed to move a mount point to a given target.
1743
+     * It is not allowed to move a mount point into a different mount point or
1744
+     * into an already shared folder
1745
+     *
1746
+     * @param string $target path
1747
+     * @return boolean
1748
+     */
1749
+    private function isTargetAllowed($target) {
1750
+
1751
+        list($targetStorage, $targetInternalPath) = \OC\Files\Filesystem::resolvePath($target);
1752
+        if (!$targetStorage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
1753
+            \OCP\Util::writeLog('files',
1754
+                'It is not allowed to move one mount point into another one',
1755
+                \OCP\Util::DEBUG);
1756
+            return false;
1757
+        }
1758
+
1759
+        // note: cannot use the view because the target is already locked
1760
+        $fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1761
+        if ($fileId === -1) {
1762
+            // target might not exist, need to check parent instead
1763
+            $fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1764
+        }
1765
+
1766
+        // check if any of the parents were shared by the current owner (include collections)
1767
+        $shares = \OCP\Share::getItemShared(
1768
+            'folder',
1769
+            $fileId,
1770
+            \OCP\Share::FORMAT_NONE,
1771
+            null,
1772
+            true
1773
+        );
1774
+
1775
+        if (count($shares) > 0) {
1776
+            \OCP\Util::writeLog('files',
1777
+                'It is not allowed to move one mount point into a shared folder',
1778
+                \OCP\Util::DEBUG);
1779
+            return false;
1780
+        }
1781
+
1782
+        return true;
1783
+    }
1784
+
1785
+    /**
1786
+     * Get a fileinfo object for files that are ignored in the cache (part files)
1787
+     *
1788
+     * @param string $path
1789
+     * @return \OCP\Files\FileInfo
1790
+     */
1791
+    private function getPartFileInfo($path) {
1792
+        $mount = $this->getMount($path);
1793
+        $storage = $mount->getStorage();
1794
+        $internalPath = $mount->getInternalPath($this->getAbsolutePath($path));
1795
+        $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1796
+        return new FileInfo(
1797
+            $this->getAbsolutePath($path),
1798
+            $storage,
1799
+            $internalPath,
1800
+            [
1801
+                'fileid' => null,
1802
+                'mimetype' => $storage->getMimeType($internalPath),
1803
+                'name' => basename($path),
1804
+                'etag' => null,
1805
+                'size' => $storage->filesize($internalPath),
1806
+                'mtime' => $storage->filemtime($internalPath),
1807
+                'encrypted' => false,
1808
+                'permissions' => \OCP\Constants::PERMISSION_ALL
1809
+            ],
1810
+            $mount,
1811
+            $owner
1812
+        );
1813
+    }
1814
+
1815
+    /**
1816
+     * @param string $path
1817
+     * @param string $fileName
1818
+     * @throws InvalidPathException
1819
+     */
1820
+    public function verifyPath($path, $fileName) {
1821
+        try {
1822
+            /** @type \OCP\Files\Storage $storage */
1823
+            list($storage, $internalPath) = $this->resolvePath($path);
1824
+            $storage->verifyPath($internalPath, $fileName);
1825
+        } catch (ReservedWordException $ex) {
1826
+            $l = \OC::$server->getL10N('lib');
1827
+            throw new InvalidPathException($l->t('File name is a reserved word'));
1828
+        } catch (InvalidCharacterInPathException $ex) {
1829
+            $l = \OC::$server->getL10N('lib');
1830
+            throw new InvalidPathException($l->t('File name contains at least one invalid character'));
1831
+        } catch (FileNameTooLongException $ex) {
1832
+            $l = \OC::$server->getL10N('lib');
1833
+            throw new InvalidPathException($l->t('File name is too long'));
1834
+        } catch (InvalidDirectoryException $ex) {
1835
+            $l = \OC::$server->getL10N('lib');
1836
+            throw new InvalidPathException($l->t('Dot files are not allowed'));
1837
+        } catch (EmptyFileNameException $ex) {
1838
+            $l = \OC::$server->getL10N('lib');
1839
+            throw new InvalidPathException($l->t('Empty filename is not allowed'));
1840
+        }
1841
+    }
1842
+
1843
+    /**
1844
+     * get all parent folders of $path
1845
+     *
1846
+     * @param string $path
1847
+     * @return string[]
1848
+     */
1849
+    private function getParents($path) {
1850
+        $path = trim($path, '/');
1851
+        if (!$path) {
1852
+            return [];
1853
+        }
1854
+
1855
+        $parts = explode('/', $path);
1856
+
1857
+        // remove the single file
1858
+        array_pop($parts);
1859
+        $result = array('/');
1860
+        $resultPath = '';
1861
+        foreach ($parts as $part) {
1862
+            if ($part) {
1863
+                $resultPath .= '/' . $part;
1864
+                $result[] = $resultPath;
1865
+            }
1866
+        }
1867
+        return $result;
1868
+    }
1869
+
1870
+    /**
1871
+     * Returns the mount point for which to lock
1872
+     *
1873
+     * @param string $absolutePath absolute path
1874
+     * @param bool $useParentMount true to return parent mount instead of whatever
1875
+     * is mounted directly on the given path, false otherwise
1876
+     * @return \OC\Files\Mount\MountPoint mount point for which to apply locks
1877
+     */
1878
+    private function getMountForLock($absolutePath, $useParentMount = false) {
1879
+        $results = [];
1880
+        $mount = Filesystem::getMountManager()->find($absolutePath);
1881
+        if (!$mount) {
1882
+            return $results;
1883
+        }
1884
+
1885
+        if ($useParentMount) {
1886
+            // find out if something is mounted directly on the path
1887
+            $internalPath = $mount->getInternalPath($absolutePath);
1888
+            if ($internalPath === '') {
1889
+                // resolve the parent mount instead
1890
+                $mount = Filesystem::getMountManager()->find(dirname($absolutePath));
1891
+            }
1892
+        }
1893
+
1894
+        return $mount;
1895
+    }
1896
+
1897
+    /**
1898
+     * Lock the given path
1899
+     *
1900
+     * @param string $path the path of the file to lock, relative to the view
1901
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1902
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1903
+     *
1904
+     * @return bool False if the path is excluded from locking, true otherwise
1905
+     * @throws \OCP\Lock\LockedException if the path is already locked
1906
+     */
1907
+    private function lockPath($path, $type, $lockMountPoint = false) {
1908
+        $absolutePath = $this->getAbsolutePath($path);
1909
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1910
+        if (!$this->shouldLockFile($absolutePath)) {
1911
+            return false;
1912
+        }
1913
+
1914
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1915
+        if ($mount) {
1916
+            try {
1917
+                $storage = $mount->getStorage();
1918
+                if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1919
+                    $storage->acquireLock(
1920
+                        $mount->getInternalPath($absolutePath),
1921
+                        $type,
1922
+                        $this->lockingProvider
1923
+                    );
1924
+                }
1925
+            } catch (\OCP\Lock\LockedException $e) {
1926
+                // rethrow with the a human-readable path
1927
+                throw new \OCP\Lock\LockedException(
1928
+                    $this->getPathRelativeToFiles($absolutePath),
1929
+                    $e
1930
+                );
1931
+            }
1932
+        }
1933
+
1934
+        return true;
1935
+    }
1936
+
1937
+    /**
1938
+     * Change the lock type
1939
+     *
1940
+     * @param string $path the path of the file to lock, relative to the view
1941
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1942
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1943
+     *
1944
+     * @return bool False if the path is excluded from locking, true otherwise
1945
+     * @throws \OCP\Lock\LockedException if the path is already locked
1946
+     */
1947
+    public function changeLock($path, $type, $lockMountPoint = false) {
1948
+        $path = Filesystem::normalizePath($path);
1949
+        $absolutePath = $this->getAbsolutePath($path);
1950
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1951
+        if (!$this->shouldLockFile($absolutePath)) {
1952
+            return false;
1953
+        }
1954
+
1955
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1956
+        if ($mount) {
1957
+            try {
1958
+                $storage = $mount->getStorage();
1959
+                if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1960
+                    $storage->changeLock(
1961
+                        $mount->getInternalPath($absolutePath),
1962
+                        $type,
1963
+                        $this->lockingProvider
1964
+                    );
1965
+                }
1966
+            } catch (\OCP\Lock\LockedException $e) {
1967
+                try {
1968
+                    // rethrow with the a human-readable path
1969
+                    throw new \OCP\Lock\LockedException(
1970
+                        $this->getPathRelativeToFiles($absolutePath),
1971
+                        $e
1972
+                    );
1973
+                } catch (\InvalidArgumentException $e) {
1974
+                    throw new \OCP\Lock\LockedException(
1975
+                        $absolutePath,
1976
+                        $e
1977
+                    );
1978
+                }
1979
+            }
1980
+        }
1981
+
1982
+        return true;
1983
+    }
1984
+
1985
+    /**
1986
+     * Unlock the given path
1987
+     *
1988
+     * @param string $path the path of the file to unlock, relative to the view
1989
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1990
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1991
+     *
1992
+     * @return bool False if the path is excluded from locking, true otherwise
1993
+     */
1994
+    private function unlockPath($path, $type, $lockMountPoint = false) {
1995
+        $absolutePath = $this->getAbsolutePath($path);
1996
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1997
+        if (!$this->shouldLockFile($absolutePath)) {
1998
+            return false;
1999
+        }
2000
+
2001
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
2002
+        if ($mount) {
2003
+            $storage = $mount->getStorage();
2004
+            if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2005
+                $storage->releaseLock(
2006
+                    $mount->getInternalPath($absolutePath),
2007
+                    $type,
2008
+                    $this->lockingProvider
2009
+                );
2010
+            }
2011
+        }
2012
+
2013
+        return true;
2014
+    }
2015
+
2016
+    /**
2017
+     * Lock a path and all its parents up to the root of the view
2018
+     *
2019
+     * @param string $path the path of the file to lock relative to the view
2020
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2021
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2022
+     *
2023
+     * @return bool False if the path is excluded from locking, true otherwise
2024
+     */
2025
+    public function lockFile($path, $type, $lockMountPoint = false) {
2026
+        $absolutePath = $this->getAbsolutePath($path);
2027
+        $absolutePath = Filesystem::normalizePath($absolutePath);
2028
+        if (!$this->shouldLockFile($absolutePath)) {
2029
+            return false;
2030
+        }
2031
+
2032
+        $this->lockPath($path, $type, $lockMountPoint);
2033
+
2034
+        $parents = $this->getParents($path);
2035
+        foreach ($parents as $parent) {
2036
+            $this->lockPath($parent, ILockingProvider::LOCK_SHARED);
2037
+        }
2038
+
2039
+        return true;
2040
+    }
2041
+
2042
+    /**
2043
+     * Unlock a path and all its parents up to the root of the view
2044
+     *
2045
+     * @param string $path the path of the file to lock relative to the view
2046
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2047
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2048
+     *
2049
+     * @return bool False if the path is excluded from locking, true otherwise
2050
+     */
2051
+    public function unlockFile($path, $type, $lockMountPoint = false) {
2052
+        $absolutePath = $this->getAbsolutePath($path);
2053
+        $absolutePath = Filesystem::normalizePath($absolutePath);
2054
+        if (!$this->shouldLockFile($absolutePath)) {
2055
+            return false;
2056
+        }
2057
+
2058
+        $this->unlockPath($path, $type, $lockMountPoint);
2059
+
2060
+        $parents = $this->getParents($path);
2061
+        foreach ($parents as $parent) {
2062
+            $this->unlockPath($parent, ILockingProvider::LOCK_SHARED);
2063
+        }
2064
+
2065
+        return true;
2066
+    }
2067
+
2068
+    /**
2069
+     * Only lock files in data/user/files/
2070
+     *
2071
+     * @param string $path Absolute path to the file/folder we try to (un)lock
2072
+     * @return bool
2073
+     */
2074
+    protected function shouldLockFile($path) {
2075
+        $path = Filesystem::normalizePath($path);
2076
+
2077
+        $pathSegments = explode('/', $path);
2078
+        if (isset($pathSegments[2])) {
2079
+            // E.g.: /username/files/path-to-file
2080
+            return ($pathSegments[2] === 'files') && (count($pathSegments) > 3);
2081
+        }
2082
+
2083
+        return strpos($path, '/appdata_') !== 0;
2084
+    }
2085
+
2086
+    /**
2087
+     * Shortens the given absolute path to be relative to
2088
+     * "$user/files".
2089
+     *
2090
+     * @param string $absolutePath absolute path which is under "files"
2091
+     *
2092
+     * @return string path relative to "files" with trimmed slashes or null
2093
+     * if the path was NOT relative to files
2094
+     *
2095
+     * @throws \InvalidArgumentException if the given path was not under "files"
2096
+     * @since 8.1.0
2097
+     */
2098
+    public function getPathRelativeToFiles($absolutePath) {
2099
+        $path = Filesystem::normalizePath($absolutePath);
2100
+        $parts = explode('/', trim($path, '/'), 3);
2101
+        // "$user", "files", "path/to/dir"
2102
+        if (!isset($parts[1]) || $parts[1] !== 'files') {
2103
+            $this->logger->error(
2104
+                '$absolutePath must be relative to "files", value is "%s"',
2105
+                [
2106
+                    $absolutePath
2107
+                ]
2108
+            );
2109
+            throw new \InvalidArgumentException('$absolutePath must be relative to "files"');
2110
+        }
2111
+        if (isset($parts[2])) {
2112
+            return $parts[2];
2113
+        }
2114
+        return '';
2115
+    }
2116
+
2117
+    /**
2118
+     * @param string $filename
2119
+     * @return array
2120
+     * @throws \OC\User\NoUserException
2121
+     * @throws NotFoundException
2122
+     */
2123
+    public function getUidAndFilename($filename) {
2124
+        $info = $this->getFileInfo($filename);
2125
+        if (!$info instanceof \OCP\Files\FileInfo) {
2126
+            throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2127
+        }
2128
+        $uid = $info->getOwner()->getUID();
2129
+        if ($uid != \OCP\User::getUser()) {
2130
+            Filesystem::initMountPoints($uid);
2131
+            $ownerView = new View('/' . $uid . '/files');
2132
+            try {
2133
+                $filename = $ownerView->getPath($info['fileid']);
2134
+            } catch (NotFoundException $e) {
2135
+                throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2136
+            }
2137
+        }
2138
+        return [$uid, $filename];
2139
+    }
2140
+
2141
+    /**
2142
+     * Creates parent non-existing folders
2143
+     *
2144
+     * @param string $filePath
2145
+     * @return bool
2146
+     */
2147
+    private function createParentDirectories($filePath) {
2148
+        $directoryParts = explode('/', $filePath);
2149
+        $directoryParts = array_filter($directoryParts);
2150
+        foreach ($directoryParts as $key => $part) {
2151
+            $currentPathElements = array_slice($directoryParts, 0, $key);
2152
+            $currentPath = '/' . implode('/', $currentPathElements);
2153
+            if ($this->is_file($currentPath)) {
2154
+                return false;
2155
+            }
2156
+            if (!$this->file_exists($currentPath)) {
2157
+                $this->mkdir($currentPath);
2158
+            }
2159
+        }
2160
+
2161
+        return true;
2162
+    }
2163 2163
 }
Please login to merge, or discard this patch.
Spacing   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -126,9 +126,9 @@  discard block
 block discarded – undo
126 126
 			$path = '/';
127 127
 		}
128 128
 		if ($path[0] !== '/') {
129
-			$path = '/' . $path;
129
+			$path = '/'.$path;
130 130
 		}
131
-		return $this->fakeRoot . $path;
131
+		return $this->fakeRoot.$path;
132 132
 	}
133 133
 
134 134
 	/**
@@ -140,7 +140,7 @@  discard block
 block discarded – undo
140 140
 	public function chroot($fakeRoot) {
141 141
 		if (!$fakeRoot == '') {
142 142
 			if ($fakeRoot[0] !== '/') {
143
-				$fakeRoot = '/' . $fakeRoot;
143
+				$fakeRoot = '/'.$fakeRoot;
144 144
 			}
145 145
 		}
146 146
 		$this->fakeRoot = $fakeRoot;
@@ -172,7 +172,7 @@  discard block
 block discarded – undo
172 172
 		}
173 173
 
174 174
 		// missing slashes can cause wrong matches!
175
-		$root = rtrim($this->fakeRoot, '/') . '/';
175
+		$root = rtrim($this->fakeRoot, '/').'/';
176 176
 
177 177
 		if (strpos($path, $root) !== 0) {
178 178
 			return null;
@@ -278,7 +278,7 @@  discard block
 block discarded – undo
278 278
 		if ($mount instanceof MoveableMount) {
279 279
 			// cut of /user/files to get the relative path to data/user/files
280 280
 			$pathParts = explode('/', $path, 4);
281
-			$relPath = '/' . $pathParts[3];
281
+			$relPath = '/'.$pathParts[3];
282 282
 			$this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
283 283
 			\OC_Hook::emit(
284 284
 				Filesystem::CLASSNAME, "umount",
@@ -700,7 +700,7 @@  discard block
 block discarded – undo
700 700
 		}
701 701
 		$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
702 702
 		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
703
-		$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
703
+		$mount = Filesystem::getMountManager()->find($absolutePath.$postFix);
704 704
 		if ($mount and $mount->getInternalPath($absolutePath) === '') {
705 705
 			return $this->removeMount($mount, $absolutePath);
706 706
 		}
@@ -820,7 +820,7 @@  discard block
 block discarded – undo
820 820
 								$this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
821 821
 							}
822 822
 						}
823
-					} catch(\Exception $e) {
823
+					} catch (\Exception $e) {
824 824
 						throw $e;
825 825
 					} finally {
826 826
 						$this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
@@ -844,7 +844,7 @@  discard block
 block discarded – undo
844 844
 						}
845 845
 					}
846 846
 				}
847
-			} catch(\Exception $e) {
847
+			} catch (\Exception $e) {
848 848
 				throw $e;
849 849
 			} finally {
850 850
 				$this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
@@ -977,7 +977,7 @@  discard block
 block discarded – undo
977 977
 				$hooks[] = 'write';
978 978
 				break;
979 979
 			default:
980
-				\OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR);
980
+				\OCP\Util::writeLog('core', 'invalid mode ('.$mode.') for '.$path, \OCP\Util::ERROR);
981 981
 		}
982 982
 
983 983
 		if ($mode !== 'r' && $mode !== 'w') {
@@ -1081,7 +1081,7 @@  discard block
 block discarded – undo
1081 1081
 					array(Filesystem::signal_param_path => $this->getHookPath($path))
1082 1082
 				);
1083 1083
 			}
1084
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1084
+			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath.$postFix);
1085 1085
 			if ($storage) {
1086 1086
 				$result = $storage->hash($type, $internalPath, $raw);
1087 1087
 				return $result;
@@ -1136,7 +1136,7 @@  discard block
 block discarded – undo
1136 1136
 
1137 1137
 			$run = $this->runHooks($hooks, $path);
1138 1138
 			/** @var \OC\Files\Storage\Storage $storage */
1139
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1139
+			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath.$postFix);
1140 1140
 			if ($run and $storage) {
1141 1141
 				if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1142 1142
 					$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
@@ -1175,7 +1175,7 @@  discard block
 block discarded – undo
1175 1175
 					$unlockLater = true;
1176 1176
 					// make sure our unlocking callback will still be called if connection is aborted
1177 1177
 					ignore_user_abort(true);
1178
-					$result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1178
+					$result = CallbackWrapper::wrap($result, null, null, function() use ($hooks, $path) {
1179 1179
 						if (in_array('write', $hooks)) {
1180 1180
 							$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1181 1181
 						} else if (in_array('read', $hooks)) {
@@ -1236,7 +1236,7 @@  discard block
 block discarded – undo
1236 1236
 			return true;
1237 1237
 		}
1238 1238
 
1239
-		return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1239
+		return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot.'/');
1240 1240
 	}
1241 1241
 
1242 1242
 	/**
@@ -1255,7 +1255,7 @@  discard block
 block discarded – undo
1255 1255
 				if ($hook != 'read') {
1256 1256
 					\OC_Hook::emit(
1257 1257
 						Filesystem::CLASSNAME,
1258
-						$prefix . $hook,
1258
+						$prefix.$hook,
1259 1259
 						array(
1260 1260
 							Filesystem::signal_param_run => &$run,
1261 1261
 							Filesystem::signal_param_path => $path
@@ -1264,7 +1264,7 @@  discard block
 block discarded – undo
1264 1264
 				} elseif (!$post) {
1265 1265
 					\OC_Hook::emit(
1266 1266
 						Filesystem::CLASSNAME,
1267
-						$prefix . $hook,
1267
+						$prefix.$hook,
1268 1268
 						array(
1269 1269
 							Filesystem::signal_param_path => $path
1270 1270
 						)
@@ -1357,7 +1357,7 @@  discard block
 block discarded – undo
1357 1357
 			return $this->getPartFileInfo($path);
1358 1358
 		}
1359 1359
 		$relativePath = $path;
1360
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1360
+		$path = Filesystem::normalizePath($this->fakeRoot.'/'.$path);
1361 1361
 
1362 1362
 		$mount = Filesystem::getMountManager()->find($path);
1363 1363
 		if (!$mount) {
@@ -1384,7 +1384,7 @@  discard block
 block discarded – undo
1384 1384
 					//add the sizes of other mount points to the folder
1385 1385
 					$extOnly = ($includeMountPoints === 'ext');
1386 1386
 					$mounts = Filesystem::getMountManager()->findIn($path);
1387
-					$info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1387
+					$info->setSubMounts(array_filter($mounts, function(IMountPoint $mount) use ($extOnly) {
1388 1388
 						$subStorage = $mount->getStorage();
1389 1389
 						return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1390 1390
 					}));
@@ -1438,12 +1438,12 @@  discard block
 block discarded – undo
1438 1438
 			/**
1439 1439
 			 * @var \OC\Files\FileInfo[] $fileInfos
1440 1440
 			 */
1441
-			$fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1441
+			$fileInfos = array_map(function(ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1442 1442
 				if ($sharingDisabled) {
1443 1443
 					$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1444 1444
 				}
1445 1445
 				$owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1446
-				return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1446
+				return new FileInfo($path.'/'.$content['name'], $storage, $content['path'], $content, $mount, $owner);
1447 1447
 			}, $contents);
1448 1448
 			$files = array_combine($fileNames, $fileInfos);
1449 1449
 
@@ -1469,8 +1469,8 @@  discard block
 block discarded – undo
1469 1469
 							// sometimes when the storage is not available it can be any exception
1470 1470
 							\OCP\Util::writeLog(
1471 1471
 								'core',
1472
-								'Exception while scanning storage "' . $subStorage->getId() . '": ' .
1473
-								get_class($e) . ': ' . $e->getMessage(),
1472
+								'Exception while scanning storage "'.$subStorage->getId().'": '.
1473
+								get_class($e).': '.$e->getMessage(),
1474 1474
 								\OCP\Util::ERROR
1475 1475
 							);
1476 1476
 							continue;
@@ -1500,7 +1500,7 @@  discard block
 block discarded – undo
1500 1500
 								$rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
1501 1501
 							}
1502 1502
 
1503
-							$rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1503
+							$rootEntry['path'] = substr(Filesystem::normalizePath($path.'/'.$rootEntry['name']), strlen($user) + 2); // full path without /$user/
1504 1504
 
1505 1505
 							// if sharing was disabled for the user we remove the share permissions
1506 1506
 							if (\OCP\Util::isSharingDisabledForUser()) {
@@ -1508,14 +1508,14 @@  discard block
 block discarded – undo
1508 1508
 							}
1509 1509
 
1510 1510
 							$owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1511
-							$files[$rootEntry->getName()] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1511
+							$files[$rootEntry->getName()] = new FileInfo($path.'/'.$rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1512 1512
 						}
1513 1513
 					}
1514 1514
 				}
1515 1515
 			}
1516 1516
 
1517 1517
 			if ($mimetype_filter) {
1518
-				$files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1518
+				$files = array_filter($files, function(FileInfo $file) use ($mimetype_filter) {
1519 1519
 					if (strpos($mimetype_filter, '/')) {
1520 1520
 						return $file->getMimetype() === $mimetype_filter;
1521 1521
 					} else {
@@ -1544,7 +1544,7 @@  discard block
 block discarded – undo
1544 1544
 		if ($data instanceof FileInfo) {
1545 1545
 			$data = $data->getData();
1546 1546
 		}
1547
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1547
+		$path = Filesystem::normalizePath($this->fakeRoot.'/'.$path);
1548 1548
 		/**
1549 1549
 		 * @var \OC\Files\Storage\Storage $storage
1550 1550
 		 * @var string $internalPath
@@ -1571,7 +1571,7 @@  discard block
 block discarded – undo
1571 1571
 	 * @return FileInfo[]
1572 1572
 	 */
1573 1573
 	public function search($query) {
1574
-		return $this->searchCommon('search', array('%' . $query . '%'));
1574
+		return $this->searchCommon('search', array('%'.$query.'%'));
1575 1575
 	}
1576 1576
 
1577 1577
 	/**
@@ -1622,10 +1622,10 @@  discard block
 block discarded – undo
1622 1622
 
1623 1623
 			$results = call_user_func_array(array($cache, $method), $args);
1624 1624
 			foreach ($results as $result) {
1625
-				if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1625
+				if (substr($mountPoint.$result['path'], 0, $rootLength + 1) === $this->fakeRoot.'/') {
1626 1626
 					$internalPath = $result['path'];
1627
-					$path = $mountPoint . $result['path'];
1628
-					$result['path'] = substr($mountPoint . $result['path'], $rootLength);
1627
+					$path = $mountPoint.$result['path'];
1628
+					$result['path'] = substr($mountPoint.$result['path'], $rootLength);
1629 1629
 					$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1630 1630
 					$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1631 1631
 				}
@@ -1643,8 +1643,8 @@  discard block
 block discarded – undo
1643 1643
 					if ($results) {
1644 1644
 						foreach ($results as $result) {
1645 1645
 							$internalPath = $result['path'];
1646
-							$result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1647
-							$path = rtrim($mountPoint . $internalPath, '/');
1646
+							$result['path'] = rtrim($relativeMountPoint.$result['path'], '/');
1647
+							$path = rtrim($mountPoint.$internalPath, '/');
1648 1648
 							$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1649 1649
 							$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1650 1650
 						}
@@ -1665,7 +1665,7 @@  discard block
 block discarded – undo
1665 1665
 	public function getOwner($path) {
1666 1666
 		$info = $this->getFileInfo($path);
1667 1667
 		if (!$info) {
1668
-			throw new NotFoundException($path . ' not found while trying to get owner');
1668
+			throw new NotFoundException($path.' not found while trying to get owner');
1669 1669
 		}
1670 1670
 		return $info->getOwner()->getUID();
1671 1671
 	}
@@ -1699,7 +1699,7 @@  discard block
 block discarded – undo
1699 1699
 	 * @return string
1700 1700
 	 */
1701 1701
 	public function getPath($id) {
1702
-		$id = (int)$id;
1702
+		$id = (int) $id;
1703 1703
 		$manager = Filesystem::getMountManager();
1704 1704
 		$mounts = $manager->findIn($this->fakeRoot);
1705 1705
 		$mounts[] = $manager->find($this->fakeRoot);
@@ -1714,7 +1714,7 @@  discard block
 block discarded – undo
1714 1714
 				$cache = $mount->getStorage()->getCache();
1715 1715
 				$internalPath = $cache->getPathById($id);
1716 1716
 				if (is_string($internalPath)) {
1717
-					$fullPath = $mount->getMountPoint() . $internalPath;
1717
+					$fullPath = $mount->getMountPoint().$internalPath;
1718 1718
 					if (!is_null($path = $this->getRelativePath($fullPath))) {
1719 1719
 						return $path;
1720 1720
 					}
@@ -1757,10 +1757,10 @@  discard block
 block discarded – undo
1757 1757
 		}
1758 1758
 
1759 1759
 		// note: cannot use the view because the target is already locked
1760
-		$fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1760
+		$fileId = (int) $targetStorage->getCache()->getId($targetInternalPath);
1761 1761
 		if ($fileId === -1) {
1762 1762
 			// target might not exist, need to check parent instead
1763
-			$fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1763
+			$fileId = (int) $targetStorage->getCache()->getId(dirname($targetInternalPath));
1764 1764
 		}
1765 1765
 
1766 1766
 		// check if any of the parents were shared by the current owner (include collections)
@@ -1860,7 +1860,7 @@  discard block
 block discarded – undo
1860 1860
 		$resultPath = '';
1861 1861
 		foreach ($parts as $part) {
1862 1862
 			if ($part) {
1863
-				$resultPath .= '/' . $part;
1863
+				$resultPath .= '/'.$part;
1864 1864
 				$result[] = $resultPath;
1865 1865
 			}
1866 1866
 		}
@@ -2123,16 +2123,16 @@  discard block
 block discarded – undo
2123 2123
 	public function getUidAndFilename($filename) {
2124 2124
 		$info = $this->getFileInfo($filename);
2125 2125
 		if (!$info instanceof \OCP\Files\FileInfo) {
2126
-			throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2126
+			throw new NotFoundException($this->getAbsolutePath($filename).' not found');
2127 2127
 		}
2128 2128
 		$uid = $info->getOwner()->getUID();
2129 2129
 		if ($uid != \OCP\User::getUser()) {
2130 2130
 			Filesystem::initMountPoints($uid);
2131
-			$ownerView = new View('/' . $uid . '/files');
2131
+			$ownerView = new View('/'.$uid.'/files');
2132 2132
 			try {
2133 2133
 				$filename = $ownerView->getPath($info['fileid']);
2134 2134
 			} catch (NotFoundException $e) {
2135
-				throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2135
+				throw new NotFoundException('File with id '.$info['fileid'].' not found for user '.$uid);
2136 2136
 			}
2137 2137
 		}
2138 2138
 		return [$uid, $filename];
@@ -2149,7 +2149,7 @@  discard block
 block discarded – undo
2149 2149
 		$directoryParts = array_filter($directoryParts);
2150 2150
 		foreach ($directoryParts as $key => $part) {
2151 2151
 			$currentPathElements = array_slice($directoryParts, 0, $key);
2152
-			$currentPath = '/' . implode('/', $currentPathElements);
2152
+			$currentPath = '/'.implode('/', $currentPathElements);
2153 2153
 			if ($this->is_file($currentPath)) {
2154 2154
 				return false;
2155 2155
 			}
Please login to merge, or discard this patch.
lib/private/Share20/Manager.php 2 patches
Indentation   +1474 added lines, -1474 removed lines patch added patch discarded remove patch
@@ -70,1502 +70,1502 @@
 block discarded – undo
70 70
  */
71 71
 class Manager implements IManager {
72 72
 
73
-	/** @var IProviderFactory */
74
-	private $factory;
75
-	/** @var ILogger */
76
-	private $logger;
77
-	/** @var IConfig */
78
-	private $config;
79
-	/** @var ISecureRandom */
80
-	private $secureRandom;
81
-	/** @var IHasher */
82
-	private $hasher;
83
-	/** @var IMountManager */
84
-	private $mountManager;
85
-	/** @var IGroupManager */
86
-	private $groupManager;
87
-	/** @var IL10N */
88
-	private $l;
89
-	/** @var IFactory */
90
-	private $l10nFactory;
91
-	/** @var IUserManager */
92
-	private $userManager;
93
-	/** @var IRootFolder */
94
-	private $rootFolder;
95
-	/** @var CappedMemoryCache */
96
-	private $sharingDisabledForUsersCache;
97
-	/** @var EventDispatcher */
98
-	private $eventDispatcher;
99
-	/** @var LegacyHooks */
100
-	private $legacyHooks;
101
-	/** @var IMailer */
102
-	private $mailer;
103
-	/** @var IURLGenerator */
104
-	private $urlGenerator;
105
-	/** @var \OC_Defaults */
106
-	private $defaults;
107
-
108
-
109
-	/**
110
-	 * Manager constructor.
111
-	 *
112
-	 * @param ILogger $logger
113
-	 * @param IConfig $config
114
-	 * @param ISecureRandom $secureRandom
115
-	 * @param IHasher $hasher
116
-	 * @param IMountManager $mountManager
117
-	 * @param IGroupManager $groupManager
118
-	 * @param IL10N $l
119
-	 * @param IFactory $l10nFactory
120
-	 * @param IProviderFactory $factory
121
-	 * @param IUserManager $userManager
122
-	 * @param IRootFolder $rootFolder
123
-	 * @param EventDispatcher $eventDispatcher
124
-	 * @param IMailer $mailer
125
-	 * @param IURLGenerator $urlGenerator
126
-	 * @param \OC_Defaults $defaults
127
-	 */
128
-	public function __construct(
129
-			ILogger $logger,
130
-			IConfig $config,
131
-			ISecureRandom $secureRandom,
132
-			IHasher $hasher,
133
-			IMountManager $mountManager,
134
-			IGroupManager $groupManager,
135
-			IL10N $l,
136
-			IFactory $l10nFactory,
137
-			IProviderFactory $factory,
138
-			IUserManager $userManager,
139
-			IRootFolder $rootFolder,
140
-			EventDispatcher $eventDispatcher,
141
-			IMailer $mailer,
142
-			IURLGenerator $urlGenerator,
143
-			\OC_Defaults $defaults
144
-	) {
145
-		$this->logger = $logger;
146
-		$this->config = $config;
147
-		$this->secureRandom = $secureRandom;
148
-		$this->hasher = $hasher;
149
-		$this->mountManager = $mountManager;
150
-		$this->groupManager = $groupManager;
151
-		$this->l = $l;
152
-		$this->l10nFactory = $l10nFactory;
153
-		$this->factory = $factory;
154
-		$this->userManager = $userManager;
155
-		$this->rootFolder = $rootFolder;
156
-		$this->eventDispatcher = $eventDispatcher;
157
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
158
-		$this->legacyHooks = new LegacyHooks($this->eventDispatcher);
159
-		$this->mailer = $mailer;
160
-		$this->urlGenerator = $urlGenerator;
161
-		$this->defaults = $defaults;
162
-	}
163
-
164
-	/**
165
-	 * Convert from a full share id to a tuple (providerId, shareId)
166
-	 *
167
-	 * @param string $id
168
-	 * @return string[]
169
-	 */
170
-	private function splitFullId($id) {
171
-		return explode(':', $id, 2);
172
-	}
173
-
174
-	/**
175
-	 * Verify if a password meets all requirements
176
-	 *
177
-	 * @param string $password
178
-	 * @throws \Exception
179
-	 */
180
-	protected function verifyPassword($password) {
181
-		if ($password === null) {
182
-			// No password is set, check if this is allowed.
183
-			if ($this->shareApiLinkEnforcePassword()) {
184
-				throw new \InvalidArgumentException('Passwords are enforced for link shares');
185
-			}
186
-
187
-			return;
188
-		}
189
-
190
-		// Let others verify the password
191
-		try {
192
-			$event = new GenericEvent($password);
193
-			$this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
194
-		} catch (HintException $e) {
195
-			throw new \Exception($e->getHint());
196
-		}
197
-	}
198
-
199
-	/**
200
-	 * Check for generic requirements before creating a share
201
-	 *
202
-	 * @param \OCP\Share\IShare $share
203
-	 * @throws \InvalidArgumentException
204
-	 * @throws GenericShareException
205
-	 *
206
-	 * @suppress PhanUndeclaredClassMethod
207
-	 */
208
-	protected function generalCreateChecks(\OCP\Share\IShare $share) {
209
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
210
-			// We expect a valid user as sharedWith for user shares
211
-			if (!$this->userManager->userExists($share->getSharedWith())) {
212
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
213
-			}
214
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
215
-			// We expect a valid group as sharedWith for group shares
216
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
217
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
218
-			}
219
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
220
-			if ($share->getSharedWith() !== null) {
221
-				throw new \InvalidArgumentException('SharedWith should be empty');
222
-			}
223
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
224
-			if ($share->getSharedWith() === null) {
225
-				throw new \InvalidArgumentException('SharedWith should not be empty');
226
-			}
227
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
228
-			if ($share->getSharedWith() === null) {
229
-				throw new \InvalidArgumentException('SharedWith should not be empty');
230
-			}
231
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
232
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
233
-			if ($circle === null) {
234
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
235
-			}
236
-		} else {
237
-			// We can't handle other types yet
238
-			throw new \InvalidArgumentException('unknown share type');
239
-		}
240
-
241
-		// Verify the initiator of the share is set
242
-		if ($share->getSharedBy() === null) {
243
-			throw new \InvalidArgumentException('SharedBy should be set');
244
-		}
245
-
246
-		// Cannot share with yourself
247
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
248
-			$share->getSharedWith() === $share->getSharedBy()) {
249
-			throw new \InvalidArgumentException('Can’t share with yourself');
250
-		}
251
-
252
-		// The path should be set
253
-		if ($share->getNode() === null) {
254
-			throw new \InvalidArgumentException('Path should be set');
255
-		}
256
-
257
-		// And it should be a file or a folder
258
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
259
-				!($share->getNode() instanceof \OCP\Files\Folder)) {
260
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
261
-		}
262
-
263
-		// And you can't share your rootfolder
264
-		if ($this->userManager->userExists($share->getSharedBy())) {
265
-			$sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
266
-		} else {
267
-			$sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
268
-		}
269
-		if ($sharedPath === $share->getNode()->getPath()) {
270
-			throw new \InvalidArgumentException('You can’t share your root folder');
271
-		}
272
-
273
-		// Check if we actually have share permissions
274
-		if (!$share->getNode()->isShareable()) {
275
-			$message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
276
-			throw new GenericShareException($message_t, $message_t, 404);
277
-		}
278
-
279
-		// Permissions should be set
280
-		if ($share->getPermissions() === null) {
281
-			throw new \InvalidArgumentException('A share requires permissions');
282
-		}
283
-
284
-		/*
73
+    /** @var IProviderFactory */
74
+    private $factory;
75
+    /** @var ILogger */
76
+    private $logger;
77
+    /** @var IConfig */
78
+    private $config;
79
+    /** @var ISecureRandom */
80
+    private $secureRandom;
81
+    /** @var IHasher */
82
+    private $hasher;
83
+    /** @var IMountManager */
84
+    private $mountManager;
85
+    /** @var IGroupManager */
86
+    private $groupManager;
87
+    /** @var IL10N */
88
+    private $l;
89
+    /** @var IFactory */
90
+    private $l10nFactory;
91
+    /** @var IUserManager */
92
+    private $userManager;
93
+    /** @var IRootFolder */
94
+    private $rootFolder;
95
+    /** @var CappedMemoryCache */
96
+    private $sharingDisabledForUsersCache;
97
+    /** @var EventDispatcher */
98
+    private $eventDispatcher;
99
+    /** @var LegacyHooks */
100
+    private $legacyHooks;
101
+    /** @var IMailer */
102
+    private $mailer;
103
+    /** @var IURLGenerator */
104
+    private $urlGenerator;
105
+    /** @var \OC_Defaults */
106
+    private $defaults;
107
+
108
+
109
+    /**
110
+     * Manager constructor.
111
+     *
112
+     * @param ILogger $logger
113
+     * @param IConfig $config
114
+     * @param ISecureRandom $secureRandom
115
+     * @param IHasher $hasher
116
+     * @param IMountManager $mountManager
117
+     * @param IGroupManager $groupManager
118
+     * @param IL10N $l
119
+     * @param IFactory $l10nFactory
120
+     * @param IProviderFactory $factory
121
+     * @param IUserManager $userManager
122
+     * @param IRootFolder $rootFolder
123
+     * @param EventDispatcher $eventDispatcher
124
+     * @param IMailer $mailer
125
+     * @param IURLGenerator $urlGenerator
126
+     * @param \OC_Defaults $defaults
127
+     */
128
+    public function __construct(
129
+            ILogger $logger,
130
+            IConfig $config,
131
+            ISecureRandom $secureRandom,
132
+            IHasher $hasher,
133
+            IMountManager $mountManager,
134
+            IGroupManager $groupManager,
135
+            IL10N $l,
136
+            IFactory $l10nFactory,
137
+            IProviderFactory $factory,
138
+            IUserManager $userManager,
139
+            IRootFolder $rootFolder,
140
+            EventDispatcher $eventDispatcher,
141
+            IMailer $mailer,
142
+            IURLGenerator $urlGenerator,
143
+            \OC_Defaults $defaults
144
+    ) {
145
+        $this->logger = $logger;
146
+        $this->config = $config;
147
+        $this->secureRandom = $secureRandom;
148
+        $this->hasher = $hasher;
149
+        $this->mountManager = $mountManager;
150
+        $this->groupManager = $groupManager;
151
+        $this->l = $l;
152
+        $this->l10nFactory = $l10nFactory;
153
+        $this->factory = $factory;
154
+        $this->userManager = $userManager;
155
+        $this->rootFolder = $rootFolder;
156
+        $this->eventDispatcher = $eventDispatcher;
157
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
158
+        $this->legacyHooks = new LegacyHooks($this->eventDispatcher);
159
+        $this->mailer = $mailer;
160
+        $this->urlGenerator = $urlGenerator;
161
+        $this->defaults = $defaults;
162
+    }
163
+
164
+    /**
165
+     * Convert from a full share id to a tuple (providerId, shareId)
166
+     *
167
+     * @param string $id
168
+     * @return string[]
169
+     */
170
+    private function splitFullId($id) {
171
+        return explode(':', $id, 2);
172
+    }
173
+
174
+    /**
175
+     * Verify if a password meets all requirements
176
+     *
177
+     * @param string $password
178
+     * @throws \Exception
179
+     */
180
+    protected function verifyPassword($password) {
181
+        if ($password === null) {
182
+            // No password is set, check if this is allowed.
183
+            if ($this->shareApiLinkEnforcePassword()) {
184
+                throw new \InvalidArgumentException('Passwords are enforced for link shares');
185
+            }
186
+
187
+            return;
188
+        }
189
+
190
+        // Let others verify the password
191
+        try {
192
+            $event = new GenericEvent($password);
193
+            $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event);
194
+        } catch (HintException $e) {
195
+            throw new \Exception($e->getHint());
196
+        }
197
+    }
198
+
199
+    /**
200
+     * Check for generic requirements before creating a share
201
+     *
202
+     * @param \OCP\Share\IShare $share
203
+     * @throws \InvalidArgumentException
204
+     * @throws GenericShareException
205
+     *
206
+     * @suppress PhanUndeclaredClassMethod
207
+     */
208
+    protected function generalCreateChecks(\OCP\Share\IShare $share) {
209
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
210
+            // We expect a valid user as sharedWith for user shares
211
+            if (!$this->userManager->userExists($share->getSharedWith())) {
212
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
213
+            }
214
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
215
+            // We expect a valid group as sharedWith for group shares
216
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
217
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
218
+            }
219
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
220
+            if ($share->getSharedWith() !== null) {
221
+                throw new \InvalidArgumentException('SharedWith should be empty');
222
+            }
223
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
224
+            if ($share->getSharedWith() === null) {
225
+                throw new \InvalidArgumentException('SharedWith should not be empty');
226
+            }
227
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
228
+            if ($share->getSharedWith() === null) {
229
+                throw new \InvalidArgumentException('SharedWith should not be empty');
230
+            }
231
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE) {
232
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
233
+            if ($circle === null) {
234
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
235
+            }
236
+        } else {
237
+            // We can't handle other types yet
238
+            throw new \InvalidArgumentException('unknown share type');
239
+        }
240
+
241
+        // Verify the initiator of the share is set
242
+        if ($share->getSharedBy() === null) {
243
+            throw new \InvalidArgumentException('SharedBy should be set');
244
+        }
245
+
246
+        // Cannot share with yourself
247
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
248
+            $share->getSharedWith() === $share->getSharedBy()) {
249
+            throw new \InvalidArgumentException('Can’t share with yourself');
250
+        }
251
+
252
+        // The path should be set
253
+        if ($share->getNode() === null) {
254
+            throw new \InvalidArgumentException('Path should be set');
255
+        }
256
+
257
+        // And it should be a file or a folder
258
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
259
+                !($share->getNode() instanceof \OCP\Files\Folder)) {
260
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
261
+        }
262
+
263
+        // And you can't share your rootfolder
264
+        if ($this->userManager->userExists($share->getSharedBy())) {
265
+            $sharedPath = $this->rootFolder->getUserFolder($share->getSharedBy())->getPath();
266
+        } else {
267
+            $sharedPath = $this->rootFolder->getUserFolder($share->getShareOwner())->getPath();
268
+        }
269
+        if ($sharedPath === $share->getNode()->getPath()) {
270
+            throw new \InvalidArgumentException('You can’t share your root folder');
271
+        }
272
+
273
+        // Check if we actually have share permissions
274
+        if (!$share->getNode()->isShareable()) {
275
+            $message_t = $this->l->t('You are not allowed to share %s', [$share->getNode()->getPath()]);
276
+            throw new GenericShareException($message_t, $message_t, 404);
277
+        }
278
+
279
+        // Permissions should be set
280
+        if ($share->getPermissions() === null) {
281
+            throw new \InvalidArgumentException('A share requires permissions');
282
+        }
283
+
284
+        /*
285 285
 		 * Quick fix for #23536
286 286
 		 * Non moveable mount points do not have update and delete permissions
287 287
 		 * while we 'most likely' do have that on the storage.
288 288
 		 */
289
-		$permissions = $share->getNode()->getPermissions();
290
-		$mount = $share->getNode()->getMountPoint();
291
-		if (!($mount instanceof MoveableMount)) {
292
-			$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
293
-		}
294
-
295
-		// Check that we do not share with more permissions than we have
296
-		if ($share->getPermissions() & ~$permissions) {
297
-			$message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
298
-			throw new GenericShareException($message_t, $message_t, 404);
299
-		}
300
-
301
-
302
-		// Check that read permissions are always set
303
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
304
-		$noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
305
-			|| $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
306
-		if (!$noReadPermissionRequired &&
307
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
308
-			throw new \InvalidArgumentException('Shares need at least read permissions');
309
-		}
310
-
311
-		if ($share->getNode() instanceof \OCP\Files\File) {
312
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
313
-				$message_t = $this->l->t('Files can’t be shared with delete permissions');
314
-				throw new GenericShareException($message_t);
315
-			}
316
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
317
-				$message_t = $this->l->t('Files can’t be shared with create permissions');
318
-				throw new GenericShareException($message_t);
319
-			}
320
-		}
321
-	}
322
-
323
-	/**
324
-	 * Validate if the expiration date fits the system settings
325
-	 *
326
-	 * @param \OCP\Share\IShare $share The share to validate the expiration date of
327
-	 * @return \OCP\Share\IShare The modified share object
328
-	 * @throws GenericShareException
329
-	 * @throws \InvalidArgumentException
330
-	 * @throws \Exception
331
-	 */
332
-	protected function validateExpirationDate(\OCP\Share\IShare $share) {
333
-
334
-		$expirationDate = $share->getExpirationDate();
335
-
336
-		if ($expirationDate !== null) {
337
-			//Make sure the expiration date is a date
338
-			$expirationDate->setTime(0, 0, 0);
339
-
340
-			$date = new \DateTime();
341
-			$date->setTime(0, 0, 0);
342
-			if ($date >= $expirationDate) {
343
-				$message = $this->l->t('Expiration date is in the past');
344
-				throw new GenericShareException($message, $message, 404);
345
-			}
346
-		}
347
-
348
-		// If expiredate is empty set a default one if there is a default
349
-		$fullId = null;
350
-		try {
351
-			$fullId = $share->getFullId();
352
-		} catch (\UnexpectedValueException $e) {
353
-			// This is a new share
354
-		}
355
-
356
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
357
-			$expirationDate = new \DateTime();
358
-			$expirationDate->setTime(0,0,0);
359
-			$expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
360
-		}
361
-
362
-		// If we enforce the expiration date check that is does not exceed
363
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
364
-			if ($expirationDate === null) {
365
-				throw new \InvalidArgumentException('Expiration date is enforced');
366
-			}
367
-
368
-			$date = new \DateTime();
369
-			$date->setTime(0, 0, 0);
370
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
371
-			if ($date < $expirationDate) {
372
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
373
-				throw new GenericShareException($message, $message, 404);
374
-			}
375
-		}
376
-
377
-		$accepted = true;
378
-		$message = '';
379
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
380
-			'expirationDate' => &$expirationDate,
381
-			'accepted' => &$accepted,
382
-			'message' => &$message,
383
-			'passwordSet' => $share->getPassword() !== null,
384
-		]);
385
-
386
-		if (!$accepted) {
387
-			throw new \Exception($message);
388
-		}
389
-
390
-		$share->setExpirationDate($expirationDate);
391
-
392
-		return $share;
393
-	}
394
-
395
-	/**
396
-	 * Check for pre share requirements for user shares
397
-	 *
398
-	 * @param \OCP\Share\IShare $share
399
-	 * @throws \Exception
400
-	 */
401
-	protected function userCreateChecks(\OCP\Share\IShare $share) {
402
-		// Check if we can share with group members only
403
-		if ($this->shareWithGroupMembersOnly()) {
404
-			$sharedBy = $this->userManager->get($share->getSharedBy());
405
-			$sharedWith = $this->userManager->get($share->getSharedWith());
406
-			// Verify we can share with this user
407
-			$groups = array_intersect(
408
-					$this->groupManager->getUserGroupIds($sharedBy),
409
-					$this->groupManager->getUserGroupIds($sharedWith)
410
-			);
411
-			if (empty($groups)) {
412
-				throw new \Exception('Sharing is only allowed with group members');
413
-			}
414
-		}
415
-
416
-		/*
289
+        $permissions = $share->getNode()->getPermissions();
290
+        $mount = $share->getNode()->getMountPoint();
291
+        if (!($mount instanceof MoveableMount)) {
292
+            $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
293
+        }
294
+
295
+        // Check that we do not share with more permissions than we have
296
+        if ($share->getPermissions() & ~$permissions) {
297
+            $message_t = $this->l->t('Can’t increase permissions of %s', [$share->getNode()->getPath()]);
298
+            throw new GenericShareException($message_t, $message_t, 404);
299
+        }
300
+
301
+
302
+        // Check that read permissions are always set
303
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
304
+        $noReadPermissionRequired = $share->getShareType() === \OCP\Share::SHARE_TYPE_LINK
305
+            || $share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL;
306
+        if (!$noReadPermissionRequired &&
307
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
308
+            throw new \InvalidArgumentException('Shares need at least read permissions');
309
+        }
310
+
311
+        if ($share->getNode() instanceof \OCP\Files\File) {
312
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
313
+                $message_t = $this->l->t('Files can’t be shared with delete permissions');
314
+                throw new GenericShareException($message_t);
315
+            }
316
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
317
+                $message_t = $this->l->t('Files can’t be shared with create permissions');
318
+                throw new GenericShareException($message_t);
319
+            }
320
+        }
321
+    }
322
+
323
+    /**
324
+     * Validate if the expiration date fits the system settings
325
+     *
326
+     * @param \OCP\Share\IShare $share The share to validate the expiration date of
327
+     * @return \OCP\Share\IShare The modified share object
328
+     * @throws GenericShareException
329
+     * @throws \InvalidArgumentException
330
+     * @throws \Exception
331
+     */
332
+    protected function validateExpirationDate(\OCP\Share\IShare $share) {
333
+
334
+        $expirationDate = $share->getExpirationDate();
335
+
336
+        if ($expirationDate !== null) {
337
+            //Make sure the expiration date is a date
338
+            $expirationDate->setTime(0, 0, 0);
339
+
340
+            $date = new \DateTime();
341
+            $date->setTime(0, 0, 0);
342
+            if ($date >= $expirationDate) {
343
+                $message = $this->l->t('Expiration date is in the past');
344
+                throw new GenericShareException($message, $message, 404);
345
+            }
346
+        }
347
+
348
+        // If expiredate is empty set a default one if there is a default
349
+        $fullId = null;
350
+        try {
351
+            $fullId = $share->getFullId();
352
+        } catch (\UnexpectedValueException $e) {
353
+            // This is a new share
354
+        }
355
+
356
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
357
+            $expirationDate = new \DateTime();
358
+            $expirationDate->setTime(0,0,0);
359
+            $expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
360
+        }
361
+
362
+        // If we enforce the expiration date check that is does not exceed
363
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
364
+            if ($expirationDate === null) {
365
+                throw new \InvalidArgumentException('Expiration date is enforced');
366
+            }
367
+
368
+            $date = new \DateTime();
369
+            $date->setTime(0, 0, 0);
370
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
371
+            if ($date < $expirationDate) {
372
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
373
+                throw new GenericShareException($message, $message, 404);
374
+            }
375
+        }
376
+
377
+        $accepted = true;
378
+        $message = '';
379
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
380
+            'expirationDate' => &$expirationDate,
381
+            'accepted' => &$accepted,
382
+            'message' => &$message,
383
+            'passwordSet' => $share->getPassword() !== null,
384
+        ]);
385
+
386
+        if (!$accepted) {
387
+            throw new \Exception($message);
388
+        }
389
+
390
+        $share->setExpirationDate($expirationDate);
391
+
392
+        return $share;
393
+    }
394
+
395
+    /**
396
+     * Check for pre share requirements for user shares
397
+     *
398
+     * @param \OCP\Share\IShare $share
399
+     * @throws \Exception
400
+     */
401
+    protected function userCreateChecks(\OCP\Share\IShare $share) {
402
+        // Check if we can share with group members only
403
+        if ($this->shareWithGroupMembersOnly()) {
404
+            $sharedBy = $this->userManager->get($share->getSharedBy());
405
+            $sharedWith = $this->userManager->get($share->getSharedWith());
406
+            // Verify we can share with this user
407
+            $groups = array_intersect(
408
+                    $this->groupManager->getUserGroupIds($sharedBy),
409
+                    $this->groupManager->getUserGroupIds($sharedWith)
410
+            );
411
+            if (empty($groups)) {
412
+                throw new \Exception('Sharing is only allowed with group members');
413
+            }
414
+        }
415
+
416
+        /*
417 417
 		 * TODO: Could be costly, fix
418 418
 		 *
419 419
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
420 420
 		 */
421
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
422
-		$existingShares = $provider->getSharesByPath($share->getNode());
423
-		foreach($existingShares as $existingShare) {
424
-			// Ignore if it is the same share
425
-			try {
426
-				if ($existingShare->getFullId() === $share->getFullId()) {
427
-					continue;
428
-				}
429
-			} catch (\UnexpectedValueException $e) {
430
-				//Shares are not identical
431
-			}
432
-
433
-			// Identical share already existst
434
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
435
-				throw new \Exception('Path is already shared with this user');
436
-			}
437
-
438
-			// The share is already shared with this user via a group share
439
-			if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
440
-				$group = $this->groupManager->get($existingShare->getSharedWith());
441
-				if (!is_null($group)) {
442
-					$user = $this->userManager->get($share->getSharedWith());
443
-
444
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
445
-						throw new \Exception('Path is already shared with this user');
446
-					}
447
-				}
448
-			}
449
-		}
450
-	}
451
-
452
-	/**
453
-	 * Check for pre share requirements for group shares
454
-	 *
455
-	 * @param \OCP\Share\IShare $share
456
-	 * @throws \Exception
457
-	 */
458
-	protected function groupCreateChecks(\OCP\Share\IShare $share) {
459
-		// Verify group shares are allowed
460
-		if (!$this->allowGroupSharing()) {
461
-			throw new \Exception('Group sharing is now allowed');
462
-		}
463
-
464
-		// Verify if the user can share with this group
465
-		if ($this->shareWithGroupMembersOnly()) {
466
-			$sharedBy = $this->userManager->get($share->getSharedBy());
467
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
468
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
469
-				throw new \Exception('Sharing is only allowed within your own groups');
470
-			}
471
-		}
472
-
473
-		/*
421
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
422
+        $existingShares = $provider->getSharesByPath($share->getNode());
423
+        foreach($existingShares as $existingShare) {
424
+            // Ignore if it is the same share
425
+            try {
426
+                if ($existingShare->getFullId() === $share->getFullId()) {
427
+                    continue;
428
+                }
429
+            } catch (\UnexpectedValueException $e) {
430
+                //Shares are not identical
431
+            }
432
+
433
+            // Identical share already existst
434
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
435
+                throw new \Exception('Path is already shared with this user');
436
+            }
437
+
438
+            // The share is already shared with this user via a group share
439
+            if ($existingShare->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
440
+                $group = $this->groupManager->get($existingShare->getSharedWith());
441
+                if (!is_null($group)) {
442
+                    $user = $this->userManager->get($share->getSharedWith());
443
+
444
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
445
+                        throw new \Exception('Path is already shared with this user');
446
+                    }
447
+                }
448
+            }
449
+        }
450
+    }
451
+
452
+    /**
453
+     * Check for pre share requirements for group shares
454
+     *
455
+     * @param \OCP\Share\IShare $share
456
+     * @throws \Exception
457
+     */
458
+    protected function groupCreateChecks(\OCP\Share\IShare $share) {
459
+        // Verify group shares are allowed
460
+        if (!$this->allowGroupSharing()) {
461
+            throw new \Exception('Group sharing is now allowed');
462
+        }
463
+
464
+        // Verify if the user can share with this group
465
+        if ($this->shareWithGroupMembersOnly()) {
466
+            $sharedBy = $this->userManager->get($share->getSharedBy());
467
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
468
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
469
+                throw new \Exception('Sharing is only allowed within your own groups');
470
+            }
471
+        }
472
+
473
+        /*
474 474
 		 * TODO: Could be costly, fix
475 475
 		 *
476 476
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
477 477
 		 */
478
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
479
-		$existingShares = $provider->getSharesByPath($share->getNode());
480
-		foreach($existingShares as $existingShare) {
481
-			try {
482
-				if ($existingShare->getFullId() === $share->getFullId()) {
483
-					continue;
484
-				}
485
-			} catch (\UnexpectedValueException $e) {
486
-				//It is a new share so just continue
487
-			}
488
-
489
-			if ($existingShare->getSharedWith() === $share->getSharedWith()) {
490
-				throw new \Exception('Path is already shared with this group');
491
-			}
492
-		}
493
-	}
494
-
495
-	/**
496
-	 * Check for pre share requirements for link shares
497
-	 *
498
-	 * @param \OCP\Share\IShare $share
499
-	 * @throws \Exception
500
-	 */
501
-	protected function linkCreateChecks(\OCP\Share\IShare $share) {
502
-		// Are link shares allowed?
503
-		if (!$this->shareApiAllowLinks()) {
504
-			throw new \Exception('Link sharing is not allowed');
505
-		}
506
-
507
-		// Link shares by definition can't have share permissions
508
-		if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
509
-			throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
510
-		}
511
-
512
-		// Check if public upload is allowed
513
-		if (!$this->shareApiLinkAllowPublicUpload() &&
514
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
515
-			throw new \InvalidArgumentException('Public upload is not allowed');
516
-		}
517
-	}
518
-
519
-	/**
520
-	 * To make sure we don't get invisible link shares we set the parent
521
-	 * of a link if it is a reshare. This is a quick word around
522
-	 * until we can properly display multiple link shares in the UI
523
-	 *
524
-	 * See: https://github.com/owncloud/core/issues/22295
525
-	 *
526
-	 * FIXME: Remove once multiple link shares can be properly displayed
527
-	 *
528
-	 * @param \OCP\Share\IShare $share
529
-	 */
530
-	protected function setLinkParent(\OCP\Share\IShare $share) {
531
-
532
-		// No sense in checking if the method is not there.
533
-		if (method_exists($share, 'setParent')) {
534
-			$storage = $share->getNode()->getStorage();
535
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
536
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
537
-				$share->setParent($storage->getShareId());
538
-			}
539
-		};
540
-	}
541
-
542
-	/**
543
-	 * @param File|Folder $path
544
-	 */
545
-	protected function pathCreateChecks($path) {
546
-		// Make sure that we do not share a path that contains a shared mountpoint
547
-		if ($path instanceof \OCP\Files\Folder) {
548
-			$mounts = $this->mountManager->findIn($path->getPath());
549
-			foreach($mounts as $mount) {
550
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
551
-					throw new \InvalidArgumentException('Path contains files shared with you');
552
-				}
553
-			}
554
-		}
555
-	}
556
-
557
-	/**
558
-	 * Check if the user that is sharing can actually share
559
-	 *
560
-	 * @param \OCP\Share\IShare $share
561
-	 * @throws \Exception
562
-	 */
563
-	protected function canShare(\OCP\Share\IShare $share) {
564
-		if (!$this->shareApiEnabled()) {
565
-			throw new \Exception('Sharing is disabled');
566
-		}
567
-
568
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
569
-			throw new \Exception('Sharing is disabled for you');
570
-		}
571
-	}
572
-
573
-	/**
574
-	 * Share a path
575
-	 *
576
-	 * @param \OCP\Share\IShare $share
577
-	 * @return Share The share object
578
-	 * @throws \Exception
579
-	 *
580
-	 * TODO: handle link share permissions or check them
581
-	 */
582
-	public function createShare(\OCP\Share\IShare $share) {
583
-		$this->canShare($share);
584
-
585
-		$this->generalCreateChecks($share);
586
-
587
-		// Verify if there are any issues with the path
588
-		$this->pathCreateChecks($share->getNode());
589
-
590
-		/*
478
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
479
+        $existingShares = $provider->getSharesByPath($share->getNode());
480
+        foreach($existingShares as $existingShare) {
481
+            try {
482
+                if ($existingShare->getFullId() === $share->getFullId()) {
483
+                    continue;
484
+                }
485
+            } catch (\UnexpectedValueException $e) {
486
+                //It is a new share so just continue
487
+            }
488
+
489
+            if ($existingShare->getSharedWith() === $share->getSharedWith()) {
490
+                throw new \Exception('Path is already shared with this group');
491
+            }
492
+        }
493
+    }
494
+
495
+    /**
496
+     * Check for pre share requirements for link shares
497
+     *
498
+     * @param \OCP\Share\IShare $share
499
+     * @throws \Exception
500
+     */
501
+    protected function linkCreateChecks(\OCP\Share\IShare $share) {
502
+        // Are link shares allowed?
503
+        if (!$this->shareApiAllowLinks()) {
504
+            throw new \Exception('Link sharing is not allowed');
505
+        }
506
+
507
+        // Link shares by definition can't have share permissions
508
+        if ($share->getPermissions() & \OCP\Constants::PERMISSION_SHARE) {
509
+            throw new \InvalidArgumentException('Link shares can’t have reshare permissions');
510
+        }
511
+
512
+        // Check if public upload is allowed
513
+        if (!$this->shareApiLinkAllowPublicUpload() &&
514
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
515
+            throw new \InvalidArgumentException('Public upload is not allowed');
516
+        }
517
+    }
518
+
519
+    /**
520
+     * To make sure we don't get invisible link shares we set the parent
521
+     * of a link if it is a reshare. This is a quick word around
522
+     * until we can properly display multiple link shares in the UI
523
+     *
524
+     * See: https://github.com/owncloud/core/issues/22295
525
+     *
526
+     * FIXME: Remove once multiple link shares can be properly displayed
527
+     *
528
+     * @param \OCP\Share\IShare $share
529
+     */
530
+    protected function setLinkParent(\OCP\Share\IShare $share) {
531
+
532
+        // No sense in checking if the method is not there.
533
+        if (method_exists($share, 'setParent')) {
534
+            $storage = $share->getNode()->getStorage();
535
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
536
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
537
+                $share->setParent($storage->getShareId());
538
+            }
539
+        };
540
+    }
541
+
542
+    /**
543
+     * @param File|Folder $path
544
+     */
545
+    protected function pathCreateChecks($path) {
546
+        // Make sure that we do not share a path that contains a shared mountpoint
547
+        if ($path instanceof \OCP\Files\Folder) {
548
+            $mounts = $this->mountManager->findIn($path->getPath());
549
+            foreach($mounts as $mount) {
550
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
551
+                    throw new \InvalidArgumentException('Path contains files shared with you');
552
+                }
553
+            }
554
+        }
555
+    }
556
+
557
+    /**
558
+     * Check if the user that is sharing can actually share
559
+     *
560
+     * @param \OCP\Share\IShare $share
561
+     * @throws \Exception
562
+     */
563
+    protected function canShare(\OCP\Share\IShare $share) {
564
+        if (!$this->shareApiEnabled()) {
565
+            throw new \Exception('Sharing is disabled');
566
+        }
567
+
568
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
569
+            throw new \Exception('Sharing is disabled for you');
570
+        }
571
+    }
572
+
573
+    /**
574
+     * Share a path
575
+     *
576
+     * @param \OCP\Share\IShare $share
577
+     * @return Share The share object
578
+     * @throws \Exception
579
+     *
580
+     * TODO: handle link share permissions or check them
581
+     */
582
+    public function createShare(\OCP\Share\IShare $share) {
583
+        $this->canShare($share);
584
+
585
+        $this->generalCreateChecks($share);
586
+
587
+        // Verify if there are any issues with the path
588
+        $this->pathCreateChecks($share->getNode());
589
+
590
+        /*
591 591
 		 * On creation of a share the owner is always the owner of the path
592 592
 		 * Except for mounted federated shares.
593 593
 		 */
594
-		$storage = $share->getNode()->getStorage();
595
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
596
-			$parent = $share->getNode()->getParent();
597
-			while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
598
-				$parent = $parent->getParent();
599
-			}
600
-			$share->setShareOwner($parent->getOwner()->getUID());
601
-		} else {
602
-			$share->setShareOwner($share->getNode()->getOwner()->getUID());
603
-		}
604
-
605
-		//Verify share type
606
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
607
-			$this->userCreateChecks($share);
608
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
609
-			$this->groupCreateChecks($share);
610
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
611
-			$this->linkCreateChecks($share);
612
-			$this->setLinkParent($share);
613
-
614
-			/*
594
+        $storage = $share->getNode()->getStorage();
595
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
596
+            $parent = $share->getNode()->getParent();
597
+            while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
598
+                $parent = $parent->getParent();
599
+            }
600
+            $share->setShareOwner($parent->getOwner()->getUID());
601
+        } else {
602
+            $share->setShareOwner($share->getNode()->getOwner()->getUID());
603
+        }
604
+
605
+        //Verify share type
606
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
607
+            $this->userCreateChecks($share);
608
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
609
+            $this->groupCreateChecks($share);
610
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
611
+            $this->linkCreateChecks($share);
612
+            $this->setLinkParent($share);
613
+
614
+            /*
615 615
 			 * For now ignore a set token.
616 616
 			 */
617
-			$share->setToken(
618
-				$this->secureRandom->generate(
619
-					\OC\Share\Constants::TOKEN_LENGTH,
620
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
621
-				)
622
-			);
623
-
624
-			//Verify the expiration date
625
-			$this->validateExpirationDate($share);
626
-
627
-			//Verify the password
628
-			$this->verifyPassword($share->getPassword());
629
-
630
-			// If a password is set. Hash it!
631
-			if ($share->getPassword() !== null) {
632
-				$share->setPassword($this->hasher->hash($share->getPassword()));
633
-			}
634
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
635
-			$share->setToken(
636
-				$this->secureRandom->generate(
637
-					\OC\Share\Constants::TOKEN_LENGTH,
638
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
639
-				)
640
-			);
641
-		}
642
-
643
-		// Cannot share with the owner
644
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
645
-			$share->getSharedWith() === $share->getShareOwner()) {
646
-			throw new \InvalidArgumentException('Can’t share with the share owner');
647
-		}
648
-
649
-		// Generate the target
650
-		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
651
-		$target = \OC\Files\Filesystem::normalizePath($target);
652
-		$share->setTarget($target);
653
-
654
-		// Pre share event
655
-		$event = new GenericEvent($share);
656
-		$a = $this->eventDispatcher->dispatch('OCP\Share::preShare', $event);
657
-		if ($event->isPropagationStopped() && $event->hasArgument('error')) {
658
-			throw new \Exception($event->getArgument('error'));
659
-		}
660
-
661
-		$oldShare = $share;
662
-		$provider = $this->factory->getProviderForType($share->getShareType());
663
-		$share = $provider->create($share);
664
-		//reuse the node we already have
665
-		$share->setNode($oldShare->getNode());
666
-
667
-		// Post share event
668
-		$event = new GenericEvent($share);
669
-		$this->eventDispatcher->dispatch('OCP\Share::postShare', $event);
670
-
671
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
672
-			$mailSend = $share->getMailSend();
673
-			if($mailSend === true) {
674
-				$user = $this->userManager->get($share->getSharedWith());
675
-				if ($user !== null) {
676
-					$emailAddress = $user->getEMailAddress();
677
-					if ($emailAddress !== null && $emailAddress !== '') {
678
-						$userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null);
679
-						$l = $this->l10nFactory->get('lib', $userLang);
680
-						$this->sendMailNotification(
681
-							$l,
682
-							$share->getNode()->getName(),
683
-							$this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]),
684
-							$share->getSharedBy(),
685
-							$emailAddress,
686
-							$share->getExpirationDate()
687
-						);
688
-						$this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
689
-					} else {
690
-						$this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
691
-					}
692
-				} else {
693
-					$this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
694
-				}
695
-			} else {
696
-				$this->logger->debug('Share notification not send because mailsend is false.', ['app' => 'share']);
697
-			}
698
-		}
699
-
700
-		return $share;
701
-	}
702
-
703
-	/**
704
-	 * @param IL10N $l Language of the recipient
705
-	 * @param string $filename file/folder name
706
-	 * @param string $link link to the file/folder
707
-	 * @param string $initiator user ID of share sender
708
-	 * @param string $shareWith email address of share receiver
709
-	 * @param \DateTime|null $expiration
710
-	 * @throws \Exception If mail couldn't be sent
711
-	 */
712
-	protected function sendMailNotification(IL10N $l,
713
-											$filename,
714
-											$link,
715
-											$initiator,
716
-											$shareWith,
717
-											\DateTime $expiration = null) {
718
-		$initiatorUser = $this->userManager->get($initiator);
719
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
720
-
721
-		$message = $this->mailer->createMessage();
722
-
723
-		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
724
-			'filename' => $filename,
725
-			'link' => $link,
726
-			'initiator' => $initiatorDisplayName,
727
-			'expiration' => $expiration,
728
-			'shareWith' => $shareWith,
729
-		]);
730
-
731
-		$emailTemplate->setSubject($l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename)));
732
-		$emailTemplate->addHeader();
733
-		$emailTemplate->addHeading($l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
734
-		$text = $l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
735
-
736
-		$emailTemplate->addBodyText(
737
-			$text . ' ' . $l->t('Click the button below to open it.'),
738
-			$text
739
-		);
740
-		$emailTemplate->addBodyButton(
741
-			$l->t('Open »%s«', [$filename]),
742
-			$link
743
-		);
744
-
745
-		$message->setTo([$shareWith]);
746
-
747
-		// The "From" contains the sharers name
748
-		$instanceName = $this->defaults->getName();
749
-		$senderName = $l->t(
750
-			'%s via %s',
751
-			[
752
-				$initiatorDisplayName,
753
-				$instanceName
754
-			]
755
-		);
756
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
757
-
758
-		// The "Reply-To" is set to the sharer if an mail address is configured
759
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
760
-		$initiatorEmail = $initiatorUser->getEMailAddress();
761
-		if($initiatorEmail !== null) {
762
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
763
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
764
-		} else {
765
-			$emailTemplate->addFooter();
766
-		}
767
-
768
-		$message->useTemplate($emailTemplate);
769
-		$this->mailer->send($message);
770
-	}
771
-
772
-	/**
773
-	 * Update a share
774
-	 *
775
-	 * @param \OCP\Share\IShare $share
776
-	 * @return \OCP\Share\IShare The share object
777
-	 * @throws \InvalidArgumentException
778
-	 */
779
-	public function updateShare(\OCP\Share\IShare $share) {
780
-		$expirationDateUpdated = false;
781
-
782
-		$this->canShare($share);
783
-
784
-		try {
785
-			$originalShare = $this->getShareById($share->getFullId());
786
-		} catch (\UnexpectedValueException $e) {
787
-			throw new \InvalidArgumentException('Share does not have a full id');
788
-		}
789
-
790
-		// We can't change the share type!
791
-		if ($share->getShareType() !== $originalShare->getShareType()) {
792
-			throw new \InvalidArgumentException('Can’t change share type');
793
-		}
794
-
795
-		// We can only change the recipient on user shares
796
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
797
-		    $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
798
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
799
-		}
800
-
801
-		// Cannot share with the owner
802
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
803
-			$share->getSharedWith() === $share->getShareOwner()) {
804
-			throw new \InvalidArgumentException('Can’t share with the share owner');
805
-		}
806
-
807
-		$this->generalCreateChecks($share);
808
-
809
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
810
-			$this->userCreateChecks($share);
811
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
812
-			$this->groupCreateChecks($share);
813
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
814
-			$this->linkCreateChecks($share);
815
-
816
-			$this->updateSharePasswordIfNeeded($share, $originalShare);
817
-
818
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
819
-				//Verify the expiration date
820
-				$this->validateExpirationDate($share);
821
-				$expirationDateUpdated = true;
822
-			}
823
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
824
-			$plainTextPassword = $share->getPassword();
825
-			if (!$this->updateSharePasswordIfNeeded($share, $originalShare)) {
826
-				$plainTextPassword = null;
827
-			}
828
-		}
829
-
830
-		$this->pathCreateChecks($share->getNode());
831
-
832
-		// Now update the share!
833
-		$provider = $this->factory->getProviderForType($share->getShareType());
834
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
835
-			$share = $provider->update($share, $plainTextPassword);
836
-		} else {
837
-			$share = $provider->update($share);
838
-		}
839
-
840
-		if ($expirationDateUpdated === true) {
841
-			\OC_Hook::emit('OCP\Share', 'post_set_expiration_date', [
842
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
843
-				'itemSource' => $share->getNode()->getId(),
844
-				'date' => $share->getExpirationDate(),
845
-				'uidOwner' => $share->getSharedBy(),
846
-			]);
847
-		}
848
-
849
-		if ($share->getPassword() !== $originalShare->getPassword()) {
850
-			\OC_Hook::emit('OCP\Share', 'post_update_password', [
851
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
852
-				'itemSource' => $share->getNode()->getId(),
853
-				'uidOwner' => $share->getSharedBy(),
854
-				'token' => $share->getToken(),
855
-				'disabled' => is_null($share->getPassword()),
856
-			]);
857
-		}
858
-
859
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
860
-			if ($this->userManager->userExists($share->getShareOwner())) {
861
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
862
-			} else {
863
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
864
-			}
865
-			\OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
866
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
867
-				'itemSource' => $share->getNode()->getId(),
868
-				'shareType' => $share->getShareType(),
869
-				'shareWith' => $share->getSharedWith(),
870
-				'uidOwner' => $share->getSharedBy(),
871
-				'permissions' => $share->getPermissions(),
872
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
873
-			));
874
-		}
875
-
876
-		return $share;
877
-	}
878
-
879
-	/**
880
-	 * Updates the password of the given share if it is not the same as the
881
-	 * password of the original share.
882
-	 *
883
-	 * @param \OCP\Share\IShare $share the share to update its password.
884
-	 * @param \OCP\Share\IShare $originalShare the original share to compare its
885
-	 *        password with.
886
-	 * @return boolean whether the password was updated or not.
887
-	 */
888
-	private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
889
-		// Password updated.
890
-		if ($share->getPassword() !== $originalShare->getPassword()) {
891
-			//Verify the password
892
-			$this->verifyPassword($share->getPassword());
893
-
894
-			// If a password is set. Hash it!
895
-			if ($share->getPassword() !== null) {
896
-				$share->setPassword($this->hasher->hash($share->getPassword()));
897
-
898
-				return true;
899
-			}
900
-		}
901
-
902
-		return false;
903
-	}
904
-
905
-	/**
906
-	 * Delete all the children of this share
907
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
908
-	 *
909
-	 * @param \OCP\Share\IShare $share
910
-	 * @return \OCP\Share\IShare[] List of deleted shares
911
-	 */
912
-	protected function deleteChildren(\OCP\Share\IShare $share) {
913
-		$deletedShares = [];
914
-
915
-		$provider = $this->factory->getProviderForType($share->getShareType());
916
-
917
-		foreach ($provider->getChildren($share) as $child) {
918
-			$deletedChildren = $this->deleteChildren($child);
919
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
920
-
921
-			$provider->delete($child);
922
-			$deletedShares[] = $child;
923
-		}
924
-
925
-		return $deletedShares;
926
-	}
927
-
928
-	/**
929
-	 * Delete a share
930
-	 *
931
-	 * @param \OCP\Share\IShare $share
932
-	 * @throws ShareNotFound
933
-	 * @throws \InvalidArgumentException
934
-	 */
935
-	public function deleteShare(\OCP\Share\IShare $share) {
936
-
937
-		try {
938
-			$share->getFullId();
939
-		} catch (\UnexpectedValueException $e) {
940
-			throw new \InvalidArgumentException('Share does not have a full id');
941
-		}
942
-
943
-		$event = new GenericEvent($share);
944
-		$this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
945
-
946
-		// Get all children and delete them as well
947
-		$deletedShares = $this->deleteChildren($share);
948
-
949
-		// Do the actual delete
950
-		$provider = $this->factory->getProviderForType($share->getShareType());
951
-		$provider->delete($share);
952
-
953
-		// All the deleted shares caused by this delete
954
-		$deletedShares[] = $share;
955
-
956
-		// Emit post hook
957
-		$event->setArgument('deletedShares', $deletedShares);
958
-		$this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
959
-	}
960
-
961
-
962
-	/**
963
-	 * Unshare a file as the recipient.
964
-	 * This can be different from a regular delete for example when one of
965
-	 * the users in a groups deletes that share. But the provider should
966
-	 * handle this.
967
-	 *
968
-	 * @param \OCP\Share\IShare $share
969
-	 * @param string $recipientId
970
-	 */
971
-	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
972
-		list($providerId, ) = $this->splitFullId($share->getFullId());
973
-		$provider = $this->factory->getProvider($providerId);
974
-
975
-		$provider->deleteFromSelf($share, $recipientId);
976
-		$event = new GenericEvent($share);
977
-		$this->eventDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
978
-	}
979
-
980
-	/**
981
-	 * @inheritdoc
982
-	 */
983
-	public function moveShare(\OCP\Share\IShare $share, $recipientId) {
984
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
985
-			throw new \InvalidArgumentException('Can’t change target of link share');
986
-		}
987
-
988
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
989
-			throw new \InvalidArgumentException('Invalid recipient');
990
-		}
991
-
992
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
993
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
994
-			if (is_null($sharedWith)) {
995
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
996
-			}
997
-			$recipient = $this->userManager->get($recipientId);
998
-			if (!$sharedWith->inGroup($recipient)) {
999
-				throw new \InvalidArgumentException('Invalid recipient');
1000
-			}
1001
-		}
1002
-
1003
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1004
-		$provider = $this->factory->getProvider($providerId);
1005
-
1006
-		$provider->move($share, $recipientId);
1007
-	}
1008
-
1009
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1010
-		$providers = $this->factory->getAllProviders();
1011
-
1012
-		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1013
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1014
-			foreach ($newShares as $fid => $data) {
1015
-				if (!isset($shares[$fid])) {
1016
-					$shares[$fid] = [];
1017
-				}
1018
-
1019
-				$shares[$fid] = array_merge($shares[$fid], $data);
1020
-			}
1021
-			return $shares;
1022
-		}, []);
1023
-	}
1024
-
1025
-	/**
1026
-	 * @inheritdoc
1027
-	 */
1028
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1029
-		if ($path !== null &&
1030
-				!($path instanceof \OCP\Files\File) &&
1031
-				!($path instanceof \OCP\Files\Folder)) {
1032
-			throw new \InvalidArgumentException('invalid path');
1033
-		}
1034
-
1035
-		try {
1036
-			$provider = $this->factory->getProviderForType($shareType);
1037
-		} catch (ProviderException $e) {
1038
-			return [];
1039
-		}
1040
-
1041
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1042
-
1043
-		/*
617
+            $share->setToken(
618
+                $this->secureRandom->generate(
619
+                    \OC\Share\Constants::TOKEN_LENGTH,
620
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
621
+                )
622
+            );
623
+
624
+            //Verify the expiration date
625
+            $this->validateExpirationDate($share);
626
+
627
+            //Verify the password
628
+            $this->verifyPassword($share->getPassword());
629
+
630
+            // If a password is set. Hash it!
631
+            if ($share->getPassword() !== null) {
632
+                $share->setPassword($this->hasher->hash($share->getPassword()));
633
+            }
634
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
635
+            $share->setToken(
636
+                $this->secureRandom->generate(
637
+                    \OC\Share\Constants::TOKEN_LENGTH,
638
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
639
+                )
640
+            );
641
+        }
642
+
643
+        // Cannot share with the owner
644
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
645
+            $share->getSharedWith() === $share->getShareOwner()) {
646
+            throw new \InvalidArgumentException('Can’t share with the share owner');
647
+        }
648
+
649
+        // Generate the target
650
+        $target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
651
+        $target = \OC\Files\Filesystem::normalizePath($target);
652
+        $share->setTarget($target);
653
+
654
+        // Pre share event
655
+        $event = new GenericEvent($share);
656
+        $a = $this->eventDispatcher->dispatch('OCP\Share::preShare', $event);
657
+        if ($event->isPropagationStopped() && $event->hasArgument('error')) {
658
+            throw new \Exception($event->getArgument('error'));
659
+        }
660
+
661
+        $oldShare = $share;
662
+        $provider = $this->factory->getProviderForType($share->getShareType());
663
+        $share = $provider->create($share);
664
+        //reuse the node we already have
665
+        $share->setNode($oldShare->getNode());
666
+
667
+        // Post share event
668
+        $event = new GenericEvent($share);
669
+        $this->eventDispatcher->dispatch('OCP\Share::postShare', $event);
670
+
671
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
672
+            $mailSend = $share->getMailSend();
673
+            if($mailSend === true) {
674
+                $user = $this->userManager->get($share->getSharedWith());
675
+                if ($user !== null) {
676
+                    $emailAddress = $user->getEMailAddress();
677
+                    if ($emailAddress !== null && $emailAddress !== '') {
678
+                        $userLang = $this->config->getUserValue($share->getSharedWith(), 'core', 'lang', null);
679
+                        $l = $this->l10nFactory->get('lib', $userLang);
680
+                        $this->sendMailNotification(
681
+                            $l,
682
+                            $share->getNode()->getName(),
683
+                            $this->urlGenerator->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $share->getNode()->getId()]),
684
+                            $share->getSharedBy(),
685
+                            $emailAddress,
686
+                            $share->getExpirationDate()
687
+                        );
688
+                        $this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
689
+                    } else {
690
+                        $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
691
+                    }
692
+                } else {
693
+                    $this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
694
+                }
695
+            } else {
696
+                $this->logger->debug('Share notification not send because mailsend is false.', ['app' => 'share']);
697
+            }
698
+        }
699
+
700
+        return $share;
701
+    }
702
+
703
+    /**
704
+     * @param IL10N $l Language of the recipient
705
+     * @param string $filename file/folder name
706
+     * @param string $link link to the file/folder
707
+     * @param string $initiator user ID of share sender
708
+     * @param string $shareWith email address of share receiver
709
+     * @param \DateTime|null $expiration
710
+     * @throws \Exception If mail couldn't be sent
711
+     */
712
+    protected function sendMailNotification(IL10N $l,
713
+                                            $filename,
714
+                                            $link,
715
+                                            $initiator,
716
+                                            $shareWith,
717
+                                            \DateTime $expiration = null) {
718
+        $initiatorUser = $this->userManager->get($initiator);
719
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
720
+
721
+        $message = $this->mailer->createMessage();
722
+
723
+        $emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
724
+            'filename' => $filename,
725
+            'link' => $link,
726
+            'initiator' => $initiatorDisplayName,
727
+            'expiration' => $expiration,
728
+            'shareWith' => $shareWith,
729
+        ]);
730
+
731
+        $emailTemplate->setSubject($l->t('%s shared »%s« with you', array($initiatorDisplayName, $filename)));
732
+        $emailTemplate->addHeader();
733
+        $emailTemplate->addHeading($l->t('%s shared »%s« with you', [$initiatorDisplayName, $filename]), false);
734
+        $text = $l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
735
+
736
+        $emailTemplate->addBodyText(
737
+            $text . ' ' . $l->t('Click the button below to open it.'),
738
+            $text
739
+        );
740
+        $emailTemplate->addBodyButton(
741
+            $l->t('Open »%s«', [$filename]),
742
+            $link
743
+        );
744
+
745
+        $message->setTo([$shareWith]);
746
+
747
+        // The "From" contains the sharers name
748
+        $instanceName = $this->defaults->getName();
749
+        $senderName = $l->t(
750
+            '%s via %s',
751
+            [
752
+                $initiatorDisplayName,
753
+                $instanceName
754
+            ]
755
+        );
756
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
757
+
758
+        // The "Reply-To" is set to the sharer if an mail address is configured
759
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
760
+        $initiatorEmail = $initiatorUser->getEMailAddress();
761
+        if($initiatorEmail !== null) {
762
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
763
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
764
+        } else {
765
+            $emailTemplate->addFooter();
766
+        }
767
+
768
+        $message->useTemplate($emailTemplate);
769
+        $this->mailer->send($message);
770
+    }
771
+
772
+    /**
773
+     * Update a share
774
+     *
775
+     * @param \OCP\Share\IShare $share
776
+     * @return \OCP\Share\IShare The share object
777
+     * @throws \InvalidArgumentException
778
+     */
779
+    public function updateShare(\OCP\Share\IShare $share) {
780
+        $expirationDateUpdated = false;
781
+
782
+        $this->canShare($share);
783
+
784
+        try {
785
+            $originalShare = $this->getShareById($share->getFullId());
786
+        } catch (\UnexpectedValueException $e) {
787
+            throw new \InvalidArgumentException('Share does not have a full id');
788
+        }
789
+
790
+        // We can't change the share type!
791
+        if ($share->getShareType() !== $originalShare->getShareType()) {
792
+            throw new \InvalidArgumentException('Can’t change share type');
793
+        }
794
+
795
+        // We can only change the recipient on user shares
796
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
797
+            $share->getShareType() !== \OCP\Share::SHARE_TYPE_USER) {
798
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
799
+        }
800
+
801
+        // Cannot share with the owner
802
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
803
+            $share->getSharedWith() === $share->getShareOwner()) {
804
+            throw new \InvalidArgumentException('Can’t share with the share owner');
805
+        }
806
+
807
+        $this->generalCreateChecks($share);
808
+
809
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
810
+            $this->userCreateChecks($share);
811
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
812
+            $this->groupCreateChecks($share);
813
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
814
+            $this->linkCreateChecks($share);
815
+
816
+            $this->updateSharePasswordIfNeeded($share, $originalShare);
817
+
818
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
819
+                //Verify the expiration date
820
+                $this->validateExpirationDate($share);
821
+                $expirationDateUpdated = true;
822
+            }
823
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
824
+            $plainTextPassword = $share->getPassword();
825
+            if (!$this->updateSharePasswordIfNeeded($share, $originalShare)) {
826
+                $plainTextPassword = null;
827
+            }
828
+        }
829
+
830
+        $this->pathCreateChecks($share->getNode());
831
+
832
+        // Now update the share!
833
+        $provider = $this->factory->getProviderForType($share->getShareType());
834
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
835
+            $share = $provider->update($share, $plainTextPassword);
836
+        } else {
837
+            $share = $provider->update($share);
838
+        }
839
+
840
+        if ($expirationDateUpdated === true) {
841
+            \OC_Hook::emit('OCP\Share', 'post_set_expiration_date', [
842
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
843
+                'itemSource' => $share->getNode()->getId(),
844
+                'date' => $share->getExpirationDate(),
845
+                'uidOwner' => $share->getSharedBy(),
846
+            ]);
847
+        }
848
+
849
+        if ($share->getPassword() !== $originalShare->getPassword()) {
850
+            \OC_Hook::emit('OCP\Share', 'post_update_password', [
851
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
852
+                'itemSource' => $share->getNode()->getId(),
853
+                'uidOwner' => $share->getSharedBy(),
854
+                'token' => $share->getToken(),
855
+                'disabled' => is_null($share->getPassword()),
856
+            ]);
857
+        }
858
+
859
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
860
+            if ($this->userManager->userExists($share->getShareOwner())) {
861
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
862
+            } else {
863
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
864
+            }
865
+            \OC_Hook::emit('OCP\Share', 'post_update_permissions', array(
866
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
867
+                'itemSource' => $share->getNode()->getId(),
868
+                'shareType' => $share->getShareType(),
869
+                'shareWith' => $share->getSharedWith(),
870
+                'uidOwner' => $share->getSharedBy(),
871
+                'permissions' => $share->getPermissions(),
872
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
873
+            ));
874
+        }
875
+
876
+        return $share;
877
+    }
878
+
879
+    /**
880
+     * Updates the password of the given share if it is not the same as the
881
+     * password of the original share.
882
+     *
883
+     * @param \OCP\Share\IShare $share the share to update its password.
884
+     * @param \OCP\Share\IShare $originalShare the original share to compare its
885
+     *        password with.
886
+     * @return boolean whether the password was updated or not.
887
+     */
888
+    private function updateSharePasswordIfNeeded(\OCP\Share\IShare $share, \OCP\Share\IShare $originalShare) {
889
+        // Password updated.
890
+        if ($share->getPassword() !== $originalShare->getPassword()) {
891
+            //Verify the password
892
+            $this->verifyPassword($share->getPassword());
893
+
894
+            // If a password is set. Hash it!
895
+            if ($share->getPassword() !== null) {
896
+                $share->setPassword($this->hasher->hash($share->getPassword()));
897
+
898
+                return true;
899
+            }
900
+        }
901
+
902
+        return false;
903
+    }
904
+
905
+    /**
906
+     * Delete all the children of this share
907
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
908
+     *
909
+     * @param \OCP\Share\IShare $share
910
+     * @return \OCP\Share\IShare[] List of deleted shares
911
+     */
912
+    protected function deleteChildren(\OCP\Share\IShare $share) {
913
+        $deletedShares = [];
914
+
915
+        $provider = $this->factory->getProviderForType($share->getShareType());
916
+
917
+        foreach ($provider->getChildren($share) as $child) {
918
+            $deletedChildren = $this->deleteChildren($child);
919
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
920
+
921
+            $provider->delete($child);
922
+            $deletedShares[] = $child;
923
+        }
924
+
925
+        return $deletedShares;
926
+    }
927
+
928
+    /**
929
+     * Delete a share
930
+     *
931
+     * @param \OCP\Share\IShare $share
932
+     * @throws ShareNotFound
933
+     * @throws \InvalidArgumentException
934
+     */
935
+    public function deleteShare(\OCP\Share\IShare $share) {
936
+
937
+        try {
938
+            $share->getFullId();
939
+        } catch (\UnexpectedValueException $e) {
940
+            throw new \InvalidArgumentException('Share does not have a full id');
941
+        }
942
+
943
+        $event = new GenericEvent($share);
944
+        $this->eventDispatcher->dispatch('OCP\Share::preUnshare', $event);
945
+
946
+        // Get all children and delete them as well
947
+        $deletedShares = $this->deleteChildren($share);
948
+
949
+        // Do the actual delete
950
+        $provider = $this->factory->getProviderForType($share->getShareType());
951
+        $provider->delete($share);
952
+
953
+        // All the deleted shares caused by this delete
954
+        $deletedShares[] = $share;
955
+
956
+        // Emit post hook
957
+        $event->setArgument('deletedShares', $deletedShares);
958
+        $this->eventDispatcher->dispatch('OCP\Share::postUnshare', $event);
959
+    }
960
+
961
+
962
+    /**
963
+     * Unshare a file as the recipient.
964
+     * This can be different from a regular delete for example when one of
965
+     * the users in a groups deletes that share. But the provider should
966
+     * handle this.
967
+     *
968
+     * @param \OCP\Share\IShare $share
969
+     * @param string $recipientId
970
+     */
971
+    public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
972
+        list($providerId, ) = $this->splitFullId($share->getFullId());
973
+        $provider = $this->factory->getProvider($providerId);
974
+
975
+        $provider->deleteFromSelf($share, $recipientId);
976
+        $event = new GenericEvent($share);
977
+        $this->eventDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
978
+    }
979
+
980
+    /**
981
+     * @inheritdoc
982
+     */
983
+    public function moveShare(\OCP\Share\IShare $share, $recipientId) {
984
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
985
+            throw new \InvalidArgumentException('Can’t change target of link share');
986
+        }
987
+
988
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() !== $recipientId) {
989
+            throw new \InvalidArgumentException('Invalid recipient');
990
+        }
991
+
992
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
993
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
994
+            if (is_null($sharedWith)) {
995
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
996
+            }
997
+            $recipient = $this->userManager->get($recipientId);
998
+            if (!$sharedWith->inGroup($recipient)) {
999
+                throw new \InvalidArgumentException('Invalid recipient');
1000
+            }
1001
+        }
1002
+
1003
+        list($providerId, ) = $this->splitFullId($share->getFullId());
1004
+        $provider = $this->factory->getProvider($providerId);
1005
+
1006
+        $provider->move($share, $recipientId);
1007
+    }
1008
+
1009
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1010
+        $providers = $this->factory->getAllProviders();
1011
+
1012
+        return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1013
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1014
+            foreach ($newShares as $fid => $data) {
1015
+                if (!isset($shares[$fid])) {
1016
+                    $shares[$fid] = [];
1017
+                }
1018
+
1019
+                $shares[$fid] = array_merge($shares[$fid], $data);
1020
+            }
1021
+            return $shares;
1022
+        }, []);
1023
+    }
1024
+
1025
+    /**
1026
+     * @inheritdoc
1027
+     */
1028
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1029
+        if ($path !== null &&
1030
+                !($path instanceof \OCP\Files\File) &&
1031
+                !($path instanceof \OCP\Files\Folder)) {
1032
+            throw new \InvalidArgumentException('invalid path');
1033
+        }
1034
+
1035
+        try {
1036
+            $provider = $this->factory->getProviderForType($shareType);
1037
+        } catch (ProviderException $e) {
1038
+            return [];
1039
+        }
1040
+
1041
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1042
+
1043
+        /*
1044 1044
 		 * Work around so we don't return expired shares but still follow
1045 1045
 		 * proper pagination.
1046 1046
 		 */
1047 1047
 
1048
-		$shares2 = [];
1049
-
1050
-		while(true) {
1051
-			$added = 0;
1052
-			foreach ($shares as $share) {
1053
-
1054
-				try {
1055
-					$this->checkExpireDate($share);
1056
-				} catch (ShareNotFound $e) {
1057
-					//Ignore since this basically means the share is deleted
1058
-					continue;
1059
-				}
1060
-
1061
-				$added++;
1062
-				$shares2[] = $share;
1063
-
1064
-				if (count($shares2) === $limit) {
1065
-					break;
1066
-				}
1067
-			}
1068
-
1069
-			// If we did not fetch more shares than the limit then there are no more shares
1070
-			if (count($shares) < $limit) {
1071
-				break;
1072
-			}
1073
-
1074
-			if (count($shares2) === $limit) {
1075
-				break;
1076
-			}
1077
-
1078
-			// If there was no limit on the select we are done
1079
-			if ($limit === -1) {
1080
-				break;
1081
-			}
1082
-
1083
-			$offset += $added;
1084
-
1085
-			// Fetch again $limit shares
1086
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1087
-
1088
-			// No more shares means we are done
1089
-			if (empty($shares)) {
1090
-				break;
1091
-			}
1092
-		}
1093
-
1094
-		$shares = $shares2;
1095
-
1096
-		return $shares;
1097
-	}
1098
-
1099
-	/**
1100
-	 * @inheritdoc
1101
-	 */
1102
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1103
-		try {
1104
-			$provider = $this->factory->getProviderForType($shareType);
1105
-		} catch (ProviderException $e) {
1106
-			return [];
1107
-		}
1108
-
1109
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1110
-
1111
-		// remove all shares which are already expired
1112
-		foreach ($shares as $key => $share) {
1113
-			try {
1114
-				$this->checkExpireDate($share);
1115
-			} catch (ShareNotFound $e) {
1116
-				unset($shares[$key]);
1117
-			}
1118
-		}
1119
-
1120
-		return $shares;
1121
-	}
1122
-
1123
-	/**
1124
-	 * @inheritdoc
1125
-	 */
1126
-	public function getShareById($id, $recipient = null) {
1127
-		if ($id === null) {
1128
-			throw new ShareNotFound();
1129
-		}
1130
-
1131
-		list($providerId, $id) = $this->splitFullId($id);
1132
-
1133
-		try {
1134
-			$provider = $this->factory->getProvider($providerId);
1135
-		} catch (ProviderException $e) {
1136
-			throw new ShareNotFound();
1137
-		}
1138
-
1139
-		$share = $provider->getShareById($id, $recipient);
1140
-
1141
-		$this->checkExpireDate($share);
1142
-
1143
-		return $share;
1144
-	}
1145
-
1146
-	/**
1147
-	 * Get all the shares for a given path
1148
-	 *
1149
-	 * @param \OCP\Files\Node $path
1150
-	 * @param int $page
1151
-	 * @param int $perPage
1152
-	 *
1153
-	 * @return Share[]
1154
-	 */
1155
-	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1156
-		return [];
1157
-	}
1158
-
1159
-	/**
1160
-	 * Get the share by token possible with password
1161
-	 *
1162
-	 * @param string $token
1163
-	 * @return Share
1164
-	 *
1165
-	 * @throws ShareNotFound
1166
-	 */
1167
-	public function getShareByToken($token) {
1168
-		// tokens can't be valid local user names
1169
-		if ($this->userManager->userExists($token)) {
1170
-			throw new ShareNotFound();
1171
-		}
1172
-		$share = null;
1173
-		try {
1174
-			if($this->shareApiAllowLinks()) {
1175
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1176
-				$share = $provider->getShareByToken($token);
1177
-			}
1178
-		} catch (ProviderException $e) {
1179
-		} catch (ShareNotFound $e) {
1180
-		}
1181
-
1182
-
1183
-		// If it is not a link share try to fetch a federated share by token
1184
-		if ($share === null) {
1185
-			try {
1186
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1187
-				$share = $provider->getShareByToken($token);
1188
-			} catch (ProviderException $e) {
1189
-			} catch (ShareNotFound $e) {
1190
-			}
1191
-		}
1192
-
1193
-		// If it is not a link share try to fetch a mail share by token
1194
-		if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1195
-			try {
1196
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1197
-				$share = $provider->getShareByToken($token);
1198
-			} catch (ProviderException $e) {
1199
-			} catch (ShareNotFound $e) {
1200
-			}
1201
-		}
1202
-
1203
-		if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
1204
-			try {
1205
-				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_CIRCLE);
1206
-				$share = $provider->getShareByToken($token);
1207
-			} catch (ProviderException $e) {
1208
-			} catch (ShareNotFound $e) {
1209
-			}
1210
-		}
1211
-
1212
-		if ($share === null) {
1213
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1214
-		}
1215
-
1216
-		$this->checkExpireDate($share);
1217
-
1218
-		/*
1048
+        $shares2 = [];
1049
+
1050
+        while(true) {
1051
+            $added = 0;
1052
+            foreach ($shares as $share) {
1053
+
1054
+                try {
1055
+                    $this->checkExpireDate($share);
1056
+                } catch (ShareNotFound $e) {
1057
+                    //Ignore since this basically means the share is deleted
1058
+                    continue;
1059
+                }
1060
+
1061
+                $added++;
1062
+                $shares2[] = $share;
1063
+
1064
+                if (count($shares2) === $limit) {
1065
+                    break;
1066
+                }
1067
+            }
1068
+
1069
+            // If we did not fetch more shares than the limit then there are no more shares
1070
+            if (count($shares) < $limit) {
1071
+                break;
1072
+            }
1073
+
1074
+            if (count($shares2) === $limit) {
1075
+                break;
1076
+            }
1077
+
1078
+            // If there was no limit on the select we are done
1079
+            if ($limit === -1) {
1080
+                break;
1081
+            }
1082
+
1083
+            $offset += $added;
1084
+
1085
+            // Fetch again $limit shares
1086
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1087
+
1088
+            // No more shares means we are done
1089
+            if (empty($shares)) {
1090
+                break;
1091
+            }
1092
+        }
1093
+
1094
+        $shares = $shares2;
1095
+
1096
+        return $shares;
1097
+    }
1098
+
1099
+    /**
1100
+     * @inheritdoc
1101
+     */
1102
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1103
+        try {
1104
+            $provider = $this->factory->getProviderForType($shareType);
1105
+        } catch (ProviderException $e) {
1106
+            return [];
1107
+        }
1108
+
1109
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1110
+
1111
+        // remove all shares which are already expired
1112
+        foreach ($shares as $key => $share) {
1113
+            try {
1114
+                $this->checkExpireDate($share);
1115
+            } catch (ShareNotFound $e) {
1116
+                unset($shares[$key]);
1117
+            }
1118
+        }
1119
+
1120
+        return $shares;
1121
+    }
1122
+
1123
+    /**
1124
+     * @inheritdoc
1125
+     */
1126
+    public function getShareById($id, $recipient = null) {
1127
+        if ($id === null) {
1128
+            throw new ShareNotFound();
1129
+        }
1130
+
1131
+        list($providerId, $id) = $this->splitFullId($id);
1132
+
1133
+        try {
1134
+            $provider = $this->factory->getProvider($providerId);
1135
+        } catch (ProviderException $e) {
1136
+            throw new ShareNotFound();
1137
+        }
1138
+
1139
+        $share = $provider->getShareById($id, $recipient);
1140
+
1141
+        $this->checkExpireDate($share);
1142
+
1143
+        return $share;
1144
+    }
1145
+
1146
+    /**
1147
+     * Get all the shares for a given path
1148
+     *
1149
+     * @param \OCP\Files\Node $path
1150
+     * @param int $page
1151
+     * @param int $perPage
1152
+     *
1153
+     * @return Share[]
1154
+     */
1155
+    public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1156
+        return [];
1157
+    }
1158
+
1159
+    /**
1160
+     * Get the share by token possible with password
1161
+     *
1162
+     * @param string $token
1163
+     * @return Share
1164
+     *
1165
+     * @throws ShareNotFound
1166
+     */
1167
+    public function getShareByToken($token) {
1168
+        // tokens can't be valid local user names
1169
+        if ($this->userManager->userExists($token)) {
1170
+            throw new ShareNotFound();
1171
+        }
1172
+        $share = null;
1173
+        try {
1174
+            if($this->shareApiAllowLinks()) {
1175
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1176
+                $share = $provider->getShareByToken($token);
1177
+            }
1178
+        } catch (ProviderException $e) {
1179
+        } catch (ShareNotFound $e) {
1180
+        }
1181
+
1182
+
1183
+        // If it is not a link share try to fetch a federated share by token
1184
+        if ($share === null) {
1185
+            try {
1186
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_REMOTE);
1187
+                $share = $provider->getShareByToken($token);
1188
+            } catch (ProviderException $e) {
1189
+            } catch (ShareNotFound $e) {
1190
+            }
1191
+        }
1192
+
1193
+        // If it is not a link share try to fetch a mail share by token
1194
+        if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_EMAIL)) {
1195
+            try {
1196
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_EMAIL);
1197
+                $share = $provider->getShareByToken($token);
1198
+            } catch (ProviderException $e) {
1199
+            } catch (ShareNotFound $e) {
1200
+            }
1201
+        }
1202
+
1203
+        if ($share === null && $this->shareProviderExists(\OCP\Share::SHARE_TYPE_CIRCLE)) {
1204
+            try {
1205
+                $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_CIRCLE);
1206
+                $share = $provider->getShareByToken($token);
1207
+            } catch (ProviderException $e) {
1208
+            } catch (ShareNotFound $e) {
1209
+            }
1210
+        }
1211
+
1212
+        if ($share === null) {
1213
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1214
+        }
1215
+
1216
+        $this->checkExpireDate($share);
1217
+
1218
+        /*
1219 1219
 		 * Reduce the permissions for link shares if public upload is not enabled
1220 1220
 		 */
1221
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1222
-			!$this->shareApiLinkAllowPublicUpload()) {
1223
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1224
-		}
1225
-
1226
-		return $share;
1227
-	}
1228
-
1229
-	protected function checkExpireDate($share) {
1230
-		if ($share->getExpirationDate() !== null &&
1231
-			$share->getExpirationDate() <= new \DateTime()) {
1232
-			$this->deleteShare($share);
1233
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1234
-		}
1235
-
1236
-	}
1237
-
1238
-	/**
1239
-	 * Verify the password of a public share
1240
-	 *
1241
-	 * @param \OCP\Share\IShare $share
1242
-	 * @param string $password
1243
-	 * @return bool
1244
-	 */
1245
-	public function checkPassword(\OCP\Share\IShare $share, $password) {
1246
-		$passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1247
-			|| $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1248
-		if (!$passwordProtected) {
1249
-			//TODO maybe exception?
1250
-			return false;
1251
-		}
1252
-
1253
-		if ($password === null || $share->getPassword() === null) {
1254
-			return false;
1255
-		}
1256
-
1257
-		$newHash = '';
1258
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1259
-			return false;
1260
-		}
1261
-
1262
-		if (!empty($newHash)) {
1263
-			$share->setPassword($newHash);
1264
-			$provider = $this->factory->getProviderForType($share->getShareType());
1265
-			$provider->update($share);
1266
-		}
1267
-
1268
-		return true;
1269
-	}
1270
-
1271
-	/**
1272
-	 * @inheritdoc
1273
-	 */
1274
-	public function userDeleted($uid) {
1275
-		$types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
1276
-
1277
-		foreach ($types as $type) {
1278
-			try {
1279
-				$provider = $this->factory->getProviderForType($type);
1280
-			} catch (ProviderException $e) {
1281
-				continue;
1282
-			}
1283
-			$provider->userDeleted($uid, $type);
1284
-		}
1285
-	}
1286
-
1287
-	/**
1288
-	 * @inheritdoc
1289
-	 */
1290
-	public function groupDeleted($gid) {
1291
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1292
-		$provider->groupDeleted($gid);
1293
-	}
1294
-
1295
-	/**
1296
-	 * @inheritdoc
1297
-	 */
1298
-	public function userDeletedFromGroup($uid, $gid) {
1299
-		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1300
-		$provider->userDeletedFromGroup($uid, $gid);
1301
-	}
1302
-
1303
-	/**
1304
-	 * Get access list to a path. This means
1305
-	 * all the users that can access a given path.
1306
-	 *
1307
-	 * Consider:
1308
-	 * -root
1309
-	 * |-folder1 (23)
1310
-	 *  |-folder2 (32)
1311
-	 *   |-fileA (42)
1312
-	 *
1313
-	 * fileA is shared with user1 and user1@server1
1314
-	 * folder2 is shared with group2 (user4 is a member of group2)
1315
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1316
-	 *
1317
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1318
-	 * [
1319
-	 *  users  => [
1320
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1321
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1322
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1323
-	 *  ],
1324
-	 *  remote => [
1325
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1326
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1327
-	 *  ],
1328
-	 *  public => bool
1329
-	 *  mail => bool
1330
-	 * ]
1331
-	 *
1332
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1333
-	 * [
1334
-	 *  users  => ['user1', 'user2', 'user4'],
1335
-	 *  remote => bool,
1336
-	 *  public => bool
1337
-	 *  mail => bool
1338
-	 * ]
1339
-	 *
1340
-	 * This is required for encryption/activity
1341
-	 *
1342
-	 * @param \OCP\Files\Node $path
1343
-	 * @param bool $recursive Should we check all parent folders as well
1344
-	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1345
-	 * @return array
1346
-	 */
1347
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1348
-		$owner = $path->getOwner()->getUID();
1349
-
1350
-		if ($currentAccess) {
1351
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1352
-		} else {
1353
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1354
-		}
1355
-		if (!$this->userManager->userExists($owner)) {
1356
-			return $al;
1357
-		}
1358
-
1359
-		//Get node for the owner
1360
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1361
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1362
-			$path = $userFolder->getById($path->getId())[0];
1363
-		}
1364
-
1365
-		$providers = $this->factory->getAllProviders();
1366
-
1367
-		/** @var Node[] $nodes */
1368
-		$nodes = [];
1369
-
1370
-
1371
-		if ($currentAccess) {
1372
-			$ownerPath = $path->getPath();
1373
-			$ownerPath = explode('/', $ownerPath, 4);
1374
-			if (count($ownerPath) < 4) {
1375
-				$ownerPath = '';
1376
-			} else {
1377
-				$ownerPath = $ownerPath[3];
1378
-			}
1379
-			$al['users'][$owner] = [
1380
-				'node_id' => $path->getId(),
1381
-				'node_path' => '/' . $ownerPath,
1382
-			];
1383
-		} else {
1384
-			$al['users'][] = $owner;
1385
-		}
1386
-
1387
-		// Collect all the shares
1388
-		while ($path->getPath() !== $userFolder->getPath()) {
1389
-			$nodes[] = $path;
1390
-			if (!$recursive) {
1391
-				break;
1392
-			}
1393
-			$path = $path->getParent();
1394
-		}
1395
-
1396
-		foreach ($providers as $provider) {
1397
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1398
-
1399
-			foreach ($tmp as $k => $v) {
1400
-				if (isset($al[$k])) {
1401
-					if (is_array($al[$k])) {
1402
-						if ($currentAccess) {
1403
-							$al[$k] += $v;
1404
-						} else {
1405
-							$al[$k] = array_merge($al[$k], $v);
1406
-							$al[$k] = array_unique($al[$k]);
1407
-							$al[$k] = array_values($al[$k]);
1408
-						}
1409
-					} else {
1410
-						$al[$k] = $al[$k] || $v;
1411
-					}
1412
-				} else {
1413
-					$al[$k] = $v;
1414
-				}
1415
-			}
1416
-		}
1417
-
1418
-		return $al;
1419
-	}
1420
-
1421
-	/**
1422
-	 * Create a new share
1423
-	 * @return \OCP\Share\IShare
1424
-	 */
1425
-	public function newShare() {
1426
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1427
-	}
1428
-
1429
-	/**
1430
-	 * Is the share API enabled
1431
-	 *
1432
-	 * @return bool
1433
-	 */
1434
-	public function shareApiEnabled() {
1435
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1436
-	}
1437
-
1438
-	/**
1439
-	 * Is public link sharing enabled
1440
-	 *
1441
-	 * @return bool
1442
-	 */
1443
-	public function shareApiAllowLinks() {
1444
-		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1445
-	}
1446
-
1447
-	/**
1448
-	 * Is password on public link requires
1449
-	 *
1450
-	 * @return bool
1451
-	 */
1452
-	public function shareApiLinkEnforcePassword() {
1453
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1454
-	}
1455
-
1456
-	/**
1457
-	 * Is default expire date enabled
1458
-	 *
1459
-	 * @return bool
1460
-	 */
1461
-	public function shareApiLinkDefaultExpireDate() {
1462
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1463
-	}
1464
-
1465
-	/**
1466
-	 * Is default expire date enforced
1467
-	 *`
1468
-	 * @return bool
1469
-	 */
1470
-	public function shareApiLinkDefaultExpireDateEnforced() {
1471
-		return $this->shareApiLinkDefaultExpireDate() &&
1472
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1473
-	}
1474
-
1475
-	/**
1476
-	 * Number of default expire days
1477
-	 *shareApiLinkAllowPublicUpload
1478
-	 * @return int
1479
-	 */
1480
-	public function shareApiLinkDefaultExpireDays() {
1481
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1482
-	}
1483
-
1484
-	/**
1485
-	 * Allow public upload on link shares
1486
-	 *
1487
-	 * @return bool
1488
-	 */
1489
-	public function shareApiLinkAllowPublicUpload() {
1490
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1491
-	}
1492
-
1493
-	/**
1494
-	 * check if user can only share with group members
1495
-	 * @return bool
1496
-	 */
1497
-	public function shareWithGroupMembersOnly() {
1498
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1499
-	}
1500
-
1501
-	/**
1502
-	 * Check if users can share with groups
1503
-	 * @return bool
1504
-	 */
1505
-	public function allowGroupSharing() {
1506
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1507
-	}
1508
-
1509
-	/**
1510
-	 * Copied from \OC_Util::isSharingDisabledForUser
1511
-	 *
1512
-	 * TODO: Deprecate fuction from OC_Util
1513
-	 *
1514
-	 * @param string $userId
1515
-	 * @return bool
1516
-	 */
1517
-	public function sharingDisabledForUser($userId) {
1518
-		if ($userId === null) {
1519
-			return false;
1520
-		}
1521
-
1522
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1523
-			return $this->sharingDisabledForUsersCache[$userId];
1524
-		}
1525
-
1526
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1527
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1528
-			$excludedGroups = json_decode($groupsList);
1529
-			if (is_null($excludedGroups)) {
1530
-				$excludedGroups = explode(',', $groupsList);
1531
-				$newValue = json_encode($excludedGroups);
1532
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1533
-			}
1534
-			$user = $this->userManager->get($userId);
1535
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1536
-			if (!empty($usersGroups)) {
1537
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1538
-				// if the user is only in groups which are disabled for sharing then
1539
-				// sharing is also disabled for the user
1540
-				if (empty($remainingGroups)) {
1541
-					$this->sharingDisabledForUsersCache[$userId] = true;
1542
-					return true;
1543
-				}
1544
-			}
1545
-		}
1546
-
1547
-		$this->sharingDisabledForUsersCache[$userId] = false;
1548
-		return false;
1549
-	}
1550
-
1551
-	/**
1552
-	 * @inheritdoc
1553
-	 */
1554
-	public function outgoingServer2ServerSharesAllowed() {
1555
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1556
-	}
1557
-
1558
-	/**
1559
-	 * @inheritdoc
1560
-	 */
1561
-	public function shareProviderExists($shareType) {
1562
-		try {
1563
-			$this->factory->getProviderForType($shareType);
1564
-		} catch (ProviderException $e) {
1565
-			return false;
1566
-		}
1567
-
1568
-		return true;
1569
-	}
1221
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK &&
1222
+            !$this->shareApiLinkAllowPublicUpload()) {
1223
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1224
+        }
1225
+
1226
+        return $share;
1227
+    }
1228
+
1229
+    protected function checkExpireDate($share) {
1230
+        if ($share->getExpirationDate() !== null &&
1231
+            $share->getExpirationDate() <= new \DateTime()) {
1232
+            $this->deleteShare($share);
1233
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1234
+        }
1235
+
1236
+    }
1237
+
1238
+    /**
1239
+     * Verify the password of a public share
1240
+     *
1241
+     * @param \OCP\Share\IShare $share
1242
+     * @param string $password
1243
+     * @return bool
1244
+     */
1245
+    public function checkPassword(\OCP\Share\IShare $share, $password) {
1246
+        $passwordProtected = $share->getShareType() !== \OCP\Share::SHARE_TYPE_LINK
1247
+            || $share->getShareType() !== \OCP\Share::SHARE_TYPE_EMAIL;
1248
+        if (!$passwordProtected) {
1249
+            //TODO maybe exception?
1250
+            return false;
1251
+        }
1252
+
1253
+        if ($password === null || $share->getPassword() === null) {
1254
+            return false;
1255
+        }
1256
+
1257
+        $newHash = '';
1258
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1259
+            return false;
1260
+        }
1261
+
1262
+        if (!empty($newHash)) {
1263
+            $share->setPassword($newHash);
1264
+            $provider = $this->factory->getProviderForType($share->getShareType());
1265
+            $provider->update($share);
1266
+        }
1267
+
1268
+        return true;
1269
+    }
1270
+
1271
+    /**
1272
+     * @inheritdoc
1273
+     */
1274
+    public function userDeleted($uid) {
1275
+        $types = [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK, \OCP\Share::SHARE_TYPE_REMOTE, \OCP\Share::SHARE_TYPE_EMAIL];
1276
+
1277
+        foreach ($types as $type) {
1278
+            try {
1279
+                $provider = $this->factory->getProviderForType($type);
1280
+            } catch (ProviderException $e) {
1281
+                continue;
1282
+            }
1283
+            $provider->userDeleted($uid, $type);
1284
+        }
1285
+    }
1286
+
1287
+    /**
1288
+     * @inheritdoc
1289
+     */
1290
+    public function groupDeleted($gid) {
1291
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1292
+        $provider->groupDeleted($gid);
1293
+    }
1294
+
1295
+    /**
1296
+     * @inheritdoc
1297
+     */
1298
+    public function userDeletedFromGroup($uid, $gid) {
1299
+        $provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
1300
+        $provider->userDeletedFromGroup($uid, $gid);
1301
+    }
1302
+
1303
+    /**
1304
+     * Get access list to a path. This means
1305
+     * all the users that can access a given path.
1306
+     *
1307
+     * Consider:
1308
+     * -root
1309
+     * |-folder1 (23)
1310
+     *  |-folder2 (32)
1311
+     *   |-fileA (42)
1312
+     *
1313
+     * fileA is shared with user1 and user1@server1
1314
+     * folder2 is shared with group2 (user4 is a member of group2)
1315
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1316
+     *
1317
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1318
+     * [
1319
+     *  users  => [
1320
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1321
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1322
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1323
+     *  ],
1324
+     *  remote => [
1325
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1326
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1327
+     *  ],
1328
+     *  public => bool
1329
+     *  mail => bool
1330
+     * ]
1331
+     *
1332
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1333
+     * [
1334
+     *  users  => ['user1', 'user2', 'user4'],
1335
+     *  remote => bool,
1336
+     *  public => bool
1337
+     *  mail => bool
1338
+     * ]
1339
+     *
1340
+     * This is required for encryption/activity
1341
+     *
1342
+     * @param \OCP\Files\Node $path
1343
+     * @param bool $recursive Should we check all parent folders as well
1344
+     * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1345
+     * @return array
1346
+     */
1347
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1348
+        $owner = $path->getOwner()->getUID();
1349
+
1350
+        if ($currentAccess) {
1351
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1352
+        } else {
1353
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1354
+        }
1355
+        if (!$this->userManager->userExists($owner)) {
1356
+            return $al;
1357
+        }
1358
+
1359
+        //Get node for the owner
1360
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1361
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1362
+            $path = $userFolder->getById($path->getId())[0];
1363
+        }
1364
+
1365
+        $providers = $this->factory->getAllProviders();
1366
+
1367
+        /** @var Node[] $nodes */
1368
+        $nodes = [];
1369
+
1370
+
1371
+        if ($currentAccess) {
1372
+            $ownerPath = $path->getPath();
1373
+            $ownerPath = explode('/', $ownerPath, 4);
1374
+            if (count($ownerPath) < 4) {
1375
+                $ownerPath = '';
1376
+            } else {
1377
+                $ownerPath = $ownerPath[3];
1378
+            }
1379
+            $al['users'][$owner] = [
1380
+                'node_id' => $path->getId(),
1381
+                'node_path' => '/' . $ownerPath,
1382
+            ];
1383
+        } else {
1384
+            $al['users'][] = $owner;
1385
+        }
1386
+
1387
+        // Collect all the shares
1388
+        while ($path->getPath() !== $userFolder->getPath()) {
1389
+            $nodes[] = $path;
1390
+            if (!$recursive) {
1391
+                break;
1392
+            }
1393
+            $path = $path->getParent();
1394
+        }
1395
+
1396
+        foreach ($providers as $provider) {
1397
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1398
+
1399
+            foreach ($tmp as $k => $v) {
1400
+                if (isset($al[$k])) {
1401
+                    if (is_array($al[$k])) {
1402
+                        if ($currentAccess) {
1403
+                            $al[$k] += $v;
1404
+                        } else {
1405
+                            $al[$k] = array_merge($al[$k], $v);
1406
+                            $al[$k] = array_unique($al[$k]);
1407
+                            $al[$k] = array_values($al[$k]);
1408
+                        }
1409
+                    } else {
1410
+                        $al[$k] = $al[$k] || $v;
1411
+                    }
1412
+                } else {
1413
+                    $al[$k] = $v;
1414
+                }
1415
+            }
1416
+        }
1417
+
1418
+        return $al;
1419
+    }
1420
+
1421
+    /**
1422
+     * Create a new share
1423
+     * @return \OCP\Share\IShare
1424
+     */
1425
+    public function newShare() {
1426
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1427
+    }
1428
+
1429
+    /**
1430
+     * Is the share API enabled
1431
+     *
1432
+     * @return bool
1433
+     */
1434
+    public function shareApiEnabled() {
1435
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1436
+    }
1437
+
1438
+    /**
1439
+     * Is public link sharing enabled
1440
+     *
1441
+     * @return bool
1442
+     */
1443
+    public function shareApiAllowLinks() {
1444
+        return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1445
+    }
1446
+
1447
+    /**
1448
+     * Is password on public link requires
1449
+     *
1450
+     * @return bool
1451
+     */
1452
+    public function shareApiLinkEnforcePassword() {
1453
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1454
+    }
1455
+
1456
+    /**
1457
+     * Is default expire date enabled
1458
+     *
1459
+     * @return bool
1460
+     */
1461
+    public function shareApiLinkDefaultExpireDate() {
1462
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1463
+    }
1464
+
1465
+    /**
1466
+     * Is default expire date enforced
1467
+     *`
1468
+     * @return bool
1469
+     */
1470
+    public function shareApiLinkDefaultExpireDateEnforced() {
1471
+        return $this->shareApiLinkDefaultExpireDate() &&
1472
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1473
+    }
1474
+
1475
+    /**
1476
+     * Number of default expire days
1477
+     *shareApiLinkAllowPublicUpload
1478
+     * @return int
1479
+     */
1480
+    public function shareApiLinkDefaultExpireDays() {
1481
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1482
+    }
1483
+
1484
+    /**
1485
+     * Allow public upload on link shares
1486
+     *
1487
+     * @return bool
1488
+     */
1489
+    public function shareApiLinkAllowPublicUpload() {
1490
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1491
+    }
1492
+
1493
+    /**
1494
+     * check if user can only share with group members
1495
+     * @return bool
1496
+     */
1497
+    public function shareWithGroupMembersOnly() {
1498
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1499
+    }
1500
+
1501
+    /**
1502
+     * Check if users can share with groups
1503
+     * @return bool
1504
+     */
1505
+    public function allowGroupSharing() {
1506
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1507
+    }
1508
+
1509
+    /**
1510
+     * Copied from \OC_Util::isSharingDisabledForUser
1511
+     *
1512
+     * TODO: Deprecate fuction from OC_Util
1513
+     *
1514
+     * @param string $userId
1515
+     * @return bool
1516
+     */
1517
+    public function sharingDisabledForUser($userId) {
1518
+        if ($userId === null) {
1519
+            return false;
1520
+        }
1521
+
1522
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1523
+            return $this->sharingDisabledForUsersCache[$userId];
1524
+        }
1525
+
1526
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1527
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1528
+            $excludedGroups = json_decode($groupsList);
1529
+            if (is_null($excludedGroups)) {
1530
+                $excludedGroups = explode(',', $groupsList);
1531
+                $newValue = json_encode($excludedGroups);
1532
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1533
+            }
1534
+            $user = $this->userManager->get($userId);
1535
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1536
+            if (!empty($usersGroups)) {
1537
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1538
+                // if the user is only in groups which are disabled for sharing then
1539
+                // sharing is also disabled for the user
1540
+                if (empty($remainingGroups)) {
1541
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1542
+                    return true;
1543
+                }
1544
+            }
1545
+        }
1546
+
1547
+        $this->sharingDisabledForUsersCache[$userId] = false;
1548
+        return false;
1549
+    }
1550
+
1551
+    /**
1552
+     * @inheritdoc
1553
+     */
1554
+    public function outgoingServer2ServerSharesAllowed() {
1555
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1556
+    }
1557
+
1558
+    /**
1559
+     * @inheritdoc
1560
+     */
1561
+    public function shareProviderExists($shareType) {
1562
+        try {
1563
+            $this->factory->getProviderForType($shareType);
1564
+        } catch (ProviderException $e) {
1565
+            return false;
1566
+        }
1567
+
1568
+        return true;
1569
+    }
1570 1570
 
1571 1571
 }
Please login to merge, or discard this patch.
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -355,7 +355,7 @@  discard block
 block discarded – undo
355 355
 
356 356
 		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
357 357
 			$expirationDate = new \DateTime();
358
-			$expirationDate->setTime(0,0,0);
358
+			$expirationDate->setTime(0, 0, 0);
359 359
 			$expirationDate->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
360 360
 		}
361 361
 
@@ -367,7 +367,7 @@  discard block
 block discarded – undo
367 367
 
368 368
 			$date = new \DateTime();
369 369
 			$date->setTime(0, 0, 0);
370
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
370
+			$date->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
371 371
 			if ($date < $expirationDate) {
372 372
 				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
373 373
 				throw new GenericShareException($message, $message, 404);
@@ -420,7 +420,7 @@  discard block
 block discarded – undo
420 420
 		 */
421 421
 		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_USER);
422 422
 		$existingShares = $provider->getSharesByPath($share->getNode());
423
-		foreach($existingShares as $existingShare) {
423
+		foreach ($existingShares as $existingShare) {
424 424
 			// Ignore if it is the same share
425 425
 			try {
426 426
 				if ($existingShare->getFullId() === $share->getFullId()) {
@@ -477,7 +477,7 @@  discard block
 block discarded – undo
477 477
 		 */
478 478
 		$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_GROUP);
479 479
 		$existingShares = $provider->getSharesByPath($share->getNode());
480
-		foreach($existingShares as $existingShare) {
480
+		foreach ($existingShares as $existingShare) {
481 481
 			try {
482 482
 				if ($existingShare->getFullId() === $share->getFullId()) {
483 483
 					continue;
@@ -546,7 +546,7 @@  discard block
 block discarded – undo
546 546
 		// Make sure that we do not share a path that contains a shared mountpoint
547 547
 		if ($path instanceof \OCP\Files\Folder) {
548 548
 			$mounts = $this->mountManager->findIn($path->getPath());
549
-			foreach($mounts as $mount) {
549
+			foreach ($mounts as $mount) {
550 550
 				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
551 551
 					throw new \InvalidArgumentException('Path contains files shared with you');
552 552
 				}
@@ -594,7 +594,7 @@  discard block
 block discarded – undo
594 594
 		$storage = $share->getNode()->getStorage();
595 595
 		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
596 596
 			$parent = $share->getNode()->getParent();
597
-			while($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
597
+			while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
598 598
 				$parent = $parent->getParent();
599 599
 			}
600 600
 			$share->setShareOwner($parent->getOwner()->getUID());
@@ -647,7 +647,7 @@  discard block
 block discarded – undo
647 647
 		}
648 648
 
649 649
 		// Generate the target
650
-		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
650
+		$target = $this->config->getSystemValue('share_folder', '/').'/'.$share->getNode()->getName();
651 651
 		$target = \OC\Files\Filesystem::normalizePath($target);
652 652
 		$share->setTarget($target);
653 653
 
@@ -670,7 +670,7 @@  discard block
 block discarded – undo
670 670
 
671 671
 		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
672 672
 			$mailSend = $share->getMailSend();
673
-			if($mailSend === true) {
673
+			if ($mailSend === true) {
674 674
 				$user = $this->userManager->get($share->getSharedWith());
675 675
 				if ($user !== null) {
676 676
 					$emailAddress = $user->getEMailAddress();
@@ -685,12 +685,12 @@  discard block
 block discarded – undo
685 685
 							$emailAddress,
686 686
 							$share->getExpirationDate()
687 687
 						);
688
-						$this->logger->debug('Send share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
688
+						$this->logger->debug('Send share notification to '.$emailAddress.' for share with ID '.$share->getId(), ['app' => 'share']);
689 689
 					} else {
690
-						$this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
690
+						$this->logger->debug('Share notification not send to '.$share->getSharedWith().' because email address is not set.', ['app' => 'share']);
691 691
 					}
692 692
 				} else {
693
-					$this->logger->debug('Share notification not send to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
693
+					$this->logger->debug('Share notification not send to '.$share->getSharedWith().' because user could not be found.', ['app' => 'share']);
694 694
 				}
695 695
 			} else {
696 696
 				$this->logger->debug('Share notification not send because mailsend is false.', ['app' => 'share']);
@@ -734,7 +734,7 @@  discard block
 block discarded – undo
734 734
 		$text = $l->t('%s shared »%s« with you.', [$initiatorDisplayName, $filename]);
735 735
 
736 736
 		$emailTemplate->addBodyText(
737
-			$text . ' ' . $l->t('Click the button below to open it.'),
737
+			$text.' '.$l->t('Click the button below to open it.'),
738 738
 			$text
739 739
 		);
740 740
 		$emailTemplate->addBodyButton(
@@ -758,9 +758,9 @@  discard block
 block discarded – undo
758 758
 		// The "Reply-To" is set to the sharer if an mail address is configured
759 759
 		// also the default footer contains a "Do not reply" which needs to be adjusted.
760 760
 		$initiatorEmail = $initiatorUser->getEMailAddress();
761
-		if($initiatorEmail !== null) {
761
+		if ($initiatorEmail !== null) {
762 762
 			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
763
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : ''));
763
+			$emailTemplate->addFooter($instanceName.($this->defaults->getSlogan() !== '' ? ' - '.$this->defaults->getSlogan() : ''));
764 764
 		} else {
765 765
 			$emailTemplate->addFooter();
766 766
 		}
@@ -969,7 +969,7 @@  discard block
 block discarded – undo
969 969
 	 * @param string $recipientId
970 970
 	 */
971 971
 	public function deleteFromSelf(\OCP\Share\IShare $share, $recipientId) {
972
-		list($providerId, ) = $this->splitFullId($share->getFullId());
972
+		list($providerId,) = $this->splitFullId($share->getFullId());
973 973
 		$provider = $this->factory->getProvider($providerId);
974 974
 
975 975
 		$provider->deleteFromSelf($share, $recipientId);
@@ -992,7 +992,7 @@  discard block
 block discarded – undo
992 992
 		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
993 993
 			$sharedWith = $this->groupManager->get($share->getSharedWith());
994 994
 			if (is_null($sharedWith)) {
995
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
995
+				throw new \InvalidArgumentException('Group "'.$share->getSharedWith().'" does not exist');
996 996
 			}
997 997
 			$recipient = $this->userManager->get($recipientId);
998 998
 			if (!$sharedWith->inGroup($recipient)) {
@@ -1000,7 +1000,7 @@  discard block
 block discarded – undo
1000 1000
 			}
1001 1001
 		}
1002 1002
 
1003
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1003
+		list($providerId,) = $this->splitFullId($share->getFullId());
1004 1004
 		$provider = $this->factory->getProvider($providerId);
1005 1005
 
1006 1006
 		$provider->move($share, $recipientId);
@@ -1047,7 +1047,7 @@  discard block
 block discarded – undo
1047 1047
 
1048 1048
 		$shares2 = [];
1049 1049
 
1050
-		while(true) {
1050
+		while (true) {
1051 1051
 			$added = 0;
1052 1052
 			foreach ($shares as $share) {
1053 1053
 
@@ -1152,7 +1152,7 @@  discard block
 block discarded – undo
1152 1152
 	 *
1153 1153
 	 * @return Share[]
1154 1154
 	 */
1155
-	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1155
+	public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1156 1156
 		return [];
1157 1157
 	}
1158 1158
 
@@ -1171,7 +1171,7 @@  discard block
 block discarded – undo
1171 1171
 		}
1172 1172
 		$share = null;
1173 1173
 		try {
1174
-			if($this->shareApiAllowLinks()) {
1174
+			if ($this->shareApiAllowLinks()) {
1175 1175
 				$provider = $this->factory->getProviderForType(\OCP\Share::SHARE_TYPE_LINK);
1176 1176
 				$share = $provider->getShareByToken($token);
1177 1177
 			}
@@ -1378,7 +1378,7 @@  discard block
 block discarded – undo
1378 1378
 			}
1379 1379
 			$al['users'][$owner] = [
1380 1380
 				'node_id' => $path->getId(),
1381
-				'node_path' => '/' . $ownerPath,
1381
+				'node_path' => '/'.$ownerPath,
1382 1382
 			];
1383 1383
 		} else {
1384 1384
 			$al['users'][] = $owner;
@@ -1478,7 +1478,7 @@  discard block
 block discarded – undo
1478 1478
 	 * @return int
1479 1479
 	 */
1480 1480
 	public function shareApiLinkDefaultExpireDays() {
1481
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1481
+		return (int) $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1482 1482
 	}
1483 1483
 
1484 1484
 	/**
Please login to merge, or discard this patch.