Passed
Push — master ( ae4907...2ae60b )
by Morris
13:14 queued 12s
created
lib/private/Files/View.php 1 patch
Indentation   +2124 added lines, -2124 removed lines patch added patch discarded remove patch
@@ -84,2128 +84,2128 @@
 block discarded – undo
84 84
  * \OC\Files\Storage\Storage object
85 85
  */
86 86
 class View {
87
-	/** @var string */
88
-	private $fakeRoot = '';
89
-
90
-	/**
91
-	 * @var \OCP\Lock\ILockingProvider
92
-	 */
93
-	protected $lockingProvider;
94
-
95
-	private $lockingEnabled;
96
-
97
-	private $updaterEnabled = true;
98
-
99
-	/** @var \OC\User\Manager */
100
-	private $userManager;
101
-
102
-	/** @var \OCP\ILogger */
103
-	private $logger;
104
-
105
-	/**
106
-	 * @param string $root
107
-	 * @throws \Exception If $root contains an invalid path
108
-	 */
109
-	public function __construct($root = '') {
110
-		if (is_null($root)) {
111
-			throw new \InvalidArgumentException('Root can\'t be null');
112
-		}
113
-		if (!Filesystem::isValidPath($root)) {
114
-			throw new \Exception();
115
-		}
116
-
117
-		$this->fakeRoot = $root;
118
-		$this->lockingProvider = \OC::$server->getLockingProvider();
119
-		$this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
120
-		$this->userManager = \OC::$server->getUserManager();
121
-		$this->logger = \OC::$server->getLogger();
122
-	}
123
-
124
-	public function getAbsolutePath($path = '/') {
125
-		if ($path === null) {
126
-			return null;
127
-		}
128
-		$this->assertPathLength($path);
129
-		if ($path === '') {
130
-			$path = '/';
131
-		}
132
-		if ($path[0] !== '/') {
133
-			$path = '/' . $path;
134
-		}
135
-		return $this->fakeRoot . $path;
136
-	}
137
-
138
-	/**
139
-	 * change the root to a fake root
140
-	 *
141
-	 * @param string $fakeRoot
142
-	 * @return boolean|null
143
-	 */
144
-	public function chroot($fakeRoot) {
145
-		if (!$fakeRoot == '') {
146
-			if ($fakeRoot[0] !== '/') {
147
-				$fakeRoot = '/' . $fakeRoot;
148
-			}
149
-		}
150
-		$this->fakeRoot = $fakeRoot;
151
-	}
152
-
153
-	/**
154
-	 * get the fake root
155
-	 *
156
-	 * @return string
157
-	 */
158
-	public function getRoot() {
159
-		return $this->fakeRoot;
160
-	}
161
-
162
-	/**
163
-	 * get path relative to the root of the view
164
-	 *
165
-	 * @param string $path
166
-	 * @return string
167
-	 */
168
-	public function getRelativePath($path) {
169
-		$this->assertPathLength($path);
170
-		if ($this->fakeRoot == '') {
171
-			return $path;
172
-		}
173
-
174
-		if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) {
175
-			return '/';
176
-		}
177
-
178
-		// missing slashes can cause wrong matches!
179
-		$root = rtrim($this->fakeRoot, '/') . '/';
180
-
181
-		if (strpos($path, $root) !== 0) {
182
-			return null;
183
-		} else {
184
-			$path = substr($path, strlen($this->fakeRoot));
185
-			if (strlen($path) === 0) {
186
-				return '/';
187
-			} else {
188
-				return $path;
189
-			}
190
-		}
191
-	}
192
-
193
-	/**
194
-	 * get the mountpoint of the storage object for a path
195
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
196
-	 * returned mountpoint is relative to the absolute root of the filesystem
197
-	 * and does not take the chroot into account )
198
-	 *
199
-	 * @param string $path
200
-	 * @return string
201
-	 */
202
-	public function getMountPoint($path) {
203
-		return Filesystem::getMountPoint($this->getAbsolutePath($path));
204
-	}
205
-
206
-	/**
207
-	 * get the mountpoint of the storage object for a path
208
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
209
-	 * returned mountpoint is relative to the absolute root of the filesystem
210
-	 * and does not take the chroot into account )
211
-	 *
212
-	 * @param string $path
213
-	 * @return \OCP\Files\Mount\IMountPoint
214
-	 */
215
-	public function getMount($path) {
216
-		return Filesystem::getMountManager()->find($this->getAbsolutePath($path));
217
-	}
218
-
219
-	/**
220
-	 * resolve a path to a storage and internal path
221
-	 *
222
-	 * @param string $path
223
-	 * @return array an array consisting of the storage and the internal path
224
-	 */
225
-	public function resolvePath($path) {
226
-		$a = $this->getAbsolutePath($path);
227
-		$p = Filesystem::normalizePath($a);
228
-		return Filesystem::resolvePath($p);
229
-	}
230
-
231
-	/**
232
-	 * return the path to a local version of the file
233
-	 * we need this because we can't know if a file is stored local or not from
234
-	 * outside the filestorage and for some purposes a local file is needed
235
-	 *
236
-	 * @param string $path
237
-	 * @return string
238
-	 */
239
-	public function getLocalFile($path) {
240
-		$parent = substr($path, 0, strrpos($path, '/'));
241
-		$path = $this->getAbsolutePath($path);
242
-		[$storage, $internalPath] = Filesystem::resolvePath($path);
243
-		if (Filesystem::isValidPath($parent) and $storage) {
244
-			return $storage->getLocalFile($internalPath);
245
-		} else {
246
-			return null;
247
-		}
248
-	}
249
-
250
-	/**
251
-	 * @param string $path
252
-	 * @return string
253
-	 */
254
-	public function getLocalFolder($path) {
255
-		$parent = substr($path, 0, strrpos($path, '/'));
256
-		$path = $this->getAbsolutePath($path);
257
-		[$storage, $internalPath] = Filesystem::resolvePath($path);
258
-		if (Filesystem::isValidPath($parent) and $storage) {
259
-			return $storage->getLocalFolder($internalPath);
260
-		} else {
261
-			return null;
262
-		}
263
-	}
264
-
265
-	/**
266
-	 * the following functions operate with arguments and return values identical
267
-	 * to those of their PHP built-in equivalents. Mostly they are merely wrappers
268
-	 * for \OC\Files\Storage\Storage via basicOperation().
269
-	 */
270
-	public function mkdir($path) {
271
-		return $this->basicOperation('mkdir', $path, ['create', 'write']);
272
-	}
273
-
274
-	/**
275
-	 * remove mount point
276
-	 *
277
-	 * @param \OC\Files\Mount\MoveableMount $mount
278
-	 * @param string $path relative to data/
279
-	 * @return boolean
280
-	 */
281
-	protected function removeMount($mount, $path) {
282
-		if ($mount instanceof MoveableMount) {
283
-			// cut of /user/files to get the relative path to data/user/files
284
-			$pathParts = explode('/', $path, 4);
285
-			$relPath = '/' . $pathParts[3];
286
-			$this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
287
-			\OC_Hook::emit(
288
-				Filesystem::CLASSNAME, "umount",
289
-				[Filesystem::signal_param_path => $relPath]
290
-			);
291
-			$this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true);
292
-			$result = $mount->removeMount();
293
-			$this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true);
294
-			if ($result) {
295
-				\OC_Hook::emit(
296
-					Filesystem::CLASSNAME, "post_umount",
297
-					[Filesystem::signal_param_path => $relPath]
298
-				);
299
-			}
300
-			$this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true);
301
-			return $result;
302
-		} else {
303
-			// do not allow deleting the storage's root / the mount point
304
-			// because for some storages it might delete the whole contents
305
-			// but isn't supposed to work that way
306
-			return false;
307
-		}
308
-	}
309
-
310
-	public function disableCacheUpdate() {
311
-		$this->updaterEnabled = false;
312
-	}
313
-
314
-	public function enableCacheUpdate() {
315
-		$this->updaterEnabled = true;
316
-	}
317
-
318
-	protected function writeUpdate(Storage $storage, $internalPath, $time = null) {
319
-		if ($this->updaterEnabled) {
320
-			if (is_null($time)) {
321
-				$time = time();
322
-			}
323
-			$storage->getUpdater()->update($internalPath, $time);
324
-		}
325
-	}
326
-
327
-	protected function removeUpdate(Storage $storage, $internalPath) {
328
-		if ($this->updaterEnabled) {
329
-			$storage->getUpdater()->remove($internalPath);
330
-		}
331
-	}
332
-
333
-	protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) {
334
-		if ($this->updaterEnabled) {
335
-			$targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
336
-		}
337
-	}
338
-
339
-	/**
340
-	 * @param string $path
341
-	 * @return bool|mixed
342
-	 */
343
-	public function rmdir($path) {
344
-		$absolutePath = $this->getAbsolutePath($path);
345
-		$mount = Filesystem::getMountManager()->find($absolutePath);
346
-		if ($mount->getInternalPath($absolutePath) === '') {
347
-			return $this->removeMount($mount, $absolutePath);
348
-		}
349
-		if ($this->is_dir($path)) {
350
-			$result = $this->basicOperation('rmdir', $path, ['delete']);
351
-		} else {
352
-			$result = false;
353
-		}
354
-
355
-		if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
356
-			$storage = $mount->getStorage();
357
-			$internalPath = $mount->getInternalPath($absolutePath);
358
-			$storage->getUpdater()->remove($internalPath);
359
-		}
360
-		return $result;
361
-	}
362
-
363
-	/**
364
-	 * @param string $path
365
-	 * @return resource
366
-	 */
367
-	public function opendir($path) {
368
-		return $this->basicOperation('opendir', $path, ['read']);
369
-	}
370
-
371
-	/**
372
-	 * @param string $path
373
-	 * @return bool|mixed
374
-	 */
375
-	public function is_dir($path) {
376
-		if ($path == '/') {
377
-			return true;
378
-		}
379
-		return $this->basicOperation('is_dir', $path);
380
-	}
381
-
382
-	/**
383
-	 * @param string $path
384
-	 * @return bool|mixed
385
-	 */
386
-	public function is_file($path) {
387
-		if ($path == '/') {
388
-			return false;
389
-		}
390
-		return $this->basicOperation('is_file', $path);
391
-	}
392
-
393
-	/**
394
-	 * @param string $path
395
-	 * @return mixed
396
-	 */
397
-	public function stat($path) {
398
-		return $this->basicOperation('stat', $path);
399
-	}
400
-
401
-	/**
402
-	 * @param string $path
403
-	 * @return mixed
404
-	 */
405
-	public function filetype($path) {
406
-		return $this->basicOperation('filetype', $path);
407
-	}
408
-
409
-	/**
410
-	 * @param string $path
411
-	 * @return mixed
412
-	 */
413
-	public function filesize($path) {
414
-		return $this->basicOperation('filesize', $path);
415
-	}
416
-
417
-	/**
418
-	 * @param string $path
419
-	 * @return bool|mixed
420
-	 * @throws \OCP\Files\InvalidPathException
421
-	 */
422
-	public function readfile($path) {
423
-		$this->assertPathLength($path);
424
-		if (ob_get_level()) {
425
-			ob_end_clean();
426
-		}
427
-		$handle = $this->fopen($path, 'rb');
428
-		if ($handle) {
429
-			$chunkSize = 524288; // 512 kB chunks
430
-			while (!feof($handle)) {
431
-				echo fread($handle, $chunkSize);
432
-				flush();
433
-			}
434
-			fclose($handle);
435
-			return $this->filesize($path);
436
-		}
437
-		return false;
438
-	}
439
-
440
-	/**
441
-	 * @param string $path
442
-	 * @param int $from
443
-	 * @param int $to
444
-	 * @return bool|mixed
445
-	 * @throws \OCP\Files\InvalidPathException
446
-	 * @throws \OCP\Files\UnseekableException
447
-	 */
448
-	public function readfilePart($path, $from, $to) {
449
-		$this->assertPathLength($path);
450
-		if (ob_get_level()) {
451
-			ob_end_clean();
452
-		}
453
-		$handle = $this->fopen($path, 'rb');
454
-		if ($handle) {
455
-			$chunkSize = 524288; // 512 kB chunks
456
-			$startReading = true;
457
-
458
-			if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) {
459
-				// forward file handle via chunked fread because fseek seem to have failed
460
-
461
-				$end = $from + 1;
462
-				while (!feof($handle) && ftell($handle) < $end && ftell($handle) !== $from) {
463
-					$len = $from - ftell($handle);
464
-					if ($len > $chunkSize) {
465
-						$len = $chunkSize;
466
-					}
467
-					$result = fread($handle, $len);
468
-
469
-					if ($result === false) {
470
-						$startReading = false;
471
-						break;
472
-					}
473
-				}
474
-			}
475
-
476
-			if ($startReading) {
477
-				$end = $to + 1;
478
-				while (!feof($handle) && ftell($handle) < $end) {
479
-					$len = $end - ftell($handle);
480
-					if ($len > $chunkSize) {
481
-						$len = $chunkSize;
482
-					}
483
-					echo fread($handle, $len);
484
-					flush();
485
-				}
486
-				return ftell($handle) - $from;
487
-			}
488
-
489
-			throw new \OCP\Files\UnseekableException('fseek error');
490
-		}
491
-		return false;
492
-	}
493
-
494
-	/**
495
-	 * @param string $path
496
-	 * @return mixed
497
-	 */
498
-	public function isCreatable($path) {
499
-		return $this->basicOperation('isCreatable', $path);
500
-	}
501
-
502
-	/**
503
-	 * @param string $path
504
-	 * @return mixed
505
-	 */
506
-	public function isReadable($path) {
507
-		return $this->basicOperation('isReadable', $path);
508
-	}
509
-
510
-	/**
511
-	 * @param string $path
512
-	 * @return mixed
513
-	 */
514
-	public function isUpdatable($path) {
515
-		return $this->basicOperation('isUpdatable', $path);
516
-	}
517
-
518
-	/**
519
-	 * @param string $path
520
-	 * @return bool|mixed
521
-	 */
522
-	public function isDeletable($path) {
523
-		$absolutePath = $this->getAbsolutePath($path);
524
-		$mount = Filesystem::getMountManager()->find($absolutePath);
525
-		if ($mount->getInternalPath($absolutePath) === '') {
526
-			return $mount instanceof MoveableMount;
527
-		}
528
-		return $this->basicOperation('isDeletable', $path);
529
-	}
530
-
531
-	/**
532
-	 * @param string $path
533
-	 * @return mixed
534
-	 */
535
-	public function isSharable($path) {
536
-		return $this->basicOperation('isSharable', $path);
537
-	}
538
-
539
-	/**
540
-	 * @param string $path
541
-	 * @return bool|mixed
542
-	 */
543
-	public function file_exists($path) {
544
-		if ($path == '/') {
545
-			return true;
546
-		}
547
-		return $this->basicOperation('file_exists', $path);
548
-	}
549
-
550
-	/**
551
-	 * @param string $path
552
-	 * @return mixed
553
-	 */
554
-	public function filemtime($path) {
555
-		return $this->basicOperation('filemtime', $path);
556
-	}
557
-
558
-	/**
559
-	 * @param string $path
560
-	 * @param int|string $mtime
561
-	 * @return bool
562
-	 */
563
-	public function touch($path, $mtime = null) {
564
-		if (!is_null($mtime) and !is_numeric($mtime)) {
565
-			$mtime = strtotime($mtime);
566
-		}
567
-
568
-		$hooks = ['touch'];
569
-
570
-		if (!$this->file_exists($path)) {
571
-			$hooks[] = 'create';
572
-			$hooks[] = 'write';
573
-		}
574
-		try {
575
-			$result = $this->basicOperation('touch', $path, $hooks, $mtime);
576
-		} catch (\Exception $e) {
577
-			$this->logger->logException($e, ['level' => ILogger::INFO, 'message' => 'Error while setting modified time']);
578
-			$result = false;
579
-		}
580
-		if (!$result) {
581
-			// If create file fails because of permissions on external storage like SMB folders,
582
-			// check file exists and return false if not.
583
-			if (!$this->file_exists($path)) {
584
-				return false;
585
-			}
586
-			if (is_null($mtime)) {
587
-				$mtime = time();
588
-			}
589
-			//if native touch fails, we emulate it by changing the mtime in the cache
590
-			$this->putFileInfo($path, ['mtime' => floor($mtime)]);
591
-		}
592
-		return true;
593
-	}
594
-
595
-	/**
596
-	 * @param string $path
597
-	 * @return mixed
598
-	 * @throws LockedException
599
-	 */
600
-	public function file_get_contents($path) {
601
-		return $this->basicOperation('file_get_contents', $path, ['read']);
602
-	}
603
-
604
-	/**
605
-	 * @param bool $exists
606
-	 * @param string $path
607
-	 * @param bool $run
608
-	 */
609
-	protected function emit_file_hooks_pre($exists, $path, &$run) {
610
-		if (!$exists) {
611
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, [
612
-				Filesystem::signal_param_path => $this->getHookPath($path),
613
-				Filesystem::signal_param_run => &$run,
614
-			]);
615
-		} else {
616
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, [
617
-				Filesystem::signal_param_path => $this->getHookPath($path),
618
-				Filesystem::signal_param_run => &$run,
619
-			]);
620
-		}
621
-		\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, [
622
-			Filesystem::signal_param_path => $this->getHookPath($path),
623
-			Filesystem::signal_param_run => &$run,
624
-		]);
625
-	}
626
-
627
-	/**
628
-	 * @param bool $exists
629
-	 * @param string $path
630
-	 */
631
-	protected function emit_file_hooks_post($exists, $path) {
632
-		if (!$exists) {
633
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, [
634
-				Filesystem::signal_param_path => $this->getHookPath($path),
635
-			]);
636
-		} else {
637
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, [
638
-				Filesystem::signal_param_path => $this->getHookPath($path),
639
-			]);
640
-		}
641
-		\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, [
642
-			Filesystem::signal_param_path => $this->getHookPath($path),
643
-		]);
644
-	}
645
-
646
-	/**
647
-	 * @param string $path
648
-	 * @param string|resource $data
649
-	 * @return bool|mixed
650
-	 * @throws LockedException
651
-	 */
652
-	public function file_put_contents($path, $data) {
653
-		if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
654
-			$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
655
-			if (Filesystem::isValidPath($path)
656
-				and !Filesystem::isFileBlacklisted($path)
657
-			) {
658
-				$path = $this->getRelativePath($absolutePath);
659
-
660
-				$this->lockFile($path, ILockingProvider::LOCK_SHARED);
661
-
662
-				$exists = $this->file_exists($path);
663
-				$run = true;
664
-				if ($this->shouldEmitHooks($path)) {
665
-					$this->emit_file_hooks_pre($exists, $path, $run);
666
-				}
667
-				if (!$run) {
668
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
669
-					return false;
670
-				}
671
-
672
-				try {
673
-					$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
674
-				} catch (\Exception $e) {
675
-					// Release the shared lock before throwing.
676
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
677
-					throw $e;
678
-				}
679
-
680
-				/** @var \OC\Files\Storage\Storage $storage */
681
-				[$storage, $internalPath] = $this->resolvePath($path);
682
-				$target = $storage->fopen($internalPath, 'w');
683
-				if ($target) {
684
-					[, $result] = \OC_Helper::streamCopy($data, $target);
685
-					fclose($target);
686
-					fclose($data);
687
-
688
-					$this->writeUpdate($storage, $internalPath);
689
-
690
-					$this->changeLock($path, ILockingProvider::LOCK_SHARED);
691
-
692
-					if ($this->shouldEmitHooks($path) && $result !== false) {
693
-						$this->emit_file_hooks_post($exists, $path);
694
-					}
695
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
696
-					return $result;
697
-				} else {
698
-					$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
699
-					return false;
700
-				}
701
-			} else {
702
-				return false;
703
-			}
704
-		} else {
705
-			$hooks = $this->file_exists($path) ? ['update', 'write'] : ['create', 'write'];
706
-			return $this->basicOperation('file_put_contents', $path, $hooks, $data);
707
-		}
708
-	}
709
-
710
-	/**
711
-	 * @param string $path
712
-	 * @return bool|mixed
713
-	 */
714
-	public function unlink($path) {
715
-		if ($path === '' || $path === '/') {
716
-			// do not allow deleting the root
717
-			return false;
718
-		}
719
-		$postFix = (substr($path, -1) === '/') ? '/' : '';
720
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
721
-		$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
722
-		if ($mount and $mount->getInternalPath($absolutePath) === '') {
723
-			return $this->removeMount($mount, $absolutePath);
724
-		}
725
-		if ($this->is_dir($path)) {
726
-			$result = $this->basicOperation('rmdir', $path, ['delete']);
727
-		} else {
728
-			$result = $this->basicOperation('unlink', $path, ['delete']);
729
-		}
730
-		if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
731
-			$storage = $mount->getStorage();
732
-			$internalPath = $mount->getInternalPath($absolutePath);
733
-			$storage->getUpdater()->remove($internalPath);
734
-			return true;
735
-		} else {
736
-			return $result;
737
-		}
738
-	}
739
-
740
-	/**
741
-	 * @param string $directory
742
-	 * @return bool|mixed
743
-	 */
744
-	public function deleteAll($directory) {
745
-		return $this->rmdir($directory);
746
-	}
747
-
748
-	/**
749
-	 * Rename/move a file or folder from the source path to target path.
750
-	 *
751
-	 * @param string $path1 source path
752
-	 * @param string $path2 target path
753
-	 *
754
-	 * @return bool|mixed
755
-	 * @throws LockedException
756
-	 */
757
-	public function rename($path1, $path2) {
758
-		$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
759
-		$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
760
-		$result = false;
761
-		if (
762
-			Filesystem::isValidPath($path2)
763
-			and Filesystem::isValidPath($path1)
764
-			and !Filesystem::isFileBlacklisted($path2)
765
-		) {
766
-			$path1 = $this->getRelativePath($absolutePath1);
767
-			$path2 = $this->getRelativePath($absolutePath2);
768
-			$exists = $this->file_exists($path2);
769
-
770
-			if ($path1 == null or $path2 == null) {
771
-				return false;
772
-			}
773
-
774
-			$this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
775
-			try {
776
-				$this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
777
-
778
-				$run = true;
779
-				if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
780
-					// if it was a rename from a part file to a regular file it was a write and not a rename operation
781
-					$this->emit_file_hooks_pre($exists, $path2, $run);
782
-				} elseif ($this->shouldEmitHooks($path1)) {
783
-					\OC_Hook::emit(
784
-						Filesystem::CLASSNAME, Filesystem::signal_rename,
785
-						[
786
-							Filesystem::signal_param_oldpath => $this->getHookPath($path1),
787
-							Filesystem::signal_param_newpath => $this->getHookPath($path2),
788
-							Filesystem::signal_param_run => &$run
789
-						]
790
-					);
791
-				}
792
-				if ($run) {
793
-					$this->verifyPath(dirname($path2), basename($path2));
794
-
795
-					$manager = Filesystem::getMountManager();
796
-					$mount1 = $this->getMount($path1);
797
-					$mount2 = $this->getMount($path2);
798
-					$storage1 = $mount1->getStorage();
799
-					$storage2 = $mount2->getStorage();
800
-					$internalPath1 = $mount1->getInternalPath($absolutePath1);
801
-					$internalPath2 = $mount2->getInternalPath($absolutePath2);
802
-
803
-					$this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
804
-					try {
805
-						$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
806
-
807
-						if ($internalPath1 === '') {
808
-							if ($mount1 instanceof MoveableMount) {
809
-								$sourceParentMount = $this->getMount(dirname($path1));
810
-								if ($sourceParentMount === $mount2 && $this->targetIsNotShared($storage2, $internalPath2)) {
811
-									/**
812
-									 * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
813
-									 */
814
-									$sourceMountPoint = $mount1->getMountPoint();
815
-									$result = $mount1->moveMount($absolutePath2);
816
-									$manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
817
-								} else {
818
-									$result = false;
819
-								}
820
-							} else {
821
-								$result = false;
822
-							}
823
-							// moving a file/folder within the same mount point
824
-						} elseif ($storage1 === $storage2) {
825
-							if ($storage1) {
826
-								$result = $storage1->rename($internalPath1, $internalPath2);
827
-							} else {
828
-								$result = false;
829
-							}
830
-							// moving a file/folder between storages (from $storage1 to $storage2)
831
-						} else {
832
-							$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
833
-						}
834
-
835
-						if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
836
-							// if it was a rename from a part file to a regular file it was a write and not a rename operation
837
-							$this->writeUpdate($storage2, $internalPath2);
838
-						} elseif ($result) {
839
-							if ($internalPath1 !== '') { // don't do a cache update for moved mounts
840
-								$this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
841
-							}
842
-						}
843
-					} catch (\Exception $e) {
844
-						throw $e;
845
-					} finally {
846
-						$this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
847
-						$this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
848
-					}
849
-
850
-					if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
851
-						if ($this->shouldEmitHooks()) {
852
-							$this->emit_file_hooks_post($exists, $path2);
853
-						}
854
-					} elseif ($result) {
855
-						if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) {
856
-							\OC_Hook::emit(
857
-								Filesystem::CLASSNAME,
858
-								Filesystem::signal_post_rename,
859
-								[
860
-									Filesystem::signal_param_oldpath => $this->getHookPath($path1),
861
-									Filesystem::signal_param_newpath => $this->getHookPath($path2)
862
-								]
863
-							);
864
-						}
865
-					}
866
-				}
867
-			} catch (\Exception $e) {
868
-				throw $e;
869
-			} finally {
870
-				$this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
871
-				$this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
872
-			}
873
-		}
874
-		return $result;
875
-	}
876
-
877
-	/**
878
-	 * Copy a file/folder from the source path to target path
879
-	 *
880
-	 * @param string $path1 source path
881
-	 * @param string $path2 target path
882
-	 * @param bool $preserveMtime whether to preserve mtime on the copy
883
-	 *
884
-	 * @return bool|mixed
885
-	 */
886
-	public function copy($path1, $path2, $preserveMtime = false) {
887
-		$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
888
-		$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
889
-		$result = false;
890
-		if (
891
-			Filesystem::isValidPath($path2)
892
-			and Filesystem::isValidPath($path1)
893
-			and !Filesystem::isFileBlacklisted($path2)
894
-		) {
895
-			$path1 = $this->getRelativePath($absolutePath1);
896
-			$path2 = $this->getRelativePath($absolutePath2);
897
-
898
-			if ($path1 == null or $path2 == null) {
899
-				return false;
900
-			}
901
-			$run = true;
902
-
903
-			$this->lockFile($path2, ILockingProvider::LOCK_SHARED);
904
-			$this->lockFile($path1, ILockingProvider::LOCK_SHARED);
905
-			$lockTypePath1 = ILockingProvider::LOCK_SHARED;
906
-			$lockTypePath2 = ILockingProvider::LOCK_SHARED;
907
-
908
-			try {
909
-				$exists = $this->file_exists($path2);
910
-				if ($this->shouldEmitHooks()) {
911
-					\OC_Hook::emit(
912
-						Filesystem::CLASSNAME,
913
-						Filesystem::signal_copy,
914
-						[
915
-							Filesystem::signal_param_oldpath => $this->getHookPath($path1),
916
-							Filesystem::signal_param_newpath => $this->getHookPath($path2),
917
-							Filesystem::signal_param_run => &$run
918
-						]
919
-					);
920
-					$this->emit_file_hooks_pre($exists, $path2, $run);
921
-				}
922
-				if ($run) {
923
-					$mount1 = $this->getMount($path1);
924
-					$mount2 = $this->getMount($path2);
925
-					$storage1 = $mount1->getStorage();
926
-					$internalPath1 = $mount1->getInternalPath($absolutePath1);
927
-					$storage2 = $mount2->getStorage();
928
-					$internalPath2 = $mount2->getInternalPath($absolutePath2);
929
-
930
-					$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE);
931
-					$lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE;
932
-
933
-					if ($mount1->getMountPoint() == $mount2->getMountPoint()) {
934
-						if ($storage1) {
935
-							$result = $storage1->copy($internalPath1, $internalPath2);
936
-						} else {
937
-							$result = false;
938
-						}
939
-					} else {
940
-						$result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
941
-					}
942
-
943
-					$this->writeUpdate($storage2, $internalPath2);
944
-
945
-					$this->changeLock($path2, ILockingProvider::LOCK_SHARED);
946
-					$lockTypePath2 = ILockingProvider::LOCK_SHARED;
947
-
948
-					if ($this->shouldEmitHooks() && $result !== false) {
949
-						\OC_Hook::emit(
950
-							Filesystem::CLASSNAME,
951
-							Filesystem::signal_post_copy,
952
-							[
953
-								Filesystem::signal_param_oldpath => $this->getHookPath($path1),
954
-								Filesystem::signal_param_newpath => $this->getHookPath($path2)
955
-							]
956
-						);
957
-						$this->emit_file_hooks_post($exists, $path2);
958
-					}
959
-				}
960
-			} catch (\Exception $e) {
961
-				$this->unlockFile($path2, $lockTypePath2);
962
-				$this->unlockFile($path1, $lockTypePath1);
963
-				throw $e;
964
-			}
965
-
966
-			$this->unlockFile($path2, $lockTypePath2);
967
-			$this->unlockFile($path1, $lockTypePath1);
968
-		}
969
-		return $result;
970
-	}
971
-
972
-	/**
973
-	 * @param string $path
974
-	 * @param string $mode 'r' or 'w'
975
-	 * @return resource
976
-	 * @throws LockedException
977
-	 */
978
-	public function fopen($path, $mode) {
979
-		$mode = str_replace('b', '', $mode); // the binary flag is a windows only feature which we do not support
980
-		$hooks = [];
981
-		switch ($mode) {
982
-			case 'r':
983
-				$hooks[] = 'read';
984
-				break;
985
-			case 'r+':
986
-			case 'w+':
987
-			case 'x+':
988
-			case 'a+':
989
-				$hooks[] = 'read';
990
-				$hooks[] = 'write';
991
-				break;
992
-			case 'w':
993
-			case 'x':
994
-			case 'a':
995
-				$hooks[] = 'write';
996
-				break;
997
-			default:
998
-				\OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, ILogger::ERROR);
999
-		}
1000
-
1001
-		if ($mode !== 'r' && $mode !== 'w') {
1002
-			\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');
1003
-		}
1004
-
1005
-		return $this->basicOperation('fopen', $path, $hooks, $mode);
1006
-	}
1007
-
1008
-	/**
1009
-	 * @param string $path
1010
-	 * @return bool|string
1011
-	 * @throws \OCP\Files\InvalidPathException
1012
-	 */
1013
-	public function toTmpFile($path) {
1014
-		$this->assertPathLength($path);
1015
-		if (Filesystem::isValidPath($path)) {
1016
-			$source = $this->fopen($path, 'r');
1017
-			if ($source) {
1018
-				$extension = pathinfo($path, PATHINFO_EXTENSION);
1019
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
1020
-				file_put_contents($tmpFile, $source);
1021
-				return $tmpFile;
1022
-			} else {
1023
-				return false;
1024
-			}
1025
-		} else {
1026
-			return false;
1027
-		}
1028
-	}
1029
-
1030
-	/**
1031
-	 * @param string $tmpFile
1032
-	 * @param string $path
1033
-	 * @return bool|mixed
1034
-	 * @throws \OCP\Files\InvalidPathException
1035
-	 */
1036
-	public function fromTmpFile($tmpFile, $path) {
1037
-		$this->assertPathLength($path);
1038
-		if (Filesystem::isValidPath($path)) {
1039
-
1040
-			// Get directory that the file is going into
1041
-			$filePath = dirname($path);
1042
-
1043
-			// Create the directories if any
1044
-			if (!$this->file_exists($filePath)) {
1045
-				$result = $this->createParentDirectories($filePath);
1046
-				if ($result === false) {
1047
-					return false;
1048
-				}
1049
-			}
1050
-
1051
-			$source = fopen($tmpFile, 'r');
1052
-			if ($source) {
1053
-				$result = $this->file_put_contents($path, $source);
1054
-				// $this->file_put_contents() might have already closed
1055
-				// the resource, so we check it, before trying to close it
1056
-				// to avoid messages in the error log.
1057
-				if (is_resource($source)) {
1058
-					fclose($source);
1059
-				}
1060
-				unlink($tmpFile);
1061
-				return $result;
1062
-			} else {
1063
-				return false;
1064
-			}
1065
-		} else {
1066
-			return false;
1067
-		}
1068
-	}
1069
-
1070
-
1071
-	/**
1072
-	 * @param string $path
1073
-	 * @return mixed
1074
-	 * @throws \OCP\Files\InvalidPathException
1075
-	 */
1076
-	public function getMimeType($path) {
1077
-		$this->assertPathLength($path);
1078
-		return $this->basicOperation('getMimeType', $path);
1079
-	}
1080
-
1081
-	/**
1082
-	 * @param string $type
1083
-	 * @param string $path
1084
-	 * @param bool $raw
1085
-	 * @return bool|null|string
1086
-	 */
1087
-	public function hash($type, $path, $raw = false) {
1088
-		$postFix = (substr($path, -1) === '/') ? '/' : '';
1089
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1090
-		if (Filesystem::isValidPath($path)) {
1091
-			$path = $this->getRelativePath($absolutePath);
1092
-			if ($path == null) {
1093
-				return false;
1094
-			}
1095
-			if ($this->shouldEmitHooks($path)) {
1096
-				\OC_Hook::emit(
1097
-					Filesystem::CLASSNAME,
1098
-					Filesystem::signal_read,
1099
-					[Filesystem::signal_param_path => $this->getHookPath($path)]
1100
-				);
1101
-			}
1102
-			[$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix);
1103
-			if ($storage) {
1104
-				return $storage->hash($type, $internalPath, $raw);
1105
-			}
1106
-		}
1107
-		return null;
1108
-	}
1109
-
1110
-	/**
1111
-	 * @param string $path
1112
-	 * @return mixed
1113
-	 * @throws \OCP\Files\InvalidPathException
1114
-	 */
1115
-	public function free_space($path = '/') {
1116
-		$this->assertPathLength($path);
1117
-		$result = $this->basicOperation('free_space', $path);
1118
-		if ($result === null) {
1119
-			throw new InvalidPathException();
1120
-		}
1121
-		return $result;
1122
-	}
1123
-
1124
-	/**
1125
-	 * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage
1126
-	 *
1127
-	 * @param string $operation
1128
-	 * @param string $path
1129
-	 * @param array $hooks (optional)
1130
-	 * @param mixed $extraParam (optional)
1131
-	 * @return mixed
1132
-	 * @throws LockedException
1133
-	 *
1134
-	 * This method takes requests for basic filesystem functions (e.g. reading & writing
1135
-	 * files), processes hooks and proxies, sanitises paths, and finally passes them on to
1136
-	 * \OC\Files\Storage\Storage for delegation to a storage backend for execution
1137
-	 */
1138
-	private function basicOperation($operation, $path, $hooks = [], $extraParam = null) {
1139
-		$postFix = (substr($path, -1) === '/') ? '/' : '';
1140
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1141
-		if (Filesystem::isValidPath($path)
1142
-			and !Filesystem::isFileBlacklisted($path)
1143
-		) {
1144
-			$path = $this->getRelativePath($absolutePath);
1145
-			if ($path == null) {
1146
-				return false;
1147
-			}
1148
-
1149
-			if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) {
1150
-				// always a shared lock during pre-hooks so the hook can read the file
1151
-				$this->lockFile($path, ILockingProvider::LOCK_SHARED);
1152
-			}
1153
-
1154
-			$run = $this->runHooks($hooks, $path);
1155
-			/** @var \OC\Files\Storage\Storage $storage */
1156
-			[$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix);
1157
-			if ($run and $storage) {
1158
-				if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1159
-					try {
1160
-						$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
1161
-					} catch (LockedException $e) {
1162
-						// release the shared lock we acquired before quiting
1163
-						$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1164
-						throw $e;
1165
-					}
1166
-				}
1167
-				try {
1168
-					if (!is_null($extraParam)) {
1169
-						$result = $storage->$operation($internalPath, $extraParam);
1170
-					} else {
1171
-						$result = $storage->$operation($internalPath);
1172
-					}
1173
-				} catch (\Exception $e) {
1174
-					if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1175
-						$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1176
-					} elseif (in_array('read', $hooks)) {
1177
-						$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1178
-					}
1179
-					throw $e;
1180
-				}
1181
-
1182
-				if ($result && in_array('delete', $hooks) and $result) {
1183
-					$this->removeUpdate($storage, $internalPath);
1184
-				}
1185
-				if ($result && in_array('write', $hooks,  true) && $operation !== 'fopen' && $operation !== 'touch') {
1186
-					$this->writeUpdate($storage, $internalPath);
1187
-				}
1188
-				if ($result && in_array('touch', $hooks)) {
1189
-					$this->writeUpdate($storage, $internalPath, $extraParam);
1190
-				}
1191
-
1192
-				if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
1193
-					$this->changeLock($path, ILockingProvider::LOCK_SHARED);
1194
-				}
1195
-
1196
-				$unlockLater = false;
1197
-				if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) {
1198
-					$unlockLater = true;
1199
-					// make sure our unlocking callback will still be called if connection is aborted
1200
-					ignore_user_abort(true);
1201
-					$result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1202
-						if (in_array('write', $hooks)) {
1203
-							$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1204
-						} elseif (in_array('read', $hooks)) {
1205
-							$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1206
-						}
1207
-					});
1208
-				}
1209
-
1210
-				if ($this->shouldEmitHooks($path) && $result !== false) {
1211
-					if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
1212
-						$this->runHooks($hooks, $path, true);
1213
-					}
1214
-				}
1215
-
1216
-				if (!$unlockLater
1217
-					&& (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks))
1218
-				) {
1219
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1220
-				}
1221
-				return $result;
1222
-			} else {
1223
-				$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1224
-			}
1225
-		}
1226
-		return null;
1227
-	}
1228
-
1229
-	/**
1230
-	 * get the path relative to the default root for hook usage
1231
-	 *
1232
-	 * @param string $path
1233
-	 * @return string
1234
-	 */
1235
-	private function getHookPath($path) {
1236
-		if (!Filesystem::getView()) {
1237
-			return $path;
1238
-		}
1239
-		return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path));
1240
-	}
1241
-
1242
-	private function shouldEmitHooks($path = '') {
1243
-		if ($path && Cache\Scanner::isPartialFile($path)) {
1244
-			return false;
1245
-		}
1246
-		if (!Filesystem::$loaded) {
1247
-			return false;
1248
-		}
1249
-		$defaultRoot = Filesystem::getRoot();
1250
-		if ($defaultRoot === null) {
1251
-			return false;
1252
-		}
1253
-		if ($this->fakeRoot === $defaultRoot) {
1254
-			return true;
1255
-		}
1256
-		$fullPath = $this->getAbsolutePath($path);
1257
-
1258
-		if ($fullPath === $defaultRoot) {
1259
-			return true;
1260
-		}
1261
-
1262
-		return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1263
-	}
1264
-
1265
-	/**
1266
-	 * @param string[] $hooks
1267
-	 * @param string $path
1268
-	 * @param bool $post
1269
-	 * @return bool
1270
-	 */
1271
-	private function runHooks($hooks, $path, $post = false) {
1272
-		$relativePath = $path;
1273
-		$path = $this->getHookPath($path);
1274
-		$prefix = $post ? 'post_' : '';
1275
-		$run = true;
1276
-		if ($this->shouldEmitHooks($relativePath)) {
1277
-			foreach ($hooks as $hook) {
1278
-				if ($hook != 'read') {
1279
-					\OC_Hook::emit(
1280
-						Filesystem::CLASSNAME,
1281
-						$prefix . $hook,
1282
-						[
1283
-							Filesystem::signal_param_run => &$run,
1284
-							Filesystem::signal_param_path => $path
1285
-						]
1286
-					);
1287
-				} elseif (!$post) {
1288
-					\OC_Hook::emit(
1289
-						Filesystem::CLASSNAME,
1290
-						$prefix . $hook,
1291
-						[
1292
-							Filesystem::signal_param_path => $path
1293
-						]
1294
-					);
1295
-				}
1296
-			}
1297
-		}
1298
-		return $run;
1299
-	}
1300
-
1301
-	/**
1302
-	 * check if a file or folder has been updated since $time
1303
-	 *
1304
-	 * @param string $path
1305
-	 * @param int $time
1306
-	 * @return bool
1307
-	 */
1308
-	public function hasUpdated($path, $time) {
1309
-		return $this->basicOperation('hasUpdated', $path, [], $time);
1310
-	}
1311
-
1312
-	/**
1313
-	 * @param string $ownerId
1314
-	 * @return \OC\User\User
1315
-	 */
1316
-	private function getUserObjectForOwner($ownerId) {
1317
-		$owner = $this->userManager->get($ownerId);
1318
-		if ($owner instanceof IUser) {
1319
-			return $owner;
1320
-		} else {
1321
-			return new User($ownerId, null, \OC::$server->getEventDispatcher());
1322
-		}
1323
-	}
1324
-
1325
-	/**
1326
-	 * Get file info from cache
1327
-	 *
1328
-	 * If the file is not in cached it will be scanned
1329
-	 * If the file has changed on storage the cache will be updated
1330
-	 *
1331
-	 * @param \OC\Files\Storage\Storage $storage
1332
-	 * @param string $internalPath
1333
-	 * @param string $relativePath
1334
-	 * @return ICacheEntry|bool
1335
-	 */
1336
-	private function getCacheEntry($storage, $internalPath, $relativePath) {
1337
-		$cache = $storage->getCache($internalPath);
1338
-		$data = $cache->get($internalPath);
1339
-		$watcher = $storage->getWatcher($internalPath);
1340
-
1341
-		try {
1342
-			// if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
1343
-			if (!$data || $data['size'] === -1) {
1344
-				if (!$storage->file_exists($internalPath)) {
1345
-					return false;
1346
-				}
1347
-				// don't need to get a lock here since the scanner does it's own locking
1348
-				$scanner = $storage->getScanner($internalPath);
1349
-				$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1350
-				$data = $cache->get($internalPath);
1351
-			} elseif (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
1352
-				$this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1353
-				$watcher->update($internalPath, $data);
1354
-				$storage->getPropagator()->propagateChange($internalPath, time());
1355
-				$data = $cache->get($internalPath);
1356
-				$this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1357
-			}
1358
-		} catch (LockedException $e) {
1359
-			// if the file is locked we just use the old cache info
1360
-		}
1361
-
1362
-		return $data;
1363
-	}
1364
-
1365
-	/**
1366
-	 * get the filesystem info
1367
-	 *
1368
-	 * @param string $path
1369
-	 * @param boolean|string $includeMountPoints true to add mountpoint sizes,
1370
-	 * 'ext' to add only ext storage mount point sizes. Defaults to true.
1371
-	 * defaults to true
1372
-	 * @return \OC\Files\FileInfo|false False if file does not exist
1373
-	 */
1374
-	public function getFileInfo($path, $includeMountPoints = true) {
1375
-		$this->assertPathLength($path);
1376
-		if (!Filesystem::isValidPath($path)) {
1377
-			return false;
1378
-		}
1379
-		if (Cache\Scanner::isPartialFile($path)) {
1380
-			return $this->getPartFileInfo($path);
1381
-		}
1382
-		$relativePath = $path;
1383
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1384
-
1385
-		$mount = Filesystem::getMountManager()->find($path);
1386
-		if (!$mount) {
1387
-			\OC::$server->getLogger()->warning('Mountpoint not found for path: ' . $path);
1388
-			return false;
1389
-		}
1390
-		$storage = $mount->getStorage();
1391
-		$internalPath = $mount->getInternalPath($path);
1392
-		if ($storage) {
1393
-			$data = $this->getCacheEntry($storage, $internalPath, $relativePath);
1394
-
1395
-			if (!$data instanceof ICacheEntry) {
1396
-				return false;
1397
-			}
1398
-
1399
-			if ($mount instanceof MoveableMount && $internalPath === '') {
1400
-				$data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
1401
-			}
1402
-			$ownerId = $storage->getOwner($internalPath);
1403
-			$owner = null;
1404
-			if ($ownerId !== null && $ownerId !== false) {
1405
-				// ownerId might be null if files are accessed with an access token without file system access
1406
-				$owner = $this->getUserObjectForOwner($ownerId);
1407
-			}
1408
-			$info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
1409
-
1410
-			if ($data and isset($data['fileid'])) {
1411
-				if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
1412
-					//add the sizes of other mount points to the folder
1413
-					$extOnly = ($includeMountPoints === 'ext');
1414
-					$mounts = Filesystem::getMountManager()->findIn($path);
1415
-					$info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1416
-						$subStorage = $mount->getStorage();
1417
-						return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1418
-					}));
1419
-				}
1420
-			}
1421
-
1422
-			return $info;
1423
-		} else {
1424
-			\OC::$server->getLogger()->warning('Storage not valid for mountpoint: ' . $mount->getMountPoint());
1425
-		}
1426
-
1427
-		return false;
1428
-	}
1429
-
1430
-	/**
1431
-	 * get the content of a directory
1432
-	 *
1433
-	 * @param string $directory path under datadirectory
1434
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
1435
-	 * @return FileInfo[]
1436
-	 */
1437
-	public function getDirectoryContent($directory, $mimetype_filter = '') {
1438
-		$this->assertPathLength($directory);
1439
-		if (!Filesystem::isValidPath($directory)) {
1440
-			return [];
1441
-		}
1442
-		$path = $this->getAbsolutePath($directory);
1443
-		$path = Filesystem::normalizePath($path);
1444
-		$mount = $this->getMount($directory);
1445
-		if (!$mount) {
1446
-			return [];
1447
-		}
1448
-		$storage = $mount->getStorage();
1449
-		$internalPath = $mount->getInternalPath($path);
1450
-		if ($storage) {
1451
-			$cache = $storage->getCache($internalPath);
1452
-			$user = \OC_User::getUser();
1453
-
1454
-			$data = $this->getCacheEntry($storage, $internalPath, $directory);
1455
-
1456
-			if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
1457
-				return [];
1458
-			}
1459
-
1460
-			$folderId = $data['fileid'];
1461
-			$contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
1462
-
1463
-			$sharingDisabled = \OCP\Util::isSharingDisabledForUser();
1464
-
1465
-			$fileNames = array_map(function (ICacheEntry $content) {
1466
-				return $content->getName();
1467
-			}, $contents);
1468
-			/**
1469
-			 * @var \OC\Files\FileInfo[] $fileInfos
1470
-			 */
1471
-			$fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1472
-				if ($sharingDisabled) {
1473
-					$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1474
-				}
1475
-				$owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1476
-				return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1477
-			}, $contents);
1478
-			$files = array_combine($fileNames, $fileInfos);
1479
-
1480
-			//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
1481
-			$mounts = Filesystem::getMountManager()->findIn($path);
1482
-			$dirLength = strlen($path);
1483
-			foreach ($mounts as $mount) {
1484
-				$mountPoint = $mount->getMountPoint();
1485
-				$subStorage = $mount->getStorage();
1486
-				if ($subStorage) {
1487
-					$subCache = $subStorage->getCache('');
1488
-
1489
-					$rootEntry = $subCache->get('');
1490
-					if (!$rootEntry) {
1491
-						$subScanner = $subStorage->getScanner('');
1492
-						try {
1493
-							$subScanner->scanFile('');
1494
-						} catch (\OCP\Files\StorageNotAvailableException $e) {
1495
-							continue;
1496
-						} catch (\OCP\Files\StorageInvalidException $e) {
1497
-							continue;
1498
-						} catch (\Exception $e) {
1499
-							// sometimes when the storage is not available it can be any exception
1500
-							\OC::$server->getLogger()->logException($e, [
1501
-								'message' => 'Exception while scanning storage "' . $subStorage->getId() . '"',
1502
-								'level' => ILogger::ERROR,
1503
-								'app' => 'lib',
1504
-							]);
1505
-							continue;
1506
-						}
1507
-						$rootEntry = $subCache->get('');
1508
-					}
1509
-
1510
-					if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
1511
-						$relativePath = trim(substr($mountPoint, $dirLength), '/');
1512
-						if ($pos = strpos($relativePath, '/')) {
1513
-							//mountpoint inside subfolder add size to the correct folder
1514
-							$entryName = substr($relativePath, 0, $pos);
1515
-							foreach ($files as &$entry) {
1516
-								if ($entry->getName() === $entryName) {
1517
-									$entry->addSubEntry($rootEntry, $mountPoint);
1518
-								}
1519
-							}
1520
-						} else { //mountpoint in this folder, add an entry for it
1521
-							$rootEntry['name'] = $relativePath;
1522
-							$rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
1523
-							$permissions = $rootEntry['permissions'];
1524
-							// do not allow renaming/deleting the mount point if they are not shared files/folders
1525
-							// for shared files/folders we use the permissions given by the owner
1526
-							if ($mount instanceof MoveableMount) {
1527
-								$rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
1528
-							} else {
1529
-								$rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
1530
-							}
1531
-
1532
-							$rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1533
-
1534
-							// if sharing was disabled for the user we remove the share permissions
1535
-							if (\OCP\Util::isSharingDisabledForUser()) {
1536
-								$rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1537
-							}
1538
-
1539
-							$owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1540
-							$files[$rootEntry->getName()] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1541
-						}
1542
-					}
1543
-				}
1544
-			}
1545
-
1546
-			if ($mimetype_filter) {
1547
-				$files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1548
-					if (strpos($mimetype_filter, '/')) {
1549
-						return $file->getMimetype() === $mimetype_filter;
1550
-					} else {
1551
-						return $file->getMimePart() === $mimetype_filter;
1552
-					}
1553
-				});
1554
-			}
1555
-
1556
-			return array_values($files);
1557
-		} else {
1558
-			return [];
1559
-		}
1560
-	}
1561
-
1562
-	/**
1563
-	 * change file metadata
1564
-	 *
1565
-	 * @param string $path
1566
-	 * @param array|\OCP\Files\FileInfo $data
1567
-	 * @return int
1568
-	 *
1569
-	 * returns the fileid of the updated file
1570
-	 */
1571
-	public function putFileInfo($path, $data) {
1572
-		$this->assertPathLength($path);
1573
-		if ($data instanceof FileInfo) {
1574
-			$data = $data->getData();
1575
-		}
1576
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1577
-		/**
1578
-		 * @var \OC\Files\Storage\Storage $storage
1579
-		 * @var string $internalPath
1580
-		 */
1581
-		[$storage, $internalPath] = Filesystem::resolvePath($path);
1582
-		if ($storage) {
1583
-			$cache = $storage->getCache($path);
1584
-
1585
-			if (!$cache->inCache($internalPath)) {
1586
-				$scanner = $storage->getScanner($internalPath);
1587
-				$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1588
-			}
1589
-
1590
-			return $cache->put($internalPath, $data);
1591
-		} else {
1592
-			return -1;
1593
-		}
1594
-	}
1595
-
1596
-	/**
1597
-	 * search for files with the name matching $query
1598
-	 *
1599
-	 * @param string $query
1600
-	 * @return FileInfo[]
1601
-	 */
1602
-	public function search($query) {
1603
-		return $this->searchCommon('search', ['%' . $query . '%']);
1604
-	}
1605
-
1606
-	/**
1607
-	 * search for files with the name matching $query
1608
-	 *
1609
-	 * @param string $query
1610
-	 * @return FileInfo[]
1611
-	 */
1612
-	public function searchRaw($query) {
1613
-		return $this->searchCommon('search', [$query]);
1614
-	}
1615
-
1616
-	/**
1617
-	 * search for files by mimetype
1618
-	 *
1619
-	 * @param string $mimetype
1620
-	 * @return FileInfo[]
1621
-	 */
1622
-	public function searchByMime($mimetype) {
1623
-		return $this->searchCommon('searchByMime', [$mimetype]);
1624
-	}
1625
-
1626
-	/**
1627
-	 * search for files by tag
1628
-	 *
1629
-	 * @param string|int $tag name or tag id
1630
-	 * @param string $userId owner of the tags
1631
-	 * @return FileInfo[]
1632
-	 */
1633
-	public function searchByTag($tag, $userId) {
1634
-		return $this->searchCommon('searchByTag', [$tag, $userId]);
1635
-	}
1636
-
1637
-	/**
1638
-	 * @param string $method cache method
1639
-	 * @param array $args
1640
-	 * @return FileInfo[]
1641
-	 */
1642
-	private function searchCommon($method, $args) {
1643
-		$files = [];
1644
-		$rootLength = strlen($this->fakeRoot);
1645
-
1646
-		$mount = $this->getMount('');
1647
-		$mountPoint = $mount->getMountPoint();
1648
-		$storage = $mount->getStorage();
1649
-		$userManager = \OC::$server->getUserManager();
1650
-		if ($storage) {
1651
-			$cache = $storage->getCache('');
1652
-
1653
-			$results = call_user_func_array([$cache, $method], $args);
1654
-			foreach ($results as $result) {
1655
-				if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1656
-					$internalPath = $result['path'];
1657
-					$path = $mountPoint . $result['path'];
1658
-					$result['path'] = substr($mountPoint . $result['path'], $rootLength);
1659
-					$owner = $userManager->get($storage->getOwner($internalPath));
1660
-					$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1661
-				}
1662
-			}
1663
-
1664
-			$mounts = Filesystem::getMountManager()->findIn($this->fakeRoot);
1665
-			foreach ($mounts as $mount) {
1666
-				$mountPoint = $mount->getMountPoint();
1667
-				$storage = $mount->getStorage();
1668
-				if ($storage) {
1669
-					$cache = $storage->getCache('');
1670
-
1671
-					$relativeMountPoint = substr($mountPoint, $rootLength);
1672
-					$results = call_user_func_array([$cache, $method], $args);
1673
-					if ($results) {
1674
-						foreach ($results as $result) {
1675
-							$internalPath = $result['path'];
1676
-							$result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1677
-							$path = rtrim($mountPoint . $internalPath, '/');
1678
-							$owner = $userManager->get($storage->getOwner($internalPath));
1679
-							$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1680
-						}
1681
-					}
1682
-				}
1683
-			}
1684
-		}
1685
-		return $files;
1686
-	}
1687
-
1688
-	/**
1689
-	 * Get the owner for a file or folder
1690
-	 *
1691
-	 * @param string $path
1692
-	 * @return string the user id of the owner
1693
-	 * @throws NotFoundException
1694
-	 */
1695
-	public function getOwner($path) {
1696
-		$info = $this->getFileInfo($path);
1697
-		if (!$info) {
1698
-			throw new NotFoundException($path . ' not found while trying to get owner');
1699
-		}
1700
-
1701
-		if ($info->getOwner() === null) {
1702
-			throw new NotFoundException($path . ' has no owner');
1703
-		}
1704
-
1705
-		return $info->getOwner()->getUID();
1706
-	}
1707
-
1708
-	/**
1709
-	 * get the ETag for a file or folder
1710
-	 *
1711
-	 * @param string $path
1712
-	 * @return string
1713
-	 */
1714
-	public function getETag($path) {
1715
-		/**
1716
-		 * @var Storage\Storage $storage
1717
-		 * @var string $internalPath
1718
-		 */
1719
-		[$storage, $internalPath] = $this->resolvePath($path);
1720
-		if ($storage) {
1721
-			return $storage->getETag($internalPath);
1722
-		} else {
1723
-			return null;
1724
-		}
1725
-	}
1726
-
1727
-	/**
1728
-	 * Get the path of a file by id, relative to the view
1729
-	 *
1730
-	 * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
1731
-	 *
1732
-	 * @param int $id
1733
-	 * @param int|null $storageId
1734
-	 * @return string
1735
-	 * @throws NotFoundException
1736
-	 */
1737
-	public function getPath($id, int $storageId = null) {
1738
-		$id = (int)$id;
1739
-		$manager = Filesystem::getMountManager();
1740
-		$mounts = $manager->findIn($this->fakeRoot);
1741
-		$mounts[] = $manager->find($this->fakeRoot);
1742
-		// reverse the array so we start with the storage this view is in
1743
-		// which is the most likely to contain the file we're looking for
1744
-		$mounts = array_reverse($mounts);
1745
-
1746
-		// put non shared mounts in front of the shared mount
1747
-		// this prevent unneeded recursion into shares
1748
-		usort($mounts, function (IMountPoint $a, IMountPoint $b) {
1749
-			return $a instanceof SharedMount && (!$b instanceof SharedMount) ? 1 : -1;
1750
-		});
1751
-
1752
-		if (!is_null($storageId)) {
1753
-			$mounts = array_filter($mounts, function (IMountPoint $mount) use ($storageId) {
1754
-				return $mount->getNumericStorageId() === $storageId;
1755
-			});
1756
-		}
1757
-
1758
-		foreach ($mounts as $mount) {
1759
-			/**
1760
-			 * @var \OC\Files\Mount\MountPoint $mount
1761
-			 */
1762
-			if ($mount->getStorage()) {
1763
-				$cache = $mount->getStorage()->getCache();
1764
-				$internalPath = $cache->getPathById($id);
1765
-				if (is_string($internalPath)) {
1766
-					$fullPath = $mount->getMountPoint() . $internalPath;
1767
-					if (!is_null($path = $this->getRelativePath($fullPath))) {
1768
-						return $path;
1769
-					}
1770
-				}
1771
-			}
1772
-		}
1773
-		throw new NotFoundException(sprintf('File with id "%s" has not been found.', $id));
1774
-	}
1775
-
1776
-	/**
1777
-	 * @param string $path
1778
-	 * @throws InvalidPathException
1779
-	 */
1780
-	private function assertPathLength($path) {
1781
-		$maxLen = min(PHP_MAXPATHLEN, 4000);
1782
-		// Check for the string length - performed using isset() instead of strlen()
1783
-		// because isset() is about 5x-40x faster.
1784
-		if (isset($path[$maxLen])) {
1785
-			$pathLen = strlen($path);
1786
-			throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path");
1787
-		}
1788
-	}
1789
-
1790
-	/**
1791
-	 * check if it is allowed to move a mount point to a given target.
1792
-	 * It is not allowed to move a mount point into a different mount point or
1793
-	 * into an already shared folder
1794
-	 *
1795
-	 * @param IStorage $targetStorage
1796
-	 * @param string $targetInternalPath
1797
-	 * @return boolean
1798
-	 */
1799
-	private function targetIsNotShared(IStorage $targetStorage, string $targetInternalPath) {
1800
-
1801
-		// note: cannot use the view because the target is already locked
1802
-		$fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1803
-		if ($fileId === -1) {
1804
-			// target might not exist, need to check parent instead
1805
-			$fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1806
-		}
1807
-
1808
-		// check if any of the parents were shared by the current owner (include collections)
1809
-		$shares = \OCP\Share::getItemShared(
1810
-			'folder',
1811
-			$fileId,
1812
-			\OCP\Share::FORMAT_NONE,
1813
-			null,
1814
-			true
1815
-		);
1816
-
1817
-		if (count($shares) > 0) {
1818
-			\OCP\Util::writeLog('files',
1819
-				'It is not allowed to move one mount point into a shared folder',
1820
-				ILogger::DEBUG);
1821
-			return false;
1822
-		}
1823
-
1824
-		return true;
1825
-	}
1826
-
1827
-	/**
1828
-	 * Get a fileinfo object for files that are ignored in the cache (part files)
1829
-	 *
1830
-	 * @param string $path
1831
-	 * @return \OCP\Files\FileInfo
1832
-	 */
1833
-	private function getPartFileInfo($path) {
1834
-		$mount = $this->getMount($path);
1835
-		$storage = $mount->getStorage();
1836
-		$internalPath = $mount->getInternalPath($this->getAbsolutePath($path));
1837
-		$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1838
-		return new FileInfo(
1839
-			$this->getAbsolutePath($path),
1840
-			$storage,
1841
-			$internalPath,
1842
-			[
1843
-				'fileid' => null,
1844
-				'mimetype' => $storage->getMimeType($internalPath),
1845
-				'name' => basename($path),
1846
-				'etag' => null,
1847
-				'size' => $storage->filesize($internalPath),
1848
-				'mtime' => $storage->filemtime($internalPath),
1849
-				'encrypted' => false,
1850
-				'permissions' => \OCP\Constants::PERMISSION_ALL
1851
-			],
1852
-			$mount,
1853
-			$owner
1854
-		);
1855
-	}
1856
-
1857
-	/**
1858
-	 * @param string $path
1859
-	 * @param string $fileName
1860
-	 * @throws InvalidPathException
1861
-	 */
1862
-	public function verifyPath($path, $fileName) {
1863
-		try {
1864
-			/** @type \OCP\Files\Storage $storage */
1865
-			[$storage, $internalPath] = $this->resolvePath($path);
1866
-			$storage->verifyPath($internalPath, $fileName);
1867
-		} catch (ReservedWordException $ex) {
1868
-			$l = \OC::$server->getL10N('lib');
1869
-			throw new InvalidPathException($l->t('File name is a reserved word'));
1870
-		} catch (InvalidCharacterInPathException $ex) {
1871
-			$l = \OC::$server->getL10N('lib');
1872
-			throw new InvalidPathException($l->t('File name contains at least one invalid character'));
1873
-		} catch (FileNameTooLongException $ex) {
1874
-			$l = \OC::$server->getL10N('lib');
1875
-			throw new InvalidPathException($l->t('File name is too long'));
1876
-		} catch (InvalidDirectoryException $ex) {
1877
-			$l = \OC::$server->getL10N('lib');
1878
-			throw new InvalidPathException($l->t('Dot files are not allowed'));
1879
-		} catch (EmptyFileNameException $ex) {
1880
-			$l = \OC::$server->getL10N('lib');
1881
-			throw new InvalidPathException($l->t('Empty filename is not allowed'));
1882
-		}
1883
-	}
1884
-
1885
-	/**
1886
-	 * get all parent folders of $path
1887
-	 *
1888
-	 * @param string $path
1889
-	 * @return string[]
1890
-	 */
1891
-	private function getParents($path) {
1892
-		$path = trim($path, '/');
1893
-		if (!$path) {
1894
-			return [];
1895
-		}
1896
-
1897
-		$parts = explode('/', $path);
1898
-
1899
-		// remove the single file
1900
-		array_pop($parts);
1901
-		$result = ['/'];
1902
-		$resultPath = '';
1903
-		foreach ($parts as $part) {
1904
-			if ($part) {
1905
-				$resultPath .= '/' . $part;
1906
-				$result[] = $resultPath;
1907
-			}
1908
-		}
1909
-		return $result;
1910
-	}
1911
-
1912
-	/**
1913
-	 * Returns the mount point for which to lock
1914
-	 *
1915
-	 * @param string $absolutePath absolute path
1916
-	 * @param bool $useParentMount true to return parent mount instead of whatever
1917
-	 * is mounted directly on the given path, false otherwise
1918
-	 * @return \OC\Files\Mount\MountPoint mount point for which to apply locks
1919
-	 */
1920
-	private function getMountForLock($absolutePath, $useParentMount = false) {
1921
-		$results = [];
1922
-		$mount = Filesystem::getMountManager()->find($absolutePath);
1923
-		if (!$mount) {
1924
-			return $results;
1925
-		}
1926
-
1927
-		if ($useParentMount) {
1928
-			// find out if something is mounted directly on the path
1929
-			$internalPath = $mount->getInternalPath($absolutePath);
1930
-			if ($internalPath === '') {
1931
-				// resolve the parent mount instead
1932
-				$mount = Filesystem::getMountManager()->find(dirname($absolutePath));
1933
-			}
1934
-		}
1935
-
1936
-		return $mount;
1937
-	}
1938
-
1939
-	/**
1940
-	 * Lock the given path
1941
-	 *
1942
-	 * @param string $path the path of the file to lock, relative to the view
1943
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1944
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1945
-	 *
1946
-	 * @return bool False if the path is excluded from locking, true otherwise
1947
-	 * @throws LockedException if the path is already locked
1948
-	 */
1949
-	private function lockPath($path, $type, $lockMountPoint = false) {
1950
-		$absolutePath = $this->getAbsolutePath($path);
1951
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1952
-		if (!$this->shouldLockFile($absolutePath)) {
1953
-			return false;
1954
-		}
1955
-
1956
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1957
-		if ($mount) {
1958
-			try {
1959
-				$storage = $mount->getStorage();
1960
-				if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1961
-					$storage->acquireLock(
1962
-						$mount->getInternalPath($absolutePath),
1963
-						$type,
1964
-						$this->lockingProvider
1965
-					);
1966
-				}
1967
-			} catch (LockedException $e) {
1968
-				// rethrow with the a human-readable path
1969
-				throw new LockedException(
1970
-					$this->getPathRelativeToFiles($absolutePath),
1971
-					$e,
1972
-					$e->getExistingLock()
1973
-				);
1974
-			}
1975
-		}
1976
-
1977
-		return true;
1978
-	}
1979
-
1980
-	/**
1981
-	 * Change the lock type
1982
-	 *
1983
-	 * @param string $path the path of the file to lock, relative to the view
1984
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1985
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1986
-	 *
1987
-	 * @return bool False if the path is excluded from locking, true otherwise
1988
-	 * @throws LockedException if the path is already locked
1989
-	 */
1990
-	public function changeLock($path, $type, $lockMountPoint = false) {
1991
-		$path = Filesystem::normalizePath($path);
1992
-		$absolutePath = $this->getAbsolutePath($path);
1993
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1994
-		if (!$this->shouldLockFile($absolutePath)) {
1995
-			return false;
1996
-		}
1997
-
1998
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1999
-		if ($mount) {
2000
-			try {
2001
-				$storage = $mount->getStorage();
2002
-				if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2003
-					$storage->changeLock(
2004
-						$mount->getInternalPath($absolutePath),
2005
-						$type,
2006
-						$this->lockingProvider
2007
-					);
2008
-				}
2009
-			} catch (LockedException $e) {
2010
-				try {
2011
-					// rethrow with the a human-readable path
2012
-					throw new LockedException(
2013
-						$this->getPathRelativeToFiles($absolutePath),
2014
-						$e,
2015
-						$e->getExistingLock()
2016
-					);
2017
-				} catch (\InvalidArgumentException $ex) {
2018
-					throw new LockedException(
2019
-						$absolutePath,
2020
-						$ex,
2021
-						$e->getExistingLock()
2022
-					);
2023
-				}
2024
-			}
2025
-		}
2026
-
2027
-		return true;
2028
-	}
2029
-
2030
-	/**
2031
-	 * Unlock the given path
2032
-	 *
2033
-	 * @param string $path the path of the file to unlock, relative to the view
2034
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2035
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2036
-	 *
2037
-	 * @return bool False if the path is excluded from locking, true otherwise
2038
-	 * @throws LockedException
2039
-	 */
2040
-	private function unlockPath($path, $type, $lockMountPoint = false) {
2041
-		$absolutePath = $this->getAbsolutePath($path);
2042
-		$absolutePath = Filesystem::normalizePath($absolutePath);
2043
-		if (!$this->shouldLockFile($absolutePath)) {
2044
-			return false;
2045
-		}
2046
-
2047
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
2048
-		if ($mount) {
2049
-			$storage = $mount->getStorage();
2050
-			if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2051
-				$storage->releaseLock(
2052
-					$mount->getInternalPath($absolutePath),
2053
-					$type,
2054
-					$this->lockingProvider
2055
-				);
2056
-			}
2057
-		}
2058
-
2059
-		return true;
2060
-	}
2061
-
2062
-	/**
2063
-	 * Lock a path and all its parents up to the root of the view
2064
-	 *
2065
-	 * @param string $path the path of the file to lock relative to the view
2066
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2067
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2068
-	 *
2069
-	 * @return bool False if the path is excluded from locking, true otherwise
2070
-	 * @throws LockedException
2071
-	 */
2072
-	public function lockFile($path, $type, $lockMountPoint = false) {
2073
-		$absolutePath = $this->getAbsolutePath($path);
2074
-		$absolutePath = Filesystem::normalizePath($absolutePath);
2075
-		if (!$this->shouldLockFile($absolutePath)) {
2076
-			return false;
2077
-		}
2078
-
2079
-		$this->lockPath($path, $type, $lockMountPoint);
2080
-
2081
-		$parents = $this->getParents($path);
2082
-		foreach ($parents as $parent) {
2083
-			$this->lockPath($parent, ILockingProvider::LOCK_SHARED);
2084
-		}
2085
-
2086
-		return true;
2087
-	}
2088
-
2089
-	/**
2090
-	 * Unlock a path and all its parents up to the root of the view
2091
-	 *
2092
-	 * @param string $path the path of the file to lock relative to the view
2093
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2094
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2095
-	 *
2096
-	 * @return bool False if the path is excluded from locking, true otherwise
2097
-	 * @throws LockedException
2098
-	 */
2099
-	public function unlockFile($path, $type, $lockMountPoint = false) {
2100
-		$absolutePath = $this->getAbsolutePath($path);
2101
-		$absolutePath = Filesystem::normalizePath($absolutePath);
2102
-		if (!$this->shouldLockFile($absolutePath)) {
2103
-			return false;
2104
-		}
2105
-
2106
-		$this->unlockPath($path, $type, $lockMountPoint);
2107
-
2108
-		$parents = $this->getParents($path);
2109
-		foreach ($parents as $parent) {
2110
-			$this->unlockPath($parent, ILockingProvider::LOCK_SHARED);
2111
-		}
2112
-
2113
-		return true;
2114
-	}
2115
-
2116
-	/**
2117
-	 * Only lock files in data/user/files/
2118
-	 *
2119
-	 * @param string $path Absolute path to the file/folder we try to (un)lock
2120
-	 * @return bool
2121
-	 */
2122
-	protected function shouldLockFile($path) {
2123
-		$path = Filesystem::normalizePath($path);
2124
-
2125
-		$pathSegments = explode('/', $path);
2126
-		if (isset($pathSegments[2])) {
2127
-			// E.g.: /username/files/path-to-file
2128
-			return ($pathSegments[2] === 'files') && (count($pathSegments) > 3);
2129
-		}
2130
-
2131
-		return strpos($path, '/appdata_') !== 0;
2132
-	}
2133
-
2134
-	/**
2135
-	 * Shortens the given absolute path to be relative to
2136
-	 * "$user/files".
2137
-	 *
2138
-	 * @param string $absolutePath absolute path which is under "files"
2139
-	 *
2140
-	 * @return string path relative to "files" with trimmed slashes or null
2141
-	 * if the path was NOT relative to files
2142
-	 *
2143
-	 * @throws \InvalidArgumentException if the given path was not under "files"
2144
-	 * @since 8.1.0
2145
-	 */
2146
-	public function getPathRelativeToFiles($absolutePath) {
2147
-		$path = Filesystem::normalizePath($absolutePath);
2148
-		$parts = explode('/', trim($path, '/'), 3);
2149
-		// "$user", "files", "path/to/dir"
2150
-		if (!isset($parts[1]) || $parts[1] !== 'files') {
2151
-			$this->logger->error(
2152
-				'$absolutePath must be relative to "files", value is "%s"',
2153
-				[
2154
-					$absolutePath
2155
-				]
2156
-			);
2157
-			throw new \InvalidArgumentException('$absolutePath must be relative to "files"');
2158
-		}
2159
-		if (isset($parts[2])) {
2160
-			return $parts[2];
2161
-		}
2162
-		return '';
2163
-	}
2164
-
2165
-	/**
2166
-	 * @param string $filename
2167
-	 * @return array
2168
-	 * @throws \OC\User\NoUserException
2169
-	 * @throws NotFoundException
2170
-	 */
2171
-	public function getUidAndFilename($filename) {
2172
-		$info = $this->getFileInfo($filename);
2173
-		if (!$info instanceof \OCP\Files\FileInfo) {
2174
-			throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2175
-		}
2176
-		$uid = $info->getOwner()->getUID();
2177
-		if ($uid != \OC_User::getUser()) {
2178
-			Filesystem::initMountPoints($uid);
2179
-			$ownerView = new View('/' . $uid . '/files');
2180
-			try {
2181
-				$filename = $ownerView->getPath($info['fileid']);
2182
-			} catch (NotFoundException $e) {
2183
-				throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2184
-			}
2185
-		}
2186
-		return [$uid, $filename];
2187
-	}
2188
-
2189
-	/**
2190
-	 * Creates parent non-existing folders
2191
-	 *
2192
-	 * @param string $filePath
2193
-	 * @return bool
2194
-	 */
2195
-	private function createParentDirectories($filePath) {
2196
-		$directoryParts = explode('/', $filePath);
2197
-		$directoryParts = array_filter($directoryParts);
2198
-		foreach ($directoryParts as $key => $part) {
2199
-			$currentPathElements = array_slice($directoryParts, 0, $key);
2200
-			$currentPath = '/' . implode('/', $currentPathElements);
2201
-			if ($this->is_file($currentPath)) {
2202
-				return false;
2203
-			}
2204
-			if (!$this->file_exists($currentPath)) {
2205
-				$this->mkdir($currentPath);
2206
-			}
2207
-		}
2208
-
2209
-		return true;
2210
-	}
87
+    /** @var string */
88
+    private $fakeRoot = '';
89
+
90
+    /**
91
+     * @var \OCP\Lock\ILockingProvider
92
+     */
93
+    protected $lockingProvider;
94
+
95
+    private $lockingEnabled;
96
+
97
+    private $updaterEnabled = true;
98
+
99
+    /** @var \OC\User\Manager */
100
+    private $userManager;
101
+
102
+    /** @var \OCP\ILogger */
103
+    private $logger;
104
+
105
+    /**
106
+     * @param string $root
107
+     * @throws \Exception If $root contains an invalid path
108
+     */
109
+    public function __construct($root = '') {
110
+        if (is_null($root)) {
111
+            throw new \InvalidArgumentException('Root can\'t be null');
112
+        }
113
+        if (!Filesystem::isValidPath($root)) {
114
+            throw new \Exception();
115
+        }
116
+
117
+        $this->fakeRoot = $root;
118
+        $this->lockingProvider = \OC::$server->getLockingProvider();
119
+        $this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
120
+        $this->userManager = \OC::$server->getUserManager();
121
+        $this->logger = \OC::$server->getLogger();
122
+    }
123
+
124
+    public function getAbsolutePath($path = '/') {
125
+        if ($path === null) {
126
+            return null;
127
+        }
128
+        $this->assertPathLength($path);
129
+        if ($path === '') {
130
+            $path = '/';
131
+        }
132
+        if ($path[0] !== '/') {
133
+            $path = '/' . $path;
134
+        }
135
+        return $this->fakeRoot . $path;
136
+    }
137
+
138
+    /**
139
+     * change the root to a fake root
140
+     *
141
+     * @param string $fakeRoot
142
+     * @return boolean|null
143
+     */
144
+    public function chroot($fakeRoot) {
145
+        if (!$fakeRoot == '') {
146
+            if ($fakeRoot[0] !== '/') {
147
+                $fakeRoot = '/' . $fakeRoot;
148
+            }
149
+        }
150
+        $this->fakeRoot = $fakeRoot;
151
+    }
152
+
153
+    /**
154
+     * get the fake root
155
+     *
156
+     * @return string
157
+     */
158
+    public function getRoot() {
159
+        return $this->fakeRoot;
160
+    }
161
+
162
+    /**
163
+     * get path relative to the root of the view
164
+     *
165
+     * @param string $path
166
+     * @return string
167
+     */
168
+    public function getRelativePath($path) {
169
+        $this->assertPathLength($path);
170
+        if ($this->fakeRoot == '') {
171
+            return $path;
172
+        }
173
+
174
+        if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) {
175
+            return '/';
176
+        }
177
+
178
+        // missing slashes can cause wrong matches!
179
+        $root = rtrim($this->fakeRoot, '/') . '/';
180
+
181
+        if (strpos($path, $root) !== 0) {
182
+            return null;
183
+        } else {
184
+            $path = substr($path, strlen($this->fakeRoot));
185
+            if (strlen($path) === 0) {
186
+                return '/';
187
+            } else {
188
+                return $path;
189
+            }
190
+        }
191
+    }
192
+
193
+    /**
194
+     * get the mountpoint of the storage object for a path
195
+     * ( note: because a storage is not always mounted inside the fakeroot, the
196
+     * returned mountpoint is relative to the absolute root of the filesystem
197
+     * and does not take the chroot into account )
198
+     *
199
+     * @param string $path
200
+     * @return string
201
+     */
202
+    public function getMountPoint($path) {
203
+        return Filesystem::getMountPoint($this->getAbsolutePath($path));
204
+    }
205
+
206
+    /**
207
+     * get the mountpoint of the storage object for a path
208
+     * ( note: because a storage is not always mounted inside the fakeroot, the
209
+     * returned mountpoint is relative to the absolute root of the filesystem
210
+     * and does not take the chroot into account )
211
+     *
212
+     * @param string $path
213
+     * @return \OCP\Files\Mount\IMountPoint
214
+     */
215
+    public function getMount($path) {
216
+        return Filesystem::getMountManager()->find($this->getAbsolutePath($path));
217
+    }
218
+
219
+    /**
220
+     * resolve a path to a storage and internal path
221
+     *
222
+     * @param string $path
223
+     * @return array an array consisting of the storage and the internal path
224
+     */
225
+    public function resolvePath($path) {
226
+        $a = $this->getAbsolutePath($path);
227
+        $p = Filesystem::normalizePath($a);
228
+        return Filesystem::resolvePath($p);
229
+    }
230
+
231
+    /**
232
+     * return the path to a local version of the file
233
+     * we need this because we can't know if a file is stored local or not from
234
+     * outside the filestorage and for some purposes a local file is needed
235
+     *
236
+     * @param string $path
237
+     * @return string
238
+     */
239
+    public function getLocalFile($path) {
240
+        $parent = substr($path, 0, strrpos($path, '/'));
241
+        $path = $this->getAbsolutePath($path);
242
+        [$storage, $internalPath] = Filesystem::resolvePath($path);
243
+        if (Filesystem::isValidPath($parent) and $storage) {
244
+            return $storage->getLocalFile($internalPath);
245
+        } else {
246
+            return null;
247
+        }
248
+    }
249
+
250
+    /**
251
+     * @param string $path
252
+     * @return string
253
+     */
254
+    public function getLocalFolder($path) {
255
+        $parent = substr($path, 0, strrpos($path, '/'));
256
+        $path = $this->getAbsolutePath($path);
257
+        [$storage, $internalPath] = Filesystem::resolvePath($path);
258
+        if (Filesystem::isValidPath($parent) and $storage) {
259
+            return $storage->getLocalFolder($internalPath);
260
+        } else {
261
+            return null;
262
+        }
263
+    }
264
+
265
+    /**
266
+     * the following functions operate with arguments and return values identical
267
+     * to those of their PHP built-in equivalents. Mostly they are merely wrappers
268
+     * for \OC\Files\Storage\Storage via basicOperation().
269
+     */
270
+    public function mkdir($path) {
271
+        return $this->basicOperation('mkdir', $path, ['create', 'write']);
272
+    }
273
+
274
+    /**
275
+     * remove mount point
276
+     *
277
+     * @param \OC\Files\Mount\MoveableMount $mount
278
+     * @param string $path relative to data/
279
+     * @return boolean
280
+     */
281
+    protected function removeMount($mount, $path) {
282
+        if ($mount instanceof MoveableMount) {
283
+            // cut of /user/files to get the relative path to data/user/files
284
+            $pathParts = explode('/', $path, 4);
285
+            $relPath = '/' . $pathParts[3];
286
+            $this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
287
+            \OC_Hook::emit(
288
+                Filesystem::CLASSNAME, "umount",
289
+                [Filesystem::signal_param_path => $relPath]
290
+            );
291
+            $this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true);
292
+            $result = $mount->removeMount();
293
+            $this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true);
294
+            if ($result) {
295
+                \OC_Hook::emit(
296
+                    Filesystem::CLASSNAME, "post_umount",
297
+                    [Filesystem::signal_param_path => $relPath]
298
+                );
299
+            }
300
+            $this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true);
301
+            return $result;
302
+        } else {
303
+            // do not allow deleting the storage's root / the mount point
304
+            // because for some storages it might delete the whole contents
305
+            // but isn't supposed to work that way
306
+            return false;
307
+        }
308
+    }
309
+
310
+    public function disableCacheUpdate() {
311
+        $this->updaterEnabled = false;
312
+    }
313
+
314
+    public function enableCacheUpdate() {
315
+        $this->updaterEnabled = true;
316
+    }
317
+
318
+    protected function writeUpdate(Storage $storage, $internalPath, $time = null) {
319
+        if ($this->updaterEnabled) {
320
+            if (is_null($time)) {
321
+                $time = time();
322
+            }
323
+            $storage->getUpdater()->update($internalPath, $time);
324
+        }
325
+    }
326
+
327
+    protected function removeUpdate(Storage $storage, $internalPath) {
328
+        if ($this->updaterEnabled) {
329
+            $storage->getUpdater()->remove($internalPath);
330
+        }
331
+    }
332
+
333
+    protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) {
334
+        if ($this->updaterEnabled) {
335
+            $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
336
+        }
337
+    }
338
+
339
+    /**
340
+     * @param string $path
341
+     * @return bool|mixed
342
+     */
343
+    public function rmdir($path) {
344
+        $absolutePath = $this->getAbsolutePath($path);
345
+        $mount = Filesystem::getMountManager()->find($absolutePath);
346
+        if ($mount->getInternalPath($absolutePath) === '') {
347
+            return $this->removeMount($mount, $absolutePath);
348
+        }
349
+        if ($this->is_dir($path)) {
350
+            $result = $this->basicOperation('rmdir', $path, ['delete']);
351
+        } else {
352
+            $result = false;
353
+        }
354
+
355
+        if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
356
+            $storage = $mount->getStorage();
357
+            $internalPath = $mount->getInternalPath($absolutePath);
358
+            $storage->getUpdater()->remove($internalPath);
359
+        }
360
+        return $result;
361
+    }
362
+
363
+    /**
364
+     * @param string $path
365
+     * @return resource
366
+     */
367
+    public function opendir($path) {
368
+        return $this->basicOperation('opendir', $path, ['read']);
369
+    }
370
+
371
+    /**
372
+     * @param string $path
373
+     * @return bool|mixed
374
+     */
375
+    public function is_dir($path) {
376
+        if ($path == '/') {
377
+            return true;
378
+        }
379
+        return $this->basicOperation('is_dir', $path);
380
+    }
381
+
382
+    /**
383
+     * @param string $path
384
+     * @return bool|mixed
385
+     */
386
+    public function is_file($path) {
387
+        if ($path == '/') {
388
+            return false;
389
+        }
390
+        return $this->basicOperation('is_file', $path);
391
+    }
392
+
393
+    /**
394
+     * @param string $path
395
+     * @return mixed
396
+     */
397
+    public function stat($path) {
398
+        return $this->basicOperation('stat', $path);
399
+    }
400
+
401
+    /**
402
+     * @param string $path
403
+     * @return mixed
404
+     */
405
+    public function filetype($path) {
406
+        return $this->basicOperation('filetype', $path);
407
+    }
408
+
409
+    /**
410
+     * @param string $path
411
+     * @return mixed
412
+     */
413
+    public function filesize($path) {
414
+        return $this->basicOperation('filesize', $path);
415
+    }
416
+
417
+    /**
418
+     * @param string $path
419
+     * @return bool|mixed
420
+     * @throws \OCP\Files\InvalidPathException
421
+     */
422
+    public function readfile($path) {
423
+        $this->assertPathLength($path);
424
+        if (ob_get_level()) {
425
+            ob_end_clean();
426
+        }
427
+        $handle = $this->fopen($path, 'rb');
428
+        if ($handle) {
429
+            $chunkSize = 524288; // 512 kB chunks
430
+            while (!feof($handle)) {
431
+                echo fread($handle, $chunkSize);
432
+                flush();
433
+            }
434
+            fclose($handle);
435
+            return $this->filesize($path);
436
+        }
437
+        return false;
438
+    }
439
+
440
+    /**
441
+     * @param string $path
442
+     * @param int $from
443
+     * @param int $to
444
+     * @return bool|mixed
445
+     * @throws \OCP\Files\InvalidPathException
446
+     * @throws \OCP\Files\UnseekableException
447
+     */
448
+    public function readfilePart($path, $from, $to) {
449
+        $this->assertPathLength($path);
450
+        if (ob_get_level()) {
451
+            ob_end_clean();
452
+        }
453
+        $handle = $this->fopen($path, 'rb');
454
+        if ($handle) {
455
+            $chunkSize = 524288; // 512 kB chunks
456
+            $startReading = true;
457
+
458
+            if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) {
459
+                // forward file handle via chunked fread because fseek seem to have failed
460
+
461
+                $end = $from + 1;
462
+                while (!feof($handle) && ftell($handle) < $end && ftell($handle) !== $from) {
463
+                    $len = $from - ftell($handle);
464
+                    if ($len > $chunkSize) {
465
+                        $len = $chunkSize;
466
+                    }
467
+                    $result = fread($handle, $len);
468
+
469
+                    if ($result === false) {
470
+                        $startReading = false;
471
+                        break;
472
+                    }
473
+                }
474
+            }
475
+
476
+            if ($startReading) {
477
+                $end = $to + 1;
478
+                while (!feof($handle) && ftell($handle) < $end) {
479
+                    $len = $end - ftell($handle);
480
+                    if ($len > $chunkSize) {
481
+                        $len = $chunkSize;
482
+                    }
483
+                    echo fread($handle, $len);
484
+                    flush();
485
+                }
486
+                return ftell($handle) - $from;
487
+            }
488
+
489
+            throw new \OCP\Files\UnseekableException('fseek error');
490
+        }
491
+        return false;
492
+    }
493
+
494
+    /**
495
+     * @param string $path
496
+     * @return mixed
497
+     */
498
+    public function isCreatable($path) {
499
+        return $this->basicOperation('isCreatable', $path);
500
+    }
501
+
502
+    /**
503
+     * @param string $path
504
+     * @return mixed
505
+     */
506
+    public function isReadable($path) {
507
+        return $this->basicOperation('isReadable', $path);
508
+    }
509
+
510
+    /**
511
+     * @param string $path
512
+     * @return mixed
513
+     */
514
+    public function isUpdatable($path) {
515
+        return $this->basicOperation('isUpdatable', $path);
516
+    }
517
+
518
+    /**
519
+     * @param string $path
520
+     * @return bool|mixed
521
+     */
522
+    public function isDeletable($path) {
523
+        $absolutePath = $this->getAbsolutePath($path);
524
+        $mount = Filesystem::getMountManager()->find($absolutePath);
525
+        if ($mount->getInternalPath($absolutePath) === '') {
526
+            return $mount instanceof MoveableMount;
527
+        }
528
+        return $this->basicOperation('isDeletable', $path);
529
+    }
530
+
531
+    /**
532
+     * @param string $path
533
+     * @return mixed
534
+     */
535
+    public function isSharable($path) {
536
+        return $this->basicOperation('isSharable', $path);
537
+    }
538
+
539
+    /**
540
+     * @param string $path
541
+     * @return bool|mixed
542
+     */
543
+    public function file_exists($path) {
544
+        if ($path == '/') {
545
+            return true;
546
+        }
547
+        return $this->basicOperation('file_exists', $path);
548
+    }
549
+
550
+    /**
551
+     * @param string $path
552
+     * @return mixed
553
+     */
554
+    public function filemtime($path) {
555
+        return $this->basicOperation('filemtime', $path);
556
+    }
557
+
558
+    /**
559
+     * @param string $path
560
+     * @param int|string $mtime
561
+     * @return bool
562
+     */
563
+    public function touch($path, $mtime = null) {
564
+        if (!is_null($mtime) and !is_numeric($mtime)) {
565
+            $mtime = strtotime($mtime);
566
+        }
567
+
568
+        $hooks = ['touch'];
569
+
570
+        if (!$this->file_exists($path)) {
571
+            $hooks[] = 'create';
572
+            $hooks[] = 'write';
573
+        }
574
+        try {
575
+            $result = $this->basicOperation('touch', $path, $hooks, $mtime);
576
+        } catch (\Exception $e) {
577
+            $this->logger->logException($e, ['level' => ILogger::INFO, 'message' => 'Error while setting modified time']);
578
+            $result = false;
579
+        }
580
+        if (!$result) {
581
+            // If create file fails because of permissions on external storage like SMB folders,
582
+            // check file exists and return false if not.
583
+            if (!$this->file_exists($path)) {
584
+                return false;
585
+            }
586
+            if (is_null($mtime)) {
587
+                $mtime = time();
588
+            }
589
+            //if native touch fails, we emulate it by changing the mtime in the cache
590
+            $this->putFileInfo($path, ['mtime' => floor($mtime)]);
591
+        }
592
+        return true;
593
+    }
594
+
595
+    /**
596
+     * @param string $path
597
+     * @return mixed
598
+     * @throws LockedException
599
+     */
600
+    public function file_get_contents($path) {
601
+        return $this->basicOperation('file_get_contents', $path, ['read']);
602
+    }
603
+
604
+    /**
605
+     * @param bool $exists
606
+     * @param string $path
607
+     * @param bool $run
608
+     */
609
+    protected function emit_file_hooks_pre($exists, $path, &$run) {
610
+        if (!$exists) {
611
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, [
612
+                Filesystem::signal_param_path => $this->getHookPath($path),
613
+                Filesystem::signal_param_run => &$run,
614
+            ]);
615
+        } else {
616
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, [
617
+                Filesystem::signal_param_path => $this->getHookPath($path),
618
+                Filesystem::signal_param_run => &$run,
619
+            ]);
620
+        }
621
+        \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, [
622
+            Filesystem::signal_param_path => $this->getHookPath($path),
623
+            Filesystem::signal_param_run => &$run,
624
+        ]);
625
+    }
626
+
627
+    /**
628
+     * @param bool $exists
629
+     * @param string $path
630
+     */
631
+    protected function emit_file_hooks_post($exists, $path) {
632
+        if (!$exists) {
633
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, [
634
+                Filesystem::signal_param_path => $this->getHookPath($path),
635
+            ]);
636
+        } else {
637
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, [
638
+                Filesystem::signal_param_path => $this->getHookPath($path),
639
+            ]);
640
+        }
641
+        \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, [
642
+            Filesystem::signal_param_path => $this->getHookPath($path),
643
+        ]);
644
+    }
645
+
646
+    /**
647
+     * @param string $path
648
+     * @param string|resource $data
649
+     * @return bool|mixed
650
+     * @throws LockedException
651
+     */
652
+    public function file_put_contents($path, $data) {
653
+        if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
654
+            $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
655
+            if (Filesystem::isValidPath($path)
656
+                and !Filesystem::isFileBlacklisted($path)
657
+            ) {
658
+                $path = $this->getRelativePath($absolutePath);
659
+
660
+                $this->lockFile($path, ILockingProvider::LOCK_SHARED);
661
+
662
+                $exists = $this->file_exists($path);
663
+                $run = true;
664
+                if ($this->shouldEmitHooks($path)) {
665
+                    $this->emit_file_hooks_pre($exists, $path, $run);
666
+                }
667
+                if (!$run) {
668
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
669
+                    return false;
670
+                }
671
+
672
+                try {
673
+                    $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
674
+                } catch (\Exception $e) {
675
+                    // Release the shared lock before throwing.
676
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
677
+                    throw $e;
678
+                }
679
+
680
+                /** @var \OC\Files\Storage\Storage $storage */
681
+                [$storage, $internalPath] = $this->resolvePath($path);
682
+                $target = $storage->fopen($internalPath, 'w');
683
+                if ($target) {
684
+                    [, $result] = \OC_Helper::streamCopy($data, $target);
685
+                    fclose($target);
686
+                    fclose($data);
687
+
688
+                    $this->writeUpdate($storage, $internalPath);
689
+
690
+                    $this->changeLock($path, ILockingProvider::LOCK_SHARED);
691
+
692
+                    if ($this->shouldEmitHooks($path) && $result !== false) {
693
+                        $this->emit_file_hooks_post($exists, $path);
694
+                    }
695
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
696
+                    return $result;
697
+                } else {
698
+                    $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
699
+                    return false;
700
+                }
701
+            } else {
702
+                return false;
703
+            }
704
+        } else {
705
+            $hooks = $this->file_exists($path) ? ['update', 'write'] : ['create', 'write'];
706
+            return $this->basicOperation('file_put_contents', $path, $hooks, $data);
707
+        }
708
+    }
709
+
710
+    /**
711
+     * @param string $path
712
+     * @return bool|mixed
713
+     */
714
+    public function unlink($path) {
715
+        if ($path === '' || $path === '/') {
716
+            // do not allow deleting the root
717
+            return false;
718
+        }
719
+        $postFix = (substr($path, -1) === '/') ? '/' : '';
720
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
721
+        $mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
722
+        if ($mount and $mount->getInternalPath($absolutePath) === '') {
723
+            return $this->removeMount($mount, $absolutePath);
724
+        }
725
+        if ($this->is_dir($path)) {
726
+            $result = $this->basicOperation('rmdir', $path, ['delete']);
727
+        } else {
728
+            $result = $this->basicOperation('unlink', $path, ['delete']);
729
+        }
730
+        if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
731
+            $storage = $mount->getStorage();
732
+            $internalPath = $mount->getInternalPath($absolutePath);
733
+            $storage->getUpdater()->remove($internalPath);
734
+            return true;
735
+        } else {
736
+            return $result;
737
+        }
738
+    }
739
+
740
+    /**
741
+     * @param string $directory
742
+     * @return bool|mixed
743
+     */
744
+    public function deleteAll($directory) {
745
+        return $this->rmdir($directory);
746
+    }
747
+
748
+    /**
749
+     * Rename/move a file or folder from the source path to target path.
750
+     *
751
+     * @param string $path1 source path
752
+     * @param string $path2 target path
753
+     *
754
+     * @return bool|mixed
755
+     * @throws LockedException
756
+     */
757
+    public function rename($path1, $path2) {
758
+        $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
759
+        $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
760
+        $result = false;
761
+        if (
762
+            Filesystem::isValidPath($path2)
763
+            and Filesystem::isValidPath($path1)
764
+            and !Filesystem::isFileBlacklisted($path2)
765
+        ) {
766
+            $path1 = $this->getRelativePath($absolutePath1);
767
+            $path2 = $this->getRelativePath($absolutePath2);
768
+            $exists = $this->file_exists($path2);
769
+
770
+            if ($path1 == null or $path2 == null) {
771
+                return false;
772
+            }
773
+
774
+            $this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
775
+            try {
776
+                $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
777
+
778
+                $run = true;
779
+                if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
780
+                    // if it was a rename from a part file to a regular file it was a write and not a rename operation
781
+                    $this->emit_file_hooks_pre($exists, $path2, $run);
782
+                } elseif ($this->shouldEmitHooks($path1)) {
783
+                    \OC_Hook::emit(
784
+                        Filesystem::CLASSNAME, Filesystem::signal_rename,
785
+                        [
786
+                            Filesystem::signal_param_oldpath => $this->getHookPath($path1),
787
+                            Filesystem::signal_param_newpath => $this->getHookPath($path2),
788
+                            Filesystem::signal_param_run => &$run
789
+                        ]
790
+                    );
791
+                }
792
+                if ($run) {
793
+                    $this->verifyPath(dirname($path2), basename($path2));
794
+
795
+                    $manager = Filesystem::getMountManager();
796
+                    $mount1 = $this->getMount($path1);
797
+                    $mount2 = $this->getMount($path2);
798
+                    $storage1 = $mount1->getStorage();
799
+                    $storage2 = $mount2->getStorage();
800
+                    $internalPath1 = $mount1->getInternalPath($absolutePath1);
801
+                    $internalPath2 = $mount2->getInternalPath($absolutePath2);
802
+
803
+                    $this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
804
+                    try {
805
+                        $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
806
+
807
+                        if ($internalPath1 === '') {
808
+                            if ($mount1 instanceof MoveableMount) {
809
+                                $sourceParentMount = $this->getMount(dirname($path1));
810
+                                if ($sourceParentMount === $mount2 && $this->targetIsNotShared($storage2, $internalPath2)) {
811
+                                    /**
812
+                                     * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
813
+                                     */
814
+                                    $sourceMountPoint = $mount1->getMountPoint();
815
+                                    $result = $mount1->moveMount($absolutePath2);
816
+                                    $manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
817
+                                } else {
818
+                                    $result = false;
819
+                                }
820
+                            } else {
821
+                                $result = false;
822
+                            }
823
+                            // moving a file/folder within the same mount point
824
+                        } elseif ($storage1 === $storage2) {
825
+                            if ($storage1) {
826
+                                $result = $storage1->rename($internalPath1, $internalPath2);
827
+                            } else {
828
+                                $result = false;
829
+                            }
830
+                            // moving a file/folder between storages (from $storage1 to $storage2)
831
+                        } else {
832
+                            $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
833
+                        }
834
+
835
+                        if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
836
+                            // if it was a rename from a part file to a regular file it was a write and not a rename operation
837
+                            $this->writeUpdate($storage2, $internalPath2);
838
+                        } elseif ($result) {
839
+                            if ($internalPath1 !== '') { // don't do a cache update for moved mounts
840
+                                $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
841
+                            }
842
+                        }
843
+                    } catch (\Exception $e) {
844
+                        throw $e;
845
+                    } finally {
846
+                        $this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
847
+                        $this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
848
+                    }
849
+
850
+                    if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
851
+                        if ($this->shouldEmitHooks()) {
852
+                            $this->emit_file_hooks_post($exists, $path2);
853
+                        }
854
+                    } elseif ($result) {
855
+                        if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) {
856
+                            \OC_Hook::emit(
857
+                                Filesystem::CLASSNAME,
858
+                                Filesystem::signal_post_rename,
859
+                                [
860
+                                    Filesystem::signal_param_oldpath => $this->getHookPath($path1),
861
+                                    Filesystem::signal_param_newpath => $this->getHookPath($path2)
862
+                                ]
863
+                            );
864
+                        }
865
+                    }
866
+                }
867
+            } catch (\Exception $e) {
868
+                throw $e;
869
+            } finally {
870
+                $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
871
+                $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
872
+            }
873
+        }
874
+        return $result;
875
+    }
876
+
877
+    /**
878
+     * Copy a file/folder from the source path to target path
879
+     *
880
+     * @param string $path1 source path
881
+     * @param string $path2 target path
882
+     * @param bool $preserveMtime whether to preserve mtime on the copy
883
+     *
884
+     * @return bool|mixed
885
+     */
886
+    public function copy($path1, $path2, $preserveMtime = false) {
887
+        $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
888
+        $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
889
+        $result = false;
890
+        if (
891
+            Filesystem::isValidPath($path2)
892
+            and Filesystem::isValidPath($path1)
893
+            and !Filesystem::isFileBlacklisted($path2)
894
+        ) {
895
+            $path1 = $this->getRelativePath($absolutePath1);
896
+            $path2 = $this->getRelativePath($absolutePath2);
897
+
898
+            if ($path1 == null or $path2 == null) {
899
+                return false;
900
+            }
901
+            $run = true;
902
+
903
+            $this->lockFile($path2, ILockingProvider::LOCK_SHARED);
904
+            $this->lockFile($path1, ILockingProvider::LOCK_SHARED);
905
+            $lockTypePath1 = ILockingProvider::LOCK_SHARED;
906
+            $lockTypePath2 = ILockingProvider::LOCK_SHARED;
907
+
908
+            try {
909
+                $exists = $this->file_exists($path2);
910
+                if ($this->shouldEmitHooks()) {
911
+                    \OC_Hook::emit(
912
+                        Filesystem::CLASSNAME,
913
+                        Filesystem::signal_copy,
914
+                        [
915
+                            Filesystem::signal_param_oldpath => $this->getHookPath($path1),
916
+                            Filesystem::signal_param_newpath => $this->getHookPath($path2),
917
+                            Filesystem::signal_param_run => &$run
918
+                        ]
919
+                    );
920
+                    $this->emit_file_hooks_pre($exists, $path2, $run);
921
+                }
922
+                if ($run) {
923
+                    $mount1 = $this->getMount($path1);
924
+                    $mount2 = $this->getMount($path2);
925
+                    $storage1 = $mount1->getStorage();
926
+                    $internalPath1 = $mount1->getInternalPath($absolutePath1);
927
+                    $storage2 = $mount2->getStorage();
928
+                    $internalPath2 = $mount2->getInternalPath($absolutePath2);
929
+
930
+                    $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE);
931
+                    $lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE;
932
+
933
+                    if ($mount1->getMountPoint() == $mount2->getMountPoint()) {
934
+                        if ($storage1) {
935
+                            $result = $storage1->copy($internalPath1, $internalPath2);
936
+                        } else {
937
+                            $result = false;
938
+                        }
939
+                    } else {
940
+                        $result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
941
+                    }
942
+
943
+                    $this->writeUpdate($storage2, $internalPath2);
944
+
945
+                    $this->changeLock($path2, ILockingProvider::LOCK_SHARED);
946
+                    $lockTypePath2 = ILockingProvider::LOCK_SHARED;
947
+
948
+                    if ($this->shouldEmitHooks() && $result !== false) {
949
+                        \OC_Hook::emit(
950
+                            Filesystem::CLASSNAME,
951
+                            Filesystem::signal_post_copy,
952
+                            [
953
+                                Filesystem::signal_param_oldpath => $this->getHookPath($path1),
954
+                                Filesystem::signal_param_newpath => $this->getHookPath($path2)
955
+                            ]
956
+                        );
957
+                        $this->emit_file_hooks_post($exists, $path2);
958
+                    }
959
+                }
960
+            } catch (\Exception $e) {
961
+                $this->unlockFile($path2, $lockTypePath2);
962
+                $this->unlockFile($path1, $lockTypePath1);
963
+                throw $e;
964
+            }
965
+
966
+            $this->unlockFile($path2, $lockTypePath2);
967
+            $this->unlockFile($path1, $lockTypePath1);
968
+        }
969
+        return $result;
970
+    }
971
+
972
+    /**
973
+     * @param string $path
974
+     * @param string $mode 'r' or 'w'
975
+     * @return resource
976
+     * @throws LockedException
977
+     */
978
+    public function fopen($path, $mode) {
979
+        $mode = str_replace('b', '', $mode); // the binary flag is a windows only feature which we do not support
980
+        $hooks = [];
981
+        switch ($mode) {
982
+            case 'r':
983
+                $hooks[] = 'read';
984
+                break;
985
+            case 'r+':
986
+            case 'w+':
987
+            case 'x+':
988
+            case 'a+':
989
+                $hooks[] = 'read';
990
+                $hooks[] = 'write';
991
+                break;
992
+            case 'w':
993
+            case 'x':
994
+            case 'a':
995
+                $hooks[] = 'write';
996
+                break;
997
+            default:
998
+                \OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, ILogger::ERROR);
999
+        }
1000
+
1001
+        if ($mode !== 'r' && $mode !== 'w') {
1002
+            \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');
1003
+        }
1004
+
1005
+        return $this->basicOperation('fopen', $path, $hooks, $mode);
1006
+    }
1007
+
1008
+    /**
1009
+     * @param string $path
1010
+     * @return bool|string
1011
+     * @throws \OCP\Files\InvalidPathException
1012
+     */
1013
+    public function toTmpFile($path) {
1014
+        $this->assertPathLength($path);
1015
+        if (Filesystem::isValidPath($path)) {
1016
+            $source = $this->fopen($path, 'r');
1017
+            if ($source) {
1018
+                $extension = pathinfo($path, PATHINFO_EXTENSION);
1019
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
1020
+                file_put_contents($tmpFile, $source);
1021
+                return $tmpFile;
1022
+            } else {
1023
+                return false;
1024
+            }
1025
+        } else {
1026
+            return false;
1027
+        }
1028
+    }
1029
+
1030
+    /**
1031
+     * @param string $tmpFile
1032
+     * @param string $path
1033
+     * @return bool|mixed
1034
+     * @throws \OCP\Files\InvalidPathException
1035
+     */
1036
+    public function fromTmpFile($tmpFile, $path) {
1037
+        $this->assertPathLength($path);
1038
+        if (Filesystem::isValidPath($path)) {
1039
+
1040
+            // Get directory that the file is going into
1041
+            $filePath = dirname($path);
1042
+
1043
+            // Create the directories if any
1044
+            if (!$this->file_exists($filePath)) {
1045
+                $result = $this->createParentDirectories($filePath);
1046
+                if ($result === false) {
1047
+                    return false;
1048
+                }
1049
+            }
1050
+
1051
+            $source = fopen($tmpFile, 'r');
1052
+            if ($source) {
1053
+                $result = $this->file_put_contents($path, $source);
1054
+                // $this->file_put_contents() might have already closed
1055
+                // the resource, so we check it, before trying to close it
1056
+                // to avoid messages in the error log.
1057
+                if (is_resource($source)) {
1058
+                    fclose($source);
1059
+                }
1060
+                unlink($tmpFile);
1061
+                return $result;
1062
+            } else {
1063
+                return false;
1064
+            }
1065
+        } else {
1066
+            return false;
1067
+        }
1068
+    }
1069
+
1070
+
1071
+    /**
1072
+     * @param string $path
1073
+     * @return mixed
1074
+     * @throws \OCP\Files\InvalidPathException
1075
+     */
1076
+    public function getMimeType($path) {
1077
+        $this->assertPathLength($path);
1078
+        return $this->basicOperation('getMimeType', $path);
1079
+    }
1080
+
1081
+    /**
1082
+     * @param string $type
1083
+     * @param string $path
1084
+     * @param bool $raw
1085
+     * @return bool|null|string
1086
+     */
1087
+    public function hash($type, $path, $raw = false) {
1088
+        $postFix = (substr($path, -1) === '/') ? '/' : '';
1089
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1090
+        if (Filesystem::isValidPath($path)) {
1091
+            $path = $this->getRelativePath($absolutePath);
1092
+            if ($path == null) {
1093
+                return false;
1094
+            }
1095
+            if ($this->shouldEmitHooks($path)) {
1096
+                \OC_Hook::emit(
1097
+                    Filesystem::CLASSNAME,
1098
+                    Filesystem::signal_read,
1099
+                    [Filesystem::signal_param_path => $this->getHookPath($path)]
1100
+                );
1101
+            }
1102
+            [$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix);
1103
+            if ($storage) {
1104
+                return $storage->hash($type, $internalPath, $raw);
1105
+            }
1106
+        }
1107
+        return null;
1108
+    }
1109
+
1110
+    /**
1111
+     * @param string $path
1112
+     * @return mixed
1113
+     * @throws \OCP\Files\InvalidPathException
1114
+     */
1115
+    public function free_space($path = '/') {
1116
+        $this->assertPathLength($path);
1117
+        $result = $this->basicOperation('free_space', $path);
1118
+        if ($result === null) {
1119
+            throw new InvalidPathException();
1120
+        }
1121
+        return $result;
1122
+    }
1123
+
1124
+    /**
1125
+     * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage
1126
+     *
1127
+     * @param string $operation
1128
+     * @param string $path
1129
+     * @param array $hooks (optional)
1130
+     * @param mixed $extraParam (optional)
1131
+     * @return mixed
1132
+     * @throws LockedException
1133
+     *
1134
+     * This method takes requests for basic filesystem functions (e.g. reading & writing
1135
+     * files), processes hooks and proxies, sanitises paths, and finally passes them on to
1136
+     * \OC\Files\Storage\Storage for delegation to a storage backend for execution
1137
+     */
1138
+    private function basicOperation($operation, $path, $hooks = [], $extraParam = null) {
1139
+        $postFix = (substr($path, -1) === '/') ? '/' : '';
1140
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1141
+        if (Filesystem::isValidPath($path)
1142
+            and !Filesystem::isFileBlacklisted($path)
1143
+        ) {
1144
+            $path = $this->getRelativePath($absolutePath);
1145
+            if ($path == null) {
1146
+                return false;
1147
+            }
1148
+
1149
+            if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) {
1150
+                // always a shared lock during pre-hooks so the hook can read the file
1151
+                $this->lockFile($path, ILockingProvider::LOCK_SHARED);
1152
+            }
1153
+
1154
+            $run = $this->runHooks($hooks, $path);
1155
+            /** @var \OC\Files\Storage\Storage $storage */
1156
+            [$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix);
1157
+            if ($run and $storage) {
1158
+                if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1159
+                    try {
1160
+                        $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
1161
+                    } catch (LockedException $e) {
1162
+                        // release the shared lock we acquired before quiting
1163
+                        $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1164
+                        throw $e;
1165
+                    }
1166
+                }
1167
+                try {
1168
+                    if (!is_null($extraParam)) {
1169
+                        $result = $storage->$operation($internalPath, $extraParam);
1170
+                    } else {
1171
+                        $result = $storage->$operation($internalPath);
1172
+                    }
1173
+                } catch (\Exception $e) {
1174
+                    if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1175
+                        $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1176
+                    } elseif (in_array('read', $hooks)) {
1177
+                        $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1178
+                    }
1179
+                    throw $e;
1180
+                }
1181
+
1182
+                if ($result && in_array('delete', $hooks) and $result) {
1183
+                    $this->removeUpdate($storage, $internalPath);
1184
+                }
1185
+                if ($result && in_array('write', $hooks,  true) && $operation !== 'fopen' && $operation !== 'touch') {
1186
+                    $this->writeUpdate($storage, $internalPath);
1187
+                }
1188
+                if ($result && in_array('touch', $hooks)) {
1189
+                    $this->writeUpdate($storage, $internalPath, $extraParam);
1190
+                }
1191
+
1192
+                if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
1193
+                    $this->changeLock($path, ILockingProvider::LOCK_SHARED);
1194
+                }
1195
+
1196
+                $unlockLater = false;
1197
+                if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) {
1198
+                    $unlockLater = true;
1199
+                    // make sure our unlocking callback will still be called if connection is aborted
1200
+                    ignore_user_abort(true);
1201
+                    $result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1202
+                        if (in_array('write', $hooks)) {
1203
+                            $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1204
+                        } elseif (in_array('read', $hooks)) {
1205
+                            $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1206
+                        }
1207
+                    });
1208
+                }
1209
+
1210
+                if ($this->shouldEmitHooks($path) && $result !== false) {
1211
+                    if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
1212
+                        $this->runHooks($hooks, $path, true);
1213
+                    }
1214
+                }
1215
+
1216
+                if (!$unlockLater
1217
+                    && (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks))
1218
+                ) {
1219
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1220
+                }
1221
+                return $result;
1222
+            } else {
1223
+                $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1224
+            }
1225
+        }
1226
+        return null;
1227
+    }
1228
+
1229
+    /**
1230
+     * get the path relative to the default root for hook usage
1231
+     *
1232
+     * @param string $path
1233
+     * @return string
1234
+     */
1235
+    private function getHookPath($path) {
1236
+        if (!Filesystem::getView()) {
1237
+            return $path;
1238
+        }
1239
+        return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path));
1240
+    }
1241
+
1242
+    private function shouldEmitHooks($path = '') {
1243
+        if ($path && Cache\Scanner::isPartialFile($path)) {
1244
+            return false;
1245
+        }
1246
+        if (!Filesystem::$loaded) {
1247
+            return false;
1248
+        }
1249
+        $defaultRoot = Filesystem::getRoot();
1250
+        if ($defaultRoot === null) {
1251
+            return false;
1252
+        }
1253
+        if ($this->fakeRoot === $defaultRoot) {
1254
+            return true;
1255
+        }
1256
+        $fullPath = $this->getAbsolutePath($path);
1257
+
1258
+        if ($fullPath === $defaultRoot) {
1259
+            return true;
1260
+        }
1261
+
1262
+        return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1263
+    }
1264
+
1265
+    /**
1266
+     * @param string[] $hooks
1267
+     * @param string $path
1268
+     * @param bool $post
1269
+     * @return bool
1270
+     */
1271
+    private function runHooks($hooks, $path, $post = false) {
1272
+        $relativePath = $path;
1273
+        $path = $this->getHookPath($path);
1274
+        $prefix = $post ? 'post_' : '';
1275
+        $run = true;
1276
+        if ($this->shouldEmitHooks($relativePath)) {
1277
+            foreach ($hooks as $hook) {
1278
+                if ($hook != 'read') {
1279
+                    \OC_Hook::emit(
1280
+                        Filesystem::CLASSNAME,
1281
+                        $prefix . $hook,
1282
+                        [
1283
+                            Filesystem::signal_param_run => &$run,
1284
+                            Filesystem::signal_param_path => $path
1285
+                        ]
1286
+                    );
1287
+                } elseif (!$post) {
1288
+                    \OC_Hook::emit(
1289
+                        Filesystem::CLASSNAME,
1290
+                        $prefix . $hook,
1291
+                        [
1292
+                            Filesystem::signal_param_path => $path
1293
+                        ]
1294
+                    );
1295
+                }
1296
+            }
1297
+        }
1298
+        return $run;
1299
+    }
1300
+
1301
+    /**
1302
+     * check if a file or folder has been updated since $time
1303
+     *
1304
+     * @param string $path
1305
+     * @param int $time
1306
+     * @return bool
1307
+     */
1308
+    public function hasUpdated($path, $time) {
1309
+        return $this->basicOperation('hasUpdated', $path, [], $time);
1310
+    }
1311
+
1312
+    /**
1313
+     * @param string $ownerId
1314
+     * @return \OC\User\User
1315
+     */
1316
+    private function getUserObjectForOwner($ownerId) {
1317
+        $owner = $this->userManager->get($ownerId);
1318
+        if ($owner instanceof IUser) {
1319
+            return $owner;
1320
+        } else {
1321
+            return new User($ownerId, null, \OC::$server->getEventDispatcher());
1322
+        }
1323
+    }
1324
+
1325
+    /**
1326
+     * Get file info from cache
1327
+     *
1328
+     * If the file is not in cached it will be scanned
1329
+     * If the file has changed on storage the cache will be updated
1330
+     *
1331
+     * @param \OC\Files\Storage\Storage $storage
1332
+     * @param string $internalPath
1333
+     * @param string $relativePath
1334
+     * @return ICacheEntry|bool
1335
+     */
1336
+    private function getCacheEntry($storage, $internalPath, $relativePath) {
1337
+        $cache = $storage->getCache($internalPath);
1338
+        $data = $cache->get($internalPath);
1339
+        $watcher = $storage->getWatcher($internalPath);
1340
+
1341
+        try {
1342
+            // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
1343
+            if (!$data || $data['size'] === -1) {
1344
+                if (!$storage->file_exists($internalPath)) {
1345
+                    return false;
1346
+                }
1347
+                // don't need to get a lock here since the scanner does it's own locking
1348
+                $scanner = $storage->getScanner($internalPath);
1349
+                $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1350
+                $data = $cache->get($internalPath);
1351
+            } elseif (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
1352
+                $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1353
+                $watcher->update($internalPath, $data);
1354
+                $storage->getPropagator()->propagateChange($internalPath, time());
1355
+                $data = $cache->get($internalPath);
1356
+                $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1357
+            }
1358
+        } catch (LockedException $e) {
1359
+            // if the file is locked we just use the old cache info
1360
+        }
1361
+
1362
+        return $data;
1363
+    }
1364
+
1365
+    /**
1366
+     * get the filesystem info
1367
+     *
1368
+     * @param string $path
1369
+     * @param boolean|string $includeMountPoints true to add mountpoint sizes,
1370
+     * 'ext' to add only ext storage mount point sizes. Defaults to true.
1371
+     * defaults to true
1372
+     * @return \OC\Files\FileInfo|false False if file does not exist
1373
+     */
1374
+    public function getFileInfo($path, $includeMountPoints = true) {
1375
+        $this->assertPathLength($path);
1376
+        if (!Filesystem::isValidPath($path)) {
1377
+            return false;
1378
+        }
1379
+        if (Cache\Scanner::isPartialFile($path)) {
1380
+            return $this->getPartFileInfo($path);
1381
+        }
1382
+        $relativePath = $path;
1383
+        $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1384
+
1385
+        $mount = Filesystem::getMountManager()->find($path);
1386
+        if (!$mount) {
1387
+            \OC::$server->getLogger()->warning('Mountpoint not found for path: ' . $path);
1388
+            return false;
1389
+        }
1390
+        $storage = $mount->getStorage();
1391
+        $internalPath = $mount->getInternalPath($path);
1392
+        if ($storage) {
1393
+            $data = $this->getCacheEntry($storage, $internalPath, $relativePath);
1394
+
1395
+            if (!$data instanceof ICacheEntry) {
1396
+                return false;
1397
+            }
1398
+
1399
+            if ($mount instanceof MoveableMount && $internalPath === '') {
1400
+                $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
1401
+            }
1402
+            $ownerId = $storage->getOwner($internalPath);
1403
+            $owner = null;
1404
+            if ($ownerId !== null && $ownerId !== false) {
1405
+                // ownerId might be null if files are accessed with an access token without file system access
1406
+                $owner = $this->getUserObjectForOwner($ownerId);
1407
+            }
1408
+            $info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
1409
+
1410
+            if ($data and isset($data['fileid'])) {
1411
+                if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
1412
+                    //add the sizes of other mount points to the folder
1413
+                    $extOnly = ($includeMountPoints === 'ext');
1414
+                    $mounts = Filesystem::getMountManager()->findIn($path);
1415
+                    $info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1416
+                        $subStorage = $mount->getStorage();
1417
+                        return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1418
+                    }));
1419
+                }
1420
+            }
1421
+
1422
+            return $info;
1423
+        } else {
1424
+            \OC::$server->getLogger()->warning('Storage not valid for mountpoint: ' . $mount->getMountPoint());
1425
+        }
1426
+
1427
+        return false;
1428
+    }
1429
+
1430
+    /**
1431
+     * get the content of a directory
1432
+     *
1433
+     * @param string $directory path under datadirectory
1434
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
1435
+     * @return FileInfo[]
1436
+     */
1437
+    public function getDirectoryContent($directory, $mimetype_filter = '') {
1438
+        $this->assertPathLength($directory);
1439
+        if (!Filesystem::isValidPath($directory)) {
1440
+            return [];
1441
+        }
1442
+        $path = $this->getAbsolutePath($directory);
1443
+        $path = Filesystem::normalizePath($path);
1444
+        $mount = $this->getMount($directory);
1445
+        if (!$mount) {
1446
+            return [];
1447
+        }
1448
+        $storage = $mount->getStorage();
1449
+        $internalPath = $mount->getInternalPath($path);
1450
+        if ($storage) {
1451
+            $cache = $storage->getCache($internalPath);
1452
+            $user = \OC_User::getUser();
1453
+
1454
+            $data = $this->getCacheEntry($storage, $internalPath, $directory);
1455
+
1456
+            if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
1457
+                return [];
1458
+            }
1459
+
1460
+            $folderId = $data['fileid'];
1461
+            $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
1462
+
1463
+            $sharingDisabled = \OCP\Util::isSharingDisabledForUser();
1464
+
1465
+            $fileNames = array_map(function (ICacheEntry $content) {
1466
+                return $content->getName();
1467
+            }, $contents);
1468
+            /**
1469
+             * @var \OC\Files\FileInfo[] $fileInfos
1470
+             */
1471
+            $fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1472
+                if ($sharingDisabled) {
1473
+                    $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1474
+                }
1475
+                $owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1476
+                return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1477
+            }, $contents);
1478
+            $files = array_combine($fileNames, $fileInfos);
1479
+
1480
+            //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
1481
+            $mounts = Filesystem::getMountManager()->findIn($path);
1482
+            $dirLength = strlen($path);
1483
+            foreach ($mounts as $mount) {
1484
+                $mountPoint = $mount->getMountPoint();
1485
+                $subStorage = $mount->getStorage();
1486
+                if ($subStorage) {
1487
+                    $subCache = $subStorage->getCache('');
1488
+
1489
+                    $rootEntry = $subCache->get('');
1490
+                    if (!$rootEntry) {
1491
+                        $subScanner = $subStorage->getScanner('');
1492
+                        try {
1493
+                            $subScanner->scanFile('');
1494
+                        } catch (\OCP\Files\StorageNotAvailableException $e) {
1495
+                            continue;
1496
+                        } catch (\OCP\Files\StorageInvalidException $e) {
1497
+                            continue;
1498
+                        } catch (\Exception $e) {
1499
+                            // sometimes when the storage is not available it can be any exception
1500
+                            \OC::$server->getLogger()->logException($e, [
1501
+                                'message' => 'Exception while scanning storage "' . $subStorage->getId() . '"',
1502
+                                'level' => ILogger::ERROR,
1503
+                                'app' => 'lib',
1504
+                            ]);
1505
+                            continue;
1506
+                        }
1507
+                        $rootEntry = $subCache->get('');
1508
+                    }
1509
+
1510
+                    if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
1511
+                        $relativePath = trim(substr($mountPoint, $dirLength), '/');
1512
+                        if ($pos = strpos($relativePath, '/')) {
1513
+                            //mountpoint inside subfolder add size to the correct folder
1514
+                            $entryName = substr($relativePath, 0, $pos);
1515
+                            foreach ($files as &$entry) {
1516
+                                if ($entry->getName() === $entryName) {
1517
+                                    $entry->addSubEntry($rootEntry, $mountPoint);
1518
+                                }
1519
+                            }
1520
+                        } else { //mountpoint in this folder, add an entry for it
1521
+                            $rootEntry['name'] = $relativePath;
1522
+                            $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
1523
+                            $permissions = $rootEntry['permissions'];
1524
+                            // do not allow renaming/deleting the mount point if they are not shared files/folders
1525
+                            // for shared files/folders we use the permissions given by the owner
1526
+                            if ($mount instanceof MoveableMount) {
1527
+                                $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
1528
+                            } else {
1529
+                                $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
1530
+                            }
1531
+
1532
+                            $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1533
+
1534
+                            // if sharing was disabled for the user we remove the share permissions
1535
+                            if (\OCP\Util::isSharingDisabledForUser()) {
1536
+                                $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1537
+                            }
1538
+
1539
+                            $owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1540
+                            $files[$rootEntry->getName()] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1541
+                        }
1542
+                    }
1543
+                }
1544
+            }
1545
+
1546
+            if ($mimetype_filter) {
1547
+                $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1548
+                    if (strpos($mimetype_filter, '/')) {
1549
+                        return $file->getMimetype() === $mimetype_filter;
1550
+                    } else {
1551
+                        return $file->getMimePart() === $mimetype_filter;
1552
+                    }
1553
+                });
1554
+            }
1555
+
1556
+            return array_values($files);
1557
+        } else {
1558
+            return [];
1559
+        }
1560
+    }
1561
+
1562
+    /**
1563
+     * change file metadata
1564
+     *
1565
+     * @param string $path
1566
+     * @param array|\OCP\Files\FileInfo $data
1567
+     * @return int
1568
+     *
1569
+     * returns the fileid of the updated file
1570
+     */
1571
+    public function putFileInfo($path, $data) {
1572
+        $this->assertPathLength($path);
1573
+        if ($data instanceof FileInfo) {
1574
+            $data = $data->getData();
1575
+        }
1576
+        $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1577
+        /**
1578
+         * @var \OC\Files\Storage\Storage $storage
1579
+         * @var string $internalPath
1580
+         */
1581
+        [$storage, $internalPath] = Filesystem::resolvePath($path);
1582
+        if ($storage) {
1583
+            $cache = $storage->getCache($path);
1584
+
1585
+            if (!$cache->inCache($internalPath)) {
1586
+                $scanner = $storage->getScanner($internalPath);
1587
+                $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1588
+            }
1589
+
1590
+            return $cache->put($internalPath, $data);
1591
+        } else {
1592
+            return -1;
1593
+        }
1594
+    }
1595
+
1596
+    /**
1597
+     * search for files with the name matching $query
1598
+     *
1599
+     * @param string $query
1600
+     * @return FileInfo[]
1601
+     */
1602
+    public function search($query) {
1603
+        return $this->searchCommon('search', ['%' . $query . '%']);
1604
+    }
1605
+
1606
+    /**
1607
+     * search for files with the name matching $query
1608
+     *
1609
+     * @param string $query
1610
+     * @return FileInfo[]
1611
+     */
1612
+    public function searchRaw($query) {
1613
+        return $this->searchCommon('search', [$query]);
1614
+    }
1615
+
1616
+    /**
1617
+     * search for files by mimetype
1618
+     *
1619
+     * @param string $mimetype
1620
+     * @return FileInfo[]
1621
+     */
1622
+    public function searchByMime($mimetype) {
1623
+        return $this->searchCommon('searchByMime', [$mimetype]);
1624
+    }
1625
+
1626
+    /**
1627
+     * search for files by tag
1628
+     *
1629
+     * @param string|int $tag name or tag id
1630
+     * @param string $userId owner of the tags
1631
+     * @return FileInfo[]
1632
+     */
1633
+    public function searchByTag($tag, $userId) {
1634
+        return $this->searchCommon('searchByTag', [$tag, $userId]);
1635
+    }
1636
+
1637
+    /**
1638
+     * @param string $method cache method
1639
+     * @param array $args
1640
+     * @return FileInfo[]
1641
+     */
1642
+    private function searchCommon($method, $args) {
1643
+        $files = [];
1644
+        $rootLength = strlen($this->fakeRoot);
1645
+
1646
+        $mount = $this->getMount('');
1647
+        $mountPoint = $mount->getMountPoint();
1648
+        $storage = $mount->getStorage();
1649
+        $userManager = \OC::$server->getUserManager();
1650
+        if ($storage) {
1651
+            $cache = $storage->getCache('');
1652
+
1653
+            $results = call_user_func_array([$cache, $method], $args);
1654
+            foreach ($results as $result) {
1655
+                if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1656
+                    $internalPath = $result['path'];
1657
+                    $path = $mountPoint . $result['path'];
1658
+                    $result['path'] = substr($mountPoint . $result['path'], $rootLength);
1659
+                    $owner = $userManager->get($storage->getOwner($internalPath));
1660
+                    $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1661
+                }
1662
+            }
1663
+
1664
+            $mounts = Filesystem::getMountManager()->findIn($this->fakeRoot);
1665
+            foreach ($mounts as $mount) {
1666
+                $mountPoint = $mount->getMountPoint();
1667
+                $storage = $mount->getStorage();
1668
+                if ($storage) {
1669
+                    $cache = $storage->getCache('');
1670
+
1671
+                    $relativeMountPoint = substr($mountPoint, $rootLength);
1672
+                    $results = call_user_func_array([$cache, $method], $args);
1673
+                    if ($results) {
1674
+                        foreach ($results as $result) {
1675
+                            $internalPath = $result['path'];
1676
+                            $result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1677
+                            $path = rtrim($mountPoint . $internalPath, '/');
1678
+                            $owner = $userManager->get($storage->getOwner($internalPath));
1679
+                            $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1680
+                        }
1681
+                    }
1682
+                }
1683
+            }
1684
+        }
1685
+        return $files;
1686
+    }
1687
+
1688
+    /**
1689
+     * Get the owner for a file or folder
1690
+     *
1691
+     * @param string $path
1692
+     * @return string the user id of the owner
1693
+     * @throws NotFoundException
1694
+     */
1695
+    public function getOwner($path) {
1696
+        $info = $this->getFileInfo($path);
1697
+        if (!$info) {
1698
+            throw new NotFoundException($path . ' not found while trying to get owner');
1699
+        }
1700
+
1701
+        if ($info->getOwner() === null) {
1702
+            throw new NotFoundException($path . ' has no owner');
1703
+        }
1704
+
1705
+        return $info->getOwner()->getUID();
1706
+    }
1707
+
1708
+    /**
1709
+     * get the ETag for a file or folder
1710
+     *
1711
+     * @param string $path
1712
+     * @return string
1713
+     */
1714
+    public function getETag($path) {
1715
+        /**
1716
+         * @var Storage\Storage $storage
1717
+         * @var string $internalPath
1718
+         */
1719
+        [$storage, $internalPath] = $this->resolvePath($path);
1720
+        if ($storage) {
1721
+            return $storage->getETag($internalPath);
1722
+        } else {
1723
+            return null;
1724
+        }
1725
+    }
1726
+
1727
+    /**
1728
+     * Get the path of a file by id, relative to the view
1729
+     *
1730
+     * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
1731
+     *
1732
+     * @param int $id
1733
+     * @param int|null $storageId
1734
+     * @return string
1735
+     * @throws NotFoundException
1736
+     */
1737
+    public function getPath($id, int $storageId = null) {
1738
+        $id = (int)$id;
1739
+        $manager = Filesystem::getMountManager();
1740
+        $mounts = $manager->findIn($this->fakeRoot);
1741
+        $mounts[] = $manager->find($this->fakeRoot);
1742
+        // reverse the array so we start with the storage this view is in
1743
+        // which is the most likely to contain the file we're looking for
1744
+        $mounts = array_reverse($mounts);
1745
+
1746
+        // put non shared mounts in front of the shared mount
1747
+        // this prevent unneeded recursion into shares
1748
+        usort($mounts, function (IMountPoint $a, IMountPoint $b) {
1749
+            return $a instanceof SharedMount && (!$b instanceof SharedMount) ? 1 : -1;
1750
+        });
1751
+
1752
+        if (!is_null($storageId)) {
1753
+            $mounts = array_filter($mounts, function (IMountPoint $mount) use ($storageId) {
1754
+                return $mount->getNumericStorageId() === $storageId;
1755
+            });
1756
+        }
1757
+
1758
+        foreach ($mounts as $mount) {
1759
+            /**
1760
+             * @var \OC\Files\Mount\MountPoint $mount
1761
+             */
1762
+            if ($mount->getStorage()) {
1763
+                $cache = $mount->getStorage()->getCache();
1764
+                $internalPath = $cache->getPathById($id);
1765
+                if (is_string($internalPath)) {
1766
+                    $fullPath = $mount->getMountPoint() . $internalPath;
1767
+                    if (!is_null($path = $this->getRelativePath($fullPath))) {
1768
+                        return $path;
1769
+                    }
1770
+                }
1771
+            }
1772
+        }
1773
+        throw new NotFoundException(sprintf('File with id "%s" has not been found.', $id));
1774
+    }
1775
+
1776
+    /**
1777
+     * @param string $path
1778
+     * @throws InvalidPathException
1779
+     */
1780
+    private function assertPathLength($path) {
1781
+        $maxLen = min(PHP_MAXPATHLEN, 4000);
1782
+        // Check for the string length - performed using isset() instead of strlen()
1783
+        // because isset() is about 5x-40x faster.
1784
+        if (isset($path[$maxLen])) {
1785
+            $pathLen = strlen($path);
1786
+            throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path");
1787
+        }
1788
+    }
1789
+
1790
+    /**
1791
+     * check if it is allowed to move a mount point to a given target.
1792
+     * It is not allowed to move a mount point into a different mount point or
1793
+     * into an already shared folder
1794
+     *
1795
+     * @param IStorage $targetStorage
1796
+     * @param string $targetInternalPath
1797
+     * @return boolean
1798
+     */
1799
+    private function targetIsNotShared(IStorage $targetStorage, string $targetInternalPath) {
1800
+
1801
+        // note: cannot use the view because the target is already locked
1802
+        $fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1803
+        if ($fileId === -1) {
1804
+            // target might not exist, need to check parent instead
1805
+            $fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1806
+        }
1807
+
1808
+        // check if any of the parents were shared by the current owner (include collections)
1809
+        $shares = \OCP\Share::getItemShared(
1810
+            'folder',
1811
+            $fileId,
1812
+            \OCP\Share::FORMAT_NONE,
1813
+            null,
1814
+            true
1815
+        );
1816
+
1817
+        if (count($shares) > 0) {
1818
+            \OCP\Util::writeLog('files',
1819
+                'It is not allowed to move one mount point into a shared folder',
1820
+                ILogger::DEBUG);
1821
+            return false;
1822
+        }
1823
+
1824
+        return true;
1825
+    }
1826
+
1827
+    /**
1828
+     * Get a fileinfo object for files that are ignored in the cache (part files)
1829
+     *
1830
+     * @param string $path
1831
+     * @return \OCP\Files\FileInfo
1832
+     */
1833
+    private function getPartFileInfo($path) {
1834
+        $mount = $this->getMount($path);
1835
+        $storage = $mount->getStorage();
1836
+        $internalPath = $mount->getInternalPath($this->getAbsolutePath($path));
1837
+        $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1838
+        return new FileInfo(
1839
+            $this->getAbsolutePath($path),
1840
+            $storage,
1841
+            $internalPath,
1842
+            [
1843
+                'fileid' => null,
1844
+                'mimetype' => $storage->getMimeType($internalPath),
1845
+                'name' => basename($path),
1846
+                'etag' => null,
1847
+                'size' => $storage->filesize($internalPath),
1848
+                'mtime' => $storage->filemtime($internalPath),
1849
+                'encrypted' => false,
1850
+                'permissions' => \OCP\Constants::PERMISSION_ALL
1851
+            ],
1852
+            $mount,
1853
+            $owner
1854
+        );
1855
+    }
1856
+
1857
+    /**
1858
+     * @param string $path
1859
+     * @param string $fileName
1860
+     * @throws InvalidPathException
1861
+     */
1862
+    public function verifyPath($path, $fileName) {
1863
+        try {
1864
+            /** @type \OCP\Files\Storage $storage */
1865
+            [$storage, $internalPath] = $this->resolvePath($path);
1866
+            $storage->verifyPath($internalPath, $fileName);
1867
+        } catch (ReservedWordException $ex) {
1868
+            $l = \OC::$server->getL10N('lib');
1869
+            throw new InvalidPathException($l->t('File name is a reserved word'));
1870
+        } catch (InvalidCharacterInPathException $ex) {
1871
+            $l = \OC::$server->getL10N('lib');
1872
+            throw new InvalidPathException($l->t('File name contains at least one invalid character'));
1873
+        } catch (FileNameTooLongException $ex) {
1874
+            $l = \OC::$server->getL10N('lib');
1875
+            throw new InvalidPathException($l->t('File name is too long'));
1876
+        } catch (InvalidDirectoryException $ex) {
1877
+            $l = \OC::$server->getL10N('lib');
1878
+            throw new InvalidPathException($l->t('Dot files are not allowed'));
1879
+        } catch (EmptyFileNameException $ex) {
1880
+            $l = \OC::$server->getL10N('lib');
1881
+            throw new InvalidPathException($l->t('Empty filename is not allowed'));
1882
+        }
1883
+    }
1884
+
1885
+    /**
1886
+     * get all parent folders of $path
1887
+     *
1888
+     * @param string $path
1889
+     * @return string[]
1890
+     */
1891
+    private function getParents($path) {
1892
+        $path = trim($path, '/');
1893
+        if (!$path) {
1894
+            return [];
1895
+        }
1896
+
1897
+        $parts = explode('/', $path);
1898
+
1899
+        // remove the single file
1900
+        array_pop($parts);
1901
+        $result = ['/'];
1902
+        $resultPath = '';
1903
+        foreach ($parts as $part) {
1904
+            if ($part) {
1905
+                $resultPath .= '/' . $part;
1906
+                $result[] = $resultPath;
1907
+            }
1908
+        }
1909
+        return $result;
1910
+    }
1911
+
1912
+    /**
1913
+     * Returns the mount point for which to lock
1914
+     *
1915
+     * @param string $absolutePath absolute path
1916
+     * @param bool $useParentMount true to return parent mount instead of whatever
1917
+     * is mounted directly on the given path, false otherwise
1918
+     * @return \OC\Files\Mount\MountPoint mount point for which to apply locks
1919
+     */
1920
+    private function getMountForLock($absolutePath, $useParentMount = false) {
1921
+        $results = [];
1922
+        $mount = Filesystem::getMountManager()->find($absolutePath);
1923
+        if (!$mount) {
1924
+            return $results;
1925
+        }
1926
+
1927
+        if ($useParentMount) {
1928
+            // find out if something is mounted directly on the path
1929
+            $internalPath = $mount->getInternalPath($absolutePath);
1930
+            if ($internalPath === '') {
1931
+                // resolve the parent mount instead
1932
+                $mount = Filesystem::getMountManager()->find(dirname($absolutePath));
1933
+            }
1934
+        }
1935
+
1936
+        return $mount;
1937
+    }
1938
+
1939
+    /**
1940
+     * Lock the given path
1941
+     *
1942
+     * @param string $path the path of the file to lock, relative to the view
1943
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1944
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1945
+     *
1946
+     * @return bool False if the path is excluded from locking, true otherwise
1947
+     * @throws LockedException if the path is already locked
1948
+     */
1949
+    private function lockPath($path, $type, $lockMountPoint = false) {
1950
+        $absolutePath = $this->getAbsolutePath($path);
1951
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1952
+        if (!$this->shouldLockFile($absolutePath)) {
1953
+            return false;
1954
+        }
1955
+
1956
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1957
+        if ($mount) {
1958
+            try {
1959
+                $storage = $mount->getStorage();
1960
+                if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1961
+                    $storage->acquireLock(
1962
+                        $mount->getInternalPath($absolutePath),
1963
+                        $type,
1964
+                        $this->lockingProvider
1965
+                    );
1966
+                }
1967
+            } catch (LockedException $e) {
1968
+                // rethrow with the a human-readable path
1969
+                throw new LockedException(
1970
+                    $this->getPathRelativeToFiles($absolutePath),
1971
+                    $e,
1972
+                    $e->getExistingLock()
1973
+                );
1974
+            }
1975
+        }
1976
+
1977
+        return true;
1978
+    }
1979
+
1980
+    /**
1981
+     * Change the lock type
1982
+     *
1983
+     * @param string $path the path of the file to lock, relative to the view
1984
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1985
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1986
+     *
1987
+     * @return bool False if the path is excluded from locking, true otherwise
1988
+     * @throws LockedException if the path is already locked
1989
+     */
1990
+    public function changeLock($path, $type, $lockMountPoint = false) {
1991
+        $path = Filesystem::normalizePath($path);
1992
+        $absolutePath = $this->getAbsolutePath($path);
1993
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1994
+        if (!$this->shouldLockFile($absolutePath)) {
1995
+            return false;
1996
+        }
1997
+
1998
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1999
+        if ($mount) {
2000
+            try {
2001
+                $storage = $mount->getStorage();
2002
+                if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2003
+                    $storage->changeLock(
2004
+                        $mount->getInternalPath($absolutePath),
2005
+                        $type,
2006
+                        $this->lockingProvider
2007
+                    );
2008
+                }
2009
+            } catch (LockedException $e) {
2010
+                try {
2011
+                    // rethrow with the a human-readable path
2012
+                    throw new LockedException(
2013
+                        $this->getPathRelativeToFiles($absolutePath),
2014
+                        $e,
2015
+                        $e->getExistingLock()
2016
+                    );
2017
+                } catch (\InvalidArgumentException $ex) {
2018
+                    throw new LockedException(
2019
+                        $absolutePath,
2020
+                        $ex,
2021
+                        $e->getExistingLock()
2022
+                    );
2023
+                }
2024
+            }
2025
+        }
2026
+
2027
+        return true;
2028
+    }
2029
+
2030
+    /**
2031
+     * Unlock the given path
2032
+     *
2033
+     * @param string $path the path of the file to unlock, relative to the view
2034
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2035
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2036
+     *
2037
+     * @return bool False if the path is excluded from locking, true otherwise
2038
+     * @throws LockedException
2039
+     */
2040
+    private function unlockPath($path, $type, $lockMountPoint = false) {
2041
+        $absolutePath = $this->getAbsolutePath($path);
2042
+        $absolutePath = Filesystem::normalizePath($absolutePath);
2043
+        if (!$this->shouldLockFile($absolutePath)) {
2044
+            return false;
2045
+        }
2046
+
2047
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
2048
+        if ($mount) {
2049
+            $storage = $mount->getStorage();
2050
+            if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2051
+                $storage->releaseLock(
2052
+                    $mount->getInternalPath($absolutePath),
2053
+                    $type,
2054
+                    $this->lockingProvider
2055
+                );
2056
+            }
2057
+        }
2058
+
2059
+        return true;
2060
+    }
2061
+
2062
+    /**
2063
+     * Lock a path and all its parents up to the root of the view
2064
+     *
2065
+     * @param string $path the path of the file to lock relative to the view
2066
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2067
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2068
+     *
2069
+     * @return bool False if the path is excluded from locking, true otherwise
2070
+     * @throws LockedException
2071
+     */
2072
+    public function lockFile($path, $type, $lockMountPoint = false) {
2073
+        $absolutePath = $this->getAbsolutePath($path);
2074
+        $absolutePath = Filesystem::normalizePath($absolutePath);
2075
+        if (!$this->shouldLockFile($absolutePath)) {
2076
+            return false;
2077
+        }
2078
+
2079
+        $this->lockPath($path, $type, $lockMountPoint);
2080
+
2081
+        $parents = $this->getParents($path);
2082
+        foreach ($parents as $parent) {
2083
+            $this->lockPath($parent, ILockingProvider::LOCK_SHARED);
2084
+        }
2085
+
2086
+        return true;
2087
+    }
2088
+
2089
+    /**
2090
+     * Unlock a path and all its parents up to the root of the view
2091
+     *
2092
+     * @param string $path the path of the file to lock relative to the view
2093
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2094
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2095
+     *
2096
+     * @return bool False if the path is excluded from locking, true otherwise
2097
+     * @throws LockedException
2098
+     */
2099
+    public function unlockFile($path, $type, $lockMountPoint = false) {
2100
+        $absolutePath = $this->getAbsolutePath($path);
2101
+        $absolutePath = Filesystem::normalizePath($absolutePath);
2102
+        if (!$this->shouldLockFile($absolutePath)) {
2103
+            return false;
2104
+        }
2105
+
2106
+        $this->unlockPath($path, $type, $lockMountPoint);
2107
+
2108
+        $parents = $this->getParents($path);
2109
+        foreach ($parents as $parent) {
2110
+            $this->unlockPath($parent, ILockingProvider::LOCK_SHARED);
2111
+        }
2112
+
2113
+        return true;
2114
+    }
2115
+
2116
+    /**
2117
+     * Only lock files in data/user/files/
2118
+     *
2119
+     * @param string $path Absolute path to the file/folder we try to (un)lock
2120
+     * @return bool
2121
+     */
2122
+    protected function shouldLockFile($path) {
2123
+        $path = Filesystem::normalizePath($path);
2124
+
2125
+        $pathSegments = explode('/', $path);
2126
+        if (isset($pathSegments[2])) {
2127
+            // E.g.: /username/files/path-to-file
2128
+            return ($pathSegments[2] === 'files') && (count($pathSegments) > 3);
2129
+        }
2130
+
2131
+        return strpos($path, '/appdata_') !== 0;
2132
+    }
2133
+
2134
+    /**
2135
+     * Shortens the given absolute path to be relative to
2136
+     * "$user/files".
2137
+     *
2138
+     * @param string $absolutePath absolute path which is under "files"
2139
+     *
2140
+     * @return string path relative to "files" with trimmed slashes or null
2141
+     * if the path was NOT relative to files
2142
+     *
2143
+     * @throws \InvalidArgumentException if the given path was not under "files"
2144
+     * @since 8.1.0
2145
+     */
2146
+    public function getPathRelativeToFiles($absolutePath) {
2147
+        $path = Filesystem::normalizePath($absolutePath);
2148
+        $parts = explode('/', trim($path, '/'), 3);
2149
+        // "$user", "files", "path/to/dir"
2150
+        if (!isset($parts[1]) || $parts[1] !== 'files') {
2151
+            $this->logger->error(
2152
+                '$absolutePath must be relative to "files", value is "%s"',
2153
+                [
2154
+                    $absolutePath
2155
+                ]
2156
+            );
2157
+            throw new \InvalidArgumentException('$absolutePath must be relative to "files"');
2158
+        }
2159
+        if (isset($parts[2])) {
2160
+            return $parts[2];
2161
+        }
2162
+        return '';
2163
+    }
2164
+
2165
+    /**
2166
+     * @param string $filename
2167
+     * @return array
2168
+     * @throws \OC\User\NoUserException
2169
+     * @throws NotFoundException
2170
+     */
2171
+    public function getUidAndFilename($filename) {
2172
+        $info = $this->getFileInfo($filename);
2173
+        if (!$info instanceof \OCP\Files\FileInfo) {
2174
+            throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2175
+        }
2176
+        $uid = $info->getOwner()->getUID();
2177
+        if ($uid != \OC_User::getUser()) {
2178
+            Filesystem::initMountPoints($uid);
2179
+            $ownerView = new View('/' . $uid . '/files');
2180
+            try {
2181
+                $filename = $ownerView->getPath($info['fileid']);
2182
+            } catch (NotFoundException $e) {
2183
+                throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2184
+            }
2185
+        }
2186
+        return [$uid, $filename];
2187
+    }
2188
+
2189
+    /**
2190
+     * Creates parent non-existing folders
2191
+     *
2192
+     * @param string $filePath
2193
+     * @return bool
2194
+     */
2195
+    private function createParentDirectories($filePath) {
2196
+        $directoryParts = explode('/', $filePath);
2197
+        $directoryParts = array_filter($directoryParts);
2198
+        foreach ($directoryParts as $key => $part) {
2199
+            $currentPathElements = array_slice($directoryParts, 0, $key);
2200
+            $currentPath = '/' . implode('/', $currentPathElements);
2201
+            if ($this->is_file($currentPath)) {
2202
+                return false;
2203
+            }
2204
+            if (!$this->file_exists($currentPath)) {
2205
+                $this->mkdir($currentPath);
2206
+            }
2207
+        }
2208
+
2209
+        return true;
2210
+    }
2211 2211
 }
Please login to merge, or discard this patch.
lib/private/Files/Config/CachedMountFileInfo.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -27,23 +27,23 @@
 block discarded – undo
27 27
 use OCP\IUser;
28 28
 
29 29
 class CachedMountFileInfo extends CachedMountInfo implements ICachedMountFileInfo {
30
-	/** @var string */
31
-	private $internalPath;
30
+    /** @var string */
31
+    private $internalPath;
32 32
 
33
-	public function __construct(IUser $user, $storageId, $rootId, $mountPoint, $mountId, $rootInternalPath, $internalPath) {
34
-		parent::__construct($user, $storageId, $rootId, $mountPoint, $mountId, $rootInternalPath);
35
-		$this->internalPath = $internalPath;
36
-	}
33
+    public function __construct(IUser $user, $storageId, $rootId, $mountPoint, $mountId, $rootInternalPath, $internalPath) {
34
+        parent::__construct($user, $storageId, $rootId, $mountPoint, $mountId, $rootInternalPath);
35
+        $this->internalPath = $internalPath;
36
+    }
37 37
 
38
-	public function getInternalPath() {
39
-		if ($this->getRootInternalPath()) {
40
-			return substr($this->internalPath, strlen($this->getRootInternalPath()) + 1);
41
-		} else {
42
-			return $this->internalPath;
43
-		}
44
-	}
38
+    public function getInternalPath() {
39
+        if ($this->getRootInternalPath()) {
40
+            return substr($this->internalPath, strlen($this->getRootInternalPath()) + 1);
41
+        } else {
42
+            return $this->internalPath;
43
+        }
44
+    }
45 45
 
46
-	public function getPath() {
47
-		return $this->getMountPoint() . $this->getInternalPath();
48
-	}
46
+    public function getPath() {
47
+        return $this->getMountPoint() . $this->getInternalPath();
48
+    }
49 49
 }
Please login to merge, or discard this patch.
lib/public/AppFramework/Http/Template/PublicTemplateResponse.php 2 patches
Indentation   +108 added lines, -108 removed lines patch added patch discarded remove patch
@@ -33,124 +33,124 @@
 block discarded – undo
33 33
  * @since 14.0.0
34 34
  */
35 35
 class PublicTemplateResponse extends TemplateResponse {
36
-	private $headerTitle = '';
37
-	private $headerDetails = '';
38
-	private $headerActions = [];
39
-	private $footerVisible = true;
36
+    private $headerTitle = '';
37
+    private $headerDetails = '';
38
+    private $headerActions = [];
39
+    private $footerVisible = true;
40 40
 
41
-	/**
42
-	 * PublicTemplateResponse constructor.
43
-	 *
44
-	 * @param string $appName
45
-	 * @param string $templateName
46
-	 * @param array $params
47
-	 * @since 14.0.0
48
-	 */
49
-	public function __construct(string $appName, string $templateName, array $params = []) {
50
-		parent::__construct($appName, $templateName, $params, 'public');
51
-		\OC_Util::addScript('core', 'public/publicpage');
52
-	}
41
+    /**
42
+     * PublicTemplateResponse constructor.
43
+     *
44
+     * @param string $appName
45
+     * @param string $templateName
46
+     * @param array $params
47
+     * @since 14.0.0
48
+     */
49
+    public function __construct(string $appName, string $templateName, array $params = []) {
50
+        parent::__construct($appName, $templateName, $params, 'public');
51
+        \OC_Util::addScript('core', 'public/publicpage');
52
+    }
53 53
 
54
-	/**
55
-	 * @param string $title
56
-	 * @since 14.0.0
57
-	 */
58
-	public function setHeaderTitle(string $title) {
59
-		$this->headerTitle = $title;
60
-	}
54
+    /**
55
+     * @param string $title
56
+     * @since 14.0.0
57
+     */
58
+    public function setHeaderTitle(string $title) {
59
+        $this->headerTitle = $title;
60
+    }
61 61
 
62
-	/**
63
-	 * @return string
64
-	 * @since 14.0.0
65
-	 */
66
-	public function getHeaderTitle(): string {
67
-		return $this->headerTitle;
68
-	}
62
+    /**
63
+     * @return string
64
+     * @since 14.0.0
65
+     */
66
+    public function getHeaderTitle(): string {
67
+        return $this->headerTitle;
68
+    }
69 69
 
70
-	/**
71
-	 * @param string $details
72
-	 * @since 14.0.0
73
-	 */
74
-	public function setHeaderDetails(string $details) {
75
-		$this->headerDetails = $details;
76
-	}
70
+    /**
71
+     * @param string $details
72
+     * @since 14.0.0
73
+     */
74
+    public function setHeaderDetails(string $details) {
75
+        $this->headerDetails = $details;
76
+    }
77 77
 
78
-	/**
79
-	 * @return string
80
-	 * @since 14.0.0
81
-	 */
82
-	public function getHeaderDetails(): string {
83
-		return $this->headerDetails;
84
-	}
78
+    /**
79
+     * @return string
80
+     * @since 14.0.0
81
+     */
82
+    public function getHeaderDetails(): string {
83
+        return $this->headerDetails;
84
+    }
85 85
 
86
-	/**
87
-	 * @param array $actions
88
-	 * @since 14.0.0
89
-	 * @throws InvalidArgumentException
90
-	 */
91
-	public function setHeaderActions(array $actions) {
92
-		foreach ($actions as $action) {
93
-			if ($actions instanceof IMenuAction) {
94
-				throw new InvalidArgumentException('Actions must be of type IMenuAction');
95
-			}
96
-			$this->headerActions[] = $action;
97
-		}
98
-		usort($this->headerActions, function (IMenuAction $a, IMenuAction $b) {
99
-			return $a->getPriority() <=> $b->getPriority();
100
-		});
101
-	}
86
+    /**
87
+     * @param array $actions
88
+     * @since 14.0.0
89
+     * @throws InvalidArgumentException
90
+     */
91
+    public function setHeaderActions(array $actions) {
92
+        foreach ($actions as $action) {
93
+            if ($actions instanceof IMenuAction) {
94
+                throw new InvalidArgumentException('Actions must be of type IMenuAction');
95
+            }
96
+            $this->headerActions[] = $action;
97
+        }
98
+        usort($this->headerActions, function (IMenuAction $a, IMenuAction $b) {
99
+            return $a->getPriority() <=> $b->getPriority();
100
+        });
101
+    }
102 102
 
103
-	/**
104
-	 * @return IMenuAction
105
-	 * @since 14.0.0
106
-	 * @throws \Exception
107
-	 */
108
-	public function getPrimaryAction(): IMenuAction {
109
-		if ($this->getActionCount() > 0) {
110
-			return $this->headerActions[0];
111
-		}
112
-		throw new \Exception('No header actions have been set');
113
-	}
103
+    /**
104
+     * @return IMenuAction
105
+     * @since 14.0.0
106
+     * @throws \Exception
107
+     */
108
+    public function getPrimaryAction(): IMenuAction {
109
+        if ($this->getActionCount() > 0) {
110
+            return $this->headerActions[0];
111
+        }
112
+        throw new \Exception('No header actions have been set');
113
+    }
114 114
 
115
-	/**
116
-	 * @return int
117
-	 * @since 14.0.0
118
-	 */
119
-	public function getActionCount(): int {
120
-		return count($this->headerActions);
121
-	}
115
+    /**
116
+     * @return int
117
+     * @since 14.0.0
118
+     */
119
+    public function getActionCount(): int {
120
+        return count($this->headerActions);
121
+    }
122 122
 
123
-	/**
124
-	 * @return IMenuAction[]
125
-	 * @since 14.0.0
126
-	 */
127
-	public function getOtherActions(): array {
128
-		return array_slice($this->headerActions, 1);
129
-	}
123
+    /**
124
+     * @return IMenuAction[]
125
+     * @since 14.0.0
126
+     */
127
+    public function getOtherActions(): array {
128
+        return array_slice($this->headerActions, 1);
129
+    }
130 130
 
131
-	/**
132
-	 * @since 14.0.0
133
-	 */
134
-	public function setFooterVisible(bool $visible = false) {
135
-		$this->footerVisible = $visible;
136
-	}
131
+    /**
132
+     * @since 14.0.0
133
+     */
134
+    public function setFooterVisible(bool $visible = false) {
135
+        $this->footerVisible = $visible;
136
+    }
137 137
 
138
-	/**
139
-	 * @since 14.0.0
140
-	 */
141
-	public function getFooterVisible(): bool {
142
-		return $this->footerVisible;
143
-	}
138
+    /**
139
+     * @since 14.0.0
140
+     */
141
+    public function getFooterVisible(): bool {
142
+        return $this->footerVisible;
143
+    }
144 144
 
145
-	/**
146
-	 * @return string
147
-	 * @since 14.0.0
148
-	 */
149
-	public function render(): string {
150
-		$params = array_merge($this->getParams(), [
151
-			'template' => $this,
152
-		]);
153
-		$this->setParams($params);
154
-		return  parent::render();
155
-	}
145
+    /**
146
+     * @return string
147
+     * @since 14.0.0
148
+     */
149
+    public function render(): string {
150
+        $params = array_merge($this->getParams(), [
151
+            'template' => $this,
152
+        ]);
153
+        $this->setParams($params);
154
+        return  parent::render();
155
+    }
156 156
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -95,7 +95,7 @@
 block discarded – undo
95 95
 			}
96 96
 			$this->headerActions[] = $action;
97 97
 		}
98
-		usort($this->headerActions, function (IMenuAction $a, IMenuAction $b) {
98
+		usort($this->headerActions, function(IMenuAction $a, IMenuAction $b) {
99 99
 			return $a->getPriority() <=> $b->getPriority();
100 100
 		});
101 101
 	}
Please login to merge, or discard this patch.
core/Controller/PreviewController.php 1 patch
Indentation   +135 added lines, -135 removed lines patch added patch discarded remove patch
@@ -41,139 +41,139 @@
 block discarded – undo
41 41
 
42 42
 class PreviewController extends Controller {
43 43
 
44
-	/** @var string */
45
-	private $userId;
46
-
47
-	/** @var IRootFolder */
48
-	private $root;
49
-
50
-	/** @var IPreview */
51
-	private $preview;
52
-
53
-	/**
54
-	 * PreviewController constructor.
55
-	 *
56
-	 * @param string $appName
57
-	 * @param IRequest $request
58
-	 * @param IPreview $preview
59
-	 * @param IRootFolder $root
60
-	 * @param string $userId
61
-	 * @param ITimeFactory $timeFactory
62
-	 */
63
-	public function __construct(string $appName,
64
-								IRequest $request,
65
-								IPreview $preview,
66
-								IRootFolder $root,
67
-								?string $userId
68
-	) {
69
-		parent::__construct($appName, $request);
70
-
71
-		$this->preview = $preview;
72
-		$this->root = $root;
73
-		$this->userId = $userId;
74
-	}
75
-
76
-	/**
77
-	 * @NoAdminRequired
78
-	 * @NoCSRFRequired
79
-	 *
80
-	 * @param string $file
81
-	 * @param int $x
82
-	 * @param int $y
83
-	 * @param bool $a
84
-	 * @param bool $forceIcon
85
-	 * @param string $mode
86
-	 * @return DataResponse|FileDisplayResponse
87
-	 */
88
-	public function getPreview(
89
-		string $file = '',
90
-		int $x = 32,
91
-		int $y = 32,
92
-		bool $a = false,
93
-		bool $forceIcon = true,
94
-		string $mode = 'fill'): Http\Response {
95
-		if ($file === '' || $x === 0 || $y === 0) {
96
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
97
-		}
98
-
99
-		try {
100
-			$userFolder = $this->root->getUserFolder($this->userId);
101
-			$node = $userFolder->get($file);
102
-		} catch (NotFoundException $e) {
103
-			return new DataResponse([], Http::STATUS_NOT_FOUND);
104
-		}
105
-
106
-		return $this->fetchPreview($node, $x, $y, $a, $forceIcon, $mode);
107
-	}
108
-
109
-	/**
110
-	 * @NoAdminRequired
111
-	 * @NoCSRFRequired
112
-	 *
113
-	 * @param int $fileId
114
-	 * @param int $x
115
-	 * @param int $y
116
-	 * @param bool $a
117
-	 * @param bool $forceIcon
118
-	 * @param string $mode
119
-	 *
120
-	 * @return DataResponse|FileDisplayResponse
121
-	 */
122
-	public function getPreviewByFileId(
123
-		int $fileId = -1,
124
-		int $x = 32,
125
-		int $y = 32,
126
-		bool $a = false,
127
-		bool $forceIcon = true,
128
-		string $mode = 'fill') {
129
-		if ($fileId === -1 || $x === 0 || $y === 0) {
130
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
131
-		}
132
-
133
-		$userFolder = $this->root->getUserFolder($this->userId);
134
-		$nodes = $userFolder->getById($fileId);
135
-
136
-		if (\count($nodes) === 0) {
137
-			return new DataResponse([], Http::STATUS_NOT_FOUND);
138
-		}
139
-
140
-		$node = array_pop($nodes);
141
-
142
-		return $this->fetchPreview($node, $x, $y, $a, $forceIcon, $mode);
143
-	}
144
-
145
-	/**
146
-	 * @param Node $node
147
-	 * @param int $x
148
-	 * @param int $y
149
-	 * @param bool $a
150
-	 * @param bool $forceIcon
151
-	 * @param string $mode
152
-	 * @return DataResponse|FileDisplayResponse
153
-	 */
154
-	private function fetchPreview(
155
-		Node $node,
156
-		int $x,
157
-		int $y,
158
-		bool $a,
159
-		bool $forceIcon,
160
-		string $mode) : Http\Response {
161
-		if (!($node instanceof File) || (!$forceIcon && !$this->preview->isAvailable($node))) {
162
-			return new DataResponse([], Http::STATUS_NOT_FOUND);
163
-		}
164
-		if (!$node->isReadable()) {
165
-			return new DataResponse([], Http::STATUS_FORBIDDEN);
166
-		}
167
-
168
-		try {
169
-			$f = $this->preview->getPreview($node, $x, $y, !$a, $mode);
170
-			$response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
171
-			$response->cacheFor(3600 * 24);
172
-			return $response;
173
-		} catch (NotFoundException $e) {
174
-			return new DataResponse([], Http::STATUS_NOT_FOUND);
175
-		} catch (\InvalidArgumentException $e) {
176
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
177
-		}
178
-	}
44
+    /** @var string */
45
+    private $userId;
46
+
47
+    /** @var IRootFolder */
48
+    private $root;
49
+
50
+    /** @var IPreview */
51
+    private $preview;
52
+
53
+    /**
54
+     * PreviewController constructor.
55
+     *
56
+     * @param string $appName
57
+     * @param IRequest $request
58
+     * @param IPreview $preview
59
+     * @param IRootFolder $root
60
+     * @param string $userId
61
+     * @param ITimeFactory $timeFactory
62
+     */
63
+    public function __construct(string $appName,
64
+                                IRequest $request,
65
+                                IPreview $preview,
66
+                                IRootFolder $root,
67
+                                ?string $userId
68
+    ) {
69
+        parent::__construct($appName, $request);
70
+
71
+        $this->preview = $preview;
72
+        $this->root = $root;
73
+        $this->userId = $userId;
74
+    }
75
+
76
+    /**
77
+     * @NoAdminRequired
78
+     * @NoCSRFRequired
79
+     *
80
+     * @param string $file
81
+     * @param int $x
82
+     * @param int $y
83
+     * @param bool $a
84
+     * @param bool $forceIcon
85
+     * @param string $mode
86
+     * @return DataResponse|FileDisplayResponse
87
+     */
88
+    public function getPreview(
89
+        string $file = '',
90
+        int $x = 32,
91
+        int $y = 32,
92
+        bool $a = false,
93
+        bool $forceIcon = true,
94
+        string $mode = 'fill'): Http\Response {
95
+        if ($file === '' || $x === 0 || $y === 0) {
96
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
97
+        }
98
+
99
+        try {
100
+            $userFolder = $this->root->getUserFolder($this->userId);
101
+            $node = $userFolder->get($file);
102
+        } catch (NotFoundException $e) {
103
+            return new DataResponse([], Http::STATUS_NOT_FOUND);
104
+        }
105
+
106
+        return $this->fetchPreview($node, $x, $y, $a, $forceIcon, $mode);
107
+    }
108
+
109
+    /**
110
+     * @NoAdminRequired
111
+     * @NoCSRFRequired
112
+     *
113
+     * @param int $fileId
114
+     * @param int $x
115
+     * @param int $y
116
+     * @param bool $a
117
+     * @param bool $forceIcon
118
+     * @param string $mode
119
+     *
120
+     * @return DataResponse|FileDisplayResponse
121
+     */
122
+    public function getPreviewByFileId(
123
+        int $fileId = -1,
124
+        int $x = 32,
125
+        int $y = 32,
126
+        bool $a = false,
127
+        bool $forceIcon = true,
128
+        string $mode = 'fill') {
129
+        if ($fileId === -1 || $x === 0 || $y === 0) {
130
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
131
+        }
132
+
133
+        $userFolder = $this->root->getUserFolder($this->userId);
134
+        $nodes = $userFolder->getById($fileId);
135
+
136
+        if (\count($nodes) === 0) {
137
+            return new DataResponse([], Http::STATUS_NOT_FOUND);
138
+        }
139
+
140
+        $node = array_pop($nodes);
141
+
142
+        return $this->fetchPreview($node, $x, $y, $a, $forceIcon, $mode);
143
+    }
144
+
145
+    /**
146
+     * @param Node $node
147
+     * @param int $x
148
+     * @param int $y
149
+     * @param bool $a
150
+     * @param bool $forceIcon
151
+     * @param string $mode
152
+     * @return DataResponse|FileDisplayResponse
153
+     */
154
+    private function fetchPreview(
155
+        Node $node,
156
+        int $x,
157
+        int $y,
158
+        bool $a,
159
+        bool $forceIcon,
160
+        string $mode) : Http\Response {
161
+        if (!($node instanceof File) || (!$forceIcon && !$this->preview->isAvailable($node))) {
162
+            return new DataResponse([], Http::STATUS_NOT_FOUND);
163
+        }
164
+        if (!$node->isReadable()) {
165
+            return new DataResponse([], Http::STATUS_FORBIDDEN);
166
+        }
167
+
168
+        try {
169
+            $f = $this->preview->getPreview($node, $x, $y, !$a, $mode);
170
+            $response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
171
+            $response->cacheFor(3600 * 24);
172
+            return $response;
173
+        } catch (NotFoundException $e) {
174
+            return new DataResponse([], Http::STATUS_NOT_FOUND);
175
+        } catch (\InvalidArgumentException $e) {
176
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
177
+        }
178
+    }
179 179
 }
Please login to merge, or discard this patch.
apps/files/lib/Helper.php 1 patch
Indentation   +210 added lines, -210 removed lines patch added patch discarded remove patch
@@ -40,233 +40,233 @@
 block discarded – undo
40 40
  * Helper class for manipulating file information
41 41
  */
42 42
 class Helper {
43
-	/**
44
-	 * @param string $dir
45
-	 * @return array
46
-	 * @throws \OCP\Files\NotFoundException
47
-	 */
48
-	public static function buildFileStorageStatistics($dir) {
49
-		// information about storage capacities
50
-		$storageInfo = \OC_Helper::getStorageInfo($dir);
51
-		$l = \OC::$server->getL10N('files');
52
-		$maxUploadFileSize = \OCP\Util::maxUploadFilesize($dir, $storageInfo['free']);
53
-		$maxHumanFileSize = \OCP\Util::humanFileSize($maxUploadFileSize);
54
-		$maxHumanFileSize = $l->t('Upload (max. %s)', [$maxHumanFileSize]);
43
+    /**
44
+     * @param string $dir
45
+     * @return array
46
+     * @throws \OCP\Files\NotFoundException
47
+     */
48
+    public static function buildFileStorageStatistics($dir) {
49
+        // information about storage capacities
50
+        $storageInfo = \OC_Helper::getStorageInfo($dir);
51
+        $l = \OC::$server->getL10N('files');
52
+        $maxUploadFileSize = \OCP\Util::maxUploadFilesize($dir, $storageInfo['free']);
53
+        $maxHumanFileSize = \OCP\Util::humanFileSize($maxUploadFileSize);
54
+        $maxHumanFileSize = $l->t('Upload (max. %s)', [$maxHumanFileSize]);
55 55
 
56
-		return [
57
-			'uploadMaxFilesize' => $maxUploadFileSize,
58
-			'maxHumanFilesize' => $maxHumanFileSize,
59
-			'freeSpace' => $storageInfo['free'],
60
-			'quota' => $storageInfo['quota'],
61
-			'used' => $storageInfo['used'],
62
-			'usedSpacePercent' => (int)$storageInfo['relative'],
63
-			'owner' => $storageInfo['owner'],
64
-			'ownerDisplayName' => $storageInfo['ownerDisplayName'],
65
-			'mountType' => $storageInfo['mountType'],
66
-			'mountPoint' => $storageInfo['mountPoint'],
67
-		];
68
-	}
56
+        return [
57
+            'uploadMaxFilesize' => $maxUploadFileSize,
58
+            'maxHumanFilesize' => $maxHumanFileSize,
59
+            'freeSpace' => $storageInfo['free'],
60
+            'quota' => $storageInfo['quota'],
61
+            'used' => $storageInfo['used'],
62
+            'usedSpacePercent' => (int)$storageInfo['relative'],
63
+            'owner' => $storageInfo['owner'],
64
+            'ownerDisplayName' => $storageInfo['ownerDisplayName'],
65
+            'mountType' => $storageInfo['mountType'],
66
+            'mountPoint' => $storageInfo['mountPoint'],
67
+        ];
68
+    }
69 69
 
70
-	/**
71
-	 * Determine icon for a given file
72
-	 *
73
-	 * @param \OCP\Files\FileInfo $file file info
74
-	 * @return string icon URL
75
-	 */
76
-	public static function determineIcon($file) {
77
-		if ($file['type'] === 'dir') {
78
-			$icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir');
79
-			// TODO: move this part to the client side, using mountType
80
-			if ($file->isShared()) {
81
-				$icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-shared');
82
-			} elseif ($file->isMounted()) {
83
-				$icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-external');
84
-			}
85
-		} else {
86
-			$icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon($file->getMimetype());
87
-		}
70
+    /**
71
+     * Determine icon for a given file
72
+     *
73
+     * @param \OCP\Files\FileInfo $file file info
74
+     * @return string icon URL
75
+     */
76
+    public static function determineIcon($file) {
77
+        if ($file['type'] === 'dir') {
78
+            $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir');
79
+            // TODO: move this part to the client side, using mountType
80
+            if ($file->isShared()) {
81
+                $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-shared');
82
+            } elseif ($file->isMounted()) {
83
+                $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon('dir-external');
84
+            }
85
+        } else {
86
+            $icon = \OC::$server->getMimeTypeDetector()->mimeTypeIcon($file->getMimetype());
87
+        }
88 88
 
89
-		return substr($icon, 0, -3) . 'svg';
90
-	}
89
+        return substr($icon, 0, -3) . 'svg';
90
+    }
91 91
 
92
-	/**
93
-	 * Comparator function to sort files alphabetically and have
94
-	 * the directories appear first
95
-	 *
96
-	 * @param \OCP\Files\FileInfo $a file
97
-	 * @param \OCP\Files\FileInfo $b file
98
-	 * @return int -1 if $a must come before $b, 1 otherwise
99
-	 */
100
-	public static function compareFileNames(FileInfo $a, FileInfo $b) {
101
-		$aType = $a->getType();
102
-		$bType = $b->getType();
103
-		if ($aType === 'dir' and $bType !== 'dir') {
104
-			return -1;
105
-		} elseif ($aType !== 'dir' and $bType === 'dir') {
106
-			return 1;
107
-		} else {
108
-			return \OCP\Util::naturalSortCompare($a->getName(), $b->getName());
109
-		}
110
-	}
92
+    /**
93
+     * Comparator function to sort files alphabetically and have
94
+     * the directories appear first
95
+     *
96
+     * @param \OCP\Files\FileInfo $a file
97
+     * @param \OCP\Files\FileInfo $b file
98
+     * @return int -1 if $a must come before $b, 1 otherwise
99
+     */
100
+    public static function compareFileNames(FileInfo $a, FileInfo $b) {
101
+        $aType = $a->getType();
102
+        $bType = $b->getType();
103
+        if ($aType === 'dir' and $bType !== 'dir') {
104
+            return -1;
105
+        } elseif ($aType !== 'dir' and $bType === 'dir') {
106
+            return 1;
107
+        } else {
108
+            return \OCP\Util::naturalSortCompare($a->getName(), $b->getName());
109
+        }
110
+    }
111 111
 
112
-	/**
113
-	 * Comparator function to sort files by date
114
-	 *
115
-	 * @param \OCP\Files\FileInfo $a file
116
-	 * @param \OCP\Files\FileInfo $b file
117
-	 * @return int -1 if $a must come before $b, 1 otherwise
118
-	 */
119
-	public static function compareTimestamp(FileInfo $a, FileInfo $b) {
120
-		$aTime = $a->getMTime();
121
-		$bTime = $b->getMTime();
122
-		return ($aTime < $bTime) ? -1 : 1;
123
-	}
112
+    /**
113
+     * Comparator function to sort files by date
114
+     *
115
+     * @param \OCP\Files\FileInfo $a file
116
+     * @param \OCP\Files\FileInfo $b file
117
+     * @return int -1 if $a must come before $b, 1 otherwise
118
+     */
119
+    public static function compareTimestamp(FileInfo $a, FileInfo $b) {
120
+        $aTime = $a->getMTime();
121
+        $bTime = $b->getMTime();
122
+        return ($aTime < $bTime) ? -1 : 1;
123
+    }
124 124
 
125
-	/**
126
-	 * Comparator function to sort files by size
127
-	 *
128
-	 * @param \OCP\Files\FileInfo $a file
129
-	 * @param \OCP\Files\FileInfo $b file
130
-	 * @return int -1 if $a must come before $b, 1 otherwise
131
-	 */
132
-	public static function compareSize(FileInfo $a, FileInfo $b) {
133
-		$aSize = $a->getSize();
134
-		$bSize = $b->getSize();
135
-		return ($aSize < $bSize) ? -1 : 1;
136
-	}
125
+    /**
126
+     * Comparator function to sort files by size
127
+     *
128
+     * @param \OCP\Files\FileInfo $a file
129
+     * @param \OCP\Files\FileInfo $b file
130
+     * @return int -1 if $a must come before $b, 1 otherwise
131
+     */
132
+    public static function compareSize(FileInfo $a, FileInfo $b) {
133
+        $aSize = $a->getSize();
134
+        $bSize = $b->getSize();
135
+        return ($aSize < $bSize) ? -1 : 1;
136
+    }
137 137
 
138
-	/**
139
-	 * Formats the file info to be returned as JSON to the client.
140
-	 *
141
-	 * @param \OCP\Files\FileInfo $i
142
-	 * @return array formatted file info
143
-	 */
144
-	public static function formatFileInfo(FileInfo $i) {
145
-		$entry = [];
138
+    /**
139
+     * Formats the file info to be returned as JSON to the client.
140
+     *
141
+     * @param \OCP\Files\FileInfo $i
142
+     * @return array formatted file info
143
+     */
144
+    public static function formatFileInfo(FileInfo $i) {
145
+        $entry = [];
146 146
 
147
-		$entry['id'] = $i['fileid'];
148
-		$entry['parentId'] = $i['parent'];
149
-		$entry['mtime'] = $i['mtime'] * 1000;
150
-		// only pick out the needed attributes
151
-		$entry['name'] = $i->getName();
152
-		$entry['permissions'] = $i['permissions'];
153
-		$entry['mimetype'] = $i['mimetype'];
154
-		$entry['size'] = $i['size'];
155
-		$entry['type'] = $i['type'];
156
-		$entry['etag'] = $i['etag'];
157
-		if (isset($i['tags'])) {
158
-			$entry['tags'] = $i['tags'];
159
-		}
160
-		if (isset($i['displayname_owner'])) {
161
-			$entry['shareOwner'] = $i['displayname_owner'];
162
-		}
163
-		if (isset($i['is_share_mount_point'])) {
164
-			$entry['isShareMountPoint'] = $i['is_share_mount_point'];
165
-		}
166
-		$mountType = null;
167
-		$mount = $i->getMountPoint();
168
-		$mountType = $mount->getMountType();
169
-		if ($mountType !== '') {
170
-			if ($i->getInternalPath() === '') {
171
-				$mountType .= '-root';
172
-			}
173
-			$entry['mountType'] = $mountType;
174
-		}
175
-		if (isset($i['extraData'])) {
176
-			$entry['extraData'] = $i['extraData'];
177
-		}
178
-		return $entry;
179
-	}
147
+        $entry['id'] = $i['fileid'];
148
+        $entry['parentId'] = $i['parent'];
149
+        $entry['mtime'] = $i['mtime'] * 1000;
150
+        // only pick out the needed attributes
151
+        $entry['name'] = $i->getName();
152
+        $entry['permissions'] = $i['permissions'];
153
+        $entry['mimetype'] = $i['mimetype'];
154
+        $entry['size'] = $i['size'];
155
+        $entry['type'] = $i['type'];
156
+        $entry['etag'] = $i['etag'];
157
+        if (isset($i['tags'])) {
158
+            $entry['tags'] = $i['tags'];
159
+        }
160
+        if (isset($i['displayname_owner'])) {
161
+            $entry['shareOwner'] = $i['displayname_owner'];
162
+        }
163
+        if (isset($i['is_share_mount_point'])) {
164
+            $entry['isShareMountPoint'] = $i['is_share_mount_point'];
165
+        }
166
+        $mountType = null;
167
+        $mount = $i->getMountPoint();
168
+        $mountType = $mount->getMountType();
169
+        if ($mountType !== '') {
170
+            if ($i->getInternalPath() === '') {
171
+                $mountType .= '-root';
172
+            }
173
+            $entry['mountType'] = $mountType;
174
+        }
175
+        if (isset($i['extraData'])) {
176
+            $entry['extraData'] = $i['extraData'];
177
+        }
178
+        return $entry;
179
+    }
180 180
 
181
-	/**
182
-	 * Format file info for JSON
183
-	 * @param \OCP\Files\FileInfo[] $fileInfos file infos
184
-	 * @return array
185
-	 */
186
-	public static function formatFileInfos($fileInfos) {
187
-		$files = [];
188
-		foreach ($fileInfos as $i) {
189
-			$files[] = self::formatFileInfo($i);
190
-		}
181
+    /**
182
+     * Format file info for JSON
183
+     * @param \OCP\Files\FileInfo[] $fileInfos file infos
184
+     * @return array
185
+     */
186
+    public static function formatFileInfos($fileInfos) {
187
+        $files = [];
188
+        foreach ($fileInfos as $i) {
189
+            $files[] = self::formatFileInfo($i);
190
+        }
191 191
 
192
-		return $files;
193
-	}
192
+        return $files;
193
+    }
194 194
 
195
-	/**
196
-	 * Retrieves the contents of the given directory and
197
-	 * returns it as a sorted array of FileInfo.
198
-	 *
199
-	 * @param string $dir path to the directory
200
-	 * @param string $sortAttribute attribute to sort on
201
-	 * @param bool $sortDescending true for descending sort, false otherwise
202
-	 * @param string $mimetypeFilter limit returned content to this mimetype or mimepart
203
-	 * @return \OCP\Files\FileInfo[] files
204
-	 */
205
-	public static function getFiles($dir, $sortAttribute = 'name', $sortDescending = false, $mimetypeFilter = '') {
206
-		$content = \OC\Files\Filesystem::getDirectoryContent($dir, $mimetypeFilter);
195
+    /**
196
+     * Retrieves the contents of the given directory and
197
+     * returns it as a sorted array of FileInfo.
198
+     *
199
+     * @param string $dir path to the directory
200
+     * @param string $sortAttribute attribute to sort on
201
+     * @param bool $sortDescending true for descending sort, false otherwise
202
+     * @param string $mimetypeFilter limit returned content to this mimetype or mimepart
203
+     * @return \OCP\Files\FileInfo[] files
204
+     */
205
+    public static function getFiles($dir, $sortAttribute = 'name', $sortDescending = false, $mimetypeFilter = '') {
206
+        $content = \OC\Files\Filesystem::getDirectoryContent($dir, $mimetypeFilter);
207 207
 
208
-		return self::sortFiles($content, $sortAttribute, $sortDescending);
209
-	}
208
+        return self::sortFiles($content, $sortAttribute, $sortDescending);
209
+    }
210 210
 
211
-	/**
212
-	 * Populate the result set with file tags
213
-	 *
214
-	 * @param array $fileList
215
-	 * @param string $fileIdentifier identifier attribute name for values in $fileList
216
-	 * @param ITagManager $tagManager
217
-	 * @return array file list populated with tags
218
-	 */
219
-	public static function populateTags(array $fileList, $fileIdentifier, ITagManager $tagManager) {
220
-		$ids = [];
221
-		foreach ($fileList as $fileData) {
222
-			$ids[] = $fileData[$fileIdentifier];
223
-		}
224
-		$tagger = $tagManager->load('files');
225
-		$tags = $tagger->getTagsForObjects($ids);
211
+    /**
212
+     * Populate the result set with file tags
213
+     *
214
+     * @param array $fileList
215
+     * @param string $fileIdentifier identifier attribute name for values in $fileList
216
+     * @param ITagManager $tagManager
217
+     * @return array file list populated with tags
218
+     */
219
+    public static function populateTags(array $fileList, $fileIdentifier, ITagManager $tagManager) {
220
+        $ids = [];
221
+        foreach ($fileList as $fileData) {
222
+            $ids[] = $fileData[$fileIdentifier];
223
+        }
224
+        $tagger = $tagManager->load('files');
225
+        $tags = $tagger->getTagsForObjects($ids);
226 226
 
227
-		if (!is_array($tags)) {
228
-			throw new \UnexpectedValueException('$tags must be an array');
229
-		}
227
+        if (!is_array($tags)) {
228
+            throw new \UnexpectedValueException('$tags must be an array');
229
+        }
230 230
 
231
-		// Set empty tag array
232
-		foreach ($fileList as $key => $fileData) {
233
-			$fileList[$key]['tags'] = [];
234
-		}
231
+        // Set empty tag array
232
+        foreach ($fileList as $key => $fileData) {
233
+            $fileList[$key]['tags'] = [];
234
+        }
235 235
 
236
-		if (!empty($tags)) {
237
-			foreach ($tags as $fileId => $fileTags) {
238
-				foreach ($fileList as $key => $fileData) {
239
-					if ($fileId !== $fileData[$fileIdentifier]) {
240
-						continue;
241
-					}
236
+        if (!empty($tags)) {
237
+            foreach ($tags as $fileId => $fileTags) {
238
+                foreach ($fileList as $key => $fileData) {
239
+                    if ($fileId !== $fileData[$fileIdentifier]) {
240
+                        continue;
241
+                    }
242 242
 
243
-					$fileList[$key]['tags'] = $fileTags;
244
-				}
245
-			}
246
-		}
243
+                    $fileList[$key]['tags'] = $fileTags;
244
+                }
245
+            }
246
+        }
247 247
 
248
-		return $fileList;
249
-	}
248
+        return $fileList;
249
+    }
250 250
 
251
-	/**
252
-	 * Sort the given file info array
253
-	 *
254
-	 * @param \OCP\Files\FileInfo[] $files files to sort
255
-	 * @param string $sortAttribute attribute to sort on
256
-	 * @param bool $sortDescending true for descending sort, false otherwise
257
-	 * @return \OCP\Files\FileInfo[] sorted files
258
-	 */
259
-	public static function sortFiles($files, $sortAttribute = 'name', $sortDescending = false) {
260
-		$sortFunc = 'compareFileNames';
261
-		if ($sortAttribute === 'mtime') {
262
-			$sortFunc = 'compareTimestamp';
263
-		} elseif ($sortAttribute === 'size') {
264
-			$sortFunc = 'compareSize';
265
-		}
266
-		usort($files, [Helper::class, $sortFunc]);
267
-		if ($sortDescending) {
268
-			$files = array_reverse($files);
269
-		}
270
-		return $files;
271
-	}
251
+    /**
252
+     * Sort the given file info array
253
+     *
254
+     * @param \OCP\Files\FileInfo[] $files files to sort
255
+     * @param string $sortAttribute attribute to sort on
256
+     * @param bool $sortDescending true for descending sort, false otherwise
257
+     * @return \OCP\Files\FileInfo[] sorted files
258
+     */
259
+    public static function sortFiles($files, $sortAttribute = 'name', $sortDescending = false) {
260
+        $sortFunc = 'compareFileNames';
261
+        if ($sortAttribute === 'mtime') {
262
+            $sortFunc = 'compareTimestamp';
263
+        } elseif ($sortAttribute === 'size') {
264
+            $sortFunc = 'compareSize';
265
+        }
266
+        usort($files, [Helper::class, $sortFunc]);
267
+        if ($sortDescending) {
268
+            $files = array_reverse($files);
269
+        }
270
+        return $files;
271
+    }
272 272
 }
Please login to merge, or discard this patch.