Completed
Push — stable10 ( b85e94...1e5021 )
by
unknown
23:18 queued 12:32
created
lib/private/Files/Storage/DAV.php 3 patches
Braces   +5 added lines, -2 removed lines patch added patch discarded remove patch
@@ -90,8 +90,11 @@
 block discarded – undo
90 90
 		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
91 91
 			$host = $params['host'];
92 92
 			//remove leading http[s], will be generated in createBaseUri()
93
-			if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
94
-			else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
93
+			if (substr($host, 0, 8) == "https://") {
94
+			    $host = substr($host, 8);
95
+			} else if (substr($host, 0, 7) == "http://") {
96
+			    $host = substr($host, 7);
97
+			}
95 98
 			$this->host = $host;
96 99
 			$this->user = $params['user'];
97 100
 			$this->password = $params['password'];
Please login to merge, or discard this patch.
Indentation   +786 added lines, -786 removed lines patch added patch discarded remove patch
@@ -59,791 +59,791 @@
 block discarded – undo
59 59
  * @package OC\Files\Storage
60 60
  */
61 61
 class DAV extends Common {
62
-	/** @var string */
63
-	protected $password;
64
-	/** @var string */
65
-	protected $user;
66
-	/** @var string */
67
-	protected $host;
68
-	/** @var bool */
69
-	protected $secure;
70
-	/** @var string */
71
-	protected $root;
72
-	/** @var string */
73
-	protected $certPath;
74
-	/** @var bool */
75
-	protected $ready;
76
-	/** @var Client */
77
-	private $client;
78
-	/** @var ArrayCache */
79
-	private $statCache;
80
-	/** @var array */
81
-	private static $tempFiles = [];
82
-	/** @var \OCP\Http\Client\IClientService */
83
-	private $httpClientService;
84
-
85
-	/**
86
-	 * @param array $params
87
-	 * @throws \Exception
88
-	 */
89
-	public function __construct($params) {
90
-		$this->statCache = new ArrayCache();
91
-		$this->httpClientService = \OC::$server->getHTTPClientService();
92
-		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
93
-			$host = $params['host'];
94
-			//remove leading http[s], will be generated in createBaseUri()
95
-			if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
96
-			else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
97
-			$this->host = $host;
98
-			$this->user = $params['user'];
99
-			$this->password = $params['password'];
100
-			if (isset($params['secure'])) {
101
-				if (is_string($params['secure'])) {
102
-					$this->secure = ($params['secure'] === 'true');
103
-				} else {
104
-					$this->secure = (bool)$params['secure'];
105
-				}
106
-			} else {
107
-				$this->secure = false;
108
-			}
109
-			if ($this->secure === true) {
110
-				// inject mock for testing
111
-				$certManager = \OC::$server->getCertificateManager();
112
-				if (is_null($certManager)) { //no user
113
-					$certManager = \OC::$server->getCertificateManager(null);
114
-				}
115
-				$certPath = $certManager->getAbsoluteBundlePath();
116
-				if (file_exists($certPath)) {
117
-					$this->certPath = $certPath;
118
-				}
119
-			}
120
-			$this->root = isset($params['root']) ? $params['root'] : '/';
121
-			if (!$this->root || $this->root[0] != '/') {
122
-				$this->root = '/' . $this->root;
123
-			}
124
-			if (substr($this->root, -1, 1) != '/') {
125
-				$this->root .= '/';
126
-			}
127
-		} else {
128
-			throw new \Exception('Invalid webdav storage configuration');
129
-		}
130
-	}
131
-
132
-	private function init() {
133
-		if ($this->ready) {
134
-			return;
135
-		}
136
-		$this->ready = true;
137
-
138
-		$settings = array(
139
-			'baseUri' => $this->createBaseUri(),
140
-			'userName' => $this->user,
141
-			'password' => $this->password,
142
-		);
143
-
144
-		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
145
-		if($proxy !== '') {
146
-			$settings['proxy'] = $proxy;
147
-		}
148
-
149
-		$this->client = new Client($settings);
150
-		$this->client->setThrowExceptions(true);
151
-		if ($this->secure === true && $this->certPath) {
152
-			$this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
153
-		}
154
-	}
155
-
156
-	/**
157
-	 * Clear the stat cache
158
-	 */
159
-	public function clearStatCache() {
160
-		$this->statCache->clear();
161
-	}
162
-
163
-	/** {@inheritdoc} */
164
-	public function getId() {
165
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
166
-	}
167
-
168
-	/** {@inheritdoc} */
169
-	public function createBaseUri() {
170
-		$baseUri = 'http';
171
-		if ($this->secure) {
172
-			$baseUri .= 's';
173
-		}
174
-		$baseUri .= '://' . $this->host . $this->root;
175
-		return $baseUri;
176
-	}
177
-
178
-	/** {@inheritdoc} */
179
-	public function mkdir($path) {
180
-		$this->init();
181
-		$path = $this->cleanPath($path);
182
-		$result = $this->simpleResponse('MKCOL', $path, null, 201);
183
-		if ($result) {
184
-			$this->statCache->set($path, true);
185
-		}
186
-		return $result;
187
-	}
188
-
189
-	/** {@inheritdoc} */
190
-	public function rmdir($path) {
191
-		$this->init();
192
-		$path = $this->cleanPath($path);
193
-		// FIXME: some WebDAV impl return 403 when trying to DELETE
194
-		// a non-empty folder
195
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
196
-		$this->statCache->clear($path . '/');
197
-		$this->statCache->remove($path);
198
-		return $result;
199
-	}
200
-
201
-	/** {@inheritdoc} */
202
-	public function opendir($path) {
203
-		$this->init();
204
-		$path = $this->cleanPath($path);
205
-		try {
206
-			$response = $this->client->propfind(
207
-				$this->encodePath($path),
208
-				array(),
209
-				1
210
-			);
211
-			$id = md5('webdav' . $this->root . $path);
212
-			$content = array();
213
-			$files = array_keys($response);
214
-			array_shift($files); //the first entry is the current directory
215
-
216
-			if (!$this->statCache->hasKey($path)) {
217
-				$this->statCache->set($path, true);
218
-			}
219
-			foreach ($files as $file) {
220
-				$file = urldecode($file);
221
-				// do not store the real entry, we might not have all properties
222
-				if (!$this->statCache->hasKey($path)) {
223
-					$this->statCache->set($file, true);
224
-				}
225
-				$file = basename($file);
226
-				$content[] = $file;
227
-			}
228
-			return IteratorDirectory::wrap($content);
229
-		} catch (ClientHttpException $e) {
230
-			if ($e->getHttpStatus() === 404) {
231
-				$this->statCache->clear($path . '/');
232
-				$this->statCache->set($path, false);
233
-				return false;
234
-			}
235
-			$this->convertException($e, $path);
236
-		} catch (\Exception $e) {
237
-			$this->convertException($e, $path);
238
-		}
239
-		return false;
240
-	}
241
-
242
-	/**
243
-	 * Propfind call with cache handling.
244
-	 *
245
-	 * First checks if information is cached.
246
-	 * If not, request it from the server then store to cache.
247
-	 *
248
-	 * @param string $path path to propfind
249
-	 *
250
-	 * @return array propfind response
251
-	 *
252
-	 * @throws NotFound
253
-	 */
254
-	protected function propfind($path) {
255
-		$path = $this->cleanPath($path);
256
-		$cachedResponse = $this->statCache->get($path);
257
-		if ($cachedResponse === false) {
258
-			// we know it didn't exist
259
-			throw new NotFound();
260
-		}
261
-		// we either don't know it, or we know it exists but need more details
262
-		if (is_null($cachedResponse) || $cachedResponse === true) {
263
-			$this->init();
264
-			try {
265
-				$response = $this->client->propfind(
266
-					$this->encodePath($path),
267
-					array(
268
-						'{DAV:}getlastmodified',
269
-						'{DAV:}getcontentlength',
270
-						'{DAV:}getcontenttype',
271
-						'{http://owncloud.org/ns}permissions',
272
-						'{http://open-collaboration-services.org/ns}share-permissions',
273
-						'{DAV:}resourcetype',
274
-						'{DAV:}getetag',
275
-					)
276
-				);
277
-				$this->statCache->set($path, $response);
278
-			} catch (NotFound $e) {
279
-				// remember that this path did not exist
280
-				$this->statCache->clear($path . '/');
281
-				$this->statCache->set($path, false);
282
-				throw $e;
283
-			}
284
-		} else {
285
-			$response = $cachedResponse;
286
-		}
287
-		return $response;
288
-	}
289
-
290
-	/** {@inheritdoc} */
291
-	public function filetype($path) {
292
-		try {
293
-			$response = $this->propfind($path);
294
-			$responseType = array();
295
-			if (isset($response["{DAV:}resourcetype"])) {
296
-				/** @var ResourceType[] $response */
297
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
298
-			}
299
-			return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
300
-		} catch (ClientHttpException $e) {
301
-			if ($e->getHttpStatus() === 404) {
302
-				return false;
303
-			}
304
-			$this->convertException($e, $path);
305
-		} catch (\Exception $e) {
306
-			$this->convertException($e, $path);
307
-		}
308
-		return false;
309
-	}
310
-
311
-	/** {@inheritdoc} */
312
-	public function file_exists($path) {
313
-		try {
314
-			$path = $this->cleanPath($path);
315
-			$cachedState = $this->statCache->get($path);
316
-			if ($cachedState === false) {
317
-				// we know the file doesn't exist
318
-				return false;
319
-			} else if (!is_null($cachedState)) {
320
-				return true;
321
-			}
322
-			// need to get from server
323
-			$this->propfind($path);
324
-			return true; //no 404 exception
325
-		} catch (ClientHttpException $e) {
326
-			if ($e->getHttpStatus() === 404) {
327
-				return false;
328
-			}
329
-			$this->convertException($e, $path);
330
-		} catch (\Exception $e) {
331
-			$this->convertException($e, $path);
332
-		}
333
-		return false;
334
-	}
335
-
336
-	/** {@inheritdoc} */
337
-	public function unlink($path) {
338
-		$this->init();
339
-		$path = $this->cleanPath($path);
340
-		$result = $this->simpleResponse('DELETE', $path, null, 204);
341
-		$this->statCache->clear($path . '/');
342
-		$this->statCache->remove($path);
343
-		return $result;
344
-	}
345
-
346
-	/** {@inheritdoc} */
347
-	public function fopen($path, $mode) {
348
-		$this->init();
349
-		$path = $this->cleanPath($path);
350
-		switch ($mode) {
351
-			case 'r':
352
-			case 'rb':
353
-				try {
354
-					$response = $this->httpClientService
355
-							->newClient()
356
-							->get($this->createBaseUri() . $this->encodePath($path), [
357
-									'auth' => [$this->user, $this->password],
358
-									'stream' => true
359
-							]);
360
-				} catch (RequestException $e) {
361
-					if ($e->getResponse() instanceof ResponseInterface
362
-						&& $e->getResponse()->getStatusCode() === 404) {
363
-						return false;
364
-					} else {
365
-						throw $e;
366
-					}
367
-				}
368
-
369
-				if ($response->getStatusCode() !== Http::STATUS_OK) {
370
-					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
371
-						throw new \OCP\Lock\LockedException($path);
372
-					} else {
373
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
374
-					}
375
-				}
376
-
377
-				return $response->getBody();
378
-			case 'w':
379
-			case 'wb':
380
-			case 'a':
381
-			case 'ab':
382
-			case 'r+':
383
-			case 'w+':
384
-			case 'wb+':
385
-			case 'a+':
386
-			case 'x':
387
-			case 'x+':
388
-			case 'c':
389
-			case 'c+':
390
-				//emulate these
391
-				$tempManager = \OC::$server->getTempManager();
392
-				if (strrpos($path, '.') !== false) {
393
-					$ext = substr($path, strrpos($path, '.'));
394
-				} else {
395
-					$ext = '';
396
-				}
397
-				if ($this->file_exists($path)) {
398
-					if (!$this->isUpdatable($path)) {
399
-						return false;
400
-					}
401
-					if ($mode === 'w' or $mode === 'w+') {
402
-						$tmpFile = $tempManager->getTemporaryFile($ext);
403
-					} else {
404
-						$tmpFile = $this->getCachedFile($path);
405
-					}
406
-				} else {
407
-					if (!$this->isCreatable(dirname($path))) {
408
-						return false;
409
-					}
410
-					$tmpFile = $tempManager->getTemporaryFile($ext);
411
-				}
412
-				Close::registerCallback($tmpFile, array($this, 'writeBack'));
413
-				self::$tempFiles[$tmpFile] = $path;
414
-				return fopen('close://' . $tmpFile, $mode);
415
-		}
416
-	}
417
-
418
-	/**
419
-	 * @param string $tmpFile
420
-	 */
421
-	public function writeBack($tmpFile) {
422
-		if (isset(self::$tempFiles[$tmpFile])) {
423
-			$this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]);
424
-			unlink($tmpFile);
425
-		}
426
-	}
427
-
428
-	/** {@inheritdoc} */
429
-	public function free_space($path) {
430
-		$this->init();
431
-		$path = $this->cleanPath($path);
432
-		try {
433
-			// TODO: cacheable ?
434
-			$response = $this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes'));
435
-			if (isset($response['{DAV:}quota-available-bytes'])) {
436
-				return (int)$response['{DAV:}quota-available-bytes'];
437
-			} else {
438
-				return FileInfo::SPACE_UNKNOWN;
439
-			}
440
-		} catch (\Exception $e) {
441
-			return FileInfo::SPACE_UNKNOWN;
442
-		}
443
-	}
444
-
445
-	/** {@inheritdoc} */
446
-	public function touch($path, $mtime = null) {
447
-		$this->init();
448
-		if (is_null($mtime)) {
449
-			$mtime = time();
450
-		}
451
-		$path = $this->cleanPath($path);
452
-
453
-		// if file exists, update the mtime, else create a new empty file
454
-		if ($this->file_exists($path)) {
455
-			try {
456
-				$this->statCache->remove($path);
457
-				$this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
458
-				// non-owncloud clients might not have accepted the property, need to recheck it
459
-				$response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
460
-				if (isset($response['{DAV:}getlastmodified'])) {
461
-					$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
462
-					if ($remoteMtime !== $mtime) {
463
-						// server has not accepted the mtime
464
-						return false;
465
-					}
466
-				}
467
-			} catch (ClientHttpException $e) {
468
-				if ($e->getHttpStatus() === 501) {
469
-					return false;
470
-				}
471
-				$this->convertException($e, $path);
472
-				return false;
473
-			} catch (\Exception $e) {
474
-				$this->convertException($e, $path);
475
-				return false;
476
-			}
477
-		} else {
478
-			$this->file_put_contents($path, '');
479
-		}
480
-		return true;
481
-	}
482
-
483
-	/**
484
-	 * @param string $path
485
-	 * @param string $data
486
-	 * @return int
487
-	 */
488
-	public function file_put_contents($path, $data) {
489
-		$path = $this->cleanPath($path);
490
-		$result = parent::file_put_contents($path, $data);
491
-		$this->statCache->remove($path);
492
-		return $result;
493
-	}
494
-
495
-	/**
496
-	 * @param string $path
497
-	 * @param string $target
498
-	 */
499
-	protected function uploadFile($path, $target) {
500
-		$this->init();
501
-
502
-		// invalidate
503
-		$target = $this->cleanPath($target);
504
-		$this->statCache->remove($target);
505
-		$source = fopen($path, 'r');
506
-
507
-		$this->httpClientService
508
-			->newClient()
509
-			->put($this->createBaseUri() . $this->encodePath($target), [
510
-				'body' => $source,
511
-				'auth' => [$this->user, $this->password]
512
-			]);
513
-
514
-		$this->removeCachedFile($target);
515
-	}
516
-
517
-	/** {@inheritdoc} */
518
-	public function rename($path1, $path2) {
519
-		$this->init();
520
-		$path1 = $this->cleanPath($path1);
521
-		$path2 = $this->cleanPath($path2);
522
-		try {
523
-			// overwrite directory ?
524
-			if ($this->is_dir($path2)) {
525
-				// needs trailing slash in destination
526
-				$path2 = rtrim($path2, '/') . '/';
527
-			}
528
-			$this->client->request(
529
-				'MOVE',
530
-				$this->encodePath($path1),
531
-				null,
532
-				[
533
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
534
-				]
535
-			);
536
-			$this->statCache->clear($path1 . '/');
537
-			$this->statCache->clear($path2 . '/');
538
-			$this->statCache->set($path1, false);
539
-			$this->statCache->set($path2, true);
540
-			$this->removeCachedFile($path1);
541
-			$this->removeCachedFile($path2);
542
-			return true;
543
-		} catch (\Exception $e) {
544
-			$this->convertException($e);
545
-		}
546
-		return false;
547
-	}
548
-
549
-	/** {@inheritdoc} */
550
-	public function copy($path1, $path2) {
551
-		$this->init();
552
-		$path1 = $this->cleanPath($path1);
553
-		$path2 = $this->cleanPath($path2);
554
-		try {
555
-			// overwrite directory ?
556
-			if ($this->is_dir($path2)) {
557
-				// needs trailing slash in destination
558
-				$path2 = rtrim($path2, '/') . '/';
559
-			}
560
-			$this->client->request(
561
-				'COPY',
562
-				$this->encodePath($path1),
563
-				null,
564
-				[
565
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
566
-				]
567
-			);
568
-			$this->statCache->clear($path2 . '/');
569
-			$this->statCache->set($path2, true);
570
-			$this->removeCachedFile($path2);
571
-			return true;
572
-		} catch (\Exception $e) {
573
-			$this->convertException($e);
574
-		}
575
-		return false;
576
-	}
577
-
578
-	/** {@inheritdoc} */
579
-	public function stat($path) {
580
-		try {
581
-			$response = $this->propfind($path);
582
-			return array(
583
-				'mtime' => strtotime($response['{DAV:}getlastmodified']),
584
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
585
-			);
586
-		} catch (ClientHttpException $e) {
587
-			if ($e->getHttpStatus() === 404) {
588
-				return array();
589
-			}
590
-			$this->convertException($e, $path);
591
-		} catch (\Exception $e) {
592
-			$this->convertException($e, $path);
593
-		}
594
-		return array();
595
-	}
596
-
597
-	/** {@inheritdoc} */
598
-	public function getMimeType($path) {
599
-		try {
600
-			$response = $this->propfind($path);
601
-			$responseType = array();
602
-			if (isset($response["{DAV:}resourcetype"])) {
603
-				/** @var ResourceType[] $response */
604
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
605
-			}
606
-			$type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
607
-			if ($type == 'dir') {
608
-				return 'httpd/unix-directory';
609
-			} elseif (isset($response['{DAV:}getcontenttype'])) {
610
-				return $response['{DAV:}getcontenttype'];
611
-			} else {
612
-				return false;
613
-			}
614
-		} catch (ClientHttpException $e) {
615
-			if ($e->getHttpStatus() === 404) {
616
-				return false;
617
-			}
618
-			$this->convertException($e, $path);
619
-		} catch (\Exception $e) {
620
-			$this->convertException($e, $path);
621
-		}
622
-		return false;
623
-	}
624
-
625
-	/**
626
-	 * @param string $path
627
-	 * @return string
628
-	 */
629
-	public function cleanPath($path) {
630
-		if ($path === '') {
631
-			return $path;
632
-		}
633
-		$path = Filesystem::normalizePath($path);
634
-		// remove leading slash
635
-		return substr($path, 1);
636
-	}
637
-
638
-	/**
639
-	 * URL encodes the given path but keeps the slashes
640
-	 *
641
-	 * @param string $path to encode
642
-	 * @return string encoded path
643
-	 */
644
-	private function encodePath($path) {
645
-		// slashes need to stay
646
-		return str_replace('%2F', '/', rawurlencode($path));
647
-	}
648
-
649
-	/**
650
-	 * @param string $method
651
-	 * @param string $path
652
-	 * @param string|resource|null $body
653
-	 * @param int $expected
654
-	 * @return bool
655
-	 * @throws StorageInvalidException
656
-	 * @throws StorageNotAvailableException
657
-	 */
658
-	private function simpleResponse($method, $path, $body, $expected) {
659
-		$path = $this->cleanPath($path);
660
-		try {
661
-			$response = $this->client->request($method, $this->encodePath($path), $body);
662
-			return $response['statusCode'] == $expected;
663
-		} catch (ClientHttpException $e) {
664
-			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
665
-				$this->statCache->clear($path . '/');
666
-				$this->statCache->set($path, false);
667
-				return false;
668
-			}
669
-
670
-			$this->convertException($e, $path);
671
-		} catch (\Exception $e) {
672
-			$this->convertException($e, $path);
673
-		}
674
-		return false;
675
-	}
676
-
677
-	/**
678
-	 * check if curl is installed
679
-	 */
680
-	public static function checkDependencies() {
681
-		return true;
682
-	}
683
-
684
-	/** {@inheritdoc} */
685
-	public function isUpdatable($path) {
686
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
687
-	}
688
-
689
-	/** {@inheritdoc} */
690
-	public function isCreatable($path) {
691
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
692
-	}
693
-
694
-	/** {@inheritdoc} */
695
-	public function isSharable($path) {
696
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
697
-	}
698
-
699
-	/** {@inheritdoc} */
700
-	public function isDeletable($path) {
701
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
702
-	}
703
-
704
-	/** {@inheritdoc} */
705
-	public function getPermissions($path) {
706
-		$this->init();
707
-		$path = $this->cleanPath($path);
708
-		$response = $this->propfind($path);
709
-		if (isset($response['{http://owncloud.org/ns}permissions'])) {
710
-			return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
711
-		} else if ($this->is_dir($path)) {
712
-			return Constants::PERMISSION_ALL;
713
-		} else if ($this->file_exists($path)) {
714
-			return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
715
-		} else {
716
-			return 0;
717
-		}
718
-	}
719
-
720
-	/** {@inheritdoc} */
721
-	public function getETag($path) {
722
-		$this->init();
723
-		$path = $this->cleanPath($path);
724
-		$response = $this->propfind($path);
725
-		if (isset($response['{DAV:}getetag'])) {
726
-			return trim($response['{DAV:}getetag'], '"');
727
-		}
728
-		return parent::getEtag($path);
729
-	}
730
-
731
-	/**
732
-	 * @param string $permissionsString
733
-	 * @return int
734
-	 */
735
-	protected function parsePermissions($permissionsString) {
736
-		$permissions = Constants::PERMISSION_READ;
737
-		if (strpos($permissionsString, 'R') !== false) {
738
-			$permissions |= Constants::PERMISSION_SHARE;
739
-		}
740
-		if (strpos($permissionsString, 'D') !== false) {
741
-			$permissions |= Constants::PERMISSION_DELETE;
742
-		}
743
-		if (strpos($permissionsString, 'W') !== false) {
744
-			$permissions |= Constants::PERMISSION_UPDATE;
745
-		}
746
-		if (strpos($permissionsString, 'CK') !== false) {
747
-			$permissions |= Constants::PERMISSION_CREATE;
748
-			$permissions |= Constants::PERMISSION_UPDATE;
749
-		}
750
-		return $permissions;
751
-	}
752
-
753
-	/**
754
-	 * check if a file or folder has been updated since $time
755
-	 *
756
-	 * @param string $path
757
-	 * @param int $time
758
-	 * @throws \OCP\Files\StorageNotAvailableException
759
-	 * @return bool
760
-	 */
761
-	public function hasUpdated($path, $time) {
762
-		$this->init();
763
-		$path = $this->cleanPath($path);
764
-		try {
765
-			// force refresh for $path
766
-			$this->statCache->remove($path);
767
-			$response = $this->propfind($path);
768
-			if (isset($response['{DAV:}getetag'])) {
769
-				$cachedData = $this->getCache()->get($path);
770
-				$etag = null;
771
-				if (isset($response['{DAV:}getetag'])) {
772
-					$etag = trim($response['{DAV:}getetag'], '"');
773
-				}
774
-				if (!empty($etag) && $cachedData['etag'] !== $etag) {
775
-					return true;
776
-				} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
777
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
778
-					return $sharePermissions !== $cachedData['permissions'];
779
-				} else if (isset($response['{http://owncloud.org/ns}permissions'])) {
780
-					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
781
-					return $permissions !== $cachedData['permissions'];
782
-				} else {
783
-					return false;
784
-				}
785
-			} else {
786
-				$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
787
-				return $remoteMtime > $time;
788
-			}
789
-		} catch (ClientHttpException $e) {
790
-			if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) {
791
-				if ($path === '') {
792
-					// if root is gone it means the storage is not available
793
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
794
-				}
795
-				return false;
796
-			}
797
-			$this->convertException($e, $path);
798
-			return false;
799
-		} catch (\Exception $e) {
800
-			$this->convertException($e, $path);
801
-			return false;
802
-		}
803
-	}
804
-
805
-	/**
806
-	 * Interpret the given exception and decide whether it is due to an
807
-	 * unavailable storage, invalid storage or other.
808
-	 * This will either throw StorageInvalidException, StorageNotAvailableException
809
-	 * or do nothing.
810
-	 *
811
-	 * @param Exception $e sabre exception
812
-	 * @param string $path optional path from the operation
813
-	 *
814
-	 * @throws StorageInvalidException if the storage is invalid, for example
815
-	 * when the authentication expired or is invalid
816
-	 * @throws StorageNotAvailableException if the storage is not available,
817
-	 * which might be temporary
818
-	 */
819
-	private function convertException(Exception $e, $path = '') {
820
-		\OC::$server->getLogger()->logException($e);
821
-		Util::writeLog('files_external', $e->getMessage(), Util::ERROR);
822
-		if ($e instanceof ClientHttpException) {
823
-			if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
824
-				throw new \OCP\Lock\LockedException($path);
825
-			}
826
-			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
827
-				// either password was changed or was invalid all along
828
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
829
-			} else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
830
-				// ignore exception for MethodNotAllowed, false will be returned
831
-				return;
832
-			}
833
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
834
-		} else if ($e instanceof ClientException) {
835
-			// connection timeout or refused, server could be temporarily down
836
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
837
-		} else if ($e instanceof \InvalidArgumentException) {
838
-			// parse error because the server returned HTML instead of XML,
839
-			// possibly temporarily down
840
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
841
-		} else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
842
-			// rethrow
843
-			throw $e;
844
-		}
845
-
846
-		// TODO: only log for now, but in the future need to wrap/rethrow exception
847
-	}
62
+    /** @var string */
63
+    protected $password;
64
+    /** @var string */
65
+    protected $user;
66
+    /** @var string */
67
+    protected $host;
68
+    /** @var bool */
69
+    protected $secure;
70
+    /** @var string */
71
+    protected $root;
72
+    /** @var string */
73
+    protected $certPath;
74
+    /** @var bool */
75
+    protected $ready;
76
+    /** @var Client */
77
+    private $client;
78
+    /** @var ArrayCache */
79
+    private $statCache;
80
+    /** @var array */
81
+    private static $tempFiles = [];
82
+    /** @var \OCP\Http\Client\IClientService */
83
+    private $httpClientService;
84
+
85
+    /**
86
+     * @param array $params
87
+     * @throws \Exception
88
+     */
89
+    public function __construct($params) {
90
+        $this->statCache = new ArrayCache();
91
+        $this->httpClientService = \OC::$server->getHTTPClientService();
92
+        if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
93
+            $host = $params['host'];
94
+            //remove leading http[s], will be generated in createBaseUri()
95
+            if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
96
+            else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
97
+            $this->host = $host;
98
+            $this->user = $params['user'];
99
+            $this->password = $params['password'];
100
+            if (isset($params['secure'])) {
101
+                if (is_string($params['secure'])) {
102
+                    $this->secure = ($params['secure'] === 'true');
103
+                } else {
104
+                    $this->secure = (bool)$params['secure'];
105
+                }
106
+            } else {
107
+                $this->secure = false;
108
+            }
109
+            if ($this->secure === true) {
110
+                // inject mock for testing
111
+                $certManager = \OC::$server->getCertificateManager();
112
+                if (is_null($certManager)) { //no user
113
+                    $certManager = \OC::$server->getCertificateManager(null);
114
+                }
115
+                $certPath = $certManager->getAbsoluteBundlePath();
116
+                if (file_exists($certPath)) {
117
+                    $this->certPath = $certPath;
118
+                }
119
+            }
120
+            $this->root = isset($params['root']) ? $params['root'] : '/';
121
+            if (!$this->root || $this->root[0] != '/') {
122
+                $this->root = '/' . $this->root;
123
+            }
124
+            if (substr($this->root, -1, 1) != '/') {
125
+                $this->root .= '/';
126
+            }
127
+        } else {
128
+            throw new \Exception('Invalid webdav storage configuration');
129
+        }
130
+    }
131
+
132
+    private function init() {
133
+        if ($this->ready) {
134
+            return;
135
+        }
136
+        $this->ready = true;
137
+
138
+        $settings = array(
139
+            'baseUri' => $this->createBaseUri(),
140
+            'userName' => $this->user,
141
+            'password' => $this->password,
142
+        );
143
+
144
+        $proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
145
+        if($proxy !== '') {
146
+            $settings['proxy'] = $proxy;
147
+        }
148
+
149
+        $this->client = new Client($settings);
150
+        $this->client->setThrowExceptions(true);
151
+        if ($this->secure === true && $this->certPath) {
152
+            $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
153
+        }
154
+    }
155
+
156
+    /**
157
+     * Clear the stat cache
158
+     */
159
+    public function clearStatCache() {
160
+        $this->statCache->clear();
161
+    }
162
+
163
+    /** {@inheritdoc} */
164
+    public function getId() {
165
+        return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
166
+    }
167
+
168
+    /** {@inheritdoc} */
169
+    public function createBaseUri() {
170
+        $baseUri = 'http';
171
+        if ($this->secure) {
172
+            $baseUri .= 's';
173
+        }
174
+        $baseUri .= '://' . $this->host . $this->root;
175
+        return $baseUri;
176
+    }
177
+
178
+    /** {@inheritdoc} */
179
+    public function mkdir($path) {
180
+        $this->init();
181
+        $path = $this->cleanPath($path);
182
+        $result = $this->simpleResponse('MKCOL', $path, null, 201);
183
+        if ($result) {
184
+            $this->statCache->set($path, true);
185
+        }
186
+        return $result;
187
+    }
188
+
189
+    /** {@inheritdoc} */
190
+    public function rmdir($path) {
191
+        $this->init();
192
+        $path = $this->cleanPath($path);
193
+        // FIXME: some WebDAV impl return 403 when trying to DELETE
194
+        // a non-empty folder
195
+        $result = $this->simpleResponse('DELETE', $path . '/', null, 204);
196
+        $this->statCache->clear($path . '/');
197
+        $this->statCache->remove($path);
198
+        return $result;
199
+    }
200
+
201
+    /** {@inheritdoc} */
202
+    public function opendir($path) {
203
+        $this->init();
204
+        $path = $this->cleanPath($path);
205
+        try {
206
+            $response = $this->client->propfind(
207
+                $this->encodePath($path),
208
+                array(),
209
+                1
210
+            );
211
+            $id = md5('webdav' . $this->root . $path);
212
+            $content = array();
213
+            $files = array_keys($response);
214
+            array_shift($files); //the first entry is the current directory
215
+
216
+            if (!$this->statCache->hasKey($path)) {
217
+                $this->statCache->set($path, true);
218
+            }
219
+            foreach ($files as $file) {
220
+                $file = urldecode($file);
221
+                // do not store the real entry, we might not have all properties
222
+                if (!$this->statCache->hasKey($path)) {
223
+                    $this->statCache->set($file, true);
224
+                }
225
+                $file = basename($file);
226
+                $content[] = $file;
227
+            }
228
+            return IteratorDirectory::wrap($content);
229
+        } catch (ClientHttpException $e) {
230
+            if ($e->getHttpStatus() === 404) {
231
+                $this->statCache->clear($path . '/');
232
+                $this->statCache->set($path, false);
233
+                return false;
234
+            }
235
+            $this->convertException($e, $path);
236
+        } catch (\Exception $e) {
237
+            $this->convertException($e, $path);
238
+        }
239
+        return false;
240
+    }
241
+
242
+    /**
243
+     * Propfind call with cache handling.
244
+     *
245
+     * First checks if information is cached.
246
+     * If not, request it from the server then store to cache.
247
+     *
248
+     * @param string $path path to propfind
249
+     *
250
+     * @return array propfind response
251
+     *
252
+     * @throws NotFound
253
+     */
254
+    protected function propfind($path) {
255
+        $path = $this->cleanPath($path);
256
+        $cachedResponse = $this->statCache->get($path);
257
+        if ($cachedResponse === false) {
258
+            // we know it didn't exist
259
+            throw new NotFound();
260
+        }
261
+        // we either don't know it, or we know it exists but need more details
262
+        if (is_null($cachedResponse) || $cachedResponse === true) {
263
+            $this->init();
264
+            try {
265
+                $response = $this->client->propfind(
266
+                    $this->encodePath($path),
267
+                    array(
268
+                        '{DAV:}getlastmodified',
269
+                        '{DAV:}getcontentlength',
270
+                        '{DAV:}getcontenttype',
271
+                        '{http://owncloud.org/ns}permissions',
272
+                        '{http://open-collaboration-services.org/ns}share-permissions',
273
+                        '{DAV:}resourcetype',
274
+                        '{DAV:}getetag',
275
+                    )
276
+                );
277
+                $this->statCache->set($path, $response);
278
+            } catch (NotFound $e) {
279
+                // remember that this path did not exist
280
+                $this->statCache->clear($path . '/');
281
+                $this->statCache->set($path, false);
282
+                throw $e;
283
+            }
284
+        } else {
285
+            $response = $cachedResponse;
286
+        }
287
+        return $response;
288
+    }
289
+
290
+    /** {@inheritdoc} */
291
+    public function filetype($path) {
292
+        try {
293
+            $response = $this->propfind($path);
294
+            $responseType = array();
295
+            if (isset($response["{DAV:}resourcetype"])) {
296
+                /** @var ResourceType[] $response */
297
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
298
+            }
299
+            return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
300
+        } catch (ClientHttpException $e) {
301
+            if ($e->getHttpStatus() === 404) {
302
+                return false;
303
+            }
304
+            $this->convertException($e, $path);
305
+        } catch (\Exception $e) {
306
+            $this->convertException($e, $path);
307
+        }
308
+        return false;
309
+    }
310
+
311
+    /** {@inheritdoc} */
312
+    public function file_exists($path) {
313
+        try {
314
+            $path = $this->cleanPath($path);
315
+            $cachedState = $this->statCache->get($path);
316
+            if ($cachedState === false) {
317
+                // we know the file doesn't exist
318
+                return false;
319
+            } else if (!is_null($cachedState)) {
320
+                return true;
321
+            }
322
+            // need to get from server
323
+            $this->propfind($path);
324
+            return true; //no 404 exception
325
+        } catch (ClientHttpException $e) {
326
+            if ($e->getHttpStatus() === 404) {
327
+                return false;
328
+            }
329
+            $this->convertException($e, $path);
330
+        } catch (\Exception $e) {
331
+            $this->convertException($e, $path);
332
+        }
333
+        return false;
334
+    }
335
+
336
+    /** {@inheritdoc} */
337
+    public function unlink($path) {
338
+        $this->init();
339
+        $path = $this->cleanPath($path);
340
+        $result = $this->simpleResponse('DELETE', $path, null, 204);
341
+        $this->statCache->clear($path . '/');
342
+        $this->statCache->remove($path);
343
+        return $result;
344
+    }
345
+
346
+    /** {@inheritdoc} */
347
+    public function fopen($path, $mode) {
348
+        $this->init();
349
+        $path = $this->cleanPath($path);
350
+        switch ($mode) {
351
+            case 'r':
352
+            case 'rb':
353
+                try {
354
+                    $response = $this->httpClientService
355
+                            ->newClient()
356
+                            ->get($this->createBaseUri() . $this->encodePath($path), [
357
+                                    'auth' => [$this->user, $this->password],
358
+                                    'stream' => true
359
+                            ]);
360
+                } catch (RequestException $e) {
361
+                    if ($e->getResponse() instanceof ResponseInterface
362
+                        && $e->getResponse()->getStatusCode() === 404) {
363
+                        return false;
364
+                    } else {
365
+                        throw $e;
366
+                    }
367
+                }
368
+
369
+                if ($response->getStatusCode() !== Http::STATUS_OK) {
370
+                    if ($response->getStatusCode() === Http::STATUS_LOCKED) {
371
+                        throw new \OCP\Lock\LockedException($path);
372
+                    } else {
373
+                        Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
374
+                    }
375
+                }
376
+
377
+                return $response->getBody();
378
+            case 'w':
379
+            case 'wb':
380
+            case 'a':
381
+            case 'ab':
382
+            case 'r+':
383
+            case 'w+':
384
+            case 'wb+':
385
+            case 'a+':
386
+            case 'x':
387
+            case 'x+':
388
+            case 'c':
389
+            case 'c+':
390
+                //emulate these
391
+                $tempManager = \OC::$server->getTempManager();
392
+                if (strrpos($path, '.') !== false) {
393
+                    $ext = substr($path, strrpos($path, '.'));
394
+                } else {
395
+                    $ext = '';
396
+                }
397
+                if ($this->file_exists($path)) {
398
+                    if (!$this->isUpdatable($path)) {
399
+                        return false;
400
+                    }
401
+                    if ($mode === 'w' or $mode === 'w+') {
402
+                        $tmpFile = $tempManager->getTemporaryFile($ext);
403
+                    } else {
404
+                        $tmpFile = $this->getCachedFile($path);
405
+                    }
406
+                } else {
407
+                    if (!$this->isCreatable(dirname($path))) {
408
+                        return false;
409
+                    }
410
+                    $tmpFile = $tempManager->getTemporaryFile($ext);
411
+                }
412
+                Close::registerCallback($tmpFile, array($this, 'writeBack'));
413
+                self::$tempFiles[$tmpFile] = $path;
414
+                return fopen('close://' . $tmpFile, $mode);
415
+        }
416
+    }
417
+
418
+    /**
419
+     * @param string $tmpFile
420
+     */
421
+    public function writeBack($tmpFile) {
422
+        if (isset(self::$tempFiles[$tmpFile])) {
423
+            $this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]);
424
+            unlink($tmpFile);
425
+        }
426
+    }
427
+
428
+    /** {@inheritdoc} */
429
+    public function free_space($path) {
430
+        $this->init();
431
+        $path = $this->cleanPath($path);
432
+        try {
433
+            // TODO: cacheable ?
434
+            $response = $this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes'));
435
+            if (isset($response['{DAV:}quota-available-bytes'])) {
436
+                return (int)$response['{DAV:}quota-available-bytes'];
437
+            } else {
438
+                return FileInfo::SPACE_UNKNOWN;
439
+            }
440
+        } catch (\Exception $e) {
441
+            return FileInfo::SPACE_UNKNOWN;
442
+        }
443
+    }
444
+
445
+    /** {@inheritdoc} */
446
+    public function touch($path, $mtime = null) {
447
+        $this->init();
448
+        if (is_null($mtime)) {
449
+            $mtime = time();
450
+        }
451
+        $path = $this->cleanPath($path);
452
+
453
+        // if file exists, update the mtime, else create a new empty file
454
+        if ($this->file_exists($path)) {
455
+            try {
456
+                $this->statCache->remove($path);
457
+                $this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
458
+                // non-owncloud clients might not have accepted the property, need to recheck it
459
+                $response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
460
+                if (isset($response['{DAV:}getlastmodified'])) {
461
+                    $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
462
+                    if ($remoteMtime !== $mtime) {
463
+                        // server has not accepted the mtime
464
+                        return false;
465
+                    }
466
+                }
467
+            } catch (ClientHttpException $e) {
468
+                if ($e->getHttpStatus() === 501) {
469
+                    return false;
470
+                }
471
+                $this->convertException($e, $path);
472
+                return false;
473
+            } catch (\Exception $e) {
474
+                $this->convertException($e, $path);
475
+                return false;
476
+            }
477
+        } else {
478
+            $this->file_put_contents($path, '');
479
+        }
480
+        return true;
481
+    }
482
+
483
+    /**
484
+     * @param string $path
485
+     * @param string $data
486
+     * @return int
487
+     */
488
+    public function file_put_contents($path, $data) {
489
+        $path = $this->cleanPath($path);
490
+        $result = parent::file_put_contents($path, $data);
491
+        $this->statCache->remove($path);
492
+        return $result;
493
+    }
494
+
495
+    /**
496
+     * @param string $path
497
+     * @param string $target
498
+     */
499
+    protected function uploadFile($path, $target) {
500
+        $this->init();
501
+
502
+        // invalidate
503
+        $target = $this->cleanPath($target);
504
+        $this->statCache->remove($target);
505
+        $source = fopen($path, 'r');
506
+
507
+        $this->httpClientService
508
+            ->newClient()
509
+            ->put($this->createBaseUri() . $this->encodePath($target), [
510
+                'body' => $source,
511
+                'auth' => [$this->user, $this->password]
512
+            ]);
513
+
514
+        $this->removeCachedFile($target);
515
+    }
516
+
517
+    /** {@inheritdoc} */
518
+    public function rename($path1, $path2) {
519
+        $this->init();
520
+        $path1 = $this->cleanPath($path1);
521
+        $path2 = $this->cleanPath($path2);
522
+        try {
523
+            // overwrite directory ?
524
+            if ($this->is_dir($path2)) {
525
+                // needs trailing slash in destination
526
+                $path2 = rtrim($path2, '/') . '/';
527
+            }
528
+            $this->client->request(
529
+                'MOVE',
530
+                $this->encodePath($path1),
531
+                null,
532
+                [
533
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
534
+                ]
535
+            );
536
+            $this->statCache->clear($path1 . '/');
537
+            $this->statCache->clear($path2 . '/');
538
+            $this->statCache->set($path1, false);
539
+            $this->statCache->set($path2, true);
540
+            $this->removeCachedFile($path1);
541
+            $this->removeCachedFile($path2);
542
+            return true;
543
+        } catch (\Exception $e) {
544
+            $this->convertException($e);
545
+        }
546
+        return false;
547
+    }
548
+
549
+    /** {@inheritdoc} */
550
+    public function copy($path1, $path2) {
551
+        $this->init();
552
+        $path1 = $this->cleanPath($path1);
553
+        $path2 = $this->cleanPath($path2);
554
+        try {
555
+            // overwrite directory ?
556
+            if ($this->is_dir($path2)) {
557
+                // needs trailing slash in destination
558
+                $path2 = rtrim($path2, '/') . '/';
559
+            }
560
+            $this->client->request(
561
+                'COPY',
562
+                $this->encodePath($path1),
563
+                null,
564
+                [
565
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
566
+                ]
567
+            );
568
+            $this->statCache->clear($path2 . '/');
569
+            $this->statCache->set($path2, true);
570
+            $this->removeCachedFile($path2);
571
+            return true;
572
+        } catch (\Exception $e) {
573
+            $this->convertException($e);
574
+        }
575
+        return false;
576
+    }
577
+
578
+    /** {@inheritdoc} */
579
+    public function stat($path) {
580
+        try {
581
+            $response = $this->propfind($path);
582
+            return array(
583
+                'mtime' => strtotime($response['{DAV:}getlastmodified']),
584
+                'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
585
+            );
586
+        } catch (ClientHttpException $e) {
587
+            if ($e->getHttpStatus() === 404) {
588
+                return array();
589
+            }
590
+            $this->convertException($e, $path);
591
+        } catch (\Exception $e) {
592
+            $this->convertException($e, $path);
593
+        }
594
+        return array();
595
+    }
596
+
597
+    /** {@inheritdoc} */
598
+    public function getMimeType($path) {
599
+        try {
600
+            $response = $this->propfind($path);
601
+            $responseType = array();
602
+            if (isset($response["{DAV:}resourcetype"])) {
603
+                /** @var ResourceType[] $response */
604
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
605
+            }
606
+            $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
607
+            if ($type == 'dir') {
608
+                return 'httpd/unix-directory';
609
+            } elseif (isset($response['{DAV:}getcontenttype'])) {
610
+                return $response['{DAV:}getcontenttype'];
611
+            } else {
612
+                return false;
613
+            }
614
+        } catch (ClientHttpException $e) {
615
+            if ($e->getHttpStatus() === 404) {
616
+                return false;
617
+            }
618
+            $this->convertException($e, $path);
619
+        } catch (\Exception $e) {
620
+            $this->convertException($e, $path);
621
+        }
622
+        return false;
623
+    }
624
+
625
+    /**
626
+     * @param string $path
627
+     * @return string
628
+     */
629
+    public function cleanPath($path) {
630
+        if ($path === '') {
631
+            return $path;
632
+        }
633
+        $path = Filesystem::normalizePath($path);
634
+        // remove leading slash
635
+        return substr($path, 1);
636
+    }
637
+
638
+    /**
639
+     * URL encodes the given path but keeps the slashes
640
+     *
641
+     * @param string $path to encode
642
+     * @return string encoded path
643
+     */
644
+    private function encodePath($path) {
645
+        // slashes need to stay
646
+        return str_replace('%2F', '/', rawurlencode($path));
647
+    }
648
+
649
+    /**
650
+     * @param string $method
651
+     * @param string $path
652
+     * @param string|resource|null $body
653
+     * @param int $expected
654
+     * @return bool
655
+     * @throws StorageInvalidException
656
+     * @throws StorageNotAvailableException
657
+     */
658
+    private function simpleResponse($method, $path, $body, $expected) {
659
+        $path = $this->cleanPath($path);
660
+        try {
661
+            $response = $this->client->request($method, $this->encodePath($path), $body);
662
+            return $response['statusCode'] == $expected;
663
+        } catch (ClientHttpException $e) {
664
+            if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
665
+                $this->statCache->clear($path . '/');
666
+                $this->statCache->set($path, false);
667
+                return false;
668
+            }
669
+
670
+            $this->convertException($e, $path);
671
+        } catch (\Exception $e) {
672
+            $this->convertException($e, $path);
673
+        }
674
+        return false;
675
+    }
676
+
677
+    /**
678
+     * check if curl is installed
679
+     */
680
+    public static function checkDependencies() {
681
+        return true;
682
+    }
683
+
684
+    /** {@inheritdoc} */
685
+    public function isUpdatable($path) {
686
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
687
+    }
688
+
689
+    /** {@inheritdoc} */
690
+    public function isCreatable($path) {
691
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
692
+    }
693
+
694
+    /** {@inheritdoc} */
695
+    public function isSharable($path) {
696
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
697
+    }
698
+
699
+    /** {@inheritdoc} */
700
+    public function isDeletable($path) {
701
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
702
+    }
703
+
704
+    /** {@inheritdoc} */
705
+    public function getPermissions($path) {
706
+        $this->init();
707
+        $path = $this->cleanPath($path);
708
+        $response = $this->propfind($path);
709
+        if (isset($response['{http://owncloud.org/ns}permissions'])) {
710
+            return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
711
+        } else if ($this->is_dir($path)) {
712
+            return Constants::PERMISSION_ALL;
713
+        } else if ($this->file_exists($path)) {
714
+            return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
715
+        } else {
716
+            return 0;
717
+        }
718
+    }
719
+
720
+    /** {@inheritdoc} */
721
+    public function getETag($path) {
722
+        $this->init();
723
+        $path = $this->cleanPath($path);
724
+        $response = $this->propfind($path);
725
+        if (isset($response['{DAV:}getetag'])) {
726
+            return trim($response['{DAV:}getetag'], '"');
727
+        }
728
+        return parent::getEtag($path);
729
+    }
730
+
731
+    /**
732
+     * @param string $permissionsString
733
+     * @return int
734
+     */
735
+    protected function parsePermissions($permissionsString) {
736
+        $permissions = Constants::PERMISSION_READ;
737
+        if (strpos($permissionsString, 'R') !== false) {
738
+            $permissions |= Constants::PERMISSION_SHARE;
739
+        }
740
+        if (strpos($permissionsString, 'D') !== false) {
741
+            $permissions |= Constants::PERMISSION_DELETE;
742
+        }
743
+        if (strpos($permissionsString, 'W') !== false) {
744
+            $permissions |= Constants::PERMISSION_UPDATE;
745
+        }
746
+        if (strpos($permissionsString, 'CK') !== false) {
747
+            $permissions |= Constants::PERMISSION_CREATE;
748
+            $permissions |= Constants::PERMISSION_UPDATE;
749
+        }
750
+        return $permissions;
751
+    }
752
+
753
+    /**
754
+     * check if a file or folder has been updated since $time
755
+     *
756
+     * @param string $path
757
+     * @param int $time
758
+     * @throws \OCP\Files\StorageNotAvailableException
759
+     * @return bool
760
+     */
761
+    public function hasUpdated($path, $time) {
762
+        $this->init();
763
+        $path = $this->cleanPath($path);
764
+        try {
765
+            // force refresh for $path
766
+            $this->statCache->remove($path);
767
+            $response = $this->propfind($path);
768
+            if (isset($response['{DAV:}getetag'])) {
769
+                $cachedData = $this->getCache()->get($path);
770
+                $etag = null;
771
+                if (isset($response['{DAV:}getetag'])) {
772
+                    $etag = trim($response['{DAV:}getetag'], '"');
773
+                }
774
+                if (!empty($etag) && $cachedData['etag'] !== $etag) {
775
+                    return true;
776
+                } else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
777
+                    $sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
778
+                    return $sharePermissions !== $cachedData['permissions'];
779
+                } else if (isset($response['{http://owncloud.org/ns}permissions'])) {
780
+                    $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
781
+                    return $permissions !== $cachedData['permissions'];
782
+                } else {
783
+                    return false;
784
+                }
785
+            } else {
786
+                $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
787
+                return $remoteMtime > $time;
788
+            }
789
+        } catch (ClientHttpException $e) {
790
+            if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) {
791
+                if ($path === '') {
792
+                    // if root is gone it means the storage is not available
793
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
794
+                }
795
+                return false;
796
+            }
797
+            $this->convertException($e, $path);
798
+            return false;
799
+        } catch (\Exception $e) {
800
+            $this->convertException($e, $path);
801
+            return false;
802
+        }
803
+    }
804
+
805
+    /**
806
+     * Interpret the given exception and decide whether it is due to an
807
+     * unavailable storage, invalid storage or other.
808
+     * This will either throw StorageInvalidException, StorageNotAvailableException
809
+     * or do nothing.
810
+     *
811
+     * @param Exception $e sabre exception
812
+     * @param string $path optional path from the operation
813
+     *
814
+     * @throws StorageInvalidException if the storage is invalid, for example
815
+     * when the authentication expired or is invalid
816
+     * @throws StorageNotAvailableException if the storage is not available,
817
+     * which might be temporary
818
+     */
819
+    private function convertException(Exception $e, $path = '') {
820
+        \OC::$server->getLogger()->logException($e);
821
+        Util::writeLog('files_external', $e->getMessage(), Util::ERROR);
822
+        if ($e instanceof ClientHttpException) {
823
+            if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
824
+                throw new \OCP\Lock\LockedException($path);
825
+            }
826
+            if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
827
+                // either password was changed or was invalid all along
828
+                throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
829
+            } else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
830
+                // ignore exception for MethodNotAllowed, false will be returned
831
+                return;
832
+            }
833
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
834
+        } else if ($e instanceof ClientException) {
835
+            // connection timeout or refused, server could be temporarily down
836
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
837
+        } else if ($e instanceof \InvalidArgumentException) {
838
+            // parse error because the server returned HTML instead of XML,
839
+            // possibly temporarily down
840
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
841
+        } else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
842
+            // rethrow
843
+            throw $e;
844
+        }
845
+
846
+        // TODO: only log for now, but in the future need to wrap/rethrow exception
847
+    }
848 848
 }
849 849
 
Please login to merge, or discard this patch.
Spacing   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -101,7 +101,7 @@  discard block
 block discarded – undo
101 101
 				if (is_string($params['secure'])) {
102 102
 					$this->secure = ($params['secure'] === 'true');
103 103
 				} else {
104
-					$this->secure = (bool)$params['secure'];
104
+					$this->secure = (bool) $params['secure'];
105 105
 				}
106 106
 			} else {
107 107
 				$this->secure = false;
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
 			}
120 120
 			$this->root = isset($params['root']) ? $params['root'] : '/';
121 121
 			if (!$this->root || $this->root[0] != '/') {
122
-				$this->root = '/' . $this->root;
122
+				$this->root = '/'.$this->root;
123 123
 			}
124 124
 			if (substr($this->root, -1, 1) != '/') {
125 125
 				$this->root .= '/';
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
 		);
143 143
 
144 144
 		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
145
-		if($proxy !== '') {
145
+		if ($proxy !== '') {
146 146
 			$settings['proxy'] = $proxy;
147 147
 		}
148 148
 
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
 
163 163
 	/** {@inheritdoc} */
164 164
 	public function getId() {
165
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
165
+		return 'webdav::'.$this->user.'@'.$this->host.'/'.$this->root;
166 166
 	}
167 167
 
168 168
 	/** {@inheritdoc} */
@@ -171,7 +171,7 @@  discard block
 block discarded – undo
171 171
 		if ($this->secure) {
172 172
 			$baseUri .= 's';
173 173
 		}
174
-		$baseUri .= '://' . $this->host . $this->root;
174
+		$baseUri .= '://'.$this->host.$this->root;
175 175
 		return $baseUri;
176 176
 	}
177 177
 
@@ -192,8 +192,8 @@  discard block
 block discarded – undo
192 192
 		$path = $this->cleanPath($path);
193 193
 		// FIXME: some WebDAV impl return 403 when trying to DELETE
194 194
 		// a non-empty folder
195
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
196
-		$this->statCache->clear($path . '/');
195
+		$result = $this->simpleResponse('DELETE', $path.'/', null, 204);
196
+		$this->statCache->clear($path.'/');
197 197
 		$this->statCache->remove($path);
198 198
 		return $result;
199 199
 	}
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 				array(),
209 209
 				1
210 210
 			);
211
-			$id = md5('webdav' . $this->root . $path);
211
+			$id = md5('webdav'.$this->root.$path);
212 212
 			$content = array();
213 213
 			$files = array_keys($response);
214 214
 			array_shift($files); //the first entry is the current directory
@@ -228,7 +228,7 @@  discard block
 block discarded – undo
228 228
 			return IteratorDirectory::wrap($content);
229 229
 		} catch (ClientHttpException $e) {
230 230
 			if ($e->getHttpStatus() === 404) {
231
-				$this->statCache->clear($path . '/');
231
+				$this->statCache->clear($path.'/');
232 232
 				$this->statCache->set($path, false);
233 233
 				return false;
234 234
 			}
@@ -277,7 +277,7 @@  discard block
 block discarded – undo
277 277
 				$this->statCache->set($path, $response);
278 278
 			} catch (NotFound $e) {
279 279
 				// remember that this path did not exist
280
-				$this->statCache->clear($path . '/');
280
+				$this->statCache->clear($path.'/');
281 281
 				$this->statCache->set($path, false);
282 282
 				throw $e;
283 283
 			}
@@ -338,7 +338,7 @@  discard block
 block discarded – undo
338 338
 		$this->init();
339 339
 		$path = $this->cleanPath($path);
340 340
 		$result = $this->simpleResponse('DELETE', $path, null, 204);
341
-		$this->statCache->clear($path . '/');
341
+		$this->statCache->clear($path.'/');
342 342
 		$this->statCache->remove($path);
343 343
 		return $result;
344 344
 	}
@@ -353,7 +353,7 @@  discard block
 block discarded – undo
353 353
 				try {
354 354
 					$response = $this->httpClientService
355 355
 							->newClient()
356
-							->get($this->createBaseUri() . $this->encodePath($path), [
356
+							->get($this->createBaseUri().$this->encodePath($path), [
357 357
 									'auth' => [$this->user, $this->password],
358 358
 									'stream' => true
359 359
 							]);
@@ -370,7 +370,7 @@  discard block
 block discarded – undo
370 370
 					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
371 371
 						throw new \OCP\Lock\LockedException($path);
372 372
 					} else {
373
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
373
+						Util::writeLog("webdav client", 'Guzzle get returned status code '.$response->getStatusCode(), Util::ERROR);
374 374
 					}
375 375
 				}
376 376
 
@@ -411,7 +411,7 @@  discard block
 block discarded – undo
411 411
 				}
412 412
 				Close::registerCallback($tmpFile, array($this, 'writeBack'));
413 413
 				self::$tempFiles[$tmpFile] = $path;
414
-				return fopen('close://' . $tmpFile, $mode);
414
+				return fopen('close://'.$tmpFile, $mode);
415 415
 		}
416 416
 	}
417 417
 
@@ -433,7 +433,7 @@  discard block
 block discarded – undo
433 433
 			// TODO: cacheable ?
434 434
 			$response = $this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes'));
435 435
 			if (isset($response['{DAV:}quota-available-bytes'])) {
436
-				return (int)$response['{DAV:}quota-available-bytes'];
436
+				return (int) $response['{DAV:}quota-available-bytes'];
437 437
 			} else {
438 438
 				return FileInfo::SPACE_UNKNOWN;
439 439
 			}
@@ -506,7 +506,7 @@  discard block
 block discarded – undo
506 506
 
507 507
 		$this->httpClientService
508 508
 			->newClient()
509
-			->put($this->createBaseUri() . $this->encodePath($target), [
509
+			->put($this->createBaseUri().$this->encodePath($target), [
510 510
 				'body' => $source,
511 511
 				'auth' => [$this->user, $this->password]
512 512
 			]);
@@ -523,18 +523,18 @@  discard block
 block discarded – undo
523 523
 			// overwrite directory ?
524 524
 			if ($this->is_dir($path2)) {
525 525
 				// needs trailing slash in destination
526
-				$path2 = rtrim($path2, '/') . '/';
526
+				$path2 = rtrim($path2, '/').'/';
527 527
 			}
528 528
 			$this->client->request(
529 529
 				'MOVE',
530 530
 				$this->encodePath($path1),
531 531
 				null,
532 532
 				[
533
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
533
+					'Destination' => $this->createBaseUri().$this->encodePath($path2),
534 534
 				]
535 535
 			);
536
-			$this->statCache->clear($path1 . '/');
537
-			$this->statCache->clear($path2 . '/');
536
+			$this->statCache->clear($path1.'/');
537
+			$this->statCache->clear($path2.'/');
538 538
 			$this->statCache->set($path1, false);
539 539
 			$this->statCache->set($path2, true);
540 540
 			$this->removeCachedFile($path1);
@@ -555,17 +555,17 @@  discard block
 block discarded – undo
555 555
 			// overwrite directory ?
556 556
 			if ($this->is_dir($path2)) {
557 557
 				// needs trailing slash in destination
558
-				$path2 = rtrim($path2, '/') . '/';
558
+				$path2 = rtrim($path2, '/').'/';
559 559
 			}
560 560
 			$this->client->request(
561 561
 				'COPY',
562 562
 				$this->encodePath($path1),
563 563
 				null,
564 564
 				[
565
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
565
+					'Destination' => $this->createBaseUri().$this->encodePath($path2),
566 566
 				]
567 567
 			);
568
-			$this->statCache->clear($path2 . '/');
568
+			$this->statCache->clear($path2.'/');
569 569
 			$this->statCache->set($path2, true);
570 570
 			$this->removeCachedFile($path2);
571 571
 			return true;
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
 			$response = $this->propfind($path);
582 582
 			return array(
583 583
 				'mtime' => strtotime($response['{DAV:}getlastmodified']),
584
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
584
+				'size' => (int) isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
585 585
 			);
586 586
 		} catch (ClientHttpException $e) {
587 587
 			if ($e->getHttpStatus() === 404) {
@@ -662,7 +662,7 @@  discard block
 block discarded – undo
662 662
 			return $response['statusCode'] == $expected;
663 663
 		} catch (ClientHttpException $e) {
664 664
 			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
665
-				$this->statCache->clear($path . '/');
665
+				$this->statCache->clear($path.'/');
666 666
 				$this->statCache->set($path, false);
667 667
 				return false;
668 668
 			}
@@ -683,22 +683,22 @@  discard block
 block discarded – undo
683 683
 
684 684
 	/** {@inheritdoc} */
685 685
 	public function isUpdatable($path) {
686
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
686
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
687 687
 	}
688 688
 
689 689
 	/** {@inheritdoc} */
690 690
 	public function isCreatable($path) {
691
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
691
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_CREATE);
692 692
 	}
693 693
 
694 694
 	/** {@inheritdoc} */
695 695
 	public function isSharable($path) {
696
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
696
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_SHARE);
697 697
 	}
698 698
 
699 699
 	/** {@inheritdoc} */
700 700
 	public function isDeletable($path) {
701
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
701
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_DELETE);
702 702
 	}
703 703
 
704 704
 	/** {@inheritdoc} */
@@ -774,7 +774,7 @@  discard block
 block discarded – undo
774 774
 				if (!empty($etag) && $cachedData['etag'] !== $etag) {
775 775
 					return true;
776 776
 				} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
777
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
777
+					$sharePermissions = (int) $response['{http://open-collaboration-services.org/ns}share-permissions'];
778 778
 					return $sharePermissions !== $cachedData['permissions'];
779 779
 				} else if (isset($response['{http://owncloud.org/ns}permissions'])) {
780 780
 					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
@@ -790,7 +790,7 @@  discard block
 block discarded – undo
790 790
 			if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) {
791 791
 				if ($path === '') {
792 792
 					// if root is gone it means the storage is not available
793
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
793
+					throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
794 794
 				}
795 795
 				return false;
796 796
 			}
@@ -825,19 +825,19 @@  discard block
 block discarded – undo
825 825
 			}
826 826
 			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
827 827
 				// either password was changed or was invalid all along
828
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
828
+				throw new StorageInvalidException(get_class($e).': '.$e->getMessage());
829 829
 			} else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
830 830
 				// ignore exception for MethodNotAllowed, false will be returned
831 831
 				return;
832 832
 			}
833
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
833
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
834 834
 		} else if ($e instanceof ClientException) {
835 835
 			// connection timeout or refused, server could be temporarily down
836
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
836
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
837 837
 		} else if ($e instanceof \InvalidArgumentException) {
838 838
 			// parse error because the server returned HTML instead of XML,
839 839
 			// possibly temporarily down
840
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
840
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
841 841
 		} else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
842 842
 			// rethrow
843 843
 			throw $e;
Please login to merge, or discard this patch.
lib/private/Files/Storage/Temporary.php 2 patches
Indentation   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -29,20 +29,20 @@
 block discarded – undo
29 29
  * local storage backend in temporary folder for testing purpose
30 30
  */
31 31
 class Temporary extends Local{
32
-	public function __construct($arguments = null) {
33
-		parent::__construct(array('datadir' => \OC::$server->getTempManager()->getTemporaryFolder()));
34
-	}
32
+    public function __construct($arguments = null) {
33
+        parent::__construct(array('datadir' => \OC::$server->getTempManager()->getTemporaryFolder()));
34
+    }
35 35
 
36
-	public function cleanUp() {
37
-		\OC_Helper::rmdirr($this->datadir);
38
-	}
36
+    public function cleanUp() {
37
+        \OC_Helper::rmdirr($this->datadir);
38
+    }
39 39
 
40
-	public function __destruct() {
41
-		parent::__destruct();
42
-		$this->cleanUp();
43
-	}
40
+    public function __destruct() {
41
+        parent::__destruct();
42
+        $this->cleanUp();
43
+    }
44 44
 
45
-	public function getDataDir() {
46
-		return $this->datadir;
47
-	}
45
+    public function getDataDir() {
46
+        return $this->datadir;
47
+    }
48 48
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -28,7 +28,7 @@
 block discarded – undo
28 28
 /**
29 29
  * local storage backend in temporary folder for testing purpose
30 30
  */
31
-class Temporary extends Local{
31
+class Temporary extends Local {
32 32
 	public function __construct($arguments = null) {
33 33
 		parent::__construct(array('datadir' => \OC::$server->getTempManager()->getTemporaryFolder()));
34 34
 	}
Please login to merge, or discard this patch.
lib/private/Files/Storage/Local.php 3 patches
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -58,7 +58,7 @@  discard block
 block discarded – undo
58 58
 		if ($this->datadir === '/') {
59 59
 			$this->realDataDir = $this->datadir;
60 60
 		} else {
61
-			$this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
61
+			$this->realDataDir = rtrim(realpath($this->datadir), '/').'/';
62 62
 		}
63 63
 		if (substr($this->datadir, -1) !== '/') {
64 64
 			$this->datadir .= '/';
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
 	}
71 71
 
72 72
 	public function getId() {
73
-		return 'local::' . $this->datadir;
73
+		return 'local::'.$this->datadir;
74 74
 	}
75 75
 
76 76
 	public function mkdir($path) {
@@ -228,17 +228,17 @@  discard block
 block discarded – undo
228 228
 		$dstParent = dirname($path2);
229 229
 
230 230
 		if (!$this->isUpdatable($srcParent)) {
231
-			\OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, \OCP\Util::ERROR);
231
+			\OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : '.$srcParent, \OCP\Util::ERROR);
232 232
 			return false;
233 233
 		}
234 234
 
235 235
 		if (!$this->isUpdatable($dstParent)) {
236
-			\OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, \OCP\Util::ERROR);
236
+			\OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : '.$dstParent, \OCP\Util::ERROR);
237 237
 			return false;
238 238
 		}
239 239
 
240 240
 		if (!$this->file_exists($path1)) {
241
-			\OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, \OCP\Util::ERROR);
241
+			\OCP\Util::writeLog('core', 'unable to rename, file does not exists : '.$path1, \OCP\Util::ERROR);
242 242
 			return false;
243 243
 		}
244 244
 
@@ -319,13 +319,13 @@  discard block
 block discarded – undo
319 319
 		foreach (scandir($physicalDir) as $item) {
320 320
 			if (\OC\Files\Filesystem::isIgnoredDir($item))
321 321
 				continue;
322
-			$physicalItem = $physicalDir . '/' . $item;
322
+			$physicalItem = $physicalDir.'/'.$item;
323 323
 
324 324
 			if (strstr(strtolower($item), strtolower($query)) !== false) {
325
-				$files[] = $dir . '/' . $item;
325
+				$files[] = $dir.'/'.$item;
326 326
 			}
327 327
 			if (is_dir($physicalItem)) {
328
-				$files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
328
+				$files = array_merge($files, $this->searchInDir($query, $dir.'/'.$item));
329 329
 			}
330 330
 		}
331 331
 		return $files;
@@ -354,7 +354,7 @@  discard block
 block discarded – undo
354 354
 	 * @throws ForbiddenException
355 355
 	 */
356 356
 	public function getSourcePath($path) {
357
-		$fullPath = $this->datadir . $path;
357
+		$fullPath = $this->datadir.$path;
358 358
 		if ($this->allowSymlinks || $path === '') {
359 359
 			return $fullPath;
360 360
 		}
@@ -365,7 +365,7 @@  discard block
 block discarded – undo
365 365
 			$realPath = realpath($pathToResolve);
366 366
 		}
367 367
 		if ($realPath) {
368
-			$realPath = $realPath . '/';
368
+			$realPath = $realPath.'/';
369 369
 		}
370 370
 		if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
371 371
 			return $fullPath;
@@ -391,9 +391,9 @@  discard block
 block discarded – undo
391 391
 		if ($this->is_file($path)) {
392 392
 			$stat = $this->stat($path);
393 393
 			return md5(
394
-				$stat['mtime'] .
395
-				$stat['ino'] .
396
-				$stat['dev'] .
394
+				$stat['mtime'].
395
+				$stat['ino'].
396
+				$stat['dev'].
397 397
 				$stat['size']
398 398
 			);
399 399
 		} else {
Please login to merge, or discard this patch.
Braces   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -317,8 +317,9 @@
 block discarded – undo
317 317
 		$files = array();
318 318
 		$physicalDir = $this->getSourcePath($dir);
319 319
 		foreach (scandir($physicalDir) as $item) {
320
-			if (\OC\Files\Filesystem::isIgnoredDir($item))
321
-				continue;
320
+			if (\OC\Files\Filesystem::isIgnoredDir($item)) {
321
+							continue;
322
+			}
322 323
 			$physicalItem = $physicalDir . '/' . $item;
323 324
 
324 325
 			if (strstr(strtolower($item), strtolower($query)) !== false) {
Please login to merge, or discard this patch.
Indentation   +398 added lines, -398 removed lines patch added patch discarded remove patch
@@ -41,402 +41,402 @@
 block discarded – undo
41 41
  * for local filestore, we only have to map the paths
42 42
  */
43 43
 class Local extends \OC\Files\Storage\Common {
44
-	protected $datadir;
45
-
46
-	protected $dataDirLength;
47
-
48
-	protected $allowSymlinks = false;
49
-
50
-	protected $realDataDir;
51
-
52
-	public function __construct($arguments) {
53
-		if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) {
54
-			throw new \InvalidArgumentException('No data directory set for local storage');
55
-		}
56
-		$this->datadir = $arguments['datadir'];
57
-		// some crazy code uses a local storage on root...
58
-		if ($this->datadir === '/') {
59
-			$this->realDataDir = $this->datadir;
60
-		} else {
61
-			$this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
62
-		}
63
-		if (substr($this->datadir, -1) !== '/') {
64
-			$this->datadir .= '/';
65
-		}
66
-		$this->dataDirLength = strlen($this->realDataDir);
67
-	}
68
-
69
-	public function __destruct() {
70
-	}
71
-
72
-	public function getId() {
73
-		return 'local::' . $this->datadir;
74
-	}
75
-
76
-	public function mkdir($path) {
77
-		return @mkdir($this->getSourcePath($path), 0777, true);
78
-	}
79
-
80
-	public function rmdir($path) {
81
-		if (!$this->isDeletable($path)) {
82
-			return false;
83
-		}
84
-		try {
85
-			$it = new \RecursiveIteratorIterator(
86
-				new \RecursiveDirectoryIterator($this->getSourcePath($path)),
87
-				\RecursiveIteratorIterator::CHILD_FIRST
88
-			);
89
-			/**
90
-			 * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
91
-			 * This bug is fixed in PHP 5.5.9 or before
92
-			 * See #8376
93
-			 */
94
-			$it->rewind();
95
-			while ($it->valid()) {
96
-				/**
97
-				 * @var \SplFileInfo $file
98
-				 */
99
-				$file = $it->current();
100
-				if (in_array($file->getBasename(), array('.', '..'))) {
101
-					$it->next();
102
-					continue;
103
-				} elseif ($file->isDir()) {
104
-					rmdir($file->getPathname());
105
-				} elseif ($file->isFile() || $file->isLink()) {
106
-					unlink($file->getPathname());
107
-				}
108
-				$it->next();
109
-			}
110
-			return rmdir($this->getSourcePath($path));
111
-		} catch (\UnexpectedValueException $e) {
112
-			return false;
113
-		}
114
-	}
115
-
116
-	public function opendir($path) {
117
-		return opendir($this->getSourcePath($path));
118
-	}
119
-
120
-	public function is_dir($path) {
121
-		if (substr($path, -1) == '/') {
122
-			$path = substr($path, 0, -1);
123
-		}
124
-		return is_dir($this->getSourcePath($path));
125
-	}
126
-
127
-	public function is_file($path) {
128
-		return is_file($this->getSourcePath($path));
129
-	}
130
-
131
-	public function stat($path) {
132
-		clearstatcache();
133
-		$fullPath = $this->getSourcePath($path);
134
-		$statResult = stat($fullPath);
135
-		if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) {
136
-			$filesize = $this->filesize($path);
137
-			$statResult['size'] = $filesize;
138
-			$statResult[7] = $filesize;
139
-		}
140
-		return $statResult;
141
-	}
142
-
143
-	public function filetype($path) {
144
-		$filetype = filetype($this->getSourcePath($path));
145
-		if ($filetype == 'link') {
146
-			$filetype = filetype(realpath($this->getSourcePath($path)));
147
-		}
148
-		return $filetype;
149
-	}
150
-
151
-	public function filesize($path) {
152
-		if ($this->is_dir($path)) {
153
-			return 0;
154
-		}
155
-		$fullPath = $this->getSourcePath($path);
156
-		if (PHP_INT_SIZE === 4) {
157
-			$helper = new \OC\LargeFileHelper;
158
-			return $helper->getFilesize($fullPath);
159
-		}
160
-		return filesize($fullPath);
161
-	}
162
-
163
-	public function isReadable($path) {
164
-		return is_readable($this->getSourcePath($path));
165
-	}
166
-
167
-	public function isUpdatable($path) {
168
-		return is_writable($this->getSourcePath($path));
169
-	}
170
-
171
-	public function file_exists($path) {
172
-		return file_exists($this->getSourcePath($path));
173
-	}
174
-
175
-	public function filemtime($path) {
176
-		clearstatcache($this->getSourcePath($path));
177
-		return $this->file_exists($path) ? filemtime($this->getSourcePath($path)) : false;
178
-	}
179
-
180
-	public function touch($path, $mtime = null) {
181
-		// sets the modification time of the file to the given value.
182
-		// If mtime is nil the current time is set.
183
-		// note that the access time of the file always changes to the current time.
184
-		if ($this->file_exists($path) and !$this->isUpdatable($path)) {
185
-			return false;
186
-		}
187
-		if (!is_null($mtime)) {
188
-			$result = touch($this->getSourcePath($path), $mtime);
189
-		} else {
190
-			$result = touch($this->getSourcePath($path));
191
-		}
192
-		if ($result) {
193
-			clearstatcache(true, $this->getSourcePath($path));
194
-		}
195
-
196
-		return $result;
197
-	}
198
-
199
-	public function file_get_contents($path) {
200
-		// file_get_contents() has a memory leak: https://bugs.php.net/bug.php?id=61961
201
-		$fileName = $this->getSourcePath($path);
202
-
203
-		$fileSize = filesize($fileName);
204
-		if ($fileSize === 0) {
205
-			return '';
206
-		}
207
-
208
-		$handle = fopen($fileName, 'rb');
209
-		$content = fread($handle, $fileSize);
210
-		fclose($handle);
211
-		return $content;
212
-	}
213
-
214
-	public function file_put_contents($path, $data) {
215
-		return file_put_contents($this->getSourcePath($path), $data);
216
-	}
217
-
218
-	public function unlink($path) {
219
-		if ($this->is_dir($path)) {
220
-			return $this->rmdir($path);
221
-		} else if ($this->is_file($path)) {
222
-			return unlink($this->getSourcePath($path));
223
-		} else {
224
-			return false;
225
-		}
226
-
227
-	}
228
-
229
-	public function rename($path1, $path2) {
230
-		$srcParent = dirname($path1);
231
-		$dstParent = dirname($path2);
232
-
233
-		if (!$this->isUpdatable($srcParent)) {
234
-			\OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, \OCP\Util::ERROR);
235
-			return false;
236
-		}
237
-
238
-		if (!$this->isUpdatable($dstParent)) {
239
-			\OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, \OCP\Util::ERROR);
240
-			return false;
241
-		}
242
-
243
-		if (!$this->file_exists($path1)) {
244
-			\OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, \OCP\Util::ERROR);
245
-			return false;
246
-		}
247
-
248
-		if ($this->is_dir($path2)) {
249
-			$this->rmdir($path2);
250
-		} else if ($this->is_file($path2)) {
251
-			$this->unlink($path2);
252
-		}
253
-
254
-		if ($this->is_dir($path1)) {
255
-			// we can't move folders across devices, use copy instead
256
-			$stat1 = stat(dirname($this->getSourcePath($path1)));
257
-			$stat2 = stat(dirname($this->getSourcePath($path2)));
258
-			if ($stat1['dev'] !== $stat2['dev']) {
259
-				$result = $this->copy($path1, $path2);
260
-				if ($result) {
261
-					$result &= $this->rmdir($path1);
262
-				}
263
-				return $result;
264
-			}
265
-		}
266
-
267
-		return rename($this->getSourcePath($path1), $this->getSourcePath($path2));
268
-	}
269
-
270
-	public function copy($path1, $path2) {
271
-		if ($this->is_dir($path1)) {
272
-			return parent::copy($path1, $path2);
273
-		} else {
274
-			return copy($this->getSourcePath($path1), $this->getSourcePath($path2));
275
-		}
276
-	}
277
-
278
-	public function fopen($path, $mode) {
279
-		return fopen($this->getSourcePath($path), $mode);
280
-	}
281
-
282
-	public function hash($type, $path, $raw = false) {
283
-		return hash_file($type, $this->getSourcePath($path), $raw);
284
-	}
285
-
286
-	public function free_space($path) {
287
-		$sourcePath = $this->getSourcePath($path);
288
-		// using !is_dir because $sourcePath might be a part file or
289
-		// non-existing file, so we'd still want to use the parent dir
290
-		// in such cases
291
-		if (!is_dir($sourcePath)) {
292
-			// disk_free_space doesn't work on files
293
-			$sourcePath = dirname($sourcePath);
294
-		}
295
-		$space = @disk_free_space($sourcePath);
296
-		if ($space === false || is_null($space)) {
297
-			return \OCP\Files\FileInfo::SPACE_UNKNOWN;
298
-		}
299
-		return $space;
300
-	}
301
-
302
-	public function search($query) {
303
-		return $this->searchInDir($query);
304
-	}
305
-
306
-	public function getLocalFile($path) {
307
-		return $this->getSourcePath($path);
308
-	}
309
-
310
-	public function getLocalFolder($path) {
311
-		return $this->getSourcePath($path);
312
-	}
313
-
314
-	/**
315
-	 * @param string $query
316
-	 * @param string $dir
317
-	 * @return array
318
-	 */
319
-	protected function searchInDir($query, $dir = '') {
320
-		$files = array();
321
-		$physicalDir = $this->getSourcePath($dir);
322
-		foreach (scandir($physicalDir) as $item) {
323
-			if (\OC\Files\Filesystem::isIgnoredDir($item))
324
-				continue;
325
-			$physicalItem = $physicalDir . '/' . $item;
326
-
327
-			if (strstr(strtolower($item), strtolower($query)) !== false) {
328
-				$files[] = $dir . '/' . $item;
329
-			}
330
-			if (is_dir($physicalItem)) {
331
-				$files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
332
-			}
333
-		}
334
-		return $files;
335
-	}
336
-
337
-	/**
338
-	 * check if a file or folder has been updated since $time
339
-	 *
340
-	 * @param string $path
341
-	 * @param int $time
342
-	 * @return bool
343
-	 */
344
-	public function hasUpdated($path, $time) {
345
-		if ($this->file_exists($path)) {
346
-			return $this->filemtime($path) > $time;
347
-		} else {
348
-			return true;
349
-		}
350
-	}
351
-
352
-	/**
353
-	 * Get the source path (on disk) of a given path
354
-	 *
355
-	 * @param string $path
356
-	 * @return string
357
-	 * @throws ForbiddenException
358
-	 */
359
-	public function getSourcePath($path) {
360
-		$fullPath = $this->datadir . $path;
361
-		if ($this->allowSymlinks || $path === '') {
362
-			return $fullPath;
363
-		}
364
-		$pathToResolve = $fullPath;
365
-		$realPath = realpath($pathToResolve);
366
-		while ($realPath === false) { // for non existing files check the parent directory
367
-			$pathToResolve = dirname($pathToResolve);
368
-			$realPath = realpath($pathToResolve);
369
-		}
370
-		if ($realPath) {
371
-			$realPath = $realPath . '/';
372
-		}
373
-		if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
374
-			return $fullPath;
375
-		} else {
376
-			throw new ForbiddenException("Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", false);
377
-		}
378
-	}
379
-
380
-	/**
381
-	 * {@inheritdoc}
382
-	 */
383
-	public function isLocal() {
384
-		return true;
385
-	}
386
-
387
-	/**
388
-	 * get the ETag for a file or folder
389
-	 *
390
-	 * @param string $path
391
-	 * @return string
392
-	 */
393
-	public function getETag($path) {
394
-		if ($this->is_file($path)) {
395
-			$stat = $this->stat($path);
396
-			return md5(
397
-				$stat['mtime'] .
398
-				$stat['ino'] .
399
-				$stat['dev'] .
400
-				$stat['size']
401
-			);
402
-		} else {
403
-			return parent::getETag($path);
404
-		}
405
-	}
406
-
407
-	/**
408
-	 * @param \OCP\Files\Storage $sourceStorage
409
-	 * @param string $sourceInternalPath
410
-	 * @param string $targetInternalPath
411
-	 * @return bool
412
-	 */
413
-	public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
414
-		if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) {
415
-			/**
416
-			 * @var \OC\Files\Storage\Local $sourceStorage
417
-			 */
418
-			$rootStorage = new Local(['datadir' => '/']);
419
-			return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
420
-		} else {
421
-			return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
422
-		}
423
-	}
424
-
425
-	/**
426
-	 * @param \OCP\Files\Storage $sourceStorage
427
-	 * @param string $sourceInternalPath
428
-	 * @param string $targetInternalPath
429
-	 * @return bool
430
-	 */
431
-	public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
432
-		if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) {
433
-			/**
434
-			 * @var \OC\Files\Storage\Local $sourceStorage
435
-			 */
436
-			$rootStorage = new Local(['datadir' => '/']);
437
-			return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
438
-		} else {
439
-			return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
440
-		}
441
-	}
44
+    protected $datadir;
45
+
46
+    protected $dataDirLength;
47
+
48
+    protected $allowSymlinks = false;
49
+
50
+    protected $realDataDir;
51
+
52
+    public function __construct($arguments) {
53
+        if (!isset($arguments['datadir']) || !is_string($arguments['datadir'])) {
54
+            throw new \InvalidArgumentException('No data directory set for local storage');
55
+        }
56
+        $this->datadir = $arguments['datadir'];
57
+        // some crazy code uses a local storage on root...
58
+        if ($this->datadir === '/') {
59
+            $this->realDataDir = $this->datadir;
60
+        } else {
61
+            $this->realDataDir = rtrim(realpath($this->datadir), '/') . '/';
62
+        }
63
+        if (substr($this->datadir, -1) !== '/') {
64
+            $this->datadir .= '/';
65
+        }
66
+        $this->dataDirLength = strlen($this->realDataDir);
67
+    }
68
+
69
+    public function __destruct() {
70
+    }
71
+
72
+    public function getId() {
73
+        return 'local::' . $this->datadir;
74
+    }
75
+
76
+    public function mkdir($path) {
77
+        return @mkdir($this->getSourcePath($path), 0777, true);
78
+    }
79
+
80
+    public function rmdir($path) {
81
+        if (!$this->isDeletable($path)) {
82
+            return false;
83
+        }
84
+        try {
85
+            $it = new \RecursiveIteratorIterator(
86
+                new \RecursiveDirectoryIterator($this->getSourcePath($path)),
87
+                \RecursiveIteratorIterator::CHILD_FIRST
88
+            );
89
+            /**
90
+             * RecursiveDirectoryIterator on an NFS path isn't iterable with foreach
91
+             * This bug is fixed in PHP 5.5.9 or before
92
+             * See #8376
93
+             */
94
+            $it->rewind();
95
+            while ($it->valid()) {
96
+                /**
97
+                 * @var \SplFileInfo $file
98
+                 */
99
+                $file = $it->current();
100
+                if (in_array($file->getBasename(), array('.', '..'))) {
101
+                    $it->next();
102
+                    continue;
103
+                } elseif ($file->isDir()) {
104
+                    rmdir($file->getPathname());
105
+                } elseif ($file->isFile() || $file->isLink()) {
106
+                    unlink($file->getPathname());
107
+                }
108
+                $it->next();
109
+            }
110
+            return rmdir($this->getSourcePath($path));
111
+        } catch (\UnexpectedValueException $e) {
112
+            return false;
113
+        }
114
+    }
115
+
116
+    public function opendir($path) {
117
+        return opendir($this->getSourcePath($path));
118
+    }
119
+
120
+    public function is_dir($path) {
121
+        if (substr($path, -1) == '/') {
122
+            $path = substr($path, 0, -1);
123
+        }
124
+        return is_dir($this->getSourcePath($path));
125
+    }
126
+
127
+    public function is_file($path) {
128
+        return is_file($this->getSourcePath($path));
129
+    }
130
+
131
+    public function stat($path) {
132
+        clearstatcache();
133
+        $fullPath = $this->getSourcePath($path);
134
+        $statResult = stat($fullPath);
135
+        if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) {
136
+            $filesize = $this->filesize($path);
137
+            $statResult['size'] = $filesize;
138
+            $statResult[7] = $filesize;
139
+        }
140
+        return $statResult;
141
+    }
142
+
143
+    public function filetype($path) {
144
+        $filetype = filetype($this->getSourcePath($path));
145
+        if ($filetype == 'link') {
146
+            $filetype = filetype(realpath($this->getSourcePath($path)));
147
+        }
148
+        return $filetype;
149
+    }
150
+
151
+    public function filesize($path) {
152
+        if ($this->is_dir($path)) {
153
+            return 0;
154
+        }
155
+        $fullPath = $this->getSourcePath($path);
156
+        if (PHP_INT_SIZE === 4) {
157
+            $helper = new \OC\LargeFileHelper;
158
+            return $helper->getFilesize($fullPath);
159
+        }
160
+        return filesize($fullPath);
161
+    }
162
+
163
+    public function isReadable($path) {
164
+        return is_readable($this->getSourcePath($path));
165
+    }
166
+
167
+    public function isUpdatable($path) {
168
+        return is_writable($this->getSourcePath($path));
169
+    }
170
+
171
+    public function file_exists($path) {
172
+        return file_exists($this->getSourcePath($path));
173
+    }
174
+
175
+    public function filemtime($path) {
176
+        clearstatcache($this->getSourcePath($path));
177
+        return $this->file_exists($path) ? filemtime($this->getSourcePath($path)) : false;
178
+    }
179
+
180
+    public function touch($path, $mtime = null) {
181
+        // sets the modification time of the file to the given value.
182
+        // If mtime is nil the current time is set.
183
+        // note that the access time of the file always changes to the current time.
184
+        if ($this->file_exists($path) and !$this->isUpdatable($path)) {
185
+            return false;
186
+        }
187
+        if (!is_null($mtime)) {
188
+            $result = touch($this->getSourcePath($path), $mtime);
189
+        } else {
190
+            $result = touch($this->getSourcePath($path));
191
+        }
192
+        if ($result) {
193
+            clearstatcache(true, $this->getSourcePath($path));
194
+        }
195
+
196
+        return $result;
197
+    }
198
+
199
+    public function file_get_contents($path) {
200
+        // file_get_contents() has a memory leak: https://bugs.php.net/bug.php?id=61961
201
+        $fileName = $this->getSourcePath($path);
202
+
203
+        $fileSize = filesize($fileName);
204
+        if ($fileSize === 0) {
205
+            return '';
206
+        }
207
+
208
+        $handle = fopen($fileName, 'rb');
209
+        $content = fread($handle, $fileSize);
210
+        fclose($handle);
211
+        return $content;
212
+    }
213
+
214
+    public function file_put_contents($path, $data) {
215
+        return file_put_contents($this->getSourcePath($path), $data);
216
+    }
217
+
218
+    public function unlink($path) {
219
+        if ($this->is_dir($path)) {
220
+            return $this->rmdir($path);
221
+        } else if ($this->is_file($path)) {
222
+            return unlink($this->getSourcePath($path));
223
+        } else {
224
+            return false;
225
+        }
226
+
227
+    }
228
+
229
+    public function rename($path1, $path2) {
230
+        $srcParent = dirname($path1);
231
+        $dstParent = dirname($path2);
232
+
233
+        if (!$this->isUpdatable($srcParent)) {
234
+            \OCP\Util::writeLog('core', 'unable to rename, source directory is not writable : ' . $srcParent, \OCP\Util::ERROR);
235
+            return false;
236
+        }
237
+
238
+        if (!$this->isUpdatable($dstParent)) {
239
+            \OCP\Util::writeLog('core', 'unable to rename, destination directory is not writable : ' . $dstParent, \OCP\Util::ERROR);
240
+            return false;
241
+        }
242
+
243
+        if (!$this->file_exists($path1)) {
244
+            \OCP\Util::writeLog('core', 'unable to rename, file does not exists : ' . $path1, \OCP\Util::ERROR);
245
+            return false;
246
+        }
247
+
248
+        if ($this->is_dir($path2)) {
249
+            $this->rmdir($path2);
250
+        } else if ($this->is_file($path2)) {
251
+            $this->unlink($path2);
252
+        }
253
+
254
+        if ($this->is_dir($path1)) {
255
+            // we can't move folders across devices, use copy instead
256
+            $stat1 = stat(dirname($this->getSourcePath($path1)));
257
+            $stat2 = stat(dirname($this->getSourcePath($path2)));
258
+            if ($stat1['dev'] !== $stat2['dev']) {
259
+                $result = $this->copy($path1, $path2);
260
+                if ($result) {
261
+                    $result &= $this->rmdir($path1);
262
+                }
263
+                return $result;
264
+            }
265
+        }
266
+
267
+        return rename($this->getSourcePath($path1), $this->getSourcePath($path2));
268
+    }
269
+
270
+    public function copy($path1, $path2) {
271
+        if ($this->is_dir($path1)) {
272
+            return parent::copy($path1, $path2);
273
+        } else {
274
+            return copy($this->getSourcePath($path1), $this->getSourcePath($path2));
275
+        }
276
+    }
277
+
278
+    public function fopen($path, $mode) {
279
+        return fopen($this->getSourcePath($path), $mode);
280
+    }
281
+
282
+    public function hash($type, $path, $raw = false) {
283
+        return hash_file($type, $this->getSourcePath($path), $raw);
284
+    }
285
+
286
+    public function free_space($path) {
287
+        $sourcePath = $this->getSourcePath($path);
288
+        // using !is_dir because $sourcePath might be a part file or
289
+        // non-existing file, so we'd still want to use the parent dir
290
+        // in such cases
291
+        if (!is_dir($sourcePath)) {
292
+            // disk_free_space doesn't work on files
293
+            $sourcePath = dirname($sourcePath);
294
+        }
295
+        $space = @disk_free_space($sourcePath);
296
+        if ($space === false || is_null($space)) {
297
+            return \OCP\Files\FileInfo::SPACE_UNKNOWN;
298
+        }
299
+        return $space;
300
+    }
301
+
302
+    public function search($query) {
303
+        return $this->searchInDir($query);
304
+    }
305
+
306
+    public function getLocalFile($path) {
307
+        return $this->getSourcePath($path);
308
+    }
309
+
310
+    public function getLocalFolder($path) {
311
+        return $this->getSourcePath($path);
312
+    }
313
+
314
+    /**
315
+     * @param string $query
316
+     * @param string $dir
317
+     * @return array
318
+     */
319
+    protected function searchInDir($query, $dir = '') {
320
+        $files = array();
321
+        $physicalDir = $this->getSourcePath($dir);
322
+        foreach (scandir($physicalDir) as $item) {
323
+            if (\OC\Files\Filesystem::isIgnoredDir($item))
324
+                continue;
325
+            $physicalItem = $physicalDir . '/' . $item;
326
+
327
+            if (strstr(strtolower($item), strtolower($query)) !== false) {
328
+                $files[] = $dir . '/' . $item;
329
+            }
330
+            if (is_dir($physicalItem)) {
331
+                $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
332
+            }
333
+        }
334
+        return $files;
335
+    }
336
+
337
+    /**
338
+     * check if a file or folder has been updated since $time
339
+     *
340
+     * @param string $path
341
+     * @param int $time
342
+     * @return bool
343
+     */
344
+    public function hasUpdated($path, $time) {
345
+        if ($this->file_exists($path)) {
346
+            return $this->filemtime($path) > $time;
347
+        } else {
348
+            return true;
349
+        }
350
+    }
351
+
352
+    /**
353
+     * Get the source path (on disk) of a given path
354
+     *
355
+     * @param string $path
356
+     * @return string
357
+     * @throws ForbiddenException
358
+     */
359
+    public function getSourcePath($path) {
360
+        $fullPath = $this->datadir . $path;
361
+        if ($this->allowSymlinks || $path === '') {
362
+            return $fullPath;
363
+        }
364
+        $pathToResolve = $fullPath;
365
+        $realPath = realpath($pathToResolve);
366
+        while ($realPath === false) { // for non existing files check the parent directory
367
+            $pathToResolve = dirname($pathToResolve);
368
+            $realPath = realpath($pathToResolve);
369
+        }
370
+        if ($realPath) {
371
+            $realPath = $realPath . '/';
372
+        }
373
+        if (substr($realPath, 0, $this->dataDirLength) === $this->realDataDir) {
374
+            return $fullPath;
375
+        } else {
376
+            throw new ForbiddenException("Following symlinks is not allowed ('$fullPath' -> '$realPath' not inside '{$this->realDataDir}')", false);
377
+        }
378
+    }
379
+
380
+    /**
381
+     * {@inheritdoc}
382
+     */
383
+    public function isLocal() {
384
+        return true;
385
+    }
386
+
387
+    /**
388
+     * get the ETag for a file or folder
389
+     *
390
+     * @param string $path
391
+     * @return string
392
+     */
393
+    public function getETag($path) {
394
+        if ($this->is_file($path)) {
395
+            $stat = $this->stat($path);
396
+            return md5(
397
+                $stat['mtime'] .
398
+                $stat['ino'] .
399
+                $stat['dev'] .
400
+                $stat['size']
401
+            );
402
+        } else {
403
+            return parent::getETag($path);
404
+        }
405
+    }
406
+
407
+    /**
408
+     * @param \OCP\Files\Storage $sourceStorage
409
+     * @param string $sourceInternalPath
410
+     * @param string $targetInternalPath
411
+     * @return bool
412
+     */
413
+    public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
414
+        if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) {
415
+            /**
416
+             * @var \OC\Files\Storage\Local $sourceStorage
417
+             */
418
+            $rootStorage = new Local(['datadir' => '/']);
419
+            return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
420
+        } else {
421
+            return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
422
+        }
423
+    }
424
+
425
+    /**
426
+     * @param \OCP\Files\Storage $sourceStorage
427
+     * @param string $sourceInternalPath
428
+     * @param string $targetInternalPath
429
+     * @return bool
430
+     */
431
+    public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
432
+        if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) {
433
+            /**
434
+             * @var \OC\Files\Storage\Local $sourceStorage
435
+             */
436
+            $rootStorage = new Local(['datadir' => '/']);
437
+            return $rootStorage->rename($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath));
438
+        } else {
439
+            return parent::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
440
+        }
441
+    }
442 442
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/LocalTempFileTrait.php 1 patch
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -37,45 +37,45 @@
 block discarded – undo
37 37
  */
38 38
 trait LocalTempFileTrait {
39 39
 
40
-	/** @var string[] */
41
-	protected $cachedFiles = [];
40
+    /** @var string[] */
41
+    protected $cachedFiles = [];
42 42
 
43
-	/**
44
-	 * @param string $path
45
-	 * @return string
46
-	 */
47
-	protected function getCachedFile($path) {
48
-		if (!isset($this->cachedFiles[$path])) {
49
-			$this->cachedFiles[$path] = $this->toTmpFile($path);
50
-		}
51
-		return $this->cachedFiles[$path];
52
-	}
43
+    /**
44
+     * @param string $path
45
+     * @return string
46
+     */
47
+    protected function getCachedFile($path) {
48
+        if (!isset($this->cachedFiles[$path])) {
49
+            $this->cachedFiles[$path] = $this->toTmpFile($path);
50
+        }
51
+        return $this->cachedFiles[$path];
52
+    }
53 53
 
54
-	/**
55
-	 * @param string $path
56
-	 */
57
-	protected function removeCachedFile($path) {
58
-		unset($this->cachedFiles[$path]);
59
-	}
54
+    /**
55
+     * @param string $path
56
+     */
57
+    protected function removeCachedFile($path) {
58
+        unset($this->cachedFiles[$path]);
59
+    }
60 60
 
61
-	/**
62
-	 * @param string $path
63
-	 * @return string
64
-	 */
65
-	protected function toTmpFile($path) { //no longer in the storage api, still useful here
66
-		$source = $this->fopen($path, 'r');
67
-		if (!$source) {
68
-			return false;
69
-		}
70
-		if ($pos = strrpos($path, '.')) {
71
-			$extension = substr($path, $pos);
72
-		} else {
73
-			$extension = '';
74
-		}
75
-		$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
76
-		$target = fopen($tmpFile, 'w');
77
-		\OC_Helper::streamCopy($source, $target);
78
-		fclose($target);
79
-		return $tmpFile;
80
-	}
61
+    /**
62
+     * @param string $path
63
+     * @return string
64
+     */
65
+    protected function toTmpFile($path) { //no longer in the storage api, still useful here
66
+        $source = $this->fopen($path, 'r');
67
+        if (!$source) {
68
+            return false;
69
+        }
70
+        if ($pos = strrpos($path, '.')) {
71
+            $extension = substr($path, $pos);
72
+        } else {
73
+            $extension = '';
74
+        }
75
+        $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
76
+        $target = fopen($tmpFile, 'w');
77
+        \OC_Helper::streamCopy($source, $target);
78
+        fclose($target);
79
+        return $tmpFile;
80
+    }
81 81
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/Common.php 3 patches
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -289,7 +289,9 @@
 block discarded – undo
289 289
 		$dh = $this->opendir($dir);
290 290
 		if (is_resource($dh)) {
291 291
 			while (($item = readdir($dh)) !== false) {
292
-				if (\OC\Files\Filesystem::isIgnoredDir($item)) continue;
292
+				if (\OC\Files\Filesystem::isIgnoredDir($item)) {
293
+				    continue;
294
+				}
293 295
 				if (strstr(strtolower($item), strtolower($query)) !== false) {
294 296
 					$files[] = $dir . '/' . $item;
295 297
 				}
Please login to merge, or discard this patch.
Indentation   +617 added lines, -617 removed lines patch added patch discarded remove patch
@@ -65,621 +65,621 @@
 block discarded – undo
65 65
  */
66 66
 abstract class Common implements Storage, ILockingStorage {
67 67
 
68
-	use LocalTempFileTrait;
69
-
70
-	protected $cache;
71
-	protected $scanner;
72
-	protected $watcher;
73
-	protected $propagator;
74
-	protected $storageCache;
75
-	protected $updater;
76
-
77
-	protected $mountOptions = [];
78
-	protected $owner = null;
79
-
80
-	public function __construct($parameters) {
81
-	}
82
-
83
-	/**
84
-	 * Remove a file or folder
85
-	 *
86
-	 * @param string $path
87
-	 * @return bool
88
-	 */
89
-	protected function remove($path) {
90
-		if ($this->is_dir($path)) {
91
-			return $this->rmdir($path);
92
-		} else if ($this->is_file($path)) {
93
-			return $this->unlink($path);
94
-		} else {
95
-			return false;
96
-		}
97
-	}
98
-
99
-	public function is_dir($path) {
100
-		return $this->filetype($path) === 'dir';
101
-	}
102
-
103
-	public function is_file($path) {
104
-		return $this->filetype($path) === 'file';
105
-	}
106
-
107
-	public function filesize($path) {
108
-		if ($this->is_dir($path)) {
109
-			return 0; //by definition
110
-		} else {
111
-			$stat = $this->stat($path);
112
-			if (isset($stat['size'])) {
113
-				return $stat['size'];
114
-			} else {
115
-				return 0;
116
-			}
117
-		}
118
-	}
119
-
120
-	public function isReadable($path) {
121
-		// at least check whether it exists
122
-		// subclasses might want to implement this more thoroughly
123
-		return $this->file_exists($path);
124
-	}
125
-
126
-	public function isUpdatable($path) {
127
-		// at least check whether it exists
128
-		// subclasses might want to implement this more thoroughly
129
-		// a non-existing file/folder isn't updatable
130
-		return $this->file_exists($path);
131
-	}
132
-
133
-	public function isCreatable($path) {
134
-		if ($this->is_dir($path) && $this->isUpdatable($path)) {
135
-			return true;
136
-		}
137
-		return false;
138
-	}
139
-
140
-	public function isDeletable($path) {
141
-		if ($path === '' || $path === '/') {
142
-			return false;
143
-		}
144
-		$parent = dirname($path);
145
-		return $this->isUpdatable($parent) && $this->isUpdatable($path);
146
-	}
147
-
148
-	public function isSharable($path) {
149
-		return $this->isReadable($path);
150
-	}
151
-
152
-	public function getPermissions($path) {
153
-		$permissions = 0;
154
-		if ($this->isCreatable($path)) {
155
-			$permissions |= \OCP\Constants::PERMISSION_CREATE;
156
-		}
157
-		if ($this->isReadable($path)) {
158
-			$permissions |= \OCP\Constants::PERMISSION_READ;
159
-		}
160
-		if ($this->isUpdatable($path)) {
161
-			$permissions |= \OCP\Constants::PERMISSION_UPDATE;
162
-		}
163
-		if ($this->isDeletable($path)) {
164
-			$permissions |= \OCP\Constants::PERMISSION_DELETE;
165
-		}
166
-		if ($this->isSharable($path)) {
167
-			$permissions |= \OCP\Constants::PERMISSION_SHARE;
168
-		}
169
-		return $permissions;
170
-	}
171
-
172
-	public function filemtime($path) {
173
-		$stat = $this->stat($path);
174
-		if (isset($stat['mtime']) && $stat['mtime'] > 0) {
175
-			return $stat['mtime'];
176
-		} else {
177
-			return 0;
178
-		}
179
-	}
180
-
181
-	public function file_get_contents($path) {
182
-		$handle = $this->fopen($path, "r");
183
-		if (!$handle) {
184
-			return false;
185
-		}
186
-		$data = stream_get_contents($handle);
187
-		fclose($handle);
188
-		return $data;
189
-	}
190
-
191
-	public function file_put_contents($path, $data) {
192
-		$handle = $this->fopen($path, "w");
193
-		$this->removeCachedFile($path);
194
-		$count = fwrite($handle, $data);
195
-		fclose($handle);
196
-		return $count;
197
-	}
198
-
199
-	public function rename($path1, $path2) {
200
-		$this->remove($path2);
201
-
202
-		$this->removeCachedFile($path1);
203
-		return $this->copy($path1, $path2) and $this->remove($path1);
204
-	}
205
-
206
-	public function copy($path1, $path2) {
207
-		if ($this->is_dir($path1)) {
208
-			$this->remove($path2);
209
-			$dir = $this->opendir($path1);
210
-			$this->mkdir($path2);
211
-			while ($file = readdir($dir)) {
212
-				if (!Filesystem::isIgnoredDir($file)) {
213
-					if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) {
214
-						return false;
215
-					}
216
-				}
217
-			}
218
-			closedir($dir);
219
-			return true;
220
-		} else {
221
-			$source = $this->fopen($path1, 'r');
222
-			$target = $this->fopen($path2, 'w');
223
-			list(, $result) = \OC_Helper::streamCopy($source, $target);
224
-			$this->removeCachedFile($path2);
225
-			return $result;
226
-		}
227
-	}
228
-
229
-	public function getMimeType($path) {
230
-		if ($this->is_dir($path)) {
231
-			return 'httpd/unix-directory';
232
-		} elseif ($this->file_exists($path)) {
233
-			return \OC::$server->getMimeTypeDetector()->detectPath($path);
234
-		} else {
235
-			return false;
236
-		}
237
-	}
238
-
239
-	public function hash($type, $path, $raw = false) {
240
-		$fh = $this->fopen($path, 'rb');
241
-		$ctx = hash_init($type);
242
-		hash_update_stream($ctx, $fh);
243
-		fclose($fh);
244
-		return hash_final($ctx, $raw);
245
-	}
246
-
247
-	public function search($query) {
248
-		return $this->searchInDir($query);
249
-	}
250
-
251
-	public function getLocalFile($path) {
252
-		return $this->getCachedFile($path);
253
-	}
254
-
255
-	/**
256
-	 * @param string $path
257
-	 * @param string $target
258
-	 */
259
-	private function addLocalFolder($path, $target) {
260
-		$dh = $this->opendir($path);
261
-		if (is_resource($dh)) {
262
-			while (($file = readdir($dh)) !== false) {
263
-				if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
264
-					if ($this->is_dir($path . '/' . $file)) {
265
-						mkdir($target . '/' . $file);
266
-						$this->addLocalFolder($path . '/' . $file, $target . '/' . $file);
267
-					} else {
268
-						$tmp = $this->toTmpFile($path . '/' . $file);
269
-						rename($tmp, $target . '/' . $file);
270
-					}
271
-				}
272
-			}
273
-		}
274
-	}
275
-
276
-	/**
277
-	 * @param string $query
278
-	 * @param string $dir
279
-	 * @return array
280
-	 */
281
-	protected function searchInDir($query, $dir = '') {
282
-		$files = array();
283
-		$dh = $this->opendir($dir);
284
-		if (is_resource($dh)) {
285
-			while (($item = readdir($dh)) !== false) {
286
-				if (\OC\Files\Filesystem::isIgnoredDir($item)) continue;
287
-				if (strstr(strtolower($item), strtolower($query)) !== false) {
288
-					$files[] = $dir . '/' . $item;
289
-				}
290
-				if ($this->is_dir($dir . '/' . $item)) {
291
-					$files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
292
-				}
293
-			}
294
-		}
295
-		closedir($dh);
296
-		return $files;
297
-	}
298
-
299
-	/**
300
-	 * check if a file or folder has been updated since $time
301
-	 *
302
-	 * The method is only used to check if the cache needs to be updated. Storage backends that don't support checking
303
-	 * the mtime should always return false here. As a result storage implementations that always return false expect
304
-	 * exclusive access to the backend and will not pick up files that have been added in a way that circumvents
305
-	 * ownClouds filesystem.
306
-	 *
307
-	 * @param string $path
308
-	 * @param int $time
309
-	 * @return bool
310
-	 */
311
-	public function hasUpdated($path, $time) {
312
-		return $this->filemtime($path) > $time;
313
-	}
314
-
315
-	public function getCache($path = '', $storage = null) {
316
-		if (!$storage) {
317
-			$storage = $this;
318
-		}
319
-		if (!isset($storage->cache)) {
320
-			$storage->cache = new Cache($storage);
321
-		}
322
-		return $storage->cache;
323
-	}
324
-
325
-	public function getScanner($path = '', $storage = null) {
326
-		if (!$storage) {
327
-			$storage = $this;
328
-		}
329
-		if (!isset($storage->scanner)) {
330
-			$storage->scanner = new Scanner($storage);
331
-		}
332
-		return $storage->scanner;
333
-	}
334
-
335
-	public function getWatcher($path = '', $storage = null) {
336
-		if (!$storage) {
337
-			$storage = $this;
338
-		}
339
-		if (!isset($this->watcher)) {
340
-			$this->watcher = new Watcher($storage);
341
-			$globalPolicy = \OC::$server->getConfig()->getSystemValue('filesystem_check_changes', Watcher::CHECK_NEVER);
342
-			$this->watcher->setPolicy((int)$this->getMountOption('filesystem_check_changes', $globalPolicy));
343
-		}
344
-		return $this->watcher;
345
-	}
346
-
347
-	/**
348
-	 * get a propagator instance for the cache
349
-	 *
350
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
351
-	 * @return \OC\Files\Cache\Propagator
352
-	 */
353
-	public function getPropagator($storage = null) {
354
-		if (!$storage) {
355
-			$storage = $this;
356
-		}
357
-		if (!isset($storage->propagator)) {
358
-			$storage->propagator = new Propagator($storage, \OC::$server->getDatabaseConnection());
359
-		}
360
-		return $storage->propagator;
361
-	}
362
-
363
-	public function getUpdater($storage = null) {
364
-		if (!$storage) {
365
-			$storage = $this;
366
-		}
367
-		if (!isset($storage->updater)) {
368
-			$storage->updater = new Updater($storage);
369
-		}
370
-		return $storage->updater;
371
-	}
372
-
373
-	public function getStorageCache($storage = null) {
374
-		if (!$storage) {
375
-			$storage = $this;
376
-		}
377
-		if (!isset($this->storageCache)) {
378
-			$this->storageCache = new \OC\Files\Cache\Storage($storage);
379
-		}
380
-		return $this->storageCache;
381
-	}
382
-
383
-	/**
384
-	 * get the owner of a path
385
-	 *
386
-	 * @param string $path The path to get the owner
387
-	 * @return string|false uid or false
388
-	 */
389
-	public function getOwner($path) {
390
-		if ($this->owner === null) {
391
-			$this->owner = \OC_User::getUser();
392
-		}
393
-
394
-		return $this->owner;
395
-	}
396
-
397
-	/**
398
-	 * get the ETag for a file or folder
399
-	 *
400
-	 * @param string $path
401
-	 * @return string
402
-	 */
403
-	public function getETag($path) {
404
-		return uniqid();
405
-	}
406
-
407
-	/**
408
-	 * clean a path, i.e. remove all redundant '.' and '..'
409
-	 * making sure that it can't point to higher than '/'
410
-	 *
411
-	 * @param string $path The path to clean
412
-	 * @return string cleaned path
413
-	 */
414
-	public function cleanPath($path) {
415
-		if (strlen($path) == 0 or $path[0] != '/') {
416
-			$path = '/' . $path;
417
-		}
418
-
419
-		$output = array();
420
-		foreach (explode('/', $path) as $chunk) {
421
-			if ($chunk == '..') {
422
-				array_pop($output);
423
-			} else if ($chunk == '.') {
424
-			} else {
425
-				$output[] = $chunk;
426
-			}
427
-		}
428
-		return implode('/', $output);
429
-	}
430
-
431
-	/**
432
-	 * Test a storage for availability
433
-	 *
434
-	 * @return bool
435
-	 */
436
-	public function test() {
437
-		if ($this->stat('')) {
438
-			return true;
439
-		}
440
-		return false;
441
-	}
442
-
443
-	/**
444
-	 * get the free space in the storage
445
-	 *
446
-	 * @param string $path
447
-	 * @return int|false
448
-	 */
449
-	public function free_space($path) {
450
-		return \OCP\Files\FileInfo::SPACE_UNKNOWN;
451
-	}
452
-
453
-	/**
454
-	 * {@inheritdoc}
455
-	 */
456
-	public function isLocal() {
457
-		// the common implementation returns a temporary file by
458
-		// default, which is not local
459
-		return false;
460
-	}
461
-
462
-	/**
463
-	 * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
464
-	 *
465
-	 * @param string $class
466
-	 * @return bool
467
-	 */
468
-	public function instanceOfStorage($class) {
469
-		return is_a($this, $class);
470
-	}
471
-
472
-	/**
473
-	 * A custom storage implementation can return an url for direct download of a give file.
474
-	 *
475
-	 * For now the returned array can hold the parameter url - in future more attributes might follow.
476
-	 *
477
-	 * @param string $path
478
-	 * @return array|false
479
-	 */
480
-	public function getDirectDownload($path) {
481
-		return [];
482
-	}
483
-
484
-	/**
485
-	 * @inheritdoc
486
-	 */
487
-	public function verifyPath($path, $fileName) {
488
-		if (isset($fileName[255])) {
489
-			throw new FileNameTooLongException();
490
-		}
491
-
492
-		// NOTE: $path will remain unverified for now
493
-		$this->verifyPosixPath($fileName);
494
-	}
495
-
496
-	/**
497
-	 * @param string $fileName
498
-	 * @throws InvalidPathException
499
-	 */
500
-	protected function verifyPosixPath($fileName) {
501
-		$fileName = trim($fileName);
502
-		$this->scanForInvalidCharacters($fileName, "\\/");
503
-		$reservedNames = ['*'];
504
-		if (in_array($fileName, $reservedNames)) {
505
-			throw new ReservedWordException();
506
-		}
507
-	}
508
-
509
-	/**
510
-	 * @param string $fileName
511
-	 * @param string $invalidChars
512
-	 * @throws InvalidPathException
513
-	 */
514
-	private function scanForInvalidCharacters($fileName, $invalidChars) {
515
-		foreach (str_split($invalidChars) as $char) {
516
-			if (strpos($fileName, $char) !== false) {
517
-				throw new InvalidCharacterInPathException();
518
-			}
519
-		}
520
-
521
-		$sanitizedFileName = filter_var($fileName, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);
522
-		if ($sanitizedFileName !== $fileName) {
523
-			throw new InvalidCharacterInPathException();
524
-		}
525
-	}
526
-
527
-	/**
528
-	 * @param array $options
529
-	 */
530
-	public function setMountOptions(array $options) {
531
-		$this->mountOptions = $options;
532
-	}
533
-
534
-	/**
535
-	 * @param string $name
536
-	 * @param mixed $default
537
-	 * @return mixed
538
-	 */
539
-	public function getMountOption($name, $default = null) {
540
-		return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default;
541
-	}
542
-
543
-	/**
544
-	 * @param \OCP\Files\Storage $sourceStorage
545
-	 * @param string $sourceInternalPath
546
-	 * @param string $targetInternalPath
547
-	 * @param bool $preserveMtime
548
-	 * @return bool
549
-	 */
550
-	public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) {
551
-		if ($sourceStorage === $this) {
552
-			return $this->copy($sourceInternalPath, $targetInternalPath);
553
-		}
554
-
555
-		if ($sourceStorage->is_dir($sourceInternalPath)) {
556
-			$dh = $sourceStorage->opendir($sourceInternalPath);
557
-			$result = $this->mkdir($targetInternalPath);
558
-			if (is_resource($dh)) {
559
-				while ($result and ($file = readdir($dh)) !== false) {
560
-					if (!Filesystem::isIgnoredDir($file)) {
561
-						$result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file);
562
-					}
563
-				}
564
-			}
565
-		} else {
566
-			$source = $sourceStorage->fopen($sourceInternalPath, 'r');
567
-			// TODO: call fopen in a way that we execute again all storage wrappers
568
-			// to avoid that we bypass storage wrappers which perform important actions
569
-			// for this operation. Same is true for all other operations which
570
-			// are not the same as the original one.Once this is fixed we also
571
-			// need to adjust the encryption wrapper.
572
-			$target = $this->fopen($targetInternalPath, 'w');
573
-			list(, $result) = \OC_Helper::streamCopy($source, $target);
574
-			if ($result and $preserveMtime) {
575
-				$this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
576
-			}
577
-			fclose($source);
578
-			fclose($target);
579
-
580
-			if (!$result) {
581
-				// delete partially written target file
582
-				$this->unlink($targetInternalPath);
583
-				// delete cache entry that was created by fopen
584
-				$this->getCache()->remove($targetInternalPath);
585
-			}
586
-		}
587
-		return (bool)$result;
588
-	}
589
-
590
-	/**
591
-	 * @param \OCP\Files\Storage $sourceStorage
592
-	 * @param string $sourceInternalPath
593
-	 * @param string $targetInternalPath
594
-	 * @return bool
595
-	 */
596
-	public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
597
-		if ($sourceStorage === $this) {
598
-			return $this->rename($sourceInternalPath, $targetInternalPath);
599
-		}
600
-
601
-		if (!$sourceStorage->isDeletable($sourceInternalPath)) {
602
-			return false;
603
-		}
604
-
605
-		$result = $this->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true);
606
-		if ($result) {
607
-			if ($sourceStorage->is_dir($sourceInternalPath)) {
608
-				$result &= $sourceStorage->rmdir($sourceInternalPath);
609
-			} else {
610
-				$result &= $sourceStorage->unlink($sourceInternalPath);
611
-			}
612
-		}
613
-		return $result;
614
-	}
615
-
616
-	/**
617
-	 * @inheritdoc
618
-	 */
619
-	public function getMetaData($path) {
620
-		$permissions = $this->getPermissions($path);
621
-		if (!$permissions & \OCP\Constants::PERMISSION_READ) {
622
-			//can't read, nothing we can do
623
-			return null;
624
-		}
625
-
626
-		$data = [];
627
-		$data['mimetype'] = $this->getMimeType($path);
628
-		$data['mtime'] = $this->filemtime($path);
629
-		if ($data['mtime'] === false) {
630
-			$data['mtime'] = time();
631
-		}
632
-		if ($data['mimetype'] == 'httpd/unix-directory') {
633
-			$data['size'] = -1; //unknown
634
-		} else {
635
-			$data['size'] = $this->filesize($path);
636
-		}
637
-		$data['etag'] = $this->getETag($path);
638
-		$data['storage_mtime'] = $data['mtime'];
639
-		$data['permissions'] = $permissions;
640
-
641
-		return $data;
642
-	}
643
-
644
-	/**
645
-	 * @param string $path
646
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
647
-	 * @param \OCP\Lock\ILockingProvider $provider
648
-	 * @throws \OCP\Lock\LockedException
649
-	 */
650
-	public function acquireLock($path, $type, ILockingProvider $provider) {
651
-		$provider->acquireLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
652
-	}
653
-
654
-	/**
655
-	 * @param string $path
656
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
657
-	 * @param \OCP\Lock\ILockingProvider $provider
658
-	 */
659
-	public function releaseLock($path, $type, ILockingProvider $provider) {
660
-		$provider->releaseLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
661
-	}
662
-
663
-	/**
664
-	 * @param string $path
665
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
666
-	 * @param \OCP\Lock\ILockingProvider $provider
667
-	 */
668
-	public function changeLock($path, $type, ILockingProvider $provider) {
669
-		$provider->changeLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
670
-	}
671
-
672
-	/**
673
-	 * @return array [ available, last_checked ]
674
-	 */
675
-	public function getAvailability() {
676
-		return $this->getStorageCache()->getAvailability();
677
-	}
678
-
679
-	/**
680
-	 * @param bool $isAvailable
681
-	 */
682
-	public function setAvailability($isAvailable) {
683
-		$this->getStorageCache()->setAvailability($isAvailable);
684
-	}
68
+    use LocalTempFileTrait;
69
+
70
+    protected $cache;
71
+    protected $scanner;
72
+    protected $watcher;
73
+    protected $propagator;
74
+    protected $storageCache;
75
+    protected $updater;
76
+
77
+    protected $mountOptions = [];
78
+    protected $owner = null;
79
+
80
+    public function __construct($parameters) {
81
+    }
82
+
83
+    /**
84
+     * Remove a file or folder
85
+     *
86
+     * @param string $path
87
+     * @return bool
88
+     */
89
+    protected function remove($path) {
90
+        if ($this->is_dir($path)) {
91
+            return $this->rmdir($path);
92
+        } else if ($this->is_file($path)) {
93
+            return $this->unlink($path);
94
+        } else {
95
+            return false;
96
+        }
97
+    }
98
+
99
+    public function is_dir($path) {
100
+        return $this->filetype($path) === 'dir';
101
+    }
102
+
103
+    public function is_file($path) {
104
+        return $this->filetype($path) === 'file';
105
+    }
106
+
107
+    public function filesize($path) {
108
+        if ($this->is_dir($path)) {
109
+            return 0; //by definition
110
+        } else {
111
+            $stat = $this->stat($path);
112
+            if (isset($stat['size'])) {
113
+                return $stat['size'];
114
+            } else {
115
+                return 0;
116
+            }
117
+        }
118
+    }
119
+
120
+    public function isReadable($path) {
121
+        // at least check whether it exists
122
+        // subclasses might want to implement this more thoroughly
123
+        return $this->file_exists($path);
124
+    }
125
+
126
+    public function isUpdatable($path) {
127
+        // at least check whether it exists
128
+        // subclasses might want to implement this more thoroughly
129
+        // a non-existing file/folder isn't updatable
130
+        return $this->file_exists($path);
131
+    }
132
+
133
+    public function isCreatable($path) {
134
+        if ($this->is_dir($path) && $this->isUpdatable($path)) {
135
+            return true;
136
+        }
137
+        return false;
138
+    }
139
+
140
+    public function isDeletable($path) {
141
+        if ($path === '' || $path === '/') {
142
+            return false;
143
+        }
144
+        $parent = dirname($path);
145
+        return $this->isUpdatable($parent) && $this->isUpdatable($path);
146
+    }
147
+
148
+    public function isSharable($path) {
149
+        return $this->isReadable($path);
150
+    }
151
+
152
+    public function getPermissions($path) {
153
+        $permissions = 0;
154
+        if ($this->isCreatable($path)) {
155
+            $permissions |= \OCP\Constants::PERMISSION_CREATE;
156
+        }
157
+        if ($this->isReadable($path)) {
158
+            $permissions |= \OCP\Constants::PERMISSION_READ;
159
+        }
160
+        if ($this->isUpdatable($path)) {
161
+            $permissions |= \OCP\Constants::PERMISSION_UPDATE;
162
+        }
163
+        if ($this->isDeletable($path)) {
164
+            $permissions |= \OCP\Constants::PERMISSION_DELETE;
165
+        }
166
+        if ($this->isSharable($path)) {
167
+            $permissions |= \OCP\Constants::PERMISSION_SHARE;
168
+        }
169
+        return $permissions;
170
+    }
171
+
172
+    public function filemtime($path) {
173
+        $stat = $this->stat($path);
174
+        if (isset($stat['mtime']) && $stat['mtime'] > 0) {
175
+            return $stat['mtime'];
176
+        } else {
177
+            return 0;
178
+        }
179
+    }
180
+
181
+    public function file_get_contents($path) {
182
+        $handle = $this->fopen($path, "r");
183
+        if (!$handle) {
184
+            return false;
185
+        }
186
+        $data = stream_get_contents($handle);
187
+        fclose($handle);
188
+        return $data;
189
+    }
190
+
191
+    public function file_put_contents($path, $data) {
192
+        $handle = $this->fopen($path, "w");
193
+        $this->removeCachedFile($path);
194
+        $count = fwrite($handle, $data);
195
+        fclose($handle);
196
+        return $count;
197
+    }
198
+
199
+    public function rename($path1, $path2) {
200
+        $this->remove($path2);
201
+
202
+        $this->removeCachedFile($path1);
203
+        return $this->copy($path1, $path2) and $this->remove($path1);
204
+    }
205
+
206
+    public function copy($path1, $path2) {
207
+        if ($this->is_dir($path1)) {
208
+            $this->remove($path2);
209
+            $dir = $this->opendir($path1);
210
+            $this->mkdir($path2);
211
+            while ($file = readdir($dir)) {
212
+                if (!Filesystem::isIgnoredDir($file)) {
213
+                    if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) {
214
+                        return false;
215
+                    }
216
+                }
217
+            }
218
+            closedir($dir);
219
+            return true;
220
+        } else {
221
+            $source = $this->fopen($path1, 'r');
222
+            $target = $this->fopen($path2, 'w');
223
+            list(, $result) = \OC_Helper::streamCopy($source, $target);
224
+            $this->removeCachedFile($path2);
225
+            return $result;
226
+        }
227
+    }
228
+
229
+    public function getMimeType($path) {
230
+        if ($this->is_dir($path)) {
231
+            return 'httpd/unix-directory';
232
+        } elseif ($this->file_exists($path)) {
233
+            return \OC::$server->getMimeTypeDetector()->detectPath($path);
234
+        } else {
235
+            return false;
236
+        }
237
+    }
238
+
239
+    public function hash($type, $path, $raw = false) {
240
+        $fh = $this->fopen($path, 'rb');
241
+        $ctx = hash_init($type);
242
+        hash_update_stream($ctx, $fh);
243
+        fclose($fh);
244
+        return hash_final($ctx, $raw);
245
+    }
246
+
247
+    public function search($query) {
248
+        return $this->searchInDir($query);
249
+    }
250
+
251
+    public function getLocalFile($path) {
252
+        return $this->getCachedFile($path);
253
+    }
254
+
255
+    /**
256
+     * @param string $path
257
+     * @param string $target
258
+     */
259
+    private function addLocalFolder($path, $target) {
260
+        $dh = $this->opendir($path);
261
+        if (is_resource($dh)) {
262
+            while (($file = readdir($dh)) !== false) {
263
+                if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
264
+                    if ($this->is_dir($path . '/' . $file)) {
265
+                        mkdir($target . '/' . $file);
266
+                        $this->addLocalFolder($path . '/' . $file, $target . '/' . $file);
267
+                    } else {
268
+                        $tmp = $this->toTmpFile($path . '/' . $file);
269
+                        rename($tmp, $target . '/' . $file);
270
+                    }
271
+                }
272
+            }
273
+        }
274
+    }
275
+
276
+    /**
277
+     * @param string $query
278
+     * @param string $dir
279
+     * @return array
280
+     */
281
+    protected function searchInDir($query, $dir = '') {
282
+        $files = array();
283
+        $dh = $this->opendir($dir);
284
+        if (is_resource($dh)) {
285
+            while (($item = readdir($dh)) !== false) {
286
+                if (\OC\Files\Filesystem::isIgnoredDir($item)) continue;
287
+                if (strstr(strtolower($item), strtolower($query)) !== false) {
288
+                    $files[] = $dir . '/' . $item;
289
+                }
290
+                if ($this->is_dir($dir . '/' . $item)) {
291
+                    $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
292
+                }
293
+            }
294
+        }
295
+        closedir($dh);
296
+        return $files;
297
+    }
298
+
299
+    /**
300
+     * check if a file or folder has been updated since $time
301
+     *
302
+     * The method is only used to check if the cache needs to be updated. Storage backends that don't support checking
303
+     * the mtime should always return false here. As a result storage implementations that always return false expect
304
+     * exclusive access to the backend and will not pick up files that have been added in a way that circumvents
305
+     * ownClouds filesystem.
306
+     *
307
+     * @param string $path
308
+     * @param int $time
309
+     * @return bool
310
+     */
311
+    public function hasUpdated($path, $time) {
312
+        return $this->filemtime($path) > $time;
313
+    }
314
+
315
+    public function getCache($path = '', $storage = null) {
316
+        if (!$storage) {
317
+            $storage = $this;
318
+        }
319
+        if (!isset($storage->cache)) {
320
+            $storage->cache = new Cache($storage);
321
+        }
322
+        return $storage->cache;
323
+    }
324
+
325
+    public function getScanner($path = '', $storage = null) {
326
+        if (!$storage) {
327
+            $storage = $this;
328
+        }
329
+        if (!isset($storage->scanner)) {
330
+            $storage->scanner = new Scanner($storage);
331
+        }
332
+        return $storage->scanner;
333
+    }
334
+
335
+    public function getWatcher($path = '', $storage = null) {
336
+        if (!$storage) {
337
+            $storage = $this;
338
+        }
339
+        if (!isset($this->watcher)) {
340
+            $this->watcher = new Watcher($storage);
341
+            $globalPolicy = \OC::$server->getConfig()->getSystemValue('filesystem_check_changes', Watcher::CHECK_NEVER);
342
+            $this->watcher->setPolicy((int)$this->getMountOption('filesystem_check_changes', $globalPolicy));
343
+        }
344
+        return $this->watcher;
345
+    }
346
+
347
+    /**
348
+     * get a propagator instance for the cache
349
+     *
350
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
351
+     * @return \OC\Files\Cache\Propagator
352
+     */
353
+    public function getPropagator($storage = null) {
354
+        if (!$storage) {
355
+            $storage = $this;
356
+        }
357
+        if (!isset($storage->propagator)) {
358
+            $storage->propagator = new Propagator($storage, \OC::$server->getDatabaseConnection());
359
+        }
360
+        return $storage->propagator;
361
+    }
362
+
363
+    public function getUpdater($storage = null) {
364
+        if (!$storage) {
365
+            $storage = $this;
366
+        }
367
+        if (!isset($storage->updater)) {
368
+            $storage->updater = new Updater($storage);
369
+        }
370
+        return $storage->updater;
371
+    }
372
+
373
+    public function getStorageCache($storage = null) {
374
+        if (!$storage) {
375
+            $storage = $this;
376
+        }
377
+        if (!isset($this->storageCache)) {
378
+            $this->storageCache = new \OC\Files\Cache\Storage($storage);
379
+        }
380
+        return $this->storageCache;
381
+    }
382
+
383
+    /**
384
+     * get the owner of a path
385
+     *
386
+     * @param string $path The path to get the owner
387
+     * @return string|false uid or false
388
+     */
389
+    public function getOwner($path) {
390
+        if ($this->owner === null) {
391
+            $this->owner = \OC_User::getUser();
392
+        }
393
+
394
+        return $this->owner;
395
+    }
396
+
397
+    /**
398
+     * get the ETag for a file or folder
399
+     *
400
+     * @param string $path
401
+     * @return string
402
+     */
403
+    public function getETag($path) {
404
+        return uniqid();
405
+    }
406
+
407
+    /**
408
+     * clean a path, i.e. remove all redundant '.' and '..'
409
+     * making sure that it can't point to higher than '/'
410
+     *
411
+     * @param string $path The path to clean
412
+     * @return string cleaned path
413
+     */
414
+    public function cleanPath($path) {
415
+        if (strlen($path) == 0 or $path[0] != '/') {
416
+            $path = '/' . $path;
417
+        }
418
+
419
+        $output = array();
420
+        foreach (explode('/', $path) as $chunk) {
421
+            if ($chunk == '..') {
422
+                array_pop($output);
423
+            } else if ($chunk == '.') {
424
+            } else {
425
+                $output[] = $chunk;
426
+            }
427
+        }
428
+        return implode('/', $output);
429
+    }
430
+
431
+    /**
432
+     * Test a storage for availability
433
+     *
434
+     * @return bool
435
+     */
436
+    public function test() {
437
+        if ($this->stat('')) {
438
+            return true;
439
+        }
440
+        return false;
441
+    }
442
+
443
+    /**
444
+     * get the free space in the storage
445
+     *
446
+     * @param string $path
447
+     * @return int|false
448
+     */
449
+    public function free_space($path) {
450
+        return \OCP\Files\FileInfo::SPACE_UNKNOWN;
451
+    }
452
+
453
+    /**
454
+     * {@inheritdoc}
455
+     */
456
+    public function isLocal() {
457
+        // the common implementation returns a temporary file by
458
+        // default, which is not local
459
+        return false;
460
+    }
461
+
462
+    /**
463
+     * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class
464
+     *
465
+     * @param string $class
466
+     * @return bool
467
+     */
468
+    public function instanceOfStorage($class) {
469
+        return is_a($this, $class);
470
+    }
471
+
472
+    /**
473
+     * A custom storage implementation can return an url for direct download of a give file.
474
+     *
475
+     * For now the returned array can hold the parameter url - in future more attributes might follow.
476
+     *
477
+     * @param string $path
478
+     * @return array|false
479
+     */
480
+    public function getDirectDownload($path) {
481
+        return [];
482
+    }
483
+
484
+    /**
485
+     * @inheritdoc
486
+     */
487
+    public function verifyPath($path, $fileName) {
488
+        if (isset($fileName[255])) {
489
+            throw new FileNameTooLongException();
490
+        }
491
+
492
+        // NOTE: $path will remain unverified for now
493
+        $this->verifyPosixPath($fileName);
494
+    }
495
+
496
+    /**
497
+     * @param string $fileName
498
+     * @throws InvalidPathException
499
+     */
500
+    protected function verifyPosixPath($fileName) {
501
+        $fileName = trim($fileName);
502
+        $this->scanForInvalidCharacters($fileName, "\\/");
503
+        $reservedNames = ['*'];
504
+        if (in_array($fileName, $reservedNames)) {
505
+            throw new ReservedWordException();
506
+        }
507
+    }
508
+
509
+    /**
510
+     * @param string $fileName
511
+     * @param string $invalidChars
512
+     * @throws InvalidPathException
513
+     */
514
+    private function scanForInvalidCharacters($fileName, $invalidChars) {
515
+        foreach (str_split($invalidChars) as $char) {
516
+            if (strpos($fileName, $char) !== false) {
517
+                throw new InvalidCharacterInPathException();
518
+            }
519
+        }
520
+
521
+        $sanitizedFileName = filter_var($fileName, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW);
522
+        if ($sanitizedFileName !== $fileName) {
523
+            throw new InvalidCharacterInPathException();
524
+        }
525
+    }
526
+
527
+    /**
528
+     * @param array $options
529
+     */
530
+    public function setMountOptions(array $options) {
531
+        $this->mountOptions = $options;
532
+    }
533
+
534
+    /**
535
+     * @param string $name
536
+     * @param mixed $default
537
+     * @return mixed
538
+     */
539
+    public function getMountOption($name, $default = null) {
540
+        return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default;
541
+    }
542
+
543
+    /**
544
+     * @param \OCP\Files\Storage $sourceStorage
545
+     * @param string $sourceInternalPath
546
+     * @param string $targetInternalPath
547
+     * @param bool $preserveMtime
548
+     * @return bool
549
+     */
550
+    public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) {
551
+        if ($sourceStorage === $this) {
552
+            return $this->copy($sourceInternalPath, $targetInternalPath);
553
+        }
554
+
555
+        if ($sourceStorage->is_dir($sourceInternalPath)) {
556
+            $dh = $sourceStorage->opendir($sourceInternalPath);
557
+            $result = $this->mkdir($targetInternalPath);
558
+            if (is_resource($dh)) {
559
+                while ($result and ($file = readdir($dh)) !== false) {
560
+                    if (!Filesystem::isIgnoredDir($file)) {
561
+                        $result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file);
562
+                    }
563
+                }
564
+            }
565
+        } else {
566
+            $source = $sourceStorage->fopen($sourceInternalPath, 'r');
567
+            // TODO: call fopen in a way that we execute again all storage wrappers
568
+            // to avoid that we bypass storage wrappers which perform important actions
569
+            // for this operation. Same is true for all other operations which
570
+            // are not the same as the original one.Once this is fixed we also
571
+            // need to adjust the encryption wrapper.
572
+            $target = $this->fopen($targetInternalPath, 'w');
573
+            list(, $result) = \OC_Helper::streamCopy($source, $target);
574
+            if ($result and $preserveMtime) {
575
+                $this->touch($targetInternalPath, $sourceStorage->filemtime($sourceInternalPath));
576
+            }
577
+            fclose($source);
578
+            fclose($target);
579
+
580
+            if (!$result) {
581
+                // delete partially written target file
582
+                $this->unlink($targetInternalPath);
583
+                // delete cache entry that was created by fopen
584
+                $this->getCache()->remove($targetInternalPath);
585
+            }
586
+        }
587
+        return (bool)$result;
588
+    }
589
+
590
+    /**
591
+     * @param \OCP\Files\Storage $sourceStorage
592
+     * @param string $sourceInternalPath
593
+     * @param string $targetInternalPath
594
+     * @return bool
595
+     */
596
+    public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
597
+        if ($sourceStorage === $this) {
598
+            return $this->rename($sourceInternalPath, $targetInternalPath);
599
+        }
600
+
601
+        if (!$sourceStorage->isDeletable($sourceInternalPath)) {
602
+            return false;
603
+        }
604
+
605
+        $result = $this->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, true);
606
+        if ($result) {
607
+            if ($sourceStorage->is_dir($sourceInternalPath)) {
608
+                $result &= $sourceStorage->rmdir($sourceInternalPath);
609
+            } else {
610
+                $result &= $sourceStorage->unlink($sourceInternalPath);
611
+            }
612
+        }
613
+        return $result;
614
+    }
615
+
616
+    /**
617
+     * @inheritdoc
618
+     */
619
+    public function getMetaData($path) {
620
+        $permissions = $this->getPermissions($path);
621
+        if (!$permissions & \OCP\Constants::PERMISSION_READ) {
622
+            //can't read, nothing we can do
623
+            return null;
624
+        }
625
+
626
+        $data = [];
627
+        $data['mimetype'] = $this->getMimeType($path);
628
+        $data['mtime'] = $this->filemtime($path);
629
+        if ($data['mtime'] === false) {
630
+            $data['mtime'] = time();
631
+        }
632
+        if ($data['mimetype'] == 'httpd/unix-directory') {
633
+            $data['size'] = -1; //unknown
634
+        } else {
635
+            $data['size'] = $this->filesize($path);
636
+        }
637
+        $data['etag'] = $this->getETag($path);
638
+        $data['storage_mtime'] = $data['mtime'];
639
+        $data['permissions'] = $permissions;
640
+
641
+        return $data;
642
+    }
643
+
644
+    /**
645
+     * @param string $path
646
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
647
+     * @param \OCP\Lock\ILockingProvider $provider
648
+     * @throws \OCP\Lock\LockedException
649
+     */
650
+    public function acquireLock($path, $type, ILockingProvider $provider) {
651
+        $provider->acquireLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
652
+    }
653
+
654
+    /**
655
+     * @param string $path
656
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
657
+     * @param \OCP\Lock\ILockingProvider $provider
658
+     */
659
+    public function releaseLock($path, $type, ILockingProvider $provider) {
660
+        $provider->releaseLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
661
+    }
662
+
663
+    /**
664
+     * @param string $path
665
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
666
+     * @param \OCP\Lock\ILockingProvider $provider
667
+     */
668
+    public function changeLock($path, $type, ILockingProvider $provider) {
669
+        $provider->changeLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
670
+    }
671
+
672
+    /**
673
+     * @return array [ available, last_checked ]
674
+     */
675
+    public function getAvailability() {
676
+        return $this->getStorageCache()->getAvailability();
677
+    }
678
+
679
+    /**
680
+     * @param bool $isAvailable
681
+     */
682
+    public function setAvailability($isAvailable) {
683
+        $this->getStorageCache()->setAvailability($isAvailable);
684
+    }
685 685
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -210,7 +210,7 @@  discard block
 block discarded – undo
210 210
 			$this->mkdir($path2);
211 211
 			while ($file = readdir($dir)) {
212 212
 				if (!Filesystem::isIgnoredDir($file)) {
213
-					if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) {
213
+					if (!$this->copy($path1.'/'.$file, $path2.'/'.$file)) {
214 214
 						return false;
215 215
 					}
216 216
 				}
@@ -261,12 +261,12 @@  discard block
 block discarded – undo
261 261
 		if (is_resource($dh)) {
262 262
 			while (($file = readdir($dh)) !== false) {
263 263
 				if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
264
-					if ($this->is_dir($path . '/' . $file)) {
265
-						mkdir($target . '/' . $file);
266
-						$this->addLocalFolder($path . '/' . $file, $target . '/' . $file);
264
+					if ($this->is_dir($path.'/'.$file)) {
265
+						mkdir($target.'/'.$file);
266
+						$this->addLocalFolder($path.'/'.$file, $target.'/'.$file);
267 267
 					} else {
268
-						$tmp = $this->toTmpFile($path . '/' . $file);
269
-						rename($tmp, $target . '/' . $file);
268
+						$tmp = $this->toTmpFile($path.'/'.$file);
269
+						rename($tmp, $target.'/'.$file);
270 270
 					}
271 271
 				}
272 272
 			}
@@ -285,10 +285,10 @@  discard block
 block discarded – undo
285 285
 			while (($item = readdir($dh)) !== false) {
286 286
 				if (\OC\Files\Filesystem::isIgnoredDir($item)) continue;
287 287
 				if (strstr(strtolower($item), strtolower($query)) !== false) {
288
-					$files[] = $dir . '/' . $item;
288
+					$files[] = $dir.'/'.$item;
289 289
 				}
290
-				if ($this->is_dir($dir . '/' . $item)) {
291
-					$files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item));
290
+				if ($this->is_dir($dir.'/'.$item)) {
291
+					$files = array_merge($files, $this->searchInDir($query, $dir.'/'.$item));
292 292
 				}
293 293
 			}
294 294
 		}
@@ -339,7 +339,7 @@  discard block
 block discarded – undo
339 339
 		if (!isset($this->watcher)) {
340 340
 			$this->watcher = new Watcher($storage);
341 341
 			$globalPolicy = \OC::$server->getConfig()->getSystemValue('filesystem_check_changes', Watcher::CHECK_NEVER);
342
-			$this->watcher->setPolicy((int)$this->getMountOption('filesystem_check_changes', $globalPolicy));
342
+			$this->watcher->setPolicy((int) $this->getMountOption('filesystem_check_changes', $globalPolicy));
343 343
 		}
344 344
 		return $this->watcher;
345 345
 	}
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
 	 */
414 414
 	public function cleanPath($path) {
415 415
 		if (strlen($path) == 0 or $path[0] != '/') {
416
-			$path = '/' . $path;
416
+			$path = '/'.$path;
417 417
 		}
418 418
 
419 419
 		$output = array();
@@ -558,7 +558,7 @@  discard block
 block discarded – undo
558 558
 			if (is_resource($dh)) {
559 559
 				while ($result and ($file = readdir($dh)) !== false) {
560 560
 					if (!Filesystem::isIgnoredDir($file)) {
561
-						$result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath . '/' . $file, $targetInternalPath . '/' . $file);
561
+						$result &= $this->copyFromStorage($sourceStorage, $sourceInternalPath.'/'.$file, $targetInternalPath.'/'.$file);
562 562
 					}
563 563
 				}
564 564
 			}
@@ -584,7 +584,7 @@  discard block
 block discarded – undo
584 584
 				$this->getCache()->remove($targetInternalPath);
585 585
 			}
586 586
 		}
587
-		return (bool)$result;
587
+		return (bool) $result;
588 588
 	}
589 589
 
590 590
 	/**
@@ -648,7 +648,7 @@  discard block
 block discarded – undo
648 648
 	 * @throws \OCP\Lock\LockedException
649 649
 	 */
650 650
 	public function acquireLock($path, $type, ILockingProvider $provider) {
651
-		$provider->acquireLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
651
+		$provider->acquireLock('files/'.md5($this->getId().'::'.trim($path, '/')), $type);
652 652
 	}
653 653
 
654 654
 	/**
@@ -657,7 +657,7 @@  discard block
 block discarded – undo
657 657
 	 * @param \OCP\Lock\ILockingProvider $provider
658 658
 	 */
659 659
 	public function releaseLock($path, $type, ILockingProvider $provider) {
660
-		$provider->releaseLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
660
+		$provider->releaseLock('files/'.md5($this->getId().'::'.trim($path, '/')), $type);
661 661
 	}
662 662
 
663 663
 	/**
@@ -666,7 +666,7 @@  discard block
 block discarded – undo
666 666
 	 * @param \OCP\Lock\ILockingProvider $provider
667 667
 	 */
668 668
 	public function changeLock($path, $type, ILockingProvider $provider) {
669
-		$provider->changeLock('files/' . md5($this->getId() . '::' . trim($path, '/')), $type);
669
+		$provider->changeLock('files/'.md5($this->getId().'::'.trim($path, '/')), $type);
670 670
 	}
671 671
 
672 672
 	/**
Please login to merge, or discard this patch.
lib/private/Files/Storage/StorageFactory.php 2 patches
Indentation   +70 added lines, -70 removed lines patch added patch discarded remove patch
@@ -29,80 +29,80 @@
 block discarded – undo
29 29
 use OCP\Files\Storage\IStorageFactory;
30 30
 
31 31
 class StorageFactory implements IStorageFactory {
32
-	/**
33
-	 * @var array[] [$name=>['priority'=>$priority, 'wrapper'=>$callable] $storageWrappers
34
-	 */
35
-	private $storageWrappers = [];
32
+    /**
33
+     * @var array[] [$name=>['priority'=>$priority, 'wrapper'=>$callable] $storageWrappers
34
+     */
35
+    private $storageWrappers = [];
36 36
 
37
-	/**
38
-	 * allow modifier storage behaviour by adding wrappers around storages
39
-	 *
40
-	 * $callback should be a function of type (string $mountPoint, Storage $storage) => Storage
41
-	 *
42
-	 * @param string $wrapperName name of the wrapper
43
-	 * @param callable $callback callback
44
-	 * @param int $priority wrappers with the lower priority are applied last (meaning they get called first)
45
-	 * @param \OCP\Files\Mount\IMountPoint[] $existingMounts existing mount points to apply the wrapper to
46
-	 * @return bool true if the wrapper was added, false if there was already a wrapper with this
47
-	 * name registered
48
-	 */
49
-	public function addStorageWrapper($wrapperName, $callback, $priority = 50, $existingMounts = []) {
50
-		if (isset($this->storageWrappers[$wrapperName])) {
51
-			return false;
52
-		}
37
+    /**
38
+     * allow modifier storage behaviour by adding wrappers around storages
39
+     *
40
+     * $callback should be a function of type (string $mountPoint, Storage $storage) => Storage
41
+     *
42
+     * @param string $wrapperName name of the wrapper
43
+     * @param callable $callback callback
44
+     * @param int $priority wrappers with the lower priority are applied last (meaning they get called first)
45
+     * @param \OCP\Files\Mount\IMountPoint[] $existingMounts existing mount points to apply the wrapper to
46
+     * @return bool true if the wrapper was added, false if there was already a wrapper with this
47
+     * name registered
48
+     */
49
+    public function addStorageWrapper($wrapperName, $callback, $priority = 50, $existingMounts = []) {
50
+        if (isset($this->storageWrappers[$wrapperName])) {
51
+            return false;
52
+        }
53 53
 
54
-		// apply to existing mounts before registering it to prevent applying it double in MountPoint::createStorage
55
-		foreach ($existingMounts as $mount) {
56
-			$mount->wrapStorage($callback);
57
-		}
54
+        // apply to existing mounts before registering it to prevent applying it double in MountPoint::createStorage
55
+        foreach ($existingMounts as $mount) {
56
+            $mount->wrapStorage($callback);
57
+        }
58 58
 
59
-		$this->storageWrappers[$wrapperName] = ['wrapper' => $callback, 'priority' => $priority];
60
-		return true;
61
-	}
59
+        $this->storageWrappers[$wrapperName] = ['wrapper' => $callback, 'priority' => $priority];
60
+        return true;
61
+    }
62 62
 
63
-	/**
64
-	 * Remove a storage wrapper by name.
65
-	 * Note: internal method only to be used for cleanup
66
-	 *
67
-	 * @param string $wrapperName name of the wrapper
68
-	 * @internal
69
-	 */
70
-	public function removeStorageWrapper($wrapperName) {
71
-		unset($this->storageWrappers[$wrapperName]);
72
-	}
63
+    /**
64
+     * Remove a storage wrapper by name.
65
+     * Note: internal method only to be used for cleanup
66
+     *
67
+     * @param string $wrapperName name of the wrapper
68
+     * @internal
69
+     */
70
+    public function removeStorageWrapper($wrapperName) {
71
+        unset($this->storageWrappers[$wrapperName]);
72
+    }
73 73
 
74
-	/**
75
-	 * Create an instance of a storage and apply the registered storage wrappers
76
-	 *
77
-	 * @param \OCP\Files\Mount\IMountPoint $mountPoint
78
-	 * @param string $class
79
-	 * @param array $arguments
80
-	 * @return \OCP\Files\Storage
81
-	 */
82
-	public function getInstance(IMountPoint $mountPoint, $class, $arguments) {
83
-		return $this->wrap($mountPoint, new $class($arguments));
84
-	}
74
+    /**
75
+     * Create an instance of a storage and apply the registered storage wrappers
76
+     *
77
+     * @param \OCP\Files\Mount\IMountPoint $mountPoint
78
+     * @param string $class
79
+     * @param array $arguments
80
+     * @return \OCP\Files\Storage
81
+     */
82
+    public function getInstance(IMountPoint $mountPoint, $class, $arguments) {
83
+        return $this->wrap($mountPoint, new $class($arguments));
84
+    }
85 85
 
86
-	/**
87
-	 * @param \OCP\Files\Mount\IMountPoint $mountPoint
88
-	 * @param \OCP\Files\Storage $storage
89
-	 * @return \OCP\Files\Storage
90
-	 */
91
-	public function wrap(IMountPoint $mountPoint, $storage) {
92
-		$wrappers = array_values($this->storageWrappers);
93
-		usort($wrappers, function ($a, $b) {
94
-			return $b['priority'] - $a['priority'];
95
-		});
96
-		/** @var callable[] $wrappers */
97
-		$wrappers = array_map(function ($wrapper) {
98
-			return $wrapper['wrapper'];
99
-		}, $wrappers);
100
-		foreach ($wrappers as $wrapper) {
101
-			$storage = $wrapper($mountPoint->getMountPoint(), $storage, $mountPoint);
102
-			if (!($storage instanceof \OCP\Files\Storage)) {
103
-				throw new \Exception('Invalid result from storage wrapper');
104
-			}
105
-		}
106
-		return $storage;
107
-	}
86
+    /**
87
+     * @param \OCP\Files\Mount\IMountPoint $mountPoint
88
+     * @param \OCP\Files\Storage $storage
89
+     * @return \OCP\Files\Storage
90
+     */
91
+    public function wrap(IMountPoint $mountPoint, $storage) {
92
+        $wrappers = array_values($this->storageWrappers);
93
+        usort($wrappers, function ($a, $b) {
94
+            return $b['priority'] - $a['priority'];
95
+        });
96
+        /** @var callable[] $wrappers */
97
+        $wrappers = array_map(function ($wrapper) {
98
+            return $wrapper['wrapper'];
99
+        }, $wrappers);
100
+        foreach ($wrappers as $wrapper) {
101
+            $storage = $wrapper($mountPoint->getMountPoint(), $storage, $mountPoint);
102
+            if (!($storage instanceof \OCP\Files\Storage)) {
103
+                throw new \Exception('Invalid result from storage wrapper');
104
+            }
105
+        }
106
+        return $storage;
107
+    }
108 108
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -90,11 +90,11 @@
 block discarded – undo
90 90
 	 */
91 91
 	public function wrap(IMountPoint $mountPoint, $storage) {
92 92
 		$wrappers = array_values($this->storageWrappers);
93
-		usort($wrappers, function ($a, $b) {
93
+		usort($wrappers, function($a, $b) {
94 94
 			return $b['priority'] - $a['priority'];
95 95
 		});
96 96
 		/** @var callable[] $wrappers */
97
-		$wrappers = array_map(function ($wrapper) {
97
+		$wrappers = array_map(function($wrapper) {
98 98
 			return $wrapper['wrapper'];
99 99
 		}, $wrappers);
100 100
 		foreach ($wrappers as $wrapper) {
Please login to merge, or discard this patch.
lib/private/Files/Storage/PolyFill/CopyDirectory.php 2 patches
Indentation   +71 added lines, -71 removed lines patch added patch discarded remove patch
@@ -25,81 +25,81 @@
 block discarded – undo
25 25
 namespace OC\Files\Storage\PolyFill;
26 26
 
27 27
 trait CopyDirectory {
28
-	/**
29
-	 * Check if a path is a directory
30
-	 *
31
-	 * @param string $path
32
-	 * @return bool
33
-	 */
34
-	abstract public function is_dir($path);
28
+    /**
29
+     * Check if a path is a directory
30
+     *
31
+     * @param string $path
32
+     * @return bool
33
+     */
34
+    abstract public function is_dir($path);
35 35
 
36
-	/**
37
-	 * Check if a file or folder exists
38
-	 *
39
-	 * @param string $path
40
-	 * @return bool
41
-	 */
42
-	abstract public function file_exists($path);
36
+    /**
37
+     * Check if a file or folder exists
38
+     *
39
+     * @param string $path
40
+     * @return bool
41
+     */
42
+    abstract public function file_exists($path);
43 43
 
44
-	/**
45
-	 * Delete a file or folder
46
-	 *
47
-	 * @param string $path
48
-	 * @return bool
49
-	 */
50
-	abstract public function unlink($path);
44
+    /**
45
+     * Delete a file or folder
46
+     *
47
+     * @param string $path
48
+     * @return bool
49
+     */
50
+    abstract public function unlink($path);
51 51
 
52
-	/**
53
-	 * Open a directory handle for a folder
54
-	 *
55
-	 * @param string $path
56
-	 * @return resource | bool
57
-	 */
58
-	abstract public function opendir($path);
52
+    /**
53
+     * Open a directory handle for a folder
54
+     *
55
+     * @param string $path
56
+     * @return resource | bool
57
+     */
58
+    abstract public function opendir($path);
59 59
 
60
-	/**
61
-	 * Create a new folder
62
-	 *
63
-	 * @param string $path
64
-	 * @return bool
65
-	 */
66
-	abstract public function mkdir($path);
60
+    /**
61
+     * Create a new folder
62
+     *
63
+     * @param string $path
64
+     * @return bool
65
+     */
66
+    abstract public function mkdir($path);
67 67
 
68
-	public function copy($source, $target) {
69
-		if ($this->is_dir($source)) {
70
-			if ($this->file_exists($target)) {
71
-				$this->unlink($target);
72
-			}
73
-			$this->mkdir($target);
74
-			return $this->copyRecursive($source, $target);
75
-		} else {
76
-			return parent::copy($source, $target);
77
-		}
78
-	}
68
+    public function copy($source, $target) {
69
+        if ($this->is_dir($source)) {
70
+            if ($this->file_exists($target)) {
71
+                $this->unlink($target);
72
+            }
73
+            $this->mkdir($target);
74
+            return $this->copyRecursive($source, $target);
75
+        } else {
76
+            return parent::copy($source, $target);
77
+        }
78
+    }
79 79
 
80
-	/**
81
-	 * For adapters that don't support copying folders natively
82
-	 *
83
-	 * @param $source
84
-	 * @param $target
85
-	 * @return bool
86
-	 */
87
-	protected function copyRecursive($source, $target) {
88
-		$dh = $this->opendir($source);
89
-		$result = true;
90
-		while ($file = readdir($dh)) {
91
-			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
92
-				if ($this->is_dir($source . '/' . $file)) {
93
-					$this->mkdir($target . '/' . $file);
94
-					$result = $this->copyRecursive($source . '/' . $file, $target . '/' . $file);
95
-				} else {
96
-					$result = parent::copy($source . '/' . $file, $target . '/' . $file);
97
-				}
98
-				if (!$result) {
99
-					break;
100
-				}
101
-			}
102
-		}
103
-		return $result;
104
-	}
80
+    /**
81
+     * For adapters that don't support copying folders natively
82
+     *
83
+     * @param $source
84
+     * @param $target
85
+     * @return bool
86
+     */
87
+    protected function copyRecursive($source, $target) {
88
+        $dh = $this->opendir($source);
89
+        $result = true;
90
+        while ($file = readdir($dh)) {
91
+            if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
92
+                if ($this->is_dir($source . '/' . $file)) {
93
+                    $this->mkdir($target . '/' . $file);
94
+                    $result = $this->copyRecursive($source . '/' . $file, $target . '/' . $file);
95
+                } else {
96
+                    $result = parent::copy($source . '/' . $file, $target . '/' . $file);
97
+                }
98
+                if (!$result) {
99
+                    break;
100
+                }
101
+            }
102
+        }
103
+        return $result;
104
+    }
105 105
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -89,11 +89,11 @@
 block discarded – undo
89 89
 		$result = true;
90 90
 		while ($file = readdir($dh)) {
91 91
 			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
92
-				if ($this->is_dir($source . '/' . $file)) {
93
-					$this->mkdir($target . '/' . $file);
94
-					$result = $this->copyRecursive($source . '/' . $file, $target . '/' . $file);
92
+				if ($this->is_dir($source.'/'.$file)) {
93
+					$this->mkdir($target.'/'.$file);
94
+					$result = $this->copyRecursive($source.'/'.$file, $target.'/'.$file);
95 95
 				} else {
96
-					$result = parent::copy($source . '/' . $file, $target . '/' . $file);
96
+					$result = parent::copy($source.'/'.$file, $target.'/'.$file);
97 97
 				}
98 98
 				if (!$result) {
99 99
 					break;
Please login to merge, or discard this patch.
lib/private/Files/Storage/FailedStorage.php 1 patch
Indentation   +165 added lines, -165 removed lines patch added patch discarded remove patch
@@ -33,185 +33,185 @@
 block discarded – undo
33 33
  */
34 34
 class FailedStorage extends Common {
35 35
 
36
-	/** @var \Exception */
37
-	protected $e;
38
-
39
-	/**
40
-	 * @param array $params ['exception' => \Exception]
41
-	 */
42
-	public function __construct($params) {
43
-		$this->e = $params['exception'];
44
-		if (!$this->e) {
45
-			throw new \InvalidArgumentException('Missing "exception" argument in FailedStorage constructor');
46
-		}
47
-	}
48
-
49
-	public function getId() {
50
-		// we can't return anything sane here
51
-		return 'failedstorage';
52
-	}
53
-
54
-	public function mkdir($path) {
55
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
56
-	}
57
-
58
-	public function rmdir($path) {
59
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
60
-	}
61
-
62
-	public function opendir($path) {
63
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
64
-	}
65
-
66
-	public function is_dir($path) {
67
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
68
-	}
69
-
70
-	public function is_file($path) {
71
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
72
-	}
73
-
74
-	public function stat($path) {
75
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
76
-	}
77
-
78
-	public function filetype($path) {
79
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
80
-	}
81
-
82
-	public function filesize($path) {
83
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
84
-	}
85
-
86
-	public function isCreatable($path) {
87
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
88
-	}
89
-
90
-	public function isReadable($path) {
91
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
92
-	}
93
-
94
-	public function isUpdatable($path) {
95
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
96
-	}
97
-
98
-	public function isDeletable($path) {
99
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
100
-	}
101
-
102
-	public function isSharable($path) {
103
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
104
-	}
105
-
106
-	public function getPermissions($path) {
107
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
108
-	}
109
-
110
-	public function file_exists($path) {
111
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
112
-	}
113
-
114
-	public function filemtime($path) {
115
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
116
-	}
117
-
118
-	public function file_get_contents($path) {
119
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
120
-	}
121
-
122
-	public function file_put_contents($path, $data) {
123
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
124
-	}
125
-
126
-	public function unlink($path) {
127
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
128
-	}
129
-
130
-	public function rename($path1, $path2) {
131
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
132
-	}
133
-
134
-	public function copy($path1, $path2) {
135
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
136
-	}
137
-
138
-	public function fopen($path, $mode) {
139
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
140
-	}
141
-
142
-	public function getMimeType($path) {
143
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
144
-	}
145
-
146
-	public function hash($type, $path, $raw = false) {
147
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
148
-	}
149
-
150
-	public function free_space($path) {
151
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
152
-	}
36
+    /** @var \Exception */
37
+    protected $e;
38
+
39
+    /**
40
+     * @param array $params ['exception' => \Exception]
41
+     */
42
+    public function __construct($params) {
43
+        $this->e = $params['exception'];
44
+        if (!$this->e) {
45
+            throw new \InvalidArgumentException('Missing "exception" argument in FailedStorage constructor');
46
+        }
47
+    }
48
+
49
+    public function getId() {
50
+        // we can't return anything sane here
51
+        return 'failedstorage';
52
+    }
53
+
54
+    public function mkdir($path) {
55
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
56
+    }
57
+
58
+    public function rmdir($path) {
59
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
60
+    }
61
+
62
+    public function opendir($path) {
63
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
64
+    }
65
+
66
+    public function is_dir($path) {
67
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
68
+    }
69
+
70
+    public function is_file($path) {
71
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
72
+    }
73
+
74
+    public function stat($path) {
75
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
76
+    }
77
+
78
+    public function filetype($path) {
79
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
80
+    }
81
+
82
+    public function filesize($path) {
83
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
84
+    }
85
+
86
+    public function isCreatable($path) {
87
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
88
+    }
89
+
90
+    public function isReadable($path) {
91
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
92
+    }
93
+
94
+    public function isUpdatable($path) {
95
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
96
+    }
97
+
98
+    public function isDeletable($path) {
99
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
100
+    }
101
+
102
+    public function isSharable($path) {
103
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
104
+    }
105
+
106
+    public function getPermissions($path) {
107
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
108
+    }
109
+
110
+    public function file_exists($path) {
111
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
112
+    }
113
+
114
+    public function filemtime($path) {
115
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
116
+    }
117
+
118
+    public function file_get_contents($path) {
119
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
120
+    }
121
+
122
+    public function file_put_contents($path, $data) {
123
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
124
+    }
125
+
126
+    public function unlink($path) {
127
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
128
+    }
129
+
130
+    public function rename($path1, $path2) {
131
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
132
+    }
133
+
134
+    public function copy($path1, $path2) {
135
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
136
+    }
137
+
138
+    public function fopen($path, $mode) {
139
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
140
+    }
141
+
142
+    public function getMimeType($path) {
143
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
144
+    }
145
+
146
+    public function hash($type, $path, $raw = false) {
147
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
148
+    }
149
+
150
+    public function free_space($path) {
151
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
152
+    }
153 153
 
154
-	public function search($query) {
155
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
156
-	}
154
+    public function search($query) {
155
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
156
+    }
157 157
 
158
-	public function touch($path, $mtime = null) {
159
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
160
-	}
158
+    public function touch($path, $mtime = null) {
159
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
160
+    }
161 161
 
162
-	public function getLocalFile($path) {
163
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
164
-	}
162
+    public function getLocalFile($path) {
163
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
164
+    }
165 165
 
166
-	public function getLocalFolder($path) {
167
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
168
-	}
166
+    public function getLocalFolder($path) {
167
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
168
+    }
169 169
 
170
-	public function hasUpdated($path, $time) {
171
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
172
-	}
170
+    public function hasUpdated($path, $time) {
171
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
172
+    }
173 173
 
174
-	public function getETag($path) {
175
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
176
-	}
174
+    public function getETag($path) {
175
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
176
+    }
177 177
 
178
-	public function getDirectDownload($path) {
179
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
180
-	}
178
+    public function getDirectDownload($path) {
179
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
180
+    }
181 181
 
182
-	public function verifyPath($path, $fileName) {
183
-		return true;
184
-	}
182
+    public function verifyPath($path, $fileName) {
183
+        return true;
184
+    }
185 185
 
186
-	public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
187
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
188
-	}
186
+    public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
187
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
188
+    }
189 189
 
190
-	public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
191
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
192
-	}
190
+    public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
191
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
192
+    }
193 193
 
194
-	public function acquireLock($path, $type, ILockingProvider $provider) {
195
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
196
-	}
194
+    public function acquireLock($path, $type, ILockingProvider $provider) {
195
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
196
+    }
197 197
 
198
-	public function releaseLock($path, $type, ILockingProvider $provider) {
199
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
200
-	}
198
+    public function releaseLock($path, $type, ILockingProvider $provider) {
199
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
200
+    }
201 201
 
202
-	public function changeLock($path, $type, ILockingProvider $provider) {
203
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
204
-	}
202
+    public function changeLock($path, $type, ILockingProvider $provider) {
203
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
204
+    }
205 205
 
206
-	public function getAvailability() {
207
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
208
-	}
206
+    public function getAvailability() {
207
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
208
+    }
209 209
 
210
-	public function setAvailability($isAvailable) {
211
-		throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
212
-	}
210
+    public function setAvailability($isAvailable) {
211
+        throw new StorageNotAvailableException($this->e->getMessage(), $this->e->getCode(), $this->e);
212
+    }
213 213
 
214
-	public function getCache($path = '', $storage = null) {
215
-		return new FailedCache();
216
-	}
214
+    public function getCache($path = '', $storage = null) {
215
+        return new FailedCache();
216
+    }
217 217
 }
Please login to merge, or discard this patch.
lib/private/Files/Storage/CommonTest.php 2 patches
Indentation   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -33,53 +33,53 @@
 block discarded – undo
33 33
 namespace OC\Files\Storage;
34 34
 
35 35
 class CommonTest extends \OC\Files\Storage\Common{
36
-	/**
37
-	 * underlying local storage used for missing functions
38
-	 * @var \OC\Files\Storage\Local
39
-	 */
40
-	private $storage;
36
+    /**
37
+     * underlying local storage used for missing functions
38
+     * @var \OC\Files\Storage\Local
39
+     */
40
+    private $storage;
41 41
 
42
-	public function __construct($params) {
43
-		$this->storage=new \OC\Files\Storage\Local($params);
44
-	}
42
+    public function __construct($params) {
43
+        $this->storage=new \OC\Files\Storage\Local($params);
44
+    }
45 45
 
46
-	public function getId(){
47
-		return 'test::'.$this->storage->getId();
48
-	}
49
-	public function mkdir($path) {
50
-		return $this->storage->mkdir($path);
51
-	}
52
-	public function rmdir($path) {
53
-		return $this->storage->rmdir($path);
54
-	}
55
-	public function opendir($path) {
56
-		return $this->storage->opendir($path);
57
-	}
58
-	public function stat($path) {
59
-		return $this->storage->stat($path);
60
-	}
61
-	public function filetype($path) {
62
-		return @$this->storage->filetype($path);
63
-	}
64
-	public function isReadable($path) {
65
-		return $this->storage->isReadable($path);
66
-	}
67
-	public function isUpdatable($path) {
68
-		return $this->storage->isUpdatable($path);
69
-	}
70
-	public function file_exists($path) {
71
-		return $this->storage->file_exists($path);
72
-	}
73
-	public function unlink($path) {
74
-		return $this->storage->unlink($path);
75
-	}
76
-	public function fopen($path, $mode) {
77
-		return $this->storage->fopen($path, $mode);
78
-	}
79
-	public function free_space($path) {
80
-		return $this->storage->free_space($path);
81
-	}
82
-	public function touch($path, $mtime=null) {
83
-		return $this->storage->touch($path, $mtime);
84
-	}
46
+    public function getId(){
47
+        return 'test::'.$this->storage->getId();
48
+    }
49
+    public function mkdir($path) {
50
+        return $this->storage->mkdir($path);
51
+    }
52
+    public function rmdir($path) {
53
+        return $this->storage->rmdir($path);
54
+    }
55
+    public function opendir($path) {
56
+        return $this->storage->opendir($path);
57
+    }
58
+    public function stat($path) {
59
+        return $this->storage->stat($path);
60
+    }
61
+    public function filetype($path) {
62
+        return @$this->storage->filetype($path);
63
+    }
64
+    public function isReadable($path) {
65
+        return $this->storage->isReadable($path);
66
+    }
67
+    public function isUpdatable($path) {
68
+        return $this->storage->isUpdatable($path);
69
+    }
70
+    public function file_exists($path) {
71
+        return $this->storage->file_exists($path);
72
+    }
73
+    public function unlink($path) {
74
+        return $this->storage->unlink($path);
75
+    }
76
+    public function fopen($path, $mode) {
77
+        return $this->storage->fopen($path, $mode);
78
+    }
79
+    public function free_space($path) {
80
+        return $this->storage->free_space($path);
81
+    }
82
+    public function touch($path, $mtime=null) {
83
+        return $this->storage->touch($path, $mtime);
84
+    }
85 85
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -32,7 +32,7 @@  discard block
 block discarded – undo
32 32
 
33 33
 namespace OC\Files\Storage;
34 34
 
35
-class CommonTest extends \OC\Files\Storage\Common{
35
+class CommonTest extends \OC\Files\Storage\Common {
36 36
 	/**
37 37
 	 * underlying local storage used for missing functions
38 38
 	 * @var \OC\Files\Storage\Local
@@ -40,10 +40,10 @@  discard block
 block discarded – undo
40 40
 	private $storage;
41 41
 
42 42
 	public function __construct($params) {
43
-		$this->storage=new \OC\Files\Storage\Local($params);
43
+		$this->storage = new \OC\Files\Storage\Local($params);
44 44
 	}
45 45
 
46
-	public function getId(){
46
+	public function getId() {
47 47
 		return 'test::'.$this->storage->getId();
48 48
 	}
49 49
 	public function mkdir($path) {
@@ -79,7 +79,7 @@  discard block
 block discarded – undo
79 79
 	public function free_space($path) {
80 80
 		return $this->storage->free_space($path);
81 81
 	}
82
-	public function touch($path, $mtime=null) {
82
+	public function touch($path, $mtime = null) {
83 83
 		return $this->storage->touch($path, $mtime);
84 84
 	}
85 85
 }
Please login to merge, or discard this patch.