Completed
Push — master ( d842b2...8a1d3c )
by Lukas
17:12
created
lib/private/Files/Storage/DAV.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -38,7 +38,6 @@
 block discarded – undo
38 38
 use GuzzleHttp\Message\ResponseInterface;
39 39
 use Icewind\Streams\CallbackWrapper;
40 40
 use OC\Files\Filesystem;
41
-use OC\Files\Stream\Close;
42 41
 use Icewind\Streams\IteratorDirectory;
43 42
 use OC\MemCache\ArrayCache;
44 43
 use OCP\AppFramework\Http;
Please login to merge, or discard this patch.
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   +793 added lines, -793 removed lines patch added patch discarded remove patch
@@ -59,798 +59,798 @@
 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 $authType;
68
-	/** @var string */
69
-	protected $host;
70
-	/** @var bool */
71
-	protected $secure;
72
-	/** @var string */
73
-	protected $root;
74
-	/** @var string */
75
-	protected $certPath;
76
-	/** @var bool */
77
-	protected $ready;
78
-	/** @var Client */
79
-	protected $client;
80
-	/** @var ArrayCache */
81
-	protected $statCache;
82
-	/** @var \OCP\Http\Client\IClientService */
83
-	protected $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['authType'])) {
101
-				$this->authType = $params['authType'];
102
-			}
103
-			if (isset($params['secure'])) {
104
-				if (is_string($params['secure'])) {
105
-					$this->secure = ($params['secure'] === 'true');
106
-				} else {
107
-					$this->secure = (bool)$params['secure'];
108
-				}
109
-			} else {
110
-				$this->secure = false;
111
-			}
112
-			if ($this->secure === true) {
113
-				// inject mock for testing
114
-				$certManager = \OC::$server->getCertificateManager();
115
-				if (is_null($certManager)) { //no user
116
-					$certManager = \OC::$server->getCertificateManager(null);
117
-				}
118
-				$certPath = $certManager->getAbsoluteBundlePath();
119
-				if (file_exists($certPath)) {
120
-					$this->certPath = $certPath;
121
-				}
122
-			}
123
-			$this->root = isset($params['root']) ? $params['root'] : '/';
124
-			if (!$this->root || $this->root[0] != '/') {
125
-				$this->root = '/' . $this->root;
126
-			}
127
-			if (substr($this->root, -1, 1) != '/') {
128
-				$this->root .= '/';
129
-			}
130
-		} else {
131
-			throw new \Exception('Invalid webdav storage configuration');
132
-		}
133
-	}
134
-
135
-	protected function init() {
136
-		if ($this->ready) {
137
-			return;
138
-		}
139
-		$this->ready = true;
140
-
141
-		$settings = [
142
-			'baseUri' => $this->createBaseUri(),
143
-			'userName' => $this->user,
144
-			'password' => $this->password,
145
-		];
146
-		if (isset($this->authType)) {
147
-			$settings['authType'] = $this->authType;
148
-		}
149
-
150
-		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
151
-		if($proxy !== '') {
152
-			$settings['proxy'] = $proxy;
153
-		}
154
-
155
-		$this->client = new Client($settings);
156
-		$this->client->setThrowExceptions(true);
157
-		if ($this->secure === true && $this->certPath) {
158
-			$this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
159
-		}
160
-	}
161
-
162
-	/**
163
-	 * Clear the stat cache
164
-	 */
165
-	public function clearStatCache() {
166
-		$this->statCache->clear();
167
-	}
168
-
169
-	/** {@inheritdoc} */
170
-	public function getId() {
171
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
172
-	}
173
-
174
-	/** {@inheritdoc} */
175
-	public function createBaseUri() {
176
-		$baseUri = 'http';
177
-		if ($this->secure) {
178
-			$baseUri .= 's';
179
-		}
180
-		$baseUri .= '://' . $this->host . $this->root;
181
-		return $baseUri;
182
-	}
183
-
184
-	/** {@inheritdoc} */
185
-	public function mkdir($path) {
186
-		$this->init();
187
-		$path = $this->cleanPath($path);
188
-		$result = $this->simpleResponse('MKCOL', $path, null, 201);
189
-		if ($result) {
190
-			$this->statCache->set($path, true);
191
-		}
192
-		return $result;
193
-	}
194
-
195
-	/** {@inheritdoc} */
196
-	public function rmdir($path) {
197
-		$this->init();
198
-		$path = $this->cleanPath($path);
199
-		// FIXME: some WebDAV impl return 403 when trying to DELETE
200
-		// a non-empty folder
201
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
202
-		$this->statCache->clear($path . '/');
203
-		$this->statCache->remove($path);
204
-		return $result;
205
-	}
206
-
207
-	/** {@inheritdoc} */
208
-	public function opendir($path) {
209
-		$this->init();
210
-		$path = $this->cleanPath($path);
211
-		try {
212
-			$response = $this->client->propFind(
213
-				$this->encodePath($path),
214
-				['{DAV:}href'],
215
-				1
216
-			);
217
-			if ($response === false) {
218
-				return false;
219
-			}
220
-			$content = [];
221
-			$files = array_keys($response);
222
-			array_shift($files); //the first entry is the current directory
223
-
224
-			if (!$this->statCache->hasKey($path)) {
225
-				$this->statCache->set($path, true);
226
-			}
227
-			foreach ($files as $file) {
228
-				$file = urldecode($file);
229
-				// do not store the real entry, we might not have all properties
230
-				if (!$this->statCache->hasKey($path)) {
231
-					$this->statCache->set($file, true);
232
-				}
233
-				$file = basename($file);
234
-				$content[] = $file;
235
-			}
236
-			return IteratorDirectory::wrap($content);
237
-		} catch (\Exception $e) {
238
-			$this->convertException($e, $path);
239
-		}
240
-		return false;
241
-	}
242
-
243
-	/**
244
-	 * Propfind call with cache handling.
245
-	 *
246
-	 * First checks if information is cached.
247
-	 * If not, request it from the server then store to cache.
248
-	 *
249
-	 * @param string $path path to propfind
250
-	 *
251
-	 * @return array|boolean propfind response or false if the entry was not found
252
-	 *
253
-	 * @throws ClientHttpException
254
-	 */
255
-	protected function propfind($path) {
256
-		$path = $this->cleanPath($path);
257
-		$cachedResponse = $this->statCache->get($path);
258
-		// we either don't know it, or we know it exists but need more details
259
-		if (is_null($cachedResponse) || $cachedResponse === true) {
260
-			$this->init();
261
-			try {
262
-				$response = $this->client->propFind(
263
-					$this->encodePath($path),
264
-					array(
265
-						'{DAV:}getlastmodified',
266
-						'{DAV:}getcontentlength',
267
-						'{DAV:}getcontenttype',
268
-						'{http://owncloud.org/ns}permissions',
269
-						'{http://open-collaboration-services.org/ns}share-permissions',
270
-						'{DAV:}resourcetype',
271
-						'{DAV:}getetag',
272
-					)
273
-				);
274
-				$this->statCache->set($path, $response);
275
-			} catch (ClientHttpException $e) {
276
-				if ($e->getHttpStatus() === 404) {
277
-					$this->statCache->clear($path . '/');
278
-					$this->statCache->set($path, false);
279
-					return false;
280
-				}
281
-				$this->convertException($e, $path);
282
-			} catch (\Exception $e) {
283
-				$this->convertException($e, $path);
284
-			}
285
-		} else {
286
-			$response = $cachedResponse;
287
-		}
288
-		return $response;
289
-	}
290
-
291
-	/** {@inheritdoc} */
292
-	public function filetype($path) {
293
-		try {
294
-			$response = $this->propfind($path);
295
-			if ($response === false) {
296
-				return false;
297
-			}
298
-			$responseType = [];
299
-			if (isset($response["{DAV:}resourcetype"])) {
300
-				/** @var ResourceType[] $response */
301
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
302
-			}
303
-			return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
304
-		} catch (\Exception $e) {
305
-			$this->convertException($e, $path);
306
-		}
307
-		return false;
308
-	}
309
-
310
-	/** {@inheritdoc} */
311
-	public function file_exists($path) {
312
-		try {
313
-			$path = $this->cleanPath($path);
314
-			$cachedState = $this->statCache->get($path);
315
-			if ($cachedState === false) {
316
-				// we know the file doesn't exist
317
-				return false;
318
-			} else if (!is_null($cachedState)) {
319
-				return true;
320
-			}
321
-			// need to get from server
322
-			return ($this->propfind($path) !== false);
323
-		} catch (\Exception $e) {
324
-			$this->convertException($e, $path);
325
-		}
326
-		return false;
327
-	}
328
-
329
-	/** {@inheritdoc} */
330
-	public function unlink($path) {
331
-		$this->init();
332
-		$path = $this->cleanPath($path);
333
-		$result = $this->simpleResponse('DELETE', $path, null, 204);
334
-		$this->statCache->clear($path . '/');
335
-		$this->statCache->remove($path);
336
-		return $result;
337
-	}
338
-
339
-	/** {@inheritdoc} */
340
-	public function fopen($path, $mode) {
341
-		$this->init();
342
-		$path = $this->cleanPath($path);
343
-		switch ($mode) {
344
-			case 'r':
345
-			case 'rb':
346
-				try {
347
-					$response = $this->httpClientService
348
-							->newClient()
349
-							->get($this->createBaseUri() . $this->encodePath($path), [
350
-									'auth' => [$this->user, $this->password],
351
-									'stream' => true
352
-							]);
353
-				} catch (RequestException $e) {
354
-					if ($e->getResponse() instanceof ResponseInterface
355
-						&& $e->getResponse()->getStatusCode() === 404) {
356
-						return false;
357
-					} else {
358
-						throw $e;
359
-					}
360
-				}
361
-
362
-				if ($response->getStatusCode() !== Http::STATUS_OK) {
363
-					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
364
-						throw new \OCP\Lock\LockedException($path);
365
-					} else {
366
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
367
-					}
368
-				}
369
-
370
-				return $response->getBody();
371
-			case 'w':
372
-			case 'wb':
373
-			case 'a':
374
-			case 'ab':
375
-			case 'r+':
376
-			case 'w+':
377
-			case 'wb+':
378
-			case 'a+':
379
-			case 'x':
380
-			case 'x+':
381
-			case 'c':
382
-			case 'c+':
383
-				//emulate these
384
-				$tempManager = \OC::$server->getTempManager();
385
-				if (strrpos($path, '.') !== false) {
386
-					$ext = substr($path, strrpos($path, '.'));
387
-				} else {
388
-					$ext = '';
389
-				}
390
-				if ($this->file_exists($path)) {
391
-					if (!$this->isUpdatable($path)) {
392
-						return false;
393
-					}
394
-					if ($mode === 'w' or $mode === 'w+') {
395
-						$tmpFile = $tempManager->getTemporaryFile($ext);
396
-					} else {
397
-						$tmpFile = $this->getCachedFile($path);
398
-					}
399
-				} else {
400
-					if (!$this->isCreatable(dirname($path))) {
401
-						return false;
402
-					}
403
-					$tmpFile = $tempManager->getTemporaryFile($ext);
404
-				}
405
-				$handle = fopen($tmpFile, $mode);
406
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
407
-					$this->writeBack($tmpFile, $path);
408
-				});
409
-		}
410
-	}
411
-
412
-	/**
413
-	 * @param string $tmpFile
414
-	 */
415
-	public function writeBack($tmpFile, $path) {
416
-		$this->uploadFile($tmpFile, $path);
417
-		unlink($tmpFile);
418
-	}
419
-
420
-	/** {@inheritdoc} */
421
-	public function free_space($path) {
422
-		$this->init();
423
-		$path = $this->cleanPath($path);
424
-		try {
425
-			// TODO: cacheable ?
426
-			$response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
427
-			if ($response === false) {
428
-				return FileInfo::SPACE_UNKNOWN;
429
-			}
430
-			if (isset($response['{DAV:}quota-available-bytes'])) {
431
-				return (int)$response['{DAV:}quota-available-bytes'];
432
-			} else {
433
-				return FileInfo::SPACE_UNKNOWN;
434
-			}
435
-		} catch (\Exception $e) {
436
-			return FileInfo::SPACE_UNKNOWN;
437
-		}
438
-	}
439
-
440
-	/** {@inheritdoc} */
441
-	public function touch($path, $mtime = null) {
442
-		$this->init();
443
-		if (is_null($mtime)) {
444
-			$mtime = time();
445
-		}
446
-		$path = $this->cleanPath($path);
447
-
448
-		// if file exists, update the mtime, else create a new empty file
449
-		if ($this->file_exists($path)) {
450
-			try {
451
-				$this->statCache->remove($path);
452
-				$this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
453
-				// non-owncloud clients might not have accepted the property, need to recheck it
454
-				$response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
455
-				if ($response === false) {
456
-					return false;
457
-				}
458
-				if (isset($response['{DAV:}getlastmodified'])) {
459
-					$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
460
-					if ($remoteMtime !== $mtime) {
461
-						// server has not accepted the mtime
462
-						return false;
463
-					}
464
-				}
465
-			} catch (ClientHttpException $e) {
466
-				if ($e->getHttpStatus() === 501) {
467
-					return false;
468
-				}
469
-				$this->convertException($e, $path);
470
-				return false;
471
-			} catch (\Exception $e) {
472
-				$this->convertException($e, $path);
473
-				return false;
474
-			}
475
-		} else {
476
-			$this->file_put_contents($path, '');
477
-		}
478
-		return true;
479
-	}
480
-
481
-	/**
482
-	 * @param string $path
483
-	 * @param string $data
484
-	 * @return int
485
-	 */
486
-	public function file_put_contents($path, $data) {
487
-		$path = $this->cleanPath($path);
488
-		$result = parent::file_put_contents($path, $data);
489
-		$this->statCache->remove($path);
490
-		return $result;
491
-	}
492
-
493
-	/**
494
-	 * @param string $path
495
-	 * @param string $target
496
-	 */
497
-	protected function uploadFile($path, $target) {
498
-		$this->init();
499
-
500
-		// invalidate
501
-		$target = $this->cleanPath($target);
502
-		$this->statCache->remove($target);
503
-		$source = fopen($path, 'r');
504
-
505
-		$this->httpClientService
506
-			->newClient()
507
-			->put($this->createBaseUri() . $this->encodePath($target), [
508
-				'body' => $source,
509
-				'auth' => [$this->user, $this->password]
510
-			]);
511
-
512
-		$this->removeCachedFile($target);
513
-	}
514
-
515
-	/** {@inheritdoc} */
516
-	public function rename($path1, $path2) {
517
-		$this->init();
518
-		$path1 = $this->cleanPath($path1);
519
-		$path2 = $this->cleanPath($path2);
520
-		try {
521
-			// overwrite directory ?
522
-			if ($this->is_dir($path2)) {
523
-				// needs trailing slash in destination
524
-				$path2 = rtrim($path2, '/') . '/';
525
-			}
526
-			$this->client->request(
527
-				'MOVE',
528
-				$this->encodePath($path1),
529
-				null,
530
-				[
531
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
532
-				]
533
-			);
534
-			$this->statCache->clear($path1 . '/');
535
-			$this->statCache->clear($path2 . '/');
536
-			$this->statCache->set($path1, false);
537
-			$this->statCache->set($path2, true);
538
-			$this->removeCachedFile($path1);
539
-			$this->removeCachedFile($path2);
540
-			return true;
541
-		} catch (\Exception $e) {
542
-			$this->convertException($e);
543
-		}
544
-		return false;
545
-	}
546
-
547
-	/** {@inheritdoc} */
548
-	public function copy($path1, $path2) {
549
-		$this->init();
550
-		$path1 = $this->cleanPath($path1);
551
-		$path2 = $this->cleanPath($path2);
552
-		try {
553
-			// overwrite directory ?
554
-			if ($this->is_dir($path2)) {
555
-				// needs trailing slash in destination
556
-				$path2 = rtrim($path2, '/') . '/';
557
-			}
558
-			$this->client->request(
559
-				'COPY',
560
-				$this->encodePath($path1),
561
-				null,
562
-				[
563
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
564
-				]
565
-			);
566
-			$this->statCache->clear($path2 . '/');
567
-			$this->statCache->set($path2, true);
568
-			$this->removeCachedFile($path2);
569
-			return true;
570
-		} catch (\Exception $e) {
571
-			$this->convertException($e);
572
-		}
573
-		return false;
574
-	}
575
-
576
-	/** {@inheritdoc} */
577
-	public function stat($path) {
578
-		try {
579
-			$response = $this->propfind($path);
580
-			if (!$response) {
581
-				return false;
582
-			}
583
-			return [
584
-				'mtime' => strtotime($response['{DAV:}getlastmodified']),
585
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
586
-			];
587
-		} catch (\Exception $e) {
588
-			$this->convertException($e, $path);
589
-		}
590
-		return array();
591
-	}
592
-
593
-	/** {@inheritdoc} */
594
-	public function getMimeType($path) {
595
-		try {
596
-			$response = $this->propfind($path);
597
-			if ($response === false) {
598
-				return false;
599
-			}
600
-			$responseType = [];
601
-			if (isset($response["{DAV:}resourcetype"])) {
602
-				/** @var ResourceType[] $response */
603
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
604
-			}
605
-			$type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
606
-			if ($type == 'dir') {
607
-				return 'httpd/unix-directory';
608
-			} elseif (isset($response['{DAV:}getcontenttype'])) {
609
-				return $response['{DAV:}getcontenttype'];
610
-			} else {
611
-				return false;
612
-			}
613
-		} catch (\Exception $e) {
614
-			$this->convertException($e, $path);
615
-		}
616
-		return false;
617
-	}
618
-
619
-	/**
620
-	 * @param string $path
621
-	 * @return string
622
-	 */
623
-	public function cleanPath($path) {
624
-		if ($path === '') {
625
-			return $path;
626
-		}
627
-		$path = Filesystem::normalizePath($path);
628
-		// remove leading slash
629
-		return substr($path, 1);
630
-	}
631
-
632
-	/**
633
-	 * URL encodes the given path but keeps the slashes
634
-	 *
635
-	 * @param string $path to encode
636
-	 * @return string encoded path
637
-	 */
638
-	protected function encodePath($path) {
639
-		// slashes need to stay
640
-		return str_replace('%2F', '/', rawurlencode($path));
641
-	}
642
-
643
-	/**
644
-	 * @param string $method
645
-	 * @param string $path
646
-	 * @param string|resource|null $body
647
-	 * @param int $expected
648
-	 * @return bool
649
-	 * @throws StorageInvalidException
650
-	 * @throws StorageNotAvailableException
651
-	 */
652
-	protected function simpleResponse($method, $path, $body, $expected) {
653
-		$path = $this->cleanPath($path);
654
-		try {
655
-			$response = $this->client->request($method, $this->encodePath($path), $body);
656
-			return $response['statusCode'] == $expected;
657
-		} catch (ClientHttpException $e) {
658
-			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
659
-				$this->statCache->clear($path . '/');
660
-				$this->statCache->set($path, false);
661
-				return false;
662
-			}
663
-
664
-			$this->convertException($e, $path);
665
-		} catch (\Exception $e) {
666
-			$this->convertException($e, $path);
667
-		}
668
-		return false;
669
-	}
670
-
671
-	/**
672
-	 * check if curl is installed
673
-	 */
674
-	public static function checkDependencies() {
675
-		return true;
676
-	}
677
-
678
-	/** {@inheritdoc} */
679
-	public function isUpdatable($path) {
680
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
681
-	}
682
-
683
-	/** {@inheritdoc} */
684
-	public function isCreatable($path) {
685
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
686
-	}
687
-
688
-	/** {@inheritdoc} */
689
-	public function isSharable($path) {
690
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
691
-	}
692
-
693
-	/** {@inheritdoc} */
694
-	public function isDeletable($path) {
695
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
696
-	}
697
-
698
-	/** {@inheritdoc} */
699
-	public function getPermissions($path) {
700
-		$this->init();
701
-		$path = $this->cleanPath($path);
702
-		$response = $this->propfind($path);
703
-		if ($response === false) {
704
-			return 0;
705
-		}
706
-		if (isset($response['{http://owncloud.org/ns}permissions'])) {
707
-			return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
708
-		} else if ($this->is_dir($path)) {
709
-			return Constants::PERMISSION_ALL;
710
-		} else if ($this->file_exists($path)) {
711
-			return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
712
-		} else {
713
-			return 0;
714
-		}
715
-	}
716
-
717
-	/** {@inheritdoc} */
718
-	public function getETag($path) {
719
-		$this->init();
720
-		$path = $this->cleanPath($path);
721
-		$response = $this->propfind($path);
722
-		if ($response === false) {
723
-			return null;
724
-		}
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 ($response === false) {
769
-				if ($path === '') {
770
-					// if root is gone it means the storage is not available
771
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
772
-				}
773
-				return false;
774
-			}
775
-			if (isset($response['{DAV:}getetag'])) {
776
-				$cachedData = $this->getCache()->get($path);
777
-				$etag = null;
778
-				if (isset($response['{DAV:}getetag'])) {
779
-					$etag = trim($response['{DAV:}getetag'], '"');
780
-				}
781
-				if (!empty($etag) && $cachedData['etag'] !== $etag) {
782
-					return true;
783
-				} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
784
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
785
-					return $sharePermissions !== $cachedData['permissions'];
786
-				} else if (isset($response['{http://owncloud.org/ns}permissions'])) {
787
-					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
788
-					return $permissions !== $cachedData['permissions'];
789
-				} else {
790
-					return false;
791
-				}
792
-			} else {
793
-				$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
794
-				return $remoteMtime > $time;
795
-			}
796
-		} catch (ClientHttpException $e) {
797
-			if ($e->getHttpStatus() === 405) {
798
-				if ($path === '') {
799
-					// if root is gone it means the storage is not available
800
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
801
-				}
802
-				return false;
803
-			}
804
-			$this->convertException($e, $path);
805
-			return false;
806
-		} catch (\Exception $e) {
807
-			$this->convertException($e, $path);
808
-			return false;
809
-		}
810
-	}
811
-
812
-	/**
813
-	 * Interpret the given exception and decide whether it is due to an
814
-	 * unavailable storage, invalid storage or other.
815
-	 * This will either throw StorageInvalidException, StorageNotAvailableException
816
-	 * or do nothing.
817
-	 *
818
-	 * @param Exception $e sabre exception
819
-	 * @param string $path optional path from the operation
820
-	 *
821
-	 * @throws StorageInvalidException if the storage is invalid, for example
822
-	 * when the authentication expired or is invalid
823
-	 * @throws StorageNotAvailableException if the storage is not available,
824
-	 * which might be temporary
825
-	 */
826
-	protected function convertException(Exception $e, $path = '') {
827
-		\OC::$server->getLogger()->logException($e);
828
-		Util::writeLog('files_external', $e->getMessage(), Util::ERROR);
829
-		if ($e instanceof ClientHttpException) {
830
-			if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
831
-				throw new \OCP\Lock\LockedException($path);
832
-			}
833
-			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
834
-				// either password was changed or was invalid all along
835
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
836
-			} else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
837
-				// ignore exception for MethodNotAllowed, false will be returned
838
-				return;
839
-			}
840
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
841
-		} else if ($e instanceof ClientException) {
842
-			// connection timeout or refused, server could be temporarily down
843
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
844
-		} else if ($e instanceof \InvalidArgumentException) {
845
-			// parse error because the server returned HTML instead of XML,
846
-			// possibly temporarily down
847
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
848
-		} else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
849
-			// rethrow
850
-			throw $e;
851
-		}
852
-
853
-		// TODO: only log for now, but in the future need to wrap/rethrow exception
854
-	}
62
+    /** @var string */
63
+    protected $password;
64
+    /** @var string */
65
+    protected $user;
66
+    /** @var string */
67
+    protected $authType;
68
+    /** @var string */
69
+    protected $host;
70
+    /** @var bool */
71
+    protected $secure;
72
+    /** @var string */
73
+    protected $root;
74
+    /** @var string */
75
+    protected $certPath;
76
+    /** @var bool */
77
+    protected $ready;
78
+    /** @var Client */
79
+    protected $client;
80
+    /** @var ArrayCache */
81
+    protected $statCache;
82
+    /** @var \OCP\Http\Client\IClientService */
83
+    protected $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['authType'])) {
101
+                $this->authType = $params['authType'];
102
+            }
103
+            if (isset($params['secure'])) {
104
+                if (is_string($params['secure'])) {
105
+                    $this->secure = ($params['secure'] === 'true');
106
+                } else {
107
+                    $this->secure = (bool)$params['secure'];
108
+                }
109
+            } else {
110
+                $this->secure = false;
111
+            }
112
+            if ($this->secure === true) {
113
+                // inject mock for testing
114
+                $certManager = \OC::$server->getCertificateManager();
115
+                if (is_null($certManager)) { //no user
116
+                    $certManager = \OC::$server->getCertificateManager(null);
117
+                }
118
+                $certPath = $certManager->getAbsoluteBundlePath();
119
+                if (file_exists($certPath)) {
120
+                    $this->certPath = $certPath;
121
+                }
122
+            }
123
+            $this->root = isset($params['root']) ? $params['root'] : '/';
124
+            if (!$this->root || $this->root[0] != '/') {
125
+                $this->root = '/' . $this->root;
126
+            }
127
+            if (substr($this->root, -1, 1) != '/') {
128
+                $this->root .= '/';
129
+            }
130
+        } else {
131
+            throw new \Exception('Invalid webdav storage configuration');
132
+        }
133
+    }
134
+
135
+    protected function init() {
136
+        if ($this->ready) {
137
+            return;
138
+        }
139
+        $this->ready = true;
140
+
141
+        $settings = [
142
+            'baseUri' => $this->createBaseUri(),
143
+            'userName' => $this->user,
144
+            'password' => $this->password,
145
+        ];
146
+        if (isset($this->authType)) {
147
+            $settings['authType'] = $this->authType;
148
+        }
149
+
150
+        $proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
151
+        if($proxy !== '') {
152
+            $settings['proxy'] = $proxy;
153
+        }
154
+
155
+        $this->client = new Client($settings);
156
+        $this->client->setThrowExceptions(true);
157
+        if ($this->secure === true && $this->certPath) {
158
+            $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
159
+        }
160
+    }
161
+
162
+    /**
163
+     * Clear the stat cache
164
+     */
165
+    public function clearStatCache() {
166
+        $this->statCache->clear();
167
+    }
168
+
169
+    /** {@inheritdoc} */
170
+    public function getId() {
171
+        return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
172
+    }
173
+
174
+    /** {@inheritdoc} */
175
+    public function createBaseUri() {
176
+        $baseUri = 'http';
177
+        if ($this->secure) {
178
+            $baseUri .= 's';
179
+        }
180
+        $baseUri .= '://' . $this->host . $this->root;
181
+        return $baseUri;
182
+    }
183
+
184
+    /** {@inheritdoc} */
185
+    public function mkdir($path) {
186
+        $this->init();
187
+        $path = $this->cleanPath($path);
188
+        $result = $this->simpleResponse('MKCOL', $path, null, 201);
189
+        if ($result) {
190
+            $this->statCache->set($path, true);
191
+        }
192
+        return $result;
193
+    }
194
+
195
+    /** {@inheritdoc} */
196
+    public function rmdir($path) {
197
+        $this->init();
198
+        $path = $this->cleanPath($path);
199
+        // FIXME: some WebDAV impl return 403 when trying to DELETE
200
+        // a non-empty folder
201
+        $result = $this->simpleResponse('DELETE', $path . '/', null, 204);
202
+        $this->statCache->clear($path . '/');
203
+        $this->statCache->remove($path);
204
+        return $result;
205
+    }
206
+
207
+    /** {@inheritdoc} */
208
+    public function opendir($path) {
209
+        $this->init();
210
+        $path = $this->cleanPath($path);
211
+        try {
212
+            $response = $this->client->propFind(
213
+                $this->encodePath($path),
214
+                ['{DAV:}href'],
215
+                1
216
+            );
217
+            if ($response === false) {
218
+                return false;
219
+            }
220
+            $content = [];
221
+            $files = array_keys($response);
222
+            array_shift($files); //the first entry is the current directory
223
+
224
+            if (!$this->statCache->hasKey($path)) {
225
+                $this->statCache->set($path, true);
226
+            }
227
+            foreach ($files as $file) {
228
+                $file = urldecode($file);
229
+                // do not store the real entry, we might not have all properties
230
+                if (!$this->statCache->hasKey($path)) {
231
+                    $this->statCache->set($file, true);
232
+                }
233
+                $file = basename($file);
234
+                $content[] = $file;
235
+            }
236
+            return IteratorDirectory::wrap($content);
237
+        } catch (\Exception $e) {
238
+            $this->convertException($e, $path);
239
+        }
240
+        return false;
241
+    }
242
+
243
+    /**
244
+     * Propfind call with cache handling.
245
+     *
246
+     * First checks if information is cached.
247
+     * If not, request it from the server then store to cache.
248
+     *
249
+     * @param string $path path to propfind
250
+     *
251
+     * @return array|boolean propfind response or false if the entry was not found
252
+     *
253
+     * @throws ClientHttpException
254
+     */
255
+    protected function propfind($path) {
256
+        $path = $this->cleanPath($path);
257
+        $cachedResponse = $this->statCache->get($path);
258
+        // we either don't know it, or we know it exists but need more details
259
+        if (is_null($cachedResponse) || $cachedResponse === true) {
260
+            $this->init();
261
+            try {
262
+                $response = $this->client->propFind(
263
+                    $this->encodePath($path),
264
+                    array(
265
+                        '{DAV:}getlastmodified',
266
+                        '{DAV:}getcontentlength',
267
+                        '{DAV:}getcontenttype',
268
+                        '{http://owncloud.org/ns}permissions',
269
+                        '{http://open-collaboration-services.org/ns}share-permissions',
270
+                        '{DAV:}resourcetype',
271
+                        '{DAV:}getetag',
272
+                    )
273
+                );
274
+                $this->statCache->set($path, $response);
275
+            } catch (ClientHttpException $e) {
276
+                if ($e->getHttpStatus() === 404) {
277
+                    $this->statCache->clear($path . '/');
278
+                    $this->statCache->set($path, false);
279
+                    return false;
280
+                }
281
+                $this->convertException($e, $path);
282
+            } catch (\Exception $e) {
283
+                $this->convertException($e, $path);
284
+            }
285
+        } else {
286
+            $response = $cachedResponse;
287
+        }
288
+        return $response;
289
+    }
290
+
291
+    /** {@inheritdoc} */
292
+    public function filetype($path) {
293
+        try {
294
+            $response = $this->propfind($path);
295
+            if ($response === false) {
296
+                return false;
297
+            }
298
+            $responseType = [];
299
+            if (isset($response["{DAV:}resourcetype"])) {
300
+                /** @var ResourceType[] $response */
301
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
302
+            }
303
+            return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
304
+        } catch (\Exception $e) {
305
+            $this->convertException($e, $path);
306
+        }
307
+        return false;
308
+    }
309
+
310
+    /** {@inheritdoc} */
311
+    public function file_exists($path) {
312
+        try {
313
+            $path = $this->cleanPath($path);
314
+            $cachedState = $this->statCache->get($path);
315
+            if ($cachedState === false) {
316
+                // we know the file doesn't exist
317
+                return false;
318
+            } else if (!is_null($cachedState)) {
319
+                return true;
320
+            }
321
+            // need to get from server
322
+            return ($this->propfind($path) !== false);
323
+        } catch (\Exception $e) {
324
+            $this->convertException($e, $path);
325
+        }
326
+        return false;
327
+    }
328
+
329
+    /** {@inheritdoc} */
330
+    public function unlink($path) {
331
+        $this->init();
332
+        $path = $this->cleanPath($path);
333
+        $result = $this->simpleResponse('DELETE', $path, null, 204);
334
+        $this->statCache->clear($path . '/');
335
+        $this->statCache->remove($path);
336
+        return $result;
337
+    }
338
+
339
+    /** {@inheritdoc} */
340
+    public function fopen($path, $mode) {
341
+        $this->init();
342
+        $path = $this->cleanPath($path);
343
+        switch ($mode) {
344
+            case 'r':
345
+            case 'rb':
346
+                try {
347
+                    $response = $this->httpClientService
348
+                            ->newClient()
349
+                            ->get($this->createBaseUri() . $this->encodePath($path), [
350
+                                    'auth' => [$this->user, $this->password],
351
+                                    'stream' => true
352
+                            ]);
353
+                } catch (RequestException $e) {
354
+                    if ($e->getResponse() instanceof ResponseInterface
355
+                        && $e->getResponse()->getStatusCode() === 404) {
356
+                        return false;
357
+                    } else {
358
+                        throw $e;
359
+                    }
360
+                }
361
+
362
+                if ($response->getStatusCode() !== Http::STATUS_OK) {
363
+                    if ($response->getStatusCode() === Http::STATUS_LOCKED) {
364
+                        throw new \OCP\Lock\LockedException($path);
365
+                    } else {
366
+                        Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
367
+                    }
368
+                }
369
+
370
+                return $response->getBody();
371
+            case 'w':
372
+            case 'wb':
373
+            case 'a':
374
+            case 'ab':
375
+            case 'r+':
376
+            case 'w+':
377
+            case 'wb+':
378
+            case 'a+':
379
+            case 'x':
380
+            case 'x+':
381
+            case 'c':
382
+            case 'c+':
383
+                //emulate these
384
+                $tempManager = \OC::$server->getTempManager();
385
+                if (strrpos($path, '.') !== false) {
386
+                    $ext = substr($path, strrpos($path, '.'));
387
+                } else {
388
+                    $ext = '';
389
+                }
390
+                if ($this->file_exists($path)) {
391
+                    if (!$this->isUpdatable($path)) {
392
+                        return false;
393
+                    }
394
+                    if ($mode === 'w' or $mode === 'w+') {
395
+                        $tmpFile = $tempManager->getTemporaryFile($ext);
396
+                    } else {
397
+                        $tmpFile = $this->getCachedFile($path);
398
+                    }
399
+                } else {
400
+                    if (!$this->isCreatable(dirname($path))) {
401
+                        return false;
402
+                    }
403
+                    $tmpFile = $tempManager->getTemporaryFile($ext);
404
+                }
405
+                $handle = fopen($tmpFile, $mode);
406
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
407
+                    $this->writeBack($tmpFile, $path);
408
+                });
409
+        }
410
+    }
411
+
412
+    /**
413
+     * @param string $tmpFile
414
+     */
415
+    public function writeBack($tmpFile, $path) {
416
+        $this->uploadFile($tmpFile, $path);
417
+        unlink($tmpFile);
418
+    }
419
+
420
+    /** {@inheritdoc} */
421
+    public function free_space($path) {
422
+        $this->init();
423
+        $path = $this->cleanPath($path);
424
+        try {
425
+            // TODO: cacheable ?
426
+            $response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
427
+            if ($response === false) {
428
+                return FileInfo::SPACE_UNKNOWN;
429
+            }
430
+            if (isset($response['{DAV:}quota-available-bytes'])) {
431
+                return (int)$response['{DAV:}quota-available-bytes'];
432
+            } else {
433
+                return FileInfo::SPACE_UNKNOWN;
434
+            }
435
+        } catch (\Exception $e) {
436
+            return FileInfo::SPACE_UNKNOWN;
437
+        }
438
+    }
439
+
440
+    /** {@inheritdoc} */
441
+    public function touch($path, $mtime = null) {
442
+        $this->init();
443
+        if (is_null($mtime)) {
444
+            $mtime = time();
445
+        }
446
+        $path = $this->cleanPath($path);
447
+
448
+        // if file exists, update the mtime, else create a new empty file
449
+        if ($this->file_exists($path)) {
450
+            try {
451
+                $this->statCache->remove($path);
452
+                $this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
453
+                // non-owncloud clients might not have accepted the property, need to recheck it
454
+                $response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
455
+                if ($response === false) {
456
+                    return false;
457
+                }
458
+                if (isset($response['{DAV:}getlastmodified'])) {
459
+                    $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
460
+                    if ($remoteMtime !== $mtime) {
461
+                        // server has not accepted the mtime
462
+                        return false;
463
+                    }
464
+                }
465
+            } catch (ClientHttpException $e) {
466
+                if ($e->getHttpStatus() === 501) {
467
+                    return false;
468
+                }
469
+                $this->convertException($e, $path);
470
+                return false;
471
+            } catch (\Exception $e) {
472
+                $this->convertException($e, $path);
473
+                return false;
474
+            }
475
+        } else {
476
+            $this->file_put_contents($path, '');
477
+        }
478
+        return true;
479
+    }
480
+
481
+    /**
482
+     * @param string $path
483
+     * @param string $data
484
+     * @return int
485
+     */
486
+    public function file_put_contents($path, $data) {
487
+        $path = $this->cleanPath($path);
488
+        $result = parent::file_put_contents($path, $data);
489
+        $this->statCache->remove($path);
490
+        return $result;
491
+    }
492
+
493
+    /**
494
+     * @param string $path
495
+     * @param string $target
496
+     */
497
+    protected function uploadFile($path, $target) {
498
+        $this->init();
499
+
500
+        // invalidate
501
+        $target = $this->cleanPath($target);
502
+        $this->statCache->remove($target);
503
+        $source = fopen($path, 'r');
504
+
505
+        $this->httpClientService
506
+            ->newClient()
507
+            ->put($this->createBaseUri() . $this->encodePath($target), [
508
+                'body' => $source,
509
+                'auth' => [$this->user, $this->password]
510
+            ]);
511
+
512
+        $this->removeCachedFile($target);
513
+    }
514
+
515
+    /** {@inheritdoc} */
516
+    public function rename($path1, $path2) {
517
+        $this->init();
518
+        $path1 = $this->cleanPath($path1);
519
+        $path2 = $this->cleanPath($path2);
520
+        try {
521
+            // overwrite directory ?
522
+            if ($this->is_dir($path2)) {
523
+                // needs trailing slash in destination
524
+                $path2 = rtrim($path2, '/') . '/';
525
+            }
526
+            $this->client->request(
527
+                'MOVE',
528
+                $this->encodePath($path1),
529
+                null,
530
+                [
531
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
532
+                ]
533
+            );
534
+            $this->statCache->clear($path1 . '/');
535
+            $this->statCache->clear($path2 . '/');
536
+            $this->statCache->set($path1, false);
537
+            $this->statCache->set($path2, true);
538
+            $this->removeCachedFile($path1);
539
+            $this->removeCachedFile($path2);
540
+            return true;
541
+        } catch (\Exception $e) {
542
+            $this->convertException($e);
543
+        }
544
+        return false;
545
+    }
546
+
547
+    /** {@inheritdoc} */
548
+    public function copy($path1, $path2) {
549
+        $this->init();
550
+        $path1 = $this->cleanPath($path1);
551
+        $path2 = $this->cleanPath($path2);
552
+        try {
553
+            // overwrite directory ?
554
+            if ($this->is_dir($path2)) {
555
+                // needs trailing slash in destination
556
+                $path2 = rtrim($path2, '/') . '/';
557
+            }
558
+            $this->client->request(
559
+                'COPY',
560
+                $this->encodePath($path1),
561
+                null,
562
+                [
563
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
564
+                ]
565
+            );
566
+            $this->statCache->clear($path2 . '/');
567
+            $this->statCache->set($path2, true);
568
+            $this->removeCachedFile($path2);
569
+            return true;
570
+        } catch (\Exception $e) {
571
+            $this->convertException($e);
572
+        }
573
+        return false;
574
+    }
575
+
576
+    /** {@inheritdoc} */
577
+    public function stat($path) {
578
+        try {
579
+            $response = $this->propfind($path);
580
+            if (!$response) {
581
+                return false;
582
+            }
583
+            return [
584
+                'mtime' => strtotime($response['{DAV:}getlastmodified']),
585
+                'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
586
+            ];
587
+        } catch (\Exception $e) {
588
+            $this->convertException($e, $path);
589
+        }
590
+        return array();
591
+    }
592
+
593
+    /** {@inheritdoc} */
594
+    public function getMimeType($path) {
595
+        try {
596
+            $response = $this->propfind($path);
597
+            if ($response === false) {
598
+                return false;
599
+            }
600
+            $responseType = [];
601
+            if (isset($response["{DAV:}resourcetype"])) {
602
+                /** @var ResourceType[] $response */
603
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
604
+            }
605
+            $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
606
+            if ($type == 'dir') {
607
+                return 'httpd/unix-directory';
608
+            } elseif (isset($response['{DAV:}getcontenttype'])) {
609
+                return $response['{DAV:}getcontenttype'];
610
+            } else {
611
+                return false;
612
+            }
613
+        } catch (\Exception $e) {
614
+            $this->convertException($e, $path);
615
+        }
616
+        return false;
617
+    }
618
+
619
+    /**
620
+     * @param string $path
621
+     * @return string
622
+     */
623
+    public function cleanPath($path) {
624
+        if ($path === '') {
625
+            return $path;
626
+        }
627
+        $path = Filesystem::normalizePath($path);
628
+        // remove leading slash
629
+        return substr($path, 1);
630
+    }
631
+
632
+    /**
633
+     * URL encodes the given path but keeps the slashes
634
+     *
635
+     * @param string $path to encode
636
+     * @return string encoded path
637
+     */
638
+    protected function encodePath($path) {
639
+        // slashes need to stay
640
+        return str_replace('%2F', '/', rawurlencode($path));
641
+    }
642
+
643
+    /**
644
+     * @param string $method
645
+     * @param string $path
646
+     * @param string|resource|null $body
647
+     * @param int $expected
648
+     * @return bool
649
+     * @throws StorageInvalidException
650
+     * @throws StorageNotAvailableException
651
+     */
652
+    protected function simpleResponse($method, $path, $body, $expected) {
653
+        $path = $this->cleanPath($path);
654
+        try {
655
+            $response = $this->client->request($method, $this->encodePath($path), $body);
656
+            return $response['statusCode'] == $expected;
657
+        } catch (ClientHttpException $e) {
658
+            if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
659
+                $this->statCache->clear($path . '/');
660
+                $this->statCache->set($path, false);
661
+                return false;
662
+            }
663
+
664
+            $this->convertException($e, $path);
665
+        } catch (\Exception $e) {
666
+            $this->convertException($e, $path);
667
+        }
668
+        return false;
669
+    }
670
+
671
+    /**
672
+     * check if curl is installed
673
+     */
674
+    public static function checkDependencies() {
675
+        return true;
676
+    }
677
+
678
+    /** {@inheritdoc} */
679
+    public function isUpdatable($path) {
680
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
681
+    }
682
+
683
+    /** {@inheritdoc} */
684
+    public function isCreatable($path) {
685
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
686
+    }
687
+
688
+    /** {@inheritdoc} */
689
+    public function isSharable($path) {
690
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
691
+    }
692
+
693
+    /** {@inheritdoc} */
694
+    public function isDeletable($path) {
695
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
696
+    }
697
+
698
+    /** {@inheritdoc} */
699
+    public function getPermissions($path) {
700
+        $this->init();
701
+        $path = $this->cleanPath($path);
702
+        $response = $this->propfind($path);
703
+        if ($response === false) {
704
+            return 0;
705
+        }
706
+        if (isset($response['{http://owncloud.org/ns}permissions'])) {
707
+            return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
708
+        } else if ($this->is_dir($path)) {
709
+            return Constants::PERMISSION_ALL;
710
+        } else if ($this->file_exists($path)) {
711
+            return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
712
+        } else {
713
+            return 0;
714
+        }
715
+    }
716
+
717
+    /** {@inheritdoc} */
718
+    public function getETag($path) {
719
+        $this->init();
720
+        $path = $this->cleanPath($path);
721
+        $response = $this->propfind($path);
722
+        if ($response === false) {
723
+            return null;
724
+        }
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 ($response === false) {
769
+                if ($path === '') {
770
+                    // if root is gone it means the storage is not available
771
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
772
+                }
773
+                return false;
774
+            }
775
+            if (isset($response['{DAV:}getetag'])) {
776
+                $cachedData = $this->getCache()->get($path);
777
+                $etag = null;
778
+                if (isset($response['{DAV:}getetag'])) {
779
+                    $etag = trim($response['{DAV:}getetag'], '"');
780
+                }
781
+                if (!empty($etag) && $cachedData['etag'] !== $etag) {
782
+                    return true;
783
+                } else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
784
+                    $sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
785
+                    return $sharePermissions !== $cachedData['permissions'];
786
+                } else if (isset($response['{http://owncloud.org/ns}permissions'])) {
787
+                    $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
788
+                    return $permissions !== $cachedData['permissions'];
789
+                } else {
790
+                    return false;
791
+                }
792
+            } else {
793
+                $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
794
+                return $remoteMtime > $time;
795
+            }
796
+        } catch (ClientHttpException $e) {
797
+            if ($e->getHttpStatus() === 405) {
798
+                if ($path === '') {
799
+                    // if root is gone it means the storage is not available
800
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
801
+                }
802
+                return false;
803
+            }
804
+            $this->convertException($e, $path);
805
+            return false;
806
+        } catch (\Exception $e) {
807
+            $this->convertException($e, $path);
808
+            return false;
809
+        }
810
+    }
811
+
812
+    /**
813
+     * Interpret the given exception and decide whether it is due to an
814
+     * unavailable storage, invalid storage or other.
815
+     * This will either throw StorageInvalidException, StorageNotAvailableException
816
+     * or do nothing.
817
+     *
818
+     * @param Exception $e sabre exception
819
+     * @param string $path optional path from the operation
820
+     *
821
+     * @throws StorageInvalidException if the storage is invalid, for example
822
+     * when the authentication expired or is invalid
823
+     * @throws StorageNotAvailableException if the storage is not available,
824
+     * which might be temporary
825
+     */
826
+    protected function convertException(Exception $e, $path = '') {
827
+        \OC::$server->getLogger()->logException($e);
828
+        Util::writeLog('files_external', $e->getMessage(), Util::ERROR);
829
+        if ($e instanceof ClientHttpException) {
830
+            if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
831
+                throw new \OCP\Lock\LockedException($path);
832
+            }
833
+            if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
834
+                // either password was changed or was invalid all along
835
+                throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
836
+            } else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
837
+                // ignore exception for MethodNotAllowed, false will be returned
838
+                return;
839
+            }
840
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
841
+        } else if ($e instanceof ClientException) {
842
+            // connection timeout or refused, server could be temporarily down
843
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
844
+        } else if ($e instanceof \InvalidArgumentException) {
845
+            // parse error because the server returned HTML instead of XML,
846
+            // possibly temporarily down
847
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
848
+        } else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
849
+            // rethrow
850
+            throw $e;
851
+        }
852
+
853
+        // TODO: only log for now, but in the future need to wrap/rethrow exception
854
+    }
855 855
 }
856 856
 
Please login to merge, or discard this patch.
Spacing   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -104,7 +104,7 @@  discard block
 block discarded – undo
104 104
 				if (is_string($params['secure'])) {
105 105
 					$this->secure = ($params['secure'] === 'true');
106 106
 				} else {
107
-					$this->secure = (bool)$params['secure'];
107
+					$this->secure = (bool) $params['secure'];
108 108
 				}
109 109
 			} else {
110 110
 				$this->secure = false;
@@ -122,7 +122,7 @@  discard block
 block discarded – undo
122 122
 			}
123 123
 			$this->root = isset($params['root']) ? $params['root'] : '/';
124 124
 			if (!$this->root || $this->root[0] != '/') {
125
-				$this->root = '/' . $this->root;
125
+				$this->root = '/'.$this->root;
126 126
 			}
127 127
 			if (substr($this->root, -1, 1) != '/') {
128 128
 				$this->root .= '/';
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
 		}
149 149
 
150 150
 		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
151
-		if($proxy !== '') {
151
+		if ($proxy !== '') {
152 152
 			$settings['proxy'] = $proxy;
153 153
 		}
154 154
 
@@ -168,7 +168,7 @@  discard block
 block discarded – undo
168 168
 
169 169
 	/** {@inheritdoc} */
170 170
 	public function getId() {
171
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
171
+		return 'webdav::'.$this->user.'@'.$this->host.'/'.$this->root;
172 172
 	}
173 173
 
174 174
 	/** {@inheritdoc} */
@@ -177,7 +177,7 @@  discard block
 block discarded – undo
177 177
 		if ($this->secure) {
178 178
 			$baseUri .= 's';
179 179
 		}
180
-		$baseUri .= '://' . $this->host . $this->root;
180
+		$baseUri .= '://'.$this->host.$this->root;
181 181
 		return $baseUri;
182 182
 	}
183 183
 
@@ -198,8 +198,8 @@  discard block
 block discarded – undo
198 198
 		$path = $this->cleanPath($path);
199 199
 		// FIXME: some WebDAV impl return 403 when trying to DELETE
200 200
 		// a non-empty folder
201
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
202
-		$this->statCache->clear($path . '/');
201
+		$result = $this->simpleResponse('DELETE', $path.'/', null, 204);
202
+		$this->statCache->clear($path.'/');
203 203
 		$this->statCache->remove($path);
204 204
 		return $result;
205 205
 	}
@@ -274,7 +274,7 @@  discard block
 block discarded – undo
274 274
 				$this->statCache->set($path, $response);
275 275
 			} catch (ClientHttpException $e) {
276 276
 				if ($e->getHttpStatus() === 404) {
277
-					$this->statCache->clear($path . '/');
277
+					$this->statCache->clear($path.'/');
278 278
 					$this->statCache->set($path, false);
279 279
 					return false;
280 280
 				}
@@ -331,7 +331,7 @@  discard block
 block discarded – undo
331 331
 		$this->init();
332 332
 		$path = $this->cleanPath($path);
333 333
 		$result = $this->simpleResponse('DELETE', $path, null, 204);
334
-		$this->statCache->clear($path . '/');
334
+		$this->statCache->clear($path.'/');
335 335
 		$this->statCache->remove($path);
336 336
 		return $result;
337 337
 	}
@@ -346,7 +346,7 @@  discard block
 block discarded – undo
346 346
 				try {
347 347
 					$response = $this->httpClientService
348 348
 							->newClient()
349
-							->get($this->createBaseUri() . $this->encodePath($path), [
349
+							->get($this->createBaseUri().$this->encodePath($path), [
350 350
 									'auth' => [$this->user, $this->password],
351 351
 									'stream' => true
352 352
 							]);
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
 					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
364 364
 						throw new \OCP\Lock\LockedException($path);
365 365
 					} else {
366
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
366
+						Util::writeLog("webdav client", 'Guzzle get returned status code '.$response->getStatusCode(), Util::ERROR);
367 367
 					}
368 368
 				}
369 369
 
@@ -403,7 +403,7 @@  discard block
 block discarded – undo
403 403
 					$tmpFile = $tempManager->getTemporaryFile($ext);
404 404
 				}
405 405
 				$handle = fopen($tmpFile, $mode);
406
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
406
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
407 407
 					$this->writeBack($tmpFile, $path);
408 408
 				});
409 409
 		}
@@ -428,7 +428,7 @@  discard block
 block discarded – undo
428 428
 				return FileInfo::SPACE_UNKNOWN;
429 429
 			}
430 430
 			if (isset($response['{DAV:}quota-available-bytes'])) {
431
-				return (int)$response['{DAV:}quota-available-bytes'];
431
+				return (int) $response['{DAV:}quota-available-bytes'];
432 432
 			} else {
433 433
 				return FileInfo::SPACE_UNKNOWN;
434 434
 			}
@@ -504,7 +504,7 @@  discard block
 block discarded – undo
504 504
 
505 505
 		$this->httpClientService
506 506
 			->newClient()
507
-			->put($this->createBaseUri() . $this->encodePath($target), [
507
+			->put($this->createBaseUri().$this->encodePath($target), [
508 508
 				'body' => $source,
509 509
 				'auth' => [$this->user, $this->password]
510 510
 			]);
@@ -521,18 +521,18 @@  discard block
 block discarded – undo
521 521
 			// overwrite directory ?
522 522
 			if ($this->is_dir($path2)) {
523 523
 				// needs trailing slash in destination
524
-				$path2 = rtrim($path2, '/') . '/';
524
+				$path2 = rtrim($path2, '/').'/';
525 525
 			}
526 526
 			$this->client->request(
527 527
 				'MOVE',
528 528
 				$this->encodePath($path1),
529 529
 				null,
530 530
 				[
531
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
531
+					'Destination' => $this->createBaseUri().$this->encodePath($path2),
532 532
 				]
533 533
 			);
534
-			$this->statCache->clear($path1 . '/');
535
-			$this->statCache->clear($path2 . '/');
534
+			$this->statCache->clear($path1.'/');
535
+			$this->statCache->clear($path2.'/');
536 536
 			$this->statCache->set($path1, false);
537 537
 			$this->statCache->set($path2, true);
538 538
 			$this->removeCachedFile($path1);
@@ -553,17 +553,17 @@  discard block
 block discarded – undo
553 553
 			// overwrite directory ?
554 554
 			if ($this->is_dir($path2)) {
555 555
 				// needs trailing slash in destination
556
-				$path2 = rtrim($path2, '/') . '/';
556
+				$path2 = rtrim($path2, '/').'/';
557 557
 			}
558 558
 			$this->client->request(
559 559
 				'COPY',
560 560
 				$this->encodePath($path1),
561 561
 				null,
562 562
 				[
563
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
563
+					'Destination' => $this->createBaseUri().$this->encodePath($path2),
564 564
 				]
565 565
 			);
566
-			$this->statCache->clear($path2 . '/');
566
+			$this->statCache->clear($path2.'/');
567 567
 			$this->statCache->set($path2, true);
568 568
 			$this->removeCachedFile($path2);
569 569
 			return true;
@@ -582,7 +582,7 @@  discard block
 block discarded – undo
582 582
 			}
583 583
 			return [
584 584
 				'mtime' => strtotime($response['{DAV:}getlastmodified']),
585
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
585
+				'size' => (int) isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
586 586
 			];
587 587
 		} catch (\Exception $e) {
588 588
 			$this->convertException($e, $path);
@@ -656,7 +656,7 @@  discard block
 block discarded – undo
656 656
 			return $response['statusCode'] == $expected;
657 657
 		} catch (ClientHttpException $e) {
658 658
 			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
659
-				$this->statCache->clear($path . '/');
659
+				$this->statCache->clear($path.'/');
660 660
 				$this->statCache->set($path, false);
661 661
 				return false;
662 662
 			}
@@ -677,22 +677,22 @@  discard block
 block discarded – undo
677 677
 
678 678
 	/** {@inheritdoc} */
679 679
 	public function isUpdatable($path) {
680
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
680
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
681 681
 	}
682 682
 
683 683
 	/** {@inheritdoc} */
684 684
 	public function isCreatable($path) {
685
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
685
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_CREATE);
686 686
 	}
687 687
 
688 688
 	/** {@inheritdoc} */
689 689
 	public function isSharable($path) {
690
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
690
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_SHARE);
691 691
 	}
692 692
 
693 693
 	/** {@inheritdoc} */
694 694
 	public function isDeletable($path) {
695
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
695
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_DELETE);
696 696
 	}
697 697
 
698 698
 	/** {@inheritdoc} */
@@ -768,7 +768,7 @@  discard block
 block discarded – undo
768 768
 			if ($response === false) {
769 769
 				if ($path === '') {
770 770
 					// if root is gone it means the storage is not available
771
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
771
+					throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
772 772
 				}
773 773
 				return false;
774 774
 			}
@@ -781,7 +781,7 @@  discard block
 block discarded – undo
781 781
 				if (!empty($etag) && $cachedData['etag'] !== $etag) {
782 782
 					return true;
783 783
 				} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
784
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
784
+					$sharePermissions = (int) $response['{http://open-collaboration-services.org/ns}share-permissions'];
785 785
 					return $sharePermissions !== $cachedData['permissions'];
786 786
 				} else if (isset($response['{http://owncloud.org/ns}permissions'])) {
787 787
 					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
@@ -797,7 +797,7 @@  discard block
 block discarded – undo
797 797
 			if ($e->getHttpStatus() === 405) {
798 798
 				if ($path === '') {
799 799
 					// if root is gone it means the storage is not available
800
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
800
+					throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
801 801
 				}
802 802
 				return false;
803 803
 			}
@@ -832,19 +832,19 @@  discard block
 block discarded – undo
832 832
 			}
833 833
 			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
834 834
 				// either password was changed or was invalid all along
835
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
835
+				throw new StorageInvalidException(get_class($e).': '.$e->getMessage());
836 836
 			} else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
837 837
 				// ignore exception for MethodNotAllowed, false will be returned
838 838
 				return;
839 839
 			}
840
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
840
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
841 841
 		} else if ($e instanceof ClientException) {
842 842
 			// connection timeout or refused, server could be temporarily down
843
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
843
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
844 844
 		} else if ($e instanceof \InvalidArgumentException) {
845 845
 			// parse error because the server returned HTML instead of XML,
846 846
 			// possibly temporarily down
847
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
847
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
848 848
 		} else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
849 849
 			// rethrow
850 850
 			throw $e;
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Notify/SMBNotifyHandler.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -102,7 +102,7 @@
 block discarded – undo
102 102
 
103 103
 	/**
104 104
 	 * @param \Icewind\SMB\Change $change
105
-	 * @return IChange|null
105
+	 * @return null|Change
106 106
 	 */
107 107
 	private function mapChange(\Icewind\SMB\Change $change) {
108 108
 		$path = $this->relativePath($change->getPath());
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -29,122 +29,122 @@
 block discarded – undo
29 29
 use OCP\Files\Notify\INotifyHandler;
30 30
 
31 31
 class SMBNotifyHandler implements INotifyHandler {
32
-	/**
33
-	 * @var \Icewind\SMB\INotifyHandler
34
-	 */
35
-	private $shareNotifyHandler;
32
+    /**
33
+     * @var \Icewind\SMB\INotifyHandler
34
+     */
35
+    private $shareNotifyHandler;
36 36
 
37
-	/**
38
-	 * @var string
39
-	 */
40
-	private $root;
37
+    /**
38
+     * @var string
39
+     */
40
+    private $root;
41 41
 
42
-	private $oldRenamePath = null;
42
+    private $oldRenamePath = null;
43 43
 
44
-	/**
45
-	 * SMBNotifyHandler constructor.
46
-	 *
47
-	 * @param \Icewind\SMB\INotifyHandler $shareNotifyHandler
48
-	 * @param string $root
49
-	 */
50
-	public function __construct(\Icewind\SMB\INotifyHandler $shareNotifyHandler, $root) {
51
-		$this->shareNotifyHandler = $shareNotifyHandler;
52
-		$this->root = $root;
53
-	}
44
+    /**
45
+     * SMBNotifyHandler constructor.
46
+     *
47
+     * @param \Icewind\SMB\INotifyHandler $shareNotifyHandler
48
+     * @param string $root
49
+     */
50
+    public function __construct(\Icewind\SMB\INotifyHandler $shareNotifyHandler, $root) {
51
+        $this->shareNotifyHandler = $shareNotifyHandler;
52
+        $this->root = $root;
53
+    }
54 54
 
55
-	private function relativePath($fullPath) {
56
-		if ($fullPath === $this->root) {
57
-			return '';
58
-		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
59
-			return substr($fullPath, strlen($this->root));
60
-		} else {
61
-			return null;
62
-		}
63
-	}
55
+    private function relativePath($fullPath) {
56
+        if ($fullPath === $this->root) {
57
+            return '';
58
+        } else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
59
+            return substr($fullPath, strlen($this->root));
60
+        } else {
61
+            return null;
62
+        }
63
+    }
64 64
 
65
-	public function listen(callable $callback) {
66
-		$oldRenamePath = null;
67
-		$this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
68
-			$change = $this->mapChange($shareChange);
69
-			if (!is_null($change)) {
70
-				return $callback($change);
71
-			} else {
72
-				return true;
73
-			}
74
-		});
75
-	}
65
+    public function listen(callable $callback) {
66
+        $oldRenamePath = null;
67
+        $this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
68
+            $change = $this->mapChange($shareChange);
69
+            if (!is_null($change)) {
70
+                return $callback($change);
71
+            } else {
72
+                return true;
73
+            }
74
+        });
75
+    }
76 76
 
77
-	/**
78
-	 * Get all changes detected since the start of the notify process or the last call to getChanges
79
-	 *
80
-	 * @return IChange[]
81
-	 */
82
-	public function getChanges() {
83
-		$shareChanges = $this->shareNotifyHandler->getChanges();
84
-		$changes = [];
85
-		foreach ($shareChanges as $shareChange) {
86
-			$change = $this->mapChange($shareChange);
87
-			if ($change) {
88
-				$changes[] = $change;
89
-			}
90
-		}
91
-		return $changes;
92
-	}
77
+    /**
78
+     * Get all changes detected since the start of the notify process or the last call to getChanges
79
+     *
80
+     * @return IChange[]
81
+     */
82
+    public function getChanges() {
83
+        $shareChanges = $this->shareNotifyHandler->getChanges();
84
+        $changes = [];
85
+        foreach ($shareChanges as $shareChange) {
86
+            $change = $this->mapChange($shareChange);
87
+            if ($change) {
88
+                $changes[] = $change;
89
+            }
90
+        }
91
+        return $changes;
92
+    }
93 93
 
94
-	/**
95
-	 * Stop listening for changes
96
-	 *
97
-	 * Note that any pending changes will be discarded
98
-	 */
99
-	public function stop() {
100
-		$this->shareNotifyHandler->stop();
101
-	}
94
+    /**
95
+     * Stop listening for changes
96
+     *
97
+     * Note that any pending changes will be discarded
98
+     */
99
+    public function stop() {
100
+        $this->shareNotifyHandler->stop();
101
+    }
102 102
 
103
-	/**
104
-	 * @param \Icewind\SMB\Change $change
105
-	 * @return IChange|null
106
-	 */
107
-	private function mapChange(\Icewind\SMB\Change $change) {
108
-		$path = $this->relativePath($change->getPath());
109
-		if (is_null($path)) {
110
-			return null;
111
-		}
112
-		if ($change->getCode() === \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_OLD) {
113
-			$this->oldRenamePath = $path;
114
-			return null;
115
-		}
116
-		$type = $this->mapNotifyType($change->getCode());
117
-		if (is_null($type)) {
118
-			return null;
119
-		}
120
-		if ($type === IChange::RENAMED) {
121
-			if (!is_null($this->oldRenamePath)) {
122
-				$result = new RenameChange($type, $this->oldRenamePath, $path);
123
-				$this->oldRenamePath = null;
124
-			} else {
125
-				$result = null;
126
-			}
127
-		} else {
128
-			$result = new Change($type, $path);
129
-		}
130
-		return $result;
131
-	}
103
+    /**
104
+     * @param \Icewind\SMB\Change $change
105
+     * @return IChange|null
106
+     */
107
+    private function mapChange(\Icewind\SMB\Change $change) {
108
+        $path = $this->relativePath($change->getPath());
109
+        if (is_null($path)) {
110
+            return null;
111
+        }
112
+        if ($change->getCode() === \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_OLD) {
113
+            $this->oldRenamePath = $path;
114
+            return null;
115
+        }
116
+        $type = $this->mapNotifyType($change->getCode());
117
+        if (is_null($type)) {
118
+            return null;
119
+        }
120
+        if ($type === IChange::RENAMED) {
121
+            if (!is_null($this->oldRenamePath)) {
122
+                $result = new RenameChange($type, $this->oldRenamePath, $path);
123
+                $this->oldRenamePath = null;
124
+            } else {
125
+                $result = null;
126
+            }
127
+        } else {
128
+            $result = new Change($type, $path);
129
+        }
130
+        return $result;
131
+    }
132 132
 
133
-	private function mapNotifyType($smbType) {
134
-		switch ($smbType) {
135
-			case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED:
136
-				return IChange::ADDED;
137
-			case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED:
138
-				return IChange::REMOVED;
139
-			case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED:
140
-			case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED_STREAM:
141
-			case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED_STREAM:
142
-			case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED_STREAM:
143
-				return IChange::MODIFIED;
144
-			case \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_NEW:
145
-				return IChange::RENAMED;
146
-			default:
147
-				return null;
148
-		}
149
-	}
133
+    private function mapNotifyType($smbType) {
134
+        switch ($smbType) {
135
+            case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED:
136
+                return IChange::ADDED;
137
+            case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED:
138
+                return IChange::REMOVED;
139
+            case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED:
140
+            case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED_STREAM:
141
+            case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED_STREAM:
142
+            case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED_STREAM:
143
+                return IChange::MODIFIED;
144
+            case \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_NEW:
145
+                return IChange::RENAMED;
146
+            default:
147
+                return null;
148
+        }
149
+    }
150 150
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@
 block discarded – undo
64 64
 
65 65
 	public function listen(callable $callback) {
66 66
 		$oldRenamePath = null;
67
-		$this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
67
+		$this->shareNotifyHandler->listen(function(\Icewind\SMB\Change $shareChange) use ($callback) {
68 68
 			$change = $this->mapChange($shareChange);
69 69
 			if (!is_null($change)) {
70 70
 				return $callback($change);
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/SMB.php 4 patches
Unused Use Statements   -3 removed lines patch added patch discarded remove patch
@@ -31,14 +31,11 @@
 block discarded – undo
31 31
 
32 32
 namespace OCA\Files_External\Lib\Storage;
33 33
 
34
-use Icewind\SMB\Change;
35 34
 use Icewind\SMB\Exception\ConnectException;
36 35
 use Icewind\SMB\Exception\Exception;
37 36
 use Icewind\SMB\Exception\ForbiddenException;
38 37
 use Icewind\SMB\Exception\NotFoundException;
39
-use Icewind\SMB\INotifyHandler;
40 38
 use Icewind\SMB\IFileInfo;
41
-use Icewind\SMB\IShare;
42 39
 use Icewind\SMB\NativeServer;
43 40
 use Icewind\SMB\Server;
44 41
 use Icewind\Streams\CallbackWrapper;
Please login to merge, or discard this patch.
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -498,6 +498,9 @@
 block discarded – undo
498 498
 		});
499 499
 	}
500 500
 
501
+	/**
502
+	 * @param string $path
503
+	 */
501 504
 	public function notify($path) {
502 505
 		$path = '/' . ltrim($path, '/');
503 506
 		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
Please login to merge, or discard this patch.
Indentation   +450 added lines, -450 removed lines patch added patch discarded remove patch
@@ -53,454 +53,454 @@
 block discarded – undo
53 53
 use OCP\Files\StorageNotAvailableException;
54 54
 
55 55
 class SMB extends Common implements INotifyStorage {
56
-	/**
57
-	 * @var \Icewind\SMB\Server
58
-	 */
59
-	protected $server;
60
-
61
-	/**
62
-	 * @var \Icewind\SMB\Share
63
-	 */
64
-	protected $share;
65
-
66
-	/**
67
-	 * @var string
68
-	 */
69
-	protected $root;
70
-
71
-	/**
72
-	 * @var \Icewind\SMB\FileInfo[]
73
-	 */
74
-	protected $statCache;
75
-
76
-	public function __construct($params) {
77
-		if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
78
-			if (Server::NativeAvailable()) {
79
-				$this->server = new NativeServer($params['host'], $params['user'], $params['password']);
80
-			} else {
81
-				$this->server = new Server($params['host'], $params['user'], $params['password']);
82
-			}
83
-			$this->share = $this->server->getShare(trim($params['share'], '/'));
84
-
85
-			$this->root = isset($params['root']) ? $params['root'] : '/';
86
-			if (!$this->root || $this->root[0] != '/') {
87
-				$this->root = '/' . $this->root;
88
-			}
89
-			if (substr($this->root, -1, 1) != '/') {
90
-				$this->root .= '/';
91
-			}
92
-		} else {
93
-			throw new \Exception('Invalid configuration');
94
-		}
95
-		$this->statCache = new CappedMemoryCache();
96
-	}
97
-
98
-	/**
99
-	 * @return string
100
-	 */
101
-	public function getId() {
102
-		// FIXME: double slash to keep compatible with the old storage ids,
103
-		// failure to do so will lead to creation of a new storage id and
104
-		// loss of shares from the storage
105
-		return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
106
-	}
107
-
108
-	/**
109
-	 * @param string $path
110
-	 * @return string
111
-	 */
112
-	protected function buildPath($path) {
113
-		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
114
-	}
115
-
116
-	protected function relativePath($fullPath) {
117
-		if ($fullPath === $this->root) {
118
-			return '';
119
-		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
120
-			return substr($fullPath, strlen($this->root));
121
-		} else {
122
-			return null;
123
-		}
124
-	}
125
-
126
-	/**
127
-	 * @param string $path
128
-	 * @return \Icewind\SMB\IFileInfo
129
-	 * @throws StorageNotAvailableException
130
-	 */
131
-	protected function getFileInfo($path) {
132
-		try {
133
-			$path = $this->buildPath($path);
134
-			if (!isset($this->statCache[$path])) {
135
-				$this->statCache[$path] = $this->share->stat($path);
136
-			}
137
-			return $this->statCache[$path];
138
-		} catch (ConnectException $e) {
139
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
140
-		}
141
-	}
142
-
143
-	/**
144
-	 * @param string $path
145
-	 * @return \Icewind\SMB\IFileInfo[]
146
-	 * @throws StorageNotAvailableException
147
-	 */
148
-	protected function getFolderContents($path) {
149
-		try {
150
-			$path = $this->buildPath($path);
151
-			$files = $this->share->dir($path);
152
-			foreach ($files as $file) {
153
-				$this->statCache[$path . '/' . $file->getName()] = $file;
154
-			}
155
-			return array_filter($files, function (IFileInfo $file) {
156
-				return !$file->isHidden();
157
-			});
158
-		} catch (ConnectException $e) {
159
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
160
-		}
161
-	}
162
-
163
-	/**
164
-	 * @param \Icewind\SMB\IFileInfo $info
165
-	 * @return array
166
-	 */
167
-	protected function formatInfo($info) {
168
-		return array(
169
-			'size' => $info->getSize(),
170
-			'mtime' => $info->getMTime()
171
-		);
172
-	}
173
-
174
-	/**
175
-	 * @param string $path
176
-	 * @return array
177
-	 */
178
-	public function stat($path) {
179
-		$result = $this->formatInfo($this->getFileInfo($path));
180
-		if ($this->remoteIsShare() && $this->isRootDir($path)) {
181
-			$result['mtime'] = $this->shareMTime();
182
-		}
183
-		return $result;
184
-	}
185
-
186
-	/**
187
-	 * get the best guess for the modification time of the share
188
-	 *
189
-	 * @return int
190
-	 */
191
-	private function shareMTime() {
192
-		$highestMTime = 0;
193
-		$files = $this->share->dir($this->root);
194
-		foreach ($files as $fileInfo) {
195
-			if ($fileInfo->getMTime() > $highestMTime) {
196
-				$highestMTime = $fileInfo->getMTime();
197
-			}
198
-		}
199
-		return $highestMTime;
200
-	}
201
-
202
-	/**
203
-	 * Check if the path is our root dir (not the smb one)
204
-	 *
205
-	 * @param string $path the path
206
-	 * @return bool
207
-	 */
208
-	private function isRootDir($path) {
209
-		return $path === '' || $path === '/' || $path === '.';
210
-	}
211
-
212
-	/**
213
-	 * Check if our root points to a smb share
214
-	 *
215
-	 * @return bool true if our root points to a share false otherwise
216
-	 */
217
-	private function remoteIsShare() {
218
-		return $this->share->getName() && (!$this->root || $this->root === '/');
219
-	}
220
-
221
-	/**
222
-	 * @param string $path
223
-	 * @return bool
224
-	 */
225
-	public function unlink($path) {
226
-		try {
227
-			if ($this->is_dir($path)) {
228
-				return $this->rmdir($path);
229
-			} else {
230
-				$path = $this->buildPath($path);
231
-				unset($this->statCache[$path]);
232
-				$this->share->del($path);
233
-				return true;
234
-			}
235
-		} catch (NotFoundException $e) {
236
-			return false;
237
-		} catch (ForbiddenException $e) {
238
-			return false;
239
-		} catch (ConnectException $e) {
240
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
241
-		}
242
-	}
243
-
244
-	/**
245
-	 * @param string $path1 the old name
246
-	 * @param string $path2 the new name
247
-	 * @return bool
248
-	 */
249
-	public function rename($path1, $path2) {
250
-		try {
251
-			$this->remove($path2);
252
-			$path1 = $this->buildPath($path1);
253
-			$path2 = $this->buildPath($path2);
254
-			return $this->share->rename($path1, $path2);
255
-		} catch (NotFoundException $e) {
256
-			return false;
257
-		} catch (ForbiddenException $e) {
258
-			return false;
259
-		} catch (ConnectException $e) {
260
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
261
-		}
262
-	}
263
-
264
-	/**
265
-	 * check if a file or folder has been updated since $time
266
-	 *
267
-	 * @param string $path
268
-	 * @param int $time
269
-	 * @return bool
270
-	 */
271
-	public function hasUpdated($path, $time) {
272
-		if (!$path and $this->root == '/') {
273
-			// mtime doesn't work for shares, but giving the nature of the backend,
274
-			// doing a full update is still just fast enough
275
-			return true;
276
-		} else {
277
-			$actualTime = $this->filemtime($path);
278
-			return $actualTime > $time;
279
-		}
280
-	}
281
-
282
-	/**
283
-	 * @param string $path
284
-	 * @param string $mode
285
-	 * @return resource|false
286
-	 */
287
-	public function fopen($path, $mode) {
288
-		$fullPath = $this->buildPath($path);
289
-		try {
290
-			switch ($mode) {
291
-				case 'r':
292
-				case 'rb':
293
-					if (!$this->file_exists($path)) {
294
-						return false;
295
-					}
296
-					return $this->share->read($fullPath);
297
-				case 'w':
298
-				case 'wb':
299
-					$source = $this->share->write($fullPath);
300
-					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
301
-						unset($this->statCache[$fullPath]);
302
-					});
303
-				case 'a':
304
-				case 'ab':
305
-				case 'r+':
306
-				case 'w+':
307
-				case 'wb+':
308
-				case 'a+':
309
-				case 'x':
310
-				case 'x+':
311
-				case 'c':
312
-				case 'c+':
313
-					//emulate these
314
-					if (strrpos($path, '.') !== false) {
315
-						$ext = substr($path, strrpos($path, '.'));
316
-					} else {
317
-						$ext = '';
318
-					}
319
-					if ($this->file_exists($path)) {
320
-						if (!$this->isUpdatable($path)) {
321
-							return false;
322
-						}
323
-						$tmpFile = $this->getCachedFile($path);
324
-					} else {
325
-						if (!$this->isCreatable(dirname($path))) {
326
-							return false;
327
-						}
328
-						$tmpFile = \OCP\Files::tmpFile($ext);
329
-					}
330
-					$source = fopen($tmpFile, $mode);
331
-					$share = $this->share;
332
-					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
333
-						unset($this->statCache[$fullPath]);
334
-						$share->put($tmpFile, $fullPath);
335
-						unlink($tmpFile);
336
-					});
337
-			}
338
-			return false;
339
-		} catch (NotFoundException $e) {
340
-			return false;
341
-		} catch (ForbiddenException $e) {
342
-			return false;
343
-		} catch (ConnectException $e) {
344
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
345
-		}
346
-	}
347
-
348
-	public function rmdir($path) {
349
-		try {
350
-			$this->statCache = array();
351
-			$content = $this->share->dir($this->buildPath($path));
352
-			foreach ($content as $file) {
353
-				if ($file->isDirectory()) {
354
-					$this->rmdir($path . '/' . $file->getName());
355
-				} else {
356
-					$this->share->del($file->getPath());
357
-				}
358
-			}
359
-			$this->share->rmdir($this->buildPath($path));
360
-			return true;
361
-		} catch (NotFoundException $e) {
362
-			return false;
363
-		} catch (ForbiddenException $e) {
364
-			return false;
365
-		} catch (ConnectException $e) {
366
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
367
-		}
368
-	}
369
-
370
-	public function touch($path, $time = null) {
371
-		try {
372
-			if (!$this->file_exists($path)) {
373
-				$fh = $this->share->write($this->buildPath($path));
374
-				fclose($fh);
375
-				return true;
376
-			}
377
-			return false;
378
-		} catch (ConnectException $e) {
379
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
380
-		}
381
-	}
382
-
383
-	public function opendir($path) {
384
-		try {
385
-			$files = $this->getFolderContents($path);
386
-		} catch (NotFoundException $e) {
387
-			return false;
388
-		} catch (ForbiddenException $e) {
389
-			return false;
390
-		}
391
-		$names = array_map(function ($info) {
392
-			/** @var \Icewind\SMB\IFileInfo $info */
393
-			return $info->getName();
394
-		}, $files);
395
-		return IteratorDirectory::wrap($names);
396
-	}
397
-
398
-	public function filetype($path) {
399
-		try {
400
-			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
401
-		} catch (NotFoundException $e) {
402
-			return false;
403
-		} catch (ForbiddenException $e) {
404
-			return false;
405
-		}
406
-	}
407
-
408
-	public function mkdir($path) {
409
-		$path = $this->buildPath($path);
410
-		try {
411
-			$this->share->mkdir($path);
412
-			return true;
413
-		} catch (ConnectException $e) {
414
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
415
-		} catch (Exception $e) {
416
-			return false;
417
-		}
418
-	}
419
-
420
-	public function file_exists($path) {
421
-		try {
422
-			$this->getFileInfo($path);
423
-			return true;
424
-		} catch (NotFoundException $e) {
425
-			return false;
426
-		} catch (ForbiddenException $e) {
427
-			return false;
428
-		} catch (ConnectException $e) {
429
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
430
-		}
431
-	}
432
-
433
-	public function isReadable($path) {
434
-		try {
435
-			$info = $this->getFileInfo($path);
436
-			return !$info->isHidden();
437
-		} catch (NotFoundException $e) {
438
-			return false;
439
-		} catch (ForbiddenException $e) {
440
-			return false;
441
-		}
442
-	}
443
-
444
-	public function isUpdatable($path) {
445
-		try {
446
-			$info = $this->getFileInfo($path);
447
-			// following windows behaviour for read-only folders: they can be written into
448
-			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
449
-			return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
450
-		} catch (NotFoundException $e) {
451
-			return false;
452
-		} catch (ForbiddenException $e) {
453
-			return false;
454
-		}
455
-	}
456
-
457
-	public function isDeletable($path) {
458
-		try {
459
-			$info = $this->getFileInfo($path);
460
-			return !$info->isHidden() && !$info->isReadOnly();
461
-		} catch (NotFoundException $e) {
462
-			return false;
463
-		} catch (ForbiddenException $e) {
464
-			return false;
465
-		}
466
-	}
467
-
468
-	/**
469
-	 * check if smbclient is installed
470
-	 */
471
-	public static function checkDependencies() {
472
-		return (
473
-			(bool)\OC_Helper::findBinaryPath('smbclient')
474
-			|| Server::NativeAvailable()
475
-		) ? true : ['smbclient'];
476
-	}
477
-
478
-	/**
479
-	 * Test a storage for availability
480
-	 *
481
-	 * @return bool
482
-	 */
483
-	public function test() {
484
-		try {
485
-			return parent::test();
486
-		} catch (Exception $e) {
487
-			return false;
488
-		}
489
-	}
490
-
491
-	public function listen($path, callable $callback) {
492
-		$this->notify($path)->listen(function (IChange $change) use ($callback) {
493
-			if ($change instanceof IRenameChange) {
494
-				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
495
-			} else {
496
-				return $callback($change->getType(), $change->getPath());
497
-			}
498
-		});
499
-	}
500
-
501
-	public function notify($path) {
502
-		$path = '/' . ltrim($path, '/');
503
-		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
504
-		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
505
-	}
56
+    /**
57
+     * @var \Icewind\SMB\Server
58
+     */
59
+    protected $server;
60
+
61
+    /**
62
+     * @var \Icewind\SMB\Share
63
+     */
64
+    protected $share;
65
+
66
+    /**
67
+     * @var string
68
+     */
69
+    protected $root;
70
+
71
+    /**
72
+     * @var \Icewind\SMB\FileInfo[]
73
+     */
74
+    protected $statCache;
75
+
76
+    public function __construct($params) {
77
+        if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
78
+            if (Server::NativeAvailable()) {
79
+                $this->server = new NativeServer($params['host'], $params['user'], $params['password']);
80
+            } else {
81
+                $this->server = new Server($params['host'], $params['user'], $params['password']);
82
+            }
83
+            $this->share = $this->server->getShare(trim($params['share'], '/'));
84
+
85
+            $this->root = isset($params['root']) ? $params['root'] : '/';
86
+            if (!$this->root || $this->root[0] != '/') {
87
+                $this->root = '/' . $this->root;
88
+            }
89
+            if (substr($this->root, -1, 1) != '/') {
90
+                $this->root .= '/';
91
+            }
92
+        } else {
93
+            throw new \Exception('Invalid configuration');
94
+        }
95
+        $this->statCache = new CappedMemoryCache();
96
+    }
97
+
98
+    /**
99
+     * @return string
100
+     */
101
+    public function getId() {
102
+        // FIXME: double slash to keep compatible with the old storage ids,
103
+        // failure to do so will lead to creation of a new storage id and
104
+        // loss of shares from the storage
105
+        return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
106
+    }
107
+
108
+    /**
109
+     * @param string $path
110
+     * @return string
111
+     */
112
+    protected function buildPath($path) {
113
+        return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
114
+    }
115
+
116
+    protected function relativePath($fullPath) {
117
+        if ($fullPath === $this->root) {
118
+            return '';
119
+        } else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
120
+            return substr($fullPath, strlen($this->root));
121
+        } else {
122
+            return null;
123
+        }
124
+    }
125
+
126
+    /**
127
+     * @param string $path
128
+     * @return \Icewind\SMB\IFileInfo
129
+     * @throws StorageNotAvailableException
130
+     */
131
+    protected function getFileInfo($path) {
132
+        try {
133
+            $path = $this->buildPath($path);
134
+            if (!isset($this->statCache[$path])) {
135
+                $this->statCache[$path] = $this->share->stat($path);
136
+            }
137
+            return $this->statCache[$path];
138
+        } catch (ConnectException $e) {
139
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
140
+        }
141
+    }
142
+
143
+    /**
144
+     * @param string $path
145
+     * @return \Icewind\SMB\IFileInfo[]
146
+     * @throws StorageNotAvailableException
147
+     */
148
+    protected function getFolderContents($path) {
149
+        try {
150
+            $path = $this->buildPath($path);
151
+            $files = $this->share->dir($path);
152
+            foreach ($files as $file) {
153
+                $this->statCache[$path . '/' . $file->getName()] = $file;
154
+            }
155
+            return array_filter($files, function (IFileInfo $file) {
156
+                return !$file->isHidden();
157
+            });
158
+        } catch (ConnectException $e) {
159
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
160
+        }
161
+    }
162
+
163
+    /**
164
+     * @param \Icewind\SMB\IFileInfo $info
165
+     * @return array
166
+     */
167
+    protected function formatInfo($info) {
168
+        return array(
169
+            'size' => $info->getSize(),
170
+            'mtime' => $info->getMTime()
171
+        );
172
+    }
173
+
174
+    /**
175
+     * @param string $path
176
+     * @return array
177
+     */
178
+    public function stat($path) {
179
+        $result = $this->formatInfo($this->getFileInfo($path));
180
+        if ($this->remoteIsShare() && $this->isRootDir($path)) {
181
+            $result['mtime'] = $this->shareMTime();
182
+        }
183
+        return $result;
184
+    }
185
+
186
+    /**
187
+     * get the best guess for the modification time of the share
188
+     *
189
+     * @return int
190
+     */
191
+    private function shareMTime() {
192
+        $highestMTime = 0;
193
+        $files = $this->share->dir($this->root);
194
+        foreach ($files as $fileInfo) {
195
+            if ($fileInfo->getMTime() > $highestMTime) {
196
+                $highestMTime = $fileInfo->getMTime();
197
+            }
198
+        }
199
+        return $highestMTime;
200
+    }
201
+
202
+    /**
203
+     * Check if the path is our root dir (not the smb one)
204
+     *
205
+     * @param string $path the path
206
+     * @return bool
207
+     */
208
+    private function isRootDir($path) {
209
+        return $path === '' || $path === '/' || $path === '.';
210
+    }
211
+
212
+    /**
213
+     * Check if our root points to a smb share
214
+     *
215
+     * @return bool true if our root points to a share false otherwise
216
+     */
217
+    private function remoteIsShare() {
218
+        return $this->share->getName() && (!$this->root || $this->root === '/');
219
+    }
220
+
221
+    /**
222
+     * @param string $path
223
+     * @return bool
224
+     */
225
+    public function unlink($path) {
226
+        try {
227
+            if ($this->is_dir($path)) {
228
+                return $this->rmdir($path);
229
+            } else {
230
+                $path = $this->buildPath($path);
231
+                unset($this->statCache[$path]);
232
+                $this->share->del($path);
233
+                return true;
234
+            }
235
+        } catch (NotFoundException $e) {
236
+            return false;
237
+        } catch (ForbiddenException $e) {
238
+            return false;
239
+        } catch (ConnectException $e) {
240
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
241
+        }
242
+    }
243
+
244
+    /**
245
+     * @param string $path1 the old name
246
+     * @param string $path2 the new name
247
+     * @return bool
248
+     */
249
+    public function rename($path1, $path2) {
250
+        try {
251
+            $this->remove($path2);
252
+            $path1 = $this->buildPath($path1);
253
+            $path2 = $this->buildPath($path2);
254
+            return $this->share->rename($path1, $path2);
255
+        } catch (NotFoundException $e) {
256
+            return false;
257
+        } catch (ForbiddenException $e) {
258
+            return false;
259
+        } catch (ConnectException $e) {
260
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
261
+        }
262
+    }
263
+
264
+    /**
265
+     * check if a file or folder has been updated since $time
266
+     *
267
+     * @param string $path
268
+     * @param int $time
269
+     * @return bool
270
+     */
271
+    public function hasUpdated($path, $time) {
272
+        if (!$path and $this->root == '/') {
273
+            // mtime doesn't work for shares, but giving the nature of the backend,
274
+            // doing a full update is still just fast enough
275
+            return true;
276
+        } else {
277
+            $actualTime = $this->filemtime($path);
278
+            return $actualTime > $time;
279
+        }
280
+    }
281
+
282
+    /**
283
+     * @param string $path
284
+     * @param string $mode
285
+     * @return resource|false
286
+     */
287
+    public function fopen($path, $mode) {
288
+        $fullPath = $this->buildPath($path);
289
+        try {
290
+            switch ($mode) {
291
+                case 'r':
292
+                case 'rb':
293
+                    if (!$this->file_exists($path)) {
294
+                        return false;
295
+                    }
296
+                    return $this->share->read($fullPath);
297
+                case 'w':
298
+                case 'wb':
299
+                    $source = $this->share->write($fullPath);
300
+                    return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
301
+                        unset($this->statCache[$fullPath]);
302
+                    });
303
+                case 'a':
304
+                case 'ab':
305
+                case 'r+':
306
+                case 'w+':
307
+                case 'wb+':
308
+                case 'a+':
309
+                case 'x':
310
+                case 'x+':
311
+                case 'c':
312
+                case 'c+':
313
+                    //emulate these
314
+                    if (strrpos($path, '.') !== false) {
315
+                        $ext = substr($path, strrpos($path, '.'));
316
+                    } else {
317
+                        $ext = '';
318
+                    }
319
+                    if ($this->file_exists($path)) {
320
+                        if (!$this->isUpdatable($path)) {
321
+                            return false;
322
+                        }
323
+                        $tmpFile = $this->getCachedFile($path);
324
+                    } else {
325
+                        if (!$this->isCreatable(dirname($path))) {
326
+                            return false;
327
+                        }
328
+                        $tmpFile = \OCP\Files::tmpFile($ext);
329
+                    }
330
+                    $source = fopen($tmpFile, $mode);
331
+                    $share = $this->share;
332
+                    return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
333
+                        unset($this->statCache[$fullPath]);
334
+                        $share->put($tmpFile, $fullPath);
335
+                        unlink($tmpFile);
336
+                    });
337
+            }
338
+            return false;
339
+        } catch (NotFoundException $e) {
340
+            return false;
341
+        } catch (ForbiddenException $e) {
342
+            return false;
343
+        } catch (ConnectException $e) {
344
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
345
+        }
346
+    }
347
+
348
+    public function rmdir($path) {
349
+        try {
350
+            $this->statCache = array();
351
+            $content = $this->share->dir($this->buildPath($path));
352
+            foreach ($content as $file) {
353
+                if ($file->isDirectory()) {
354
+                    $this->rmdir($path . '/' . $file->getName());
355
+                } else {
356
+                    $this->share->del($file->getPath());
357
+                }
358
+            }
359
+            $this->share->rmdir($this->buildPath($path));
360
+            return true;
361
+        } catch (NotFoundException $e) {
362
+            return false;
363
+        } catch (ForbiddenException $e) {
364
+            return false;
365
+        } catch (ConnectException $e) {
366
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
367
+        }
368
+    }
369
+
370
+    public function touch($path, $time = null) {
371
+        try {
372
+            if (!$this->file_exists($path)) {
373
+                $fh = $this->share->write($this->buildPath($path));
374
+                fclose($fh);
375
+                return true;
376
+            }
377
+            return false;
378
+        } catch (ConnectException $e) {
379
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
380
+        }
381
+    }
382
+
383
+    public function opendir($path) {
384
+        try {
385
+            $files = $this->getFolderContents($path);
386
+        } catch (NotFoundException $e) {
387
+            return false;
388
+        } catch (ForbiddenException $e) {
389
+            return false;
390
+        }
391
+        $names = array_map(function ($info) {
392
+            /** @var \Icewind\SMB\IFileInfo $info */
393
+            return $info->getName();
394
+        }, $files);
395
+        return IteratorDirectory::wrap($names);
396
+    }
397
+
398
+    public function filetype($path) {
399
+        try {
400
+            return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
401
+        } catch (NotFoundException $e) {
402
+            return false;
403
+        } catch (ForbiddenException $e) {
404
+            return false;
405
+        }
406
+    }
407
+
408
+    public function mkdir($path) {
409
+        $path = $this->buildPath($path);
410
+        try {
411
+            $this->share->mkdir($path);
412
+            return true;
413
+        } catch (ConnectException $e) {
414
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
415
+        } catch (Exception $e) {
416
+            return false;
417
+        }
418
+    }
419
+
420
+    public function file_exists($path) {
421
+        try {
422
+            $this->getFileInfo($path);
423
+            return true;
424
+        } catch (NotFoundException $e) {
425
+            return false;
426
+        } catch (ForbiddenException $e) {
427
+            return false;
428
+        } catch (ConnectException $e) {
429
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
430
+        }
431
+    }
432
+
433
+    public function isReadable($path) {
434
+        try {
435
+            $info = $this->getFileInfo($path);
436
+            return !$info->isHidden();
437
+        } catch (NotFoundException $e) {
438
+            return false;
439
+        } catch (ForbiddenException $e) {
440
+            return false;
441
+        }
442
+    }
443
+
444
+    public function isUpdatable($path) {
445
+        try {
446
+            $info = $this->getFileInfo($path);
447
+            // following windows behaviour for read-only folders: they can be written into
448
+            // (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
449
+            return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
450
+        } catch (NotFoundException $e) {
451
+            return false;
452
+        } catch (ForbiddenException $e) {
453
+            return false;
454
+        }
455
+    }
456
+
457
+    public function isDeletable($path) {
458
+        try {
459
+            $info = $this->getFileInfo($path);
460
+            return !$info->isHidden() && !$info->isReadOnly();
461
+        } catch (NotFoundException $e) {
462
+            return false;
463
+        } catch (ForbiddenException $e) {
464
+            return false;
465
+        }
466
+    }
467
+
468
+    /**
469
+     * check if smbclient is installed
470
+     */
471
+    public static function checkDependencies() {
472
+        return (
473
+            (bool)\OC_Helper::findBinaryPath('smbclient')
474
+            || Server::NativeAvailable()
475
+        ) ? true : ['smbclient'];
476
+    }
477
+
478
+    /**
479
+     * Test a storage for availability
480
+     *
481
+     * @return bool
482
+     */
483
+    public function test() {
484
+        try {
485
+            return parent::test();
486
+        } catch (Exception $e) {
487
+            return false;
488
+        }
489
+    }
490
+
491
+    public function listen($path, callable $callback) {
492
+        $this->notify($path)->listen(function (IChange $change) use ($callback) {
493
+            if ($change instanceof IRenameChange) {
494
+                return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
495
+            } else {
496
+                return $callback($change->getType(), $change->getPath());
497
+            }
498
+        });
499
+    }
500
+
501
+    public function notify($path) {
502
+        $path = '/' . ltrim($path, '/');
503
+        $shareNotifyHandler = $this->share->notify($this->buildPath($path));
504
+        return new SMBNotifyHandler($shareNotifyHandler, $this->root);
505
+    }
506 506
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 
85 85
 			$this->root = isset($params['root']) ? $params['root'] : '/';
86 86
 			if (!$this->root || $this->root[0] != '/') {
87
-				$this->root = '/' . $this->root;
87
+				$this->root = '/'.$this->root;
88 88
 			}
89 89
 			if (substr($this->root, -1, 1) != '/') {
90 90
 				$this->root .= '/';
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
 		// FIXME: double slash to keep compatible with the old storage ids,
103 103
 		// failure to do so will lead to creation of a new storage id and
104 104
 		// loss of shares from the storage
105
-		return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
105
+		return 'smb::'.$this->server->getUser().'@'.$this->server->getHost().'//'.$this->share->getName().'/'.$this->root;
106 106
 	}
107 107
 
108 108
 	/**
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
 	 * @return string
111 111
 	 */
112 112
 	protected function buildPath($path) {
113
-		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
113
+		return Filesystem::normalizePath($this->root.'/'.$path, true, false, true);
114 114
 	}
115 115
 
116 116
 	protected function relativePath($fullPath) {
@@ -150,9 +150,9 @@  discard block
 block discarded – undo
150 150
 			$path = $this->buildPath($path);
151 151
 			$files = $this->share->dir($path);
152 152
 			foreach ($files as $file) {
153
-				$this->statCache[$path . '/' . $file->getName()] = $file;
153
+				$this->statCache[$path.'/'.$file->getName()] = $file;
154 154
 			}
155
-			return array_filter($files, function (IFileInfo $file) {
155
+			return array_filter($files, function(IFileInfo $file) {
156 156
 				return !$file->isHidden();
157 157
 			});
158 158
 		} catch (ConnectException $e) {
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
 				case 'w':
298 298
 				case 'wb':
299 299
 					$source = $this->share->write($fullPath);
300
-					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
300
+					return CallBackWrapper::wrap($source, null, null, function() use ($fullPath) {
301 301
 						unset($this->statCache[$fullPath]);
302 302
 					});
303 303
 				case 'a':
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
 					}
330 330
 					$source = fopen($tmpFile, $mode);
331 331
 					$share = $this->share;
332
-					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
332
+					return CallbackWrapper::wrap($source, null, null, function() use ($tmpFile, $fullPath, $share) {
333 333
 						unset($this->statCache[$fullPath]);
334 334
 						$share->put($tmpFile, $fullPath);
335 335
 						unlink($tmpFile);
@@ -351,7 +351,7 @@  discard block
 block discarded – undo
351 351
 			$content = $this->share->dir($this->buildPath($path));
352 352
 			foreach ($content as $file) {
353 353
 				if ($file->isDirectory()) {
354
-					$this->rmdir($path . '/' . $file->getName());
354
+					$this->rmdir($path.'/'.$file->getName());
355 355
 				} else {
356 356
 					$this->share->del($file->getPath());
357 357
 				}
@@ -388,7 +388,7 @@  discard block
 block discarded – undo
388 388
 		} catch (ForbiddenException $e) {
389 389
 			return false;
390 390
 		}
391
-		$names = array_map(function ($info) {
391
+		$names = array_map(function($info) {
392 392
 			/** @var \Icewind\SMB\IFileInfo $info */
393 393
 			return $info->getName();
394 394
 		}, $files);
@@ -470,7 +470,7 @@  discard block
 block discarded – undo
470 470
 	 */
471 471
 	public static function checkDependencies() {
472 472
 		return (
473
-			(bool)\OC_Helper::findBinaryPath('smbclient')
473
+			(bool) \OC_Helper::findBinaryPath('smbclient')
474 474
 			|| Server::NativeAvailable()
475 475
 		) ? true : ['smbclient'];
476 476
 	}
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
 	}
490 490
 
491 491
 	public function listen($path, callable $callback) {
492
-		$this->notify($path)->listen(function (IChange $change) use ($callback) {
492
+		$this->notify($path)->listen(function(IChange $change) use ($callback) {
493 493
 			if ($change instanceof IRenameChange) {
494 494
 				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
495 495
 			} else {
@@ -499,7 +499,7 @@  discard block
 block discarded – undo
499 499
 	}
500 500
 
501 501
 	public function notify($path) {
502
-		$path = '/' . ltrim($path, '/');
502
+		$path = '/'.ltrim($path, '/');
503 503
 		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
504 504
 		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
505 505
 	}
Please login to merge, or discard this patch.
lib/private/Files/Node/File.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -31,7 +31,7 @@
 block discarded – undo
31 31
 	 * Creates a Folder that represents a non-existing path
32 32
 	 *
33 33
 	 * @param string $path path
34
-	 * @return string non-existing node class
34
+	 * @return NonExistingFile non-existing node class
35 35
 	 */
36 36
 	protected function createNonExistingNode($path) {
37 37
 		return new NonExistingFile($this->root, $this->view, $path);
Please login to merge, or discard this patch.
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -29,113 +29,113 @@
 block discarded – undo
29 29
 use OCP\Files\NotPermittedException;
30 30
 
31 31
 class File extends Node implements \OCP\Files\File {
32
-	/**
33
-	 * Creates a Folder that represents a non-existing path
34
-	 *
35
-	 * @param string $path path
36
-	 * @return string non-existing node class
37
-	 */
38
-	protected function createNonExistingNode($path) {
39
-		return new NonExistingFile($this->root, $this->view, $path);
40
-	}
32
+    /**
33
+     * Creates a Folder that represents a non-existing path
34
+     *
35
+     * @param string $path path
36
+     * @return string non-existing node class
37
+     */
38
+    protected function createNonExistingNode($path) {
39
+        return new NonExistingFile($this->root, $this->view, $path);
40
+    }
41 41
 
42
-	/**
43
-	 * @return string
44
-	 * @throws \OCP\Files\NotPermittedException
45
-	 */
46
-	public function getContent() {
47
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
48
-			/**
49
-			 * @var \OC\Files\Storage\Storage $storage;
50
-			 */
51
-			return $this->view->file_get_contents($this->path);
52
-		} else {
53
-			throw new NotPermittedException();
54
-		}
55
-	}
42
+    /**
43
+     * @return string
44
+     * @throws \OCP\Files\NotPermittedException
45
+     */
46
+    public function getContent() {
47
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
48
+            /**
49
+             * @var \OC\Files\Storage\Storage $storage;
50
+             */
51
+            return $this->view->file_get_contents($this->path);
52
+        } else {
53
+            throw new NotPermittedException();
54
+        }
55
+    }
56 56
 
57
-	/**
58
-	 * @param string $data
59
-	 * @throws \OCP\Files\NotPermittedException
60
-	 */
61
-	public function putContent($data) {
62
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
63
-			$this->sendHooks(array('preWrite'));
64
-			$this->view->file_put_contents($this->path, $data);
65
-			$this->fileInfo = null;
66
-			$this->sendHooks(array('postWrite'));
67
-		} else {
68
-			throw new NotPermittedException();
69
-		}
70
-	}
57
+    /**
58
+     * @param string $data
59
+     * @throws \OCP\Files\NotPermittedException
60
+     */
61
+    public function putContent($data) {
62
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
63
+            $this->sendHooks(array('preWrite'));
64
+            $this->view->file_put_contents($this->path, $data);
65
+            $this->fileInfo = null;
66
+            $this->sendHooks(array('postWrite'));
67
+        } else {
68
+            throw new NotPermittedException();
69
+        }
70
+    }
71 71
 
72
-	/**
73
-	 * @param string $mode
74
-	 * @return resource
75
-	 * @throws \OCP\Files\NotPermittedException
76
-	 */
77
-	public function fopen($mode) {
78
-		$preHooks = array();
79
-		$postHooks = array();
80
-		$requiredPermissions = \OCP\Constants::PERMISSION_READ;
81
-		switch ($mode) {
82
-			case 'r+':
83
-			case 'rb+':
84
-			case 'w+':
85
-			case 'wb+':
86
-			case 'x+':
87
-			case 'xb+':
88
-			case 'a+':
89
-			case 'ab+':
90
-			case 'w':
91
-			case 'wb':
92
-			case 'x':
93
-			case 'xb':
94
-			case 'a':
95
-			case 'ab':
96
-				$preHooks[] = 'preWrite';
97
-				$postHooks[] = 'postWrite';
98
-				$requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
99
-				break;
100
-		}
72
+    /**
73
+     * @param string $mode
74
+     * @return resource
75
+     * @throws \OCP\Files\NotPermittedException
76
+     */
77
+    public function fopen($mode) {
78
+        $preHooks = array();
79
+        $postHooks = array();
80
+        $requiredPermissions = \OCP\Constants::PERMISSION_READ;
81
+        switch ($mode) {
82
+            case 'r+':
83
+            case 'rb+':
84
+            case 'w+':
85
+            case 'wb+':
86
+            case 'x+':
87
+            case 'xb+':
88
+            case 'a+':
89
+            case 'ab+':
90
+            case 'w':
91
+            case 'wb':
92
+            case 'x':
93
+            case 'xb':
94
+            case 'a':
95
+            case 'ab':
96
+                $preHooks[] = 'preWrite';
97
+                $postHooks[] = 'postWrite';
98
+                $requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
99
+                break;
100
+        }
101 101
 
102
-		if ($this->checkPermissions($requiredPermissions)) {
103
-			$this->sendHooks($preHooks);
104
-			$result = $this->view->fopen($this->path, $mode);
105
-			$this->sendHooks($postHooks);
106
-			return $result;
107
-		} else {
108
-			throw new NotPermittedException();
109
-		}
110
-	}
102
+        if ($this->checkPermissions($requiredPermissions)) {
103
+            $this->sendHooks($preHooks);
104
+            $result = $this->view->fopen($this->path, $mode);
105
+            $this->sendHooks($postHooks);
106
+            return $result;
107
+        } else {
108
+            throw new NotPermittedException();
109
+        }
110
+    }
111 111
 
112
-	public function delete() {
113
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
114
-			$this->sendHooks(array('preDelete'));
115
-			$fileInfo = $this->getFileInfo();
116
-			$this->view->unlink($this->path);
117
-			$nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
118
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
119
-			$this->exists = false;
120
-			$this->fileInfo = null;
121
-		} else {
122
-			throw new NotPermittedException();
123
-		}
124
-	}
112
+    public function delete() {
113
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
114
+            $this->sendHooks(array('preDelete'));
115
+            $fileInfo = $this->getFileInfo();
116
+            $this->view->unlink($this->path);
117
+            $nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
118
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
119
+            $this->exists = false;
120
+            $this->fileInfo = null;
121
+        } else {
122
+            throw new NotPermittedException();
123
+        }
124
+    }
125 125
 
126
-	/**
127
-	 * @param string $type
128
-	 * @param bool $raw
129
-	 * @return string
130
-	 */
131
-	public function hash($type, $raw = false) {
132
-		return $this->view->hash($type, $this->path, $raw);
133
-	}
126
+    /**
127
+     * @param string $type
128
+     * @param bool $raw
129
+     * @return string
130
+     */
131
+    public function hash($type, $raw = false) {
132
+        return $this->view->hash($type, $this->path, $raw);
133
+    }
134 134
 
135
-	/**
136
-	 * @inheritdoc
137
-	 */
138
-	public function getChecksum() {
139
-		return $this->getFileInfo()->getChecksum();
140
-	}
135
+    /**
136
+     * @inheritdoc
137
+     */
138
+    public function getChecksum() {
139
+        return $this->getFileInfo()->getChecksum();
140
+    }
141 141
 }
Please login to merge, or discard this patch.
lib/private/Files/Node/Folder.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@
 block discarded – undo
37 37
 	 * Creates a Folder that represents a non-existing path
38 38
 	 *
39 39
 	 * @param string $path path
40
-	 * @return string non-existing node class
40
+	 * @return NonExistingFolder non-existing node class
41 41
 	 */
42 42
 	protected function createNonExistingNode($path) {
43 43
 		return new NonExistingFolder($this->root, $this->view, $path);
Please login to merge, or discard this patch.
Indentation   +395 added lines, -395 removed lines patch added patch discarded remove patch
@@ -36,399 +36,399 @@
 block discarded – undo
36 36
 use OCP\Files\Search\ISearchOperator;
37 37
 
38 38
 class Folder extends Node implements \OCP\Files\Folder {
39
-	/**
40
-	 * Creates a Folder that represents a non-existing path
41
-	 *
42
-	 * @param string $path path
43
-	 * @return string non-existing node class
44
-	 */
45
-	protected function createNonExistingNode($path) {
46
-		return new NonExistingFolder($this->root, $this->view, $path);
47
-	}
48
-
49
-	/**
50
-	 * @param string $path path relative to the folder
51
-	 * @return string
52
-	 * @throws \OCP\Files\NotPermittedException
53
-	 */
54
-	public function getFullPath($path) {
55
-		if (!$this->isValidPath($path)) {
56
-			throw new NotPermittedException('Invalid path');
57
-		}
58
-		return $this->path . $this->normalizePath($path);
59
-	}
60
-
61
-	/**
62
-	 * @param string $path
63
-	 * @return string
64
-	 */
65
-	public function getRelativePath($path) {
66
-		if ($this->path === '' or $this->path === '/') {
67
-			return $this->normalizePath($path);
68
-		}
69
-		if ($path === $this->path) {
70
-			return '/';
71
-		} else if (strpos($path, $this->path . '/') !== 0) {
72
-			return null;
73
-		} else {
74
-			$path = substr($path, strlen($this->path));
75
-			return $this->normalizePath($path);
76
-		}
77
-	}
78
-
79
-	/**
80
-	 * check if a node is a (grand-)child of the folder
81
-	 *
82
-	 * @param \OC\Files\Node\Node $node
83
-	 * @return bool
84
-	 */
85
-	public function isSubNode($node) {
86
-		return strpos($node->getPath(), $this->path . '/') === 0;
87
-	}
88
-
89
-	/**
90
-	 * get the content of this directory
91
-	 *
92
-	 * @throws \OCP\Files\NotFoundException
93
-	 * @return Node[]
94
-	 */
95
-	public function getDirectoryListing() {
96
-		$folderContent = $this->view->getDirectoryContent($this->path);
97
-
98
-		return array_map(function (FileInfo $info) {
99
-			if ($info->getMimetype() === 'httpd/unix-directory') {
100
-				return new Folder($this->root, $this->view, $info->getPath(), $info);
101
-			} else {
102
-				return new File($this->root, $this->view, $info->getPath(), $info);
103
-			}
104
-		}, $folderContent);
105
-	}
106
-
107
-	/**
108
-	 * @param string $path
109
-	 * @param FileInfo $info
110
-	 * @return File|Folder
111
-	 */
112
-	protected function createNode($path, FileInfo $info = null) {
113
-		if (is_null($info)) {
114
-			$isDir = $this->view->is_dir($path);
115
-		} else {
116
-			$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
117
-		}
118
-		if ($isDir) {
119
-			return new Folder($this->root, $this->view, $path, $info);
120
-		} else {
121
-			return new File($this->root, $this->view, $path, $info);
122
-		}
123
-	}
124
-
125
-	/**
126
-	 * Get the node at $path
127
-	 *
128
-	 * @param string $path
129
-	 * @return \OC\Files\Node\Node
130
-	 * @throws \OCP\Files\NotFoundException
131
-	 */
132
-	public function get($path) {
133
-		return $this->root->get($this->getFullPath($path));
134
-	}
135
-
136
-	/**
137
-	 * @param string $path
138
-	 * @return bool
139
-	 */
140
-	public function nodeExists($path) {
141
-		try {
142
-			$this->get($path);
143
-			return true;
144
-		} catch (NotFoundException $e) {
145
-			return false;
146
-		}
147
-	}
148
-
149
-	/**
150
-	 * @param string $path
151
-	 * @return \OC\Files\Node\Folder
152
-	 * @throws \OCP\Files\NotPermittedException
153
-	 */
154
-	public function newFolder($path) {
155
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
156
-			$fullPath = $this->getFullPath($path);
157
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
158
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
159
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
160
-			$this->view->mkdir($fullPath);
161
-			$node = new Folder($this->root, $this->view, $fullPath);
162
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
163
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
164
-			return $node;
165
-		} else {
166
-			throw new NotPermittedException('No create permission for folder');
167
-		}
168
-	}
169
-
170
-	/**
171
-	 * @param string $path
172
-	 * @return \OC\Files\Node\File
173
-	 * @throws \OCP\Files\NotPermittedException
174
-	 */
175
-	public function newFile($path) {
176
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
177
-			$fullPath = $this->getFullPath($path);
178
-			$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
179
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
180
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
181
-			$this->view->touch($fullPath);
182
-			$node = new File($this->root, $this->view, $fullPath);
183
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
184
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
185
-			return $node;
186
-		} else {
187
-			throw new NotPermittedException('No create permission for path');
188
-		}
189
-	}
190
-
191
-	/**
192
-	 * search for files with the name matching $query
193
-	 *
194
-	 * @param string|ISearchOperator $query
195
-	 * @return \OC\Files\Node\Node[]
196
-	 */
197
-	public function search($query) {
198
-		if (is_string($query)) {
199
-			return $this->searchCommon('search', array('%' . $query . '%'));
200
-		} else {
201
-			return $this->searchCommon('searchQuery', array($query));
202
-		}
203
-	}
204
-
205
-	/**
206
-	 * search for files by mimetype
207
-	 *
208
-	 * @param string $mimetype
209
-	 * @return Node[]
210
-	 */
211
-	public function searchByMime($mimetype) {
212
-		return $this->searchCommon('searchByMime', array($mimetype));
213
-	}
214
-
215
-	/**
216
-	 * search for files by tag
217
-	 *
218
-	 * @param string|int $tag name or tag id
219
-	 * @param string $userId owner of the tags
220
-	 * @return Node[]
221
-	 */
222
-	public function searchByTag($tag, $userId) {
223
-		return $this->searchCommon('searchByTag', array($tag, $userId));
224
-	}
225
-
226
-	/**
227
-	 * @param string $method cache method
228
-	 * @param array $args call args
229
-	 * @return \OC\Files\Node\Node[]
230
-	 */
231
-	private function searchCommon($method, $args) {
232
-		$files = array();
233
-		$rootLength = strlen($this->path);
234
-		$mount = $this->root->getMount($this->path);
235
-		$storage = $mount->getStorage();
236
-		$internalPath = $mount->getInternalPath($this->path);
237
-		$internalPath = rtrim($internalPath, '/');
238
-		if ($internalPath !== '') {
239
-			$internalPath = $internalPath . '/';
240
-		}
241
-		$internalRootLength = strlen($internalPath);
242
-
243
-		$cache = $storage->getCache('');
244
-
245
-		$results = call_user_func_array(array($cache, $method), $args);
246
-		foreach ($results as $result) {
247
-			if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
248
-				$result['internalPath'] = $result['path'];
249
-				$result['path'] = substr($result['path'], $internalRootLength);
250
-				$result['storage'] = $storage;
251
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
252
-			}
253
-		}
254
-
255
-		$mounts = $this->root->getMountsIn($this->path);
256
-		foreach ($mounts as $mount) {
257
-			$storage = $mount->getStorage();
258
-			if ($storage) {
259
-				$cache = $storage->getCache('');
260
-
261
-				$relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
262
-				$results = call_user_func_array(array($cache, $method), $args);
263
-				foreach ($results as $result) {
264
-					$result['internalPath'] = $result['path'];
265
-					$result['path'] = $relativeMountPoint . $result['path'];
266
-					$result['storage'] = $storage;
267
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
-				}
269
-			}
270
-		}
271
-
272
-		return array_map(function (FileInfo $file) {
273
-			return $this->createNode($file->getPath(), $file);
274
-		}, $files);
275
-	}
276
-
277
-	/**
278
-	 * @param int $id
279
-	 * @return \OC\Files\Node\Node[]
280
-	 */
281
-	public function getById($id) {
282
-		$mountCache = $this->root->getUserMountCache();
283
-		if (strpos($this->getPath(), '/', 1) > 0) {
284
-			list(, $user) = explode('/', $this->getPath());
285
-		} else {
286
-			$user = null;
287
-		}
288
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
289
-		$mounts = $this->root->getMountsIn($this->path);
290
-		$mounts[] = $this->root->getMount($this->path);
291
-		/** @var IMountPoint[] $folderMounts */
292
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
293
-			return $mountPoint->getMountPoint();
294
-		}, $mounts), $mounts);
295
-
296
-		/** @var ICachedMountInfo[] $mountsContainingFile */
297
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298
-			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299
-		}));
300
-
301
-		if (count($mountsContainingFile) === 0) {
302
-			return [];
303
-		}
304
-
305
-		// we only need to get the cache info once, since all mounts we found point to the same storage
306
-
307
-		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
309
-		if (!$cacheEntry) {
310
-			return [];
311
-		}
312
-		// cache jails will hide the "true" internal path
313
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
314
-
315
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316
-			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317
-			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318
-			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
320
-			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321
-				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322
-				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323
-			));
324
-		}, $mountsContainingFile);
325
-
326
-		return array_filter($nodes, function (Node $node) {
327
-			return $this->getRelativePath($node->getPath());
328
-		});
329
-	}
330
-
331
-	public function getFreeSpace() {
332
-		return $this->view->free_space($this->path);
333
-	}
334
-
335
-	public function delete() {
336
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
337
-			$this->sendHooks(array('preDelete'));
338
-			$fileInfo = $this->getFileInfo();
339
-			$this->view->rmdir($this->path);
340
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
341
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
342
-			$this->exists = false;
343
-		} else {
344
-			throw new NotPermittedException('No delete permission for path');
345
-		}
346
-	}
347
-
348
-	/**
349
-	 * Add a suffix to the name in case the file exists
350
-	 *
351
-	 * @param string $name
352
-	 * @return string
353
-	 * @throws NotPermittedException
354
-	 */
355
-	public function getNonExistingName($name) {
356
-		$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
357
-		return trim($this->getRelativePath($uniqueName), '/');
358
-	}
359
-
360
-	/**
361
-	 * @param int $limit
362
-	 * @param int $offset
363
-	 * @return \OCP\Files\Node[]
364
-	 */
365
-	public function getRecent($limit, $offset = 0) {
366
-		$mimetypeLoader = \OC::$server->getMimeTypeLoader();
367
-		$mounts = $this->root->getMountsIn($this->path);
368
-		$mounts[] = $this->getMountPoint();
369
-
370
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
371
-			return $mount->getStorage();
372
-		});
373
-		$storageIds = array_map(function (IMountPoint $mount) {
374
-			return $mount->getStorage()->getCache()->getNumericStorageId();
375
-		}, $mounts);
376
-		/** @var IMountPoint[] $mountMap */
377
-		$mountMap = array_combine($storageIds, $mounts);
378
-		$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
379
-
380
-		//todo look into options of filtering path based on storage id (only search in files/ for home storage, filter by share root for shared, etc)
381
-
382
-		$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
383
-		$query = $builder
384
-			->select('f.*')
385
-			->from('filecache', 'f')
386
-			->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
387
-			->andWhere($builder->expr()->orX(
388
-			// handle non empty folders separate
389
-				$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
390
-				$builder->expr()->eq('f.size', new Literal(0))
391
-			))
392
-			->orderBy('f.mtime', 'DESC')
393
-			->setMaxResults($limit)
394
-			->setFirstResult($offset);
395
-
396
-		$result = $query->execute()->fetchAll();
397
-
398
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
399
-			$mount = $mountMap[$entry['storage']];
400
-			$entry['internalPath'] = $entry['path'];
401
-			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
402
-			$entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
403
-			$path = $this->getAbsolutePath($mount, $entry['path']);
404
-			if (is_null($path)) {
405
-				return null;
406
-			}
407
-			$fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
408
-			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409
-		}, $result));
410
-
411
-		return array_values(array_filter($files, function (Node $node) {
412
-			$relative = $this->getRelativePath($node->getPath());
413
-			return $relative !== null && $relative !== '/';
414
-		}));
415
-	}
416
-
417
-	private function getAbsolutePath(IMountPoint $mount, $path) {
418
-		$storage = $mount->getStorage();
419
-		if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
420
-			/** @var \OC\Files\Storage\Wrapper\Jail $storage */
421
-			$jailRoot = $storage->getUnjailedPath('');
422
-			$rootLength = strlen($jailRoot) + 1;
423
-			if ($path === $jailRoot) {
424
-				return $mount->getMountPoint();
425
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
-				return $mount->getMountPoint() . substr($path, $rootLength);
427
-			} else {
428
-				return null;
429
-			}
430
-		} else {
431
-			return $mount->getMountPoint() . $path;
432
-		}
433
-	}
39
+    /**
40
+     * Creates a Folder that represents a non-existing path
41
+     *
42
+     * @param string $path path
43
+     * @return string non-existing node class
44
+     */
45
+    protected function createNonExistingNode($path) {
46
+        return new NonExistingFolder($this->root, $this->view, $path);
47
+    }
48
+
49
+    /**
50
+     * @param string $path path relative to the folder
51
+     * @return string
52
+     * @throws \OCP\Files\NotPermittedException
53
+     */
54
+    public function getFullPath($path) {
55
+        if (!$this->isValidPath($path)) {
56
+            throw new NotPermittedException('Invalid path');
57
+        }
58
+        return $this->path . $this->normalizePath($path);
59
+    }
60
+
61
+    /**
62
+     * @param string $path
63
+     * @return string
64
+     */
65
+    public function getRelativePath($path) {
66
+        if ($this->path === '' or $this->path === '/') {
67
+            return $this->normalizePath($path);
68
+        }
69
+        if ($path === $this->path) {
70
+            return '/';
71
+        } else if (strpos($path, $this->path . '/') !== 0) {
72
+            return null;
73
+        } else {
74
+            $path = substr($path, strlen($this->path));
75
+            return $this->normalizePath($path);
76
+        }
77
+    }
78
+
79
+    /**
80
+     * check if a node is a (grand-)child of the folder
81
+     *
82
+     * @param \OC\Files\Node\Node $node
83
+     * @return bool
84
+     */
85
+    public function isSubNode($node) {
86
+        return strpos($node->getPath(), $this->path . '/') === 0;
87
+    }
88
+
89
+    /**
90
+     * get the content of this directory
91
+     *
92
+     * @throws \OCP\Files\NotFoundException
93
+     * @return Node[]
94
+     */
95
+    public function getDirectoryListing() {
96
+        $folderContent = $this->view->getDirectoryContent($this->path);
97
+
98
+        return array_map(function (FileInfo $info) {
99
+            if ($info->getMimetype() === 'httpd/unix-directory') {
100
+                return new Folder($this->root, $this->view, $info->getPath(), $info);
101
+            } else {
102
+                return new File($this->root, $this->view, $info->getPath(), $info);
103
+            }
104
+        }, $folderContent);
105
+    }
106
+
107
+    /**
108
+     * @param string $path
109
+     * @param FileInfo $info
110
+     * @return File|Folder
111
+     */
112
+    protected function createNode($path, FileInfo $info = null) {
113
+        if (is_null($info)) {
114
+            $isDir = $this->view->is_dir($path);
115
+        } else {
116
+            $isDir = $info->getType() === FileInfo::TYPE_FOLDER;
117
+        }
118
+        if ($isDir) {
119
+            return new Folder($this->root, $this->view, $path, $info);
120
+        } else {
121
+            return new File($this->root, $this->view, $path, $info);
122
+        }
123
+    }
124
+
125
+    /**
126
+     * Get the node at $path
127
+     *
128
+     * @param string $path
129
+     * @return \OC\Files\Node\Node
130
+     * @throws \OCP\Files\NotFoundException
131
+     */
132
+    public function get($path) {
133
+        return $this->root->get($this->getFullPath($path));
134
+    }
135
+
136
+    /**
137
+     * @param string $path
138
+     * @return bool
139
+     */
140
+    public function nodeExists($path) {
141
+        try {
142
+            $this->get($path);
143
+            return true;
144
+        } catch (NotFoundException $e) {
145
+            return false;
146
+        }
147
+    }
148
+
149
+    /**
150
+     * @param string $path
151
+     * @return \OC\Files\Node\Folder
152
+     * @throws \OCP\Files\NotPermittedException
153
+     */
154
+    public function newFolder($path) {
155
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
156
+            $fullPath = $this->getFullPath($path);
157
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
158
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
159
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
160
+            $this->view->mkdir($fullPath);
161
+            $node = new Folder($this->root, $this->view, $fullPath);
162
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
163
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
164
+            return $node;
165
+        } else {
166
+            throw new NotPermittedException('No create permission for folder');
167
+        }
168
+    }
169
+
170
+    /**
171
+     * @param string $path
172
+     * @return \OC\Files\Node\File
173
+     * @throws \OCP\Files\NotPermittedException
174
+     */
175
+    public function newFile($path) {
176
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
177
+            $fullPath = $this->getFullPath($path);
178
+            $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
179
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
180
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
181
+            $this->view->touch($fullPath);
182
+            $node = new File($this->root, $this->view, $fullPath);
183
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
184
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
185
+            return $node;
186
+        } else {
187
+            throw new NotPermittedException('No create permission for path');
188
+        }
189
+    }
190
+
191
+    /**
192
+     * search for files with the name matching $query
193
+     *
194
+     * @param string|ISearchOperator $query
195
+     * @return \OC\Files\Node\Node[]
196
+     */
197
+    public function search($query) {
198
+        if (is_string($query)) {
199
+            return $this->searchCommon('search', array('%' . $query . '%'));
200
+        } else {
201
+            return $this->searchCommon('searchQuery', array($query));
202
+        }
203
+    }
204
+
205
+    /**
206
+     * search for files by mimetype
207
+     *
208
+     * @param string $mimetype
209
+     * @return Node[]
210
+     */
211
+    public function searchByMime($mimetype) {
212
+        return $this->searchCommon('searchByMime', array($mimetype));
213
+    }
214
+
215
+    /**
216
+     * search for files by tag
217
+     *
218
+     * @param string|int $tag name or tag id
219
+     * @param string $userId owner of the tags
220
+     * @return Node[]
221
+     */
222
+    public function searchByTag($tag, $userId) {
223
+        return $this->searchCommon('searchByTag', array($tag, $userId));
224
+    }
225
+
226
+    /**
227
+     * @param string $method cache method
228
+     * @param array $args call args
229
+     * @return \OC\Files\Node\Node[]
230
+     */
231
+    private function searchCommon($method, $args) {
232
+        $files = array();
233
+        $rootLength = strlen($this->path);
234
+        $mount = $this->root->getMount($this->path);
235
+        $storage = $mount->getStorage();
236
+        $internalPath = $mount->getInternalPath($this->path);
237
+        $internalPath = rtrim($internalPath, '/');
238
+        if ($internalPath !== '') {
239
+            $internalPath = $internalPath . '/';
240
+        }
241
+        $internalRootLength = strlen($internalPath);
242
+
243
+        $cache = $storage->getCache('');
244
+
245
+        $results = call_user_func_array(array($cache, $method), $args);
246
+        foreach ($results as $result) {
247
+            if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
248
+                $result['internalPath'] = $result['path'];
249
+                $result['path'] = substr($result['path'], $internalRootLength);
250
+                $result['storage'] = $storage;
251
+                $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
252
+            }
253
+        }
254
+
255
+        $mounts = $this->root->getMountsIn($this->path);
256
+        foreach ($mounts as $mount) {
257
+            $storage = $mount->getStorage();
258
+            if ($storage) {
259
+                $cache = $storage->getCache('');
260
+
261
+                $relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
262
+                $results = call_user_func_array(array($cache, $method), $args);
263
+                foreach ($results as $result) {
264
+                    $result['internalPath'] = $result['path'];
265
+                    $result['path'] = $relativeMountPoint . $result['path'];
266
+                    $result['storage'] = $storage;
267
+                    $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
+                }
269
+            }
270
+        }
271
+
272
+        return array_map(function (FileInfo $file) {
273
+            return $this->createNode($file->getPath(), $file);
274
+        }, $files);
275
+    }
276
+
277
+    /**
278
+     * @param int $id
279
+     * @return \OC\Files\Node\Node[]
280
+     */
281
+    public function getById($id) {
282
+        $mountCache = $this->root->getUserMountCache();
283
+        if (strpos($this->getPath(), '/', 1) > 0) {
284
+            list(, $user) = explode('/', $this->getPath());
285
+        } else {
286
+            $user = null;
287
+        }
288
+        $mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
289
+        $mounts = $this->root->getMountsIn($this->path);
290
+        $mounts[] = $this->root->getMount($this->path);
291
+        /** @var IMountPoint[] $folderMounts */
292
+        $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
293
+            return $mountPoint->getMountPoint();
294
+        }, $mounts), $mounts);
295
+
296
+        /** @var ICachedMountInfo[] $mountsContainingFile */
297
+        $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298
+            return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299
+        }));
300
+
301
+        if (count($mountsContainingFile) === 0) {
302
+            return [];
303
+        }
304
+
305
+        // we only need to get the cache info once, since all mounts we found point to the same storage
306
+
307
+        $mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
+        $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
309
+        if (!$cacheEntry) {
310
+            return [];
311
+        }
312
+        // cache jails will hide the "true" internal path
313
+        $internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
314
+
315
+        $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316
+            $mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317
+            $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318
+            $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
+            $absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
320
+            return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321
+                $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322
+                \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323
+            ));
324
+        }, $mountsContainingFile);
325
+
326
+        return array_filter($nodes, function (Node $node) {
327
+            return $this->getRelativePath($node->getPath());
328
+        });
329
+    }
330
+
331
+    public function getFreeSpace() {
332
+        return $this->view->free_space($this->path);
333
+    }
334
+
335
+    public function delete() {
336
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
337
+            $this->sendHooks(array('preDelete'));
338
+            $fileInfo = $this->getFileInfo();
339
+            $this->view->rmdir($this->path);
340
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
341
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
342
+            $this->exists = false;
343
+        } else {
344
+            throw new NotPermittedException('No delete permission for path');
345
+        }
346
+    }
347
+
348
+    /**
349
+     * Add a suffix to the name in case the file exists
350
+     *
351
+     * @param string $name
352
+     * @return string
353
+     * @throws NotPermittedException
354
+     */
355
+    public function getNonExistingName($name) {
356
+        $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
357
+        return trim($this->getRelativePath($uniqueName), '/');
358
+    }
359
+
360
+    /**
361
+     * @param int $limit
362
+     * @param int $offset
363
+     * @return \OCP\Files\Node[]
364
+     */
365
+    public function getRecent($limit, $offset = 0) {
366
+        $mimetypeLoader = \OC::$server->getMimeTypeLoader();
367
+        $mounts = $this->root->getMountsIn($this->path);
368
+        $mounts[] = $this->getMountPoint();
369
+
370
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
371
+            return $mount->getStorage();
372
+        });
373
+        $storageIds = array_map(function (IMountPoint $mount) {
374
+            return $mount->getStorage()->getCache()->getNumericStorageId();
375
+        }, $mounts);
376
+        /** @var IMountPoint[] $mountMap */
377
+        $mountMap = array_combine($storageIds, $mounts);
378
+        $folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
379
+
380
+        //todo look into options of filtering path based on storage id (only search in files/ for home storage, filter by share root for shared, etc)
381
+
382
+        $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
383
+        $query = $builder
384
+            ->select('f.*')
385
+            ->from('filecache', 'f')
386
+            ->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
387
+            ->andWhere($builder->expr()->orX(
388
+            // handle non empty folders separate
389
+                $builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
390
+                $builder->expr()->eq('f.size', new Literal(0))
391
+            ))
392
+            ->orderBy('f.mtime', 'DESC')
393
+            ->setMaxResults($limit)
394
+            ->setFirstResult($offset);
395
+
396
+        $result = $query->execute()->fetchAll();
397
+
398
+        $files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
399
+            $mount = $mountMap[$entry['storage']];
400
+            $entry['internalPath'] = $entry['path'];
401
+            $entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
402
+            $entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
403
+            $path = $this->getAbsolutePath($mount, $entry['path']);
404
+            if (is_null($path)) {
405
+                return null;
406
+            }
407
+            $fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
408
+            return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409
+        }, $result));
410
+
411
+        return array_values(array_filter($files, function (Node $node) {
412
+            $relative = $this->getRelativePath($node->getPath());
413
+            return $relative !== null && $relative !== '/';
414
+        }));
415
+    }
416
+
417
+    private function getAbsolutePath(IMountPoint $mount, $path) {
418
+        $storage = $mount->getStorage();
419
+        if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
420
+            /** @var \OC\Files\Storage\Wrapper\Jail $storage */
421
+            $jailRoot = $storage->getUnjailedPath('');
422
+            $rootLength = strlen($jailRoot) + 1;
423
+            if ($path === $jailRoot) {
424
+                return $mount->getMountPoint();
425
+            } else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
+                return $mount->getMountPoint() . substr($path, $rootLength);
427
+            } else {
428
+                return null;
429
+            }
430
+        } else {
431
+            return $mount->getMountPoint() . $path;
432
+        }
433
+    }
434 434
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
 		if (!$this->isValidPath($path)) {
56 56
 			throw new NotPermittedException('Invalid path');
57 57
 		}
58
-		return $this->path . $this->normalizePath($path);
58
+		return $this->path.$this->normalizePath($path);
59 59
 	}
60 60
 
61 61
 	/**
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
 		}
69 69
 		if ($path === $this->path) {
70 70
 			return '/';
71
-		} else if (strpos($path, $this->path . '/') !== 0) {
71
+		} else if (strpos($path, $this->path.'/') !== 0) {
72 72
 			return null;
73 73
 		} else {
74 74
 			$path = substr($path, strlen($this->path));
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 	 * @return bool
84 84
 	 */
85 85
 	public function isSubNode($node) {
86
-		return strpos($node->getPath(), $this->path . '/') === 0;
86
+		return strpos($node->getPath(), $this->path.'/') === 0;
87 87
 	}
88 88
 
89 89
 	/**
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
 	public function getDirectoryListing() {
96 96
 		$folderContent = $this->view->getDirectoryContent($this->path);
97 97
 
98
-		return array_map(function (FileInfo $info) {
98
+		return array_map(function(FileInfo $info) {
99 99
 			if ($info->getMimetype() === 'httpd/unix-directory') {
100 100
 				return new Folder($this->root, $this->view, $info->getPath(), $info);
101 101
 			} else {
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
 	 */
197 197
 	public function search($query) {
198 198
 		if (is_string($query)) {
199
-			return $this->searchCommon('search', array('%' . $query . '%'));
199
+			return $this->searchCommon('search', array('%'.$query.'%'));
200 200
 		} else {
201 201
 			return $this->searchCommon('searchQuery', array($query));
202 202
 		}
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
 		$internalPath = $mount->getInternalPath($this->path);
237 237
 		$internalPath = rtrim($internalPath, '/');
238 238
 		if ($internalPath !== '') {
239
-			$internalPath = $internalPath . '/';
239
+			$internalPath = $internalPath.'/';
240 240
 		}
241 241
 		$internalRootLength = strlen($internalPath);
242 242
 
@@ -248,7 +248,7 @@  discard block
 block discarded – undo
248 248
 				$result['internalPath'] = $result['path'];
249 249
 				$result['path'] = substr($result['path'], $internalRootLength);
250 250
 				$result['storage'] = $storage;
251
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
251
+				$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
252 252
 			}
253 253
 		}
254 254
 
@@ -262,14 +262,14 @@  discard block
 block discarded – undo
262 262
 				$results = call_user_func_array(array($cache, $method), $args);
263 263
 				foreach ($results as $result) {
264 264
 					$result['internalPath'] = $result['path'];
265
-					$result['path'] = $relativeMountPoint . $result['path'];
265
+					$result['path'] = $relativeMountPoint.$result['path'];
266 266
 					$result['storage'] = $storage;
267
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
267
+					$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
268 268
 				}
269 269
 			}
270 270
 		}
271 271
 
272
-		return array_map(function (FileInfo $file) {
272
+		return array_map(function(FileInfo $file) {
273 273
 			return $this->createNode($file->getPath(), $file);
274 274
 		}, $files);
275 275
 	}
@@ -285,16 +285,16 @@  discard block
 block discarded – undo
285 285
 		} else {
286 286
 			$user = null;
287 287
 		}
288
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
288
+		$mountsContainingFile = $mountCache->getMountsForFileId((int) $id, $user);
289 289
 		$mounts = $this->root->getMountsIn($this->path);
290 290
 		$mounts[] = $this->root->getMount($this->path);
291 291
 		/** @var IMountPoint[] $folderMounts */
292
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
292
+		$folderMounts = array_combine(array_map(function(IMountPoint $mountPoint) {
293 293
 			return $mountPoint->getMountPoint();
294 294
 		}, $mounts), $mounts);
295 295
 
296 296
 		/** @var ICachedMountInfo[] $mountsContainingFile */
297
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
297
+		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function(ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298 298
 			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299 299
 		}));
300 300
 
@@ -305,25 +305,25 @@  discard block
 block discarded – undo
305 305
 		// we only need to get the cache info once, since all mounts we found point to the same storage
306 306
 
307 307
 		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
308
+		$cacheEntry = $mount->getStorage()->getCache()->get((int) $id);
309 309
 		if (!$cacheEntry) {
310 310
 			return [];
311 311
 		}
312 312
 		// cache jails will hide the "true" internal path
313
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
313
+		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath().'/'.$cacheEntry->getPath(), '/');
314 314
 
315
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
315
+		$nodes = array_map(function(ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316 316
 			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317 317
 			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318 318
 			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
319
+			$absolutePath = $cachedMountInfo->getMountPoint().$pathRelativeToMount;
320 320
 			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321 321
 				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322 322
 				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323 323
 			));
324 324
 		}, $mountsContainingFile);
325 325
 
326
-		return array_filter($nodes, function (Node $node) {
326
+		return array_filter($nodes, function(Node $node) {
327 327
 			return $this->getRelativePath($node->getPath());
328 328
 		});
329 329
 	}
@@ -367,10 +367,10 @@  discard block
 block discarded – undo
367 367
 		$mounts = $this->root->getMountsIn($this->path);
368 368
 		$mounts[] = $this->getMountPoint();
369 369
 
370
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
370
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
371 371
 			return $mount->getStorage();
372 372
 		});
373
-		$storageIds = array_map(function (IMountPoint $mount) {
373
+		$storageIds = array_map(function(IMountPoint $mount) {
374 374
 			return $mount->getStorage()->getCache()->getNumericStorageId();
375 375
 		}, $mounts);
376 376
 		/** @var IMountPoint[] $mountMap */
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 
396 396
 		$result = $query->execute()->fetchAll();
397 397
 
398
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
398
+		$files = array_filter(array_map(function(array $entry) use ($mountMap, $mimetypeLoader) {
399 399
 			$mount = $mountMap[$entry['storage']];
400 400
 			$entry['internalPath'] = $entry['path'];
401 401
 			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
@@ -408,7 +408,7 @@  discard block
 block discarded – undo
408 408
 			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409 409
 		}, $result));
410 410
 
411
-		return array_values(array_filter($files, function (Node $node) {
411
+		return array_values(array_filter($files, function(Node $node) {
412 412
 			$relative = $this->getRelativePath($node->getPath());
413 413
 			return $relative !== null && $relative !== '/';
414 414
 		}));
@@ -422,13 +422,13 @@  discard block
 block discarded – undo
422 422
 			$rootLength = strlen($jailRoot) + 1;
423 423
 			if ($path === $jailRoot) {
424 424
 				return $mount->getMountPoint();
425
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
-				return $mount->getMountPoint() . substr($path, $rootLength);
425
+			} else if (substr($path, 0, $rootLength) === $jailRoot.'/') {
426
+				return $mount->getMountPoint().substr($path, $rootLength);
427 427
 			} else {
428 428
 				return null;
429 429
 			}
430 430
 		} else {
431
-			return $mount->getMountPoint() . $path;
431
+			return $mount->getMountPoint().$path;
432 432
 		}
433 433
 	}
434 434
 }
Please login to merge, or discard this patch.
lib/public/Settings/IIconSection.php 2 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -33,6 +33,7 @@
 block discarded – undo
33 33
 	 *
34 34
 	 * @returns string
35 35
 	 * @since 12
36
+	 * @return string
36 37
 	 */
37 38
 	public function getIcon();
38 39
 }
Please login to merge, or discard this patch.
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -27,12 +27,12 @@
 block discarded – undo
27 27
  * @since 12
28 28
  */
29 29
 interface IIconSection extends ISection {
30
-	/**
31
-	 * returns the relative path to an 16*16 icon describing the section.
32
-	 * e.g. '/core/img/places/files.svg'
33
-	 *
34
-	 * @returns string
35
-	 * @since 12
36
-	 */
37
-	public function getIcon();
30
+    /**
31
+     * returns the relative path to an 16*16 icon describing the section.
32
+     * e.g. '/core/img/places/files.svg'
33
+     *
34
+     * @returns string
35
+     * @since 12
36
+     */
37
+    public function getIcon();
38 38
 }
Please login to merge, or discard this patch.
apps/dav/lib/CalDAV/Publishing/Xml/Publisher.php 2 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -20,7 +20,6 @@
 block discarded – undo
20 20
  */
21 21
 namespace OCA\DAV\CalDAV\Publishing\Xml;
22 22
 
23
-use OCA\DAV\CalDAV\Publishing\PublishPlugin as Plugin;
24 23
 use Sabre\Xml\Writer;
25 24
 use Sabre\Xml\XmlSerializable;
26 25
 
Please login to merge, or discard this patch.
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -26,58 +26,58 @@
 block discarded – undo
26 26
 
27 27
 class Publisher implements XmlSerializable {
28 28
 
29
-	/**
30
-	 * @var string $publishUrl
31
-	 */
32
-	protected $publishUrl;
29
+    /**
30
+     * @var string $publishUrl
31
+     */
32
+    protected $publishUrl;
33 33
 
34
-	/**
35
-	 * @var boolean $isPublished
36
-	 */
37
-	protected $isPublished;
34
+    /**
35
+     * @var boolean $isPublished
36
+     */
37
+    protected $isPublished;
38 38
 
39
-	/**
40
-	 * @param string $publishUrl
41
-	 * @param boolean $isPublished
42
-	 */
43
-	function __construct($publishUrl, $isPublished) {
44
-		$this->publishUrl = $publishUrl;
45
-		$this->isPublished = $isPublished;
46
-	}
39
+    /**
40
+     * @param string $publishUrl
41
+     * @param boolean $isPublished
42
+     */
43
+    function __construct($publishUrl, $isPublished) {
44
+        $this->publishUrl = $publishUrl;
45
+        $this->isPublished = $isPublished;
46
+    }
47 47
 
48
-	/**
49
-	 * @return string
50
-	 */
51
-	function getValue() {
52
-		return $this->publishUrl;
53
-	}
48
+    /**
49
+     * @return string
50
+     */
51
+    function getValue() {
52
+        return $this->publishUrl;
53
+    }
54 54
 
55
-	/**
56
-	 * The xmlSerialize metod is called during xml writing.
57
-	 *
58
-	 * Use the $writer argument to write its own xml serialization.
59
-	 *
60
-	 * An important note: do _not_ create a parent element. Any element
61
-	 * implementing XmlSerializble should only ever write what's considered
62
-	 * its 'inner xml'.
63
-	 *
64
-	 * The parent of the current element is responsible for writing a
65
-	 * containing element.
66
-	 *
67
-	 * This allows serializers to be re-used for different element names.
68
-	 *
69
-	 * If you are opening new elements, you must also close them again.
70
-	 *
71
-	 * @param Writer $writer
72
-	 * @return void
73
-	 */
74
-	function xmlSerialize(Writer $writer) {
75
-		if (!$this->isPublished) {
76
-			// for pre-publish-url
77
-			$writer->write($this->publishUrl);
78
-		} else {
79
-			// for publish-url
80
-			$writer->writeElement('{DAV:}href', $this->publishUrl);
81
-		}
82
-	}
55
+    /**
56
+     * The xmlSerialize metod is called during xml writing.
57
+     *
58
+     * Use the $writer argument to write its own xml serialization.
59
+     *
60
+     * An important note: do _not_ create a parent element. Any element
61
+     * implementing XmlSerializble should only ever write what's considered
62
+     * its 'inner xml'.
63
+     *
64
+     * The parent of the current element is responsible for writing a
65
+     * containing element.
66
+     *
67
+     * This allows serializers to be re-used for different element names.
68
+     *
69
+     * If you are opening new elements, you must also close them again.
70
+     *
71
+     * @param Writer $writer
72
+     * @return void
73
+     */
74
+    function xmlSerialize(Writer $writer) {
75
+        if (!$this->isPublished) {
76
+            // for pre-publish-url
77
+            $writer->write($this->publishUrl);
78
+        } else {
79
+            // for publish-url
80
+            $writer->writeElement('{DAV:}href', $this->publishUrl);
81
+        }
82
+    }
83 83
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/FilesPlugin.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -31,7 +31,6 @@
 block discarded – undo
31 31
 namespace OCA\DAV\Connector\Sabre;
32 32
 
33 33
 use OC\Files\View;
34
-use OCA\DAV\Upload\FutureFile;
35 34
 use OCP\Files\ForbiddenException;
36 35
 use OCP\IPreview;
37 36
 use Sabre\DAV\Exception\Forbidden;
Please login to merge, or discard this patch.
Braces   +3 added lines, -1 removed lines patch added patch discarded remove patch
@@ -245,7 +245,9 @@
 block discarded – undo
245 245
 	function httpGet(RequestInterface $request, ResponseInterface $response) {
246 246
 		// Only handle valid files
247 247
 		$node = $this->tree->getNodeForPath($request->getPath());
248
-		if (!($node instanceof IFile)) return;
248
+		if (!($node instanceof IFile)) {
249
+		    return;
250
+		}
249 251
 
250 252
 		// adds a 'Content-Disposition: attachment' header in case no disposition
251 253
 		// header has been set before
Please login to merge, or discard this patch.
Indentation   +391 added lines, -391 removed lines patch added patch discarded remove patch
@@ -51,395 +51,395 @@
 block discarded – undo
51 51
 
52 52
 class FilesPlugin extends ServerPlugin {
53 53
 
54
-	// namespace
55
-	const NS_OWNCLOUD = 'http://owncloud.org/ns';
56
-	const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
57
-	const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
58
-	const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid';
59
-	const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
60
-	const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions';
61
-	const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
62
-	const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
63
-	const GETETAG_PROPERTYNAME = '{DAV:}getetag';
64
-	const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
65
-	const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
66
-	const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
67
-	const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums';
68
-	const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint';
69
-	const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview';
70
-
71
-	/**
72
-	 * Reference to main server object
73
-	 *
74
-	 * @var \Sabre\DAV\Server
75
-	 */
76
-	private $server;
77
-
78
-	/**
79
-	 * @var Tree
80
-	 */
81
-	private $tree;
82
-
83
-	/**
84
-	 * Whether this is public webdav.
85
-	 * If true, some returned information will be stripped off.
86
-	 *
87
-	 * @var bool
88
-	 */
89
-	private $isPublic;
90
-
91
-	/**
92
-	 * @var View
93
-	 */
94
-	private $fileView;
95
-
96
-	/**
97
-	 * @var bool
98
-	 */
99
-	private $downloadAttachment;
100
-
101
-	/**
102
-	 * @var IConfig
103
-	 */
104
-	private $config;
105
-
106
-	/**
107
-	 * @var IRequest
108
-	 */
109
-	private $request;
110
-
111
-	/**
112
-	 * @var IPreview
113
-	 */
114
-	private $previewManager;
115
-
116
-	/**
117
-	 * @param Tree $tree
118
-	 * @param IConfig $config
119
-	 * @param IRequest $request
120
-	 * @param IPreview $previewManager
121
-	 * @param bool $isPublic
122
-	 * @param bool $downloadAttachment
123
-	 */
124
-	public function __construct(Tree $tree,
125
-								IConfig $config,
126
-								IRequest $request,
127
-								IPreview $previewManager,
128
-								$isPublic = false,
129
-								$downloadAttachment = true) {
130
-		$this->tree = $tree;
131
-		$this->config = $config;
132
-		$this->request = $request;
133
-		$this->isPublic = $isPublic;
134
-		$this->downloadAttachment = $downloadAttachment;
135
-		$this->previewManager = $previewManager;
136
-	}
137
-
138
-	/**
139
-	 * This initializes the plugin.
140
-	 *
141
-	 * This function is called by \Sabre\DAV\Server, after
142
-	 * addPlugin is called.
143
-	 *
144
-	 * This method should set up the required event subscriptions.
145
-	 *
146
-	 * @param \Sabre\DAV\Server $server
147
-	 * @return void
148
-	 */
149
-	public function initialize(\Sabre\DAV\Server $server) {
150
-
151
-		$server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
152
-		$server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc';
153
-		$server->protectedProperties[] = self::FILEID_PROPERTYNAME;
154
-		$server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME;
155
-		$server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
156
-		$server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME;
157
-		$server->protectedProperties[] = self::SIZE_PROPERTYNAME;
158
-		$server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
159
-		$server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
160
-		$server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
161
-		$server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME;
162
-		$server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME;
163
-		$server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
164
-
165
-		// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
166
-		$allowedProperties = ['{DAV:}getetag'];
167
-		$server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
168
-
169
-		$this->server = $server;
170
-		$this->server->on('propFind', array($this, 'handleGetProperties'));
171
-		$this->server->on('propPatch', array($this, 'handleUpdateProperties'));
172
-		$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
173
-		$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
174
-		$this->server->on('afterMethod:GET', [$this,'httpGet']);
175
-		$this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
176
-		$this->server->on('afterResponse', function($request, ResponseInterface $response) {
177
-			$body = $response->getBody();
178
-			if (is_resource($body)) {
179
-				fclose($body);
180
-			}
181
-		});
182
-		$this->server->on('beforeMove', [$this, 'checkMove']);
183
-	}
184
-
185
-	/**
186
-	 * Plugin that checks if a move can actually be performed.
187
-	 *
188
-	 * @param string $source source path
189
-	 * @param string $destination destination path
190
-	 * @throws Forbidden
191
-	 * @throws NotFound
192
-	 */
193
-	function checkMove($source, $destination) {
194
-		$sourceNode = $this->tree->getNodeForPath($source);
195
-		if (!$sourceNode instanceof Node) {
196
-			return;
197
-		}
198
-		list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source);
199
-		list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
200
-
201
-		if ($sourceDir !== $destinationDir) {
202
-			$sourceNodeFileInfo = $sourceNode->getFileInfo();
203
-			if (is_null($sourceNodeFileInfo)) {
204
-				throw new NotFound($source . ' does not exist');
205
-			}
206
-
207
-			if (!$sourceNodeFileInfo->isDeletable()) {
208
-				throw new Forbidden($source . " cannot be deleted");
209
-			}
210
-		}
211
-	}
212
-
213
-	/**
214
-	 * This sets a cookie to be able to recognize the start of the download
215
-	 * the content must not be longer than 32 characters and must only contain
216
-	 * alphanumeric characters
217
-	 *
218
-	 * @param RequestInterface $request
219
-	 * @param ResponseInterface $response
220
-	 */
221
-	function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
222
-		$queryParams = $request->getQueryParameters();
223
-
224
-		/**
225
-		 * this sets a cookie to be able to recognize the start of the download
226
-		 * the content must not be longer than 32 characters and must only contain
227
-		 * alphanumeric characters
228
-		 */
229
-		if (isset($queryParams['downloadStartSecret'])) {
230
-			$token = $queryParams['downloadStartSecret'];
231
-			if (!isset($token[32])
232
-				&& preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
233
-				// FIXME: use $response->setHeader() instead
234
-				setcookie('ocDownloadStarted', $token, time() + 20, '/');
235
-			}
236
-		}
237
-	}
238
-
239
-	/**
240
-	 * Add headers to file download
241
-	 *
242
-	 * @param RequestInterface $request
243
-	 * @param ResponseInterface $response
244
-	 */
245
-	function httpGet(RequestInterface $request, ResponseInterface $response) {
246
-		// Only handle valid files
247
-		$node = $this->tree->getNodeForPath($request->getPath());
248
-		if (!($node instanceof IFile)) return;
249
-
250
-		// adds a 'Content-Disposition: attachment' header in case no disposition
251
-		// header has been set before
252
-		if ($this->downloadAttachment &&
253
-			$response->getHeader('Content-Disposition') === null) {
254
-			$filename = $node->getName();
255
-			if ($this->request->isUserAgent(
256
-				[
257
-					\OC\AppFramework\Http\Request::USER_AGENT_IE,
258
-					\OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
259
-					\OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
260
-				])) {
261
-				$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
262
-			} else {
263
-				$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
264
-													 . '; filename="' . rawurlencode($filename) . '"');
265
-			}
266
-		}
267
-
268
-		if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
269
-			//Add OC-Checksum header
270
-			/** @var $node File */
271
-			$checksum = $node->getChecksum();
272
-			if ($checksum !== null && $checksum !== '') {
273
-				$response->addHeader('OC-Checksum', $checksum);
274
-			}
275
-		}
276
-	}
277
-
278
-	/**
279
-	 * Adds all ownCloud-specific properties
280
-	 *
281
-	 * @param PropFind $propFind
282
-	 * @param \Sabre\DAV\INode $node
283
-	 * @return void
284
-	 */
285
-	public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
286
-
287
-		$httpRequest = $this->server->httpRequest;
288
-
289
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
290
-
291
-			$propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
292
-				return $node->getFileId();
293
-			});
294
-
295
-			$propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) {
296
-				return $node->getInternalFileId();
297
-			});
298
-
299
-			$propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
300
-				$perms = $node->getDavPermissions();
301
-				if ($this->isPublic) {
302
-					// remove mount information
303
-					$perms = str_replace(['S', 'M'], '', $perms);
304
-				}
305
-				return $perms;
306
-			});
307
-
308
-			$propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) {
309
-				return $node->getSharePermissions(
310
-					$httpRequest->getRawServerValue('PHP_AUTH_USER')
311
-				);
312
-			});
313
-
314
-			$propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
315
-				return $node->getETag();
316
-			});
317
-
318
-			$propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
319
-				$owner = $node->getOwner();
320
-				if (!$owner) {
321
-					return null;
322
-				} else {
323
-					return $owner->getUID();
324
-				}
325
-			});
326
-			$propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
327
-				$owner = $node->getOwner();
328
-				if (!$owner) {
329
-					return null;
330
-				} else {
331
-					return $owner->getDisplayName();
332
-				}
333
-			});
334
-
335
-			$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
336
-				return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
337
-			});
338
-			$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
339
-				return $node->getSize();
340
-			});
341
-		}
342
-
343
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
344
-			$propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) {
345
-				return $this->config->getSystemValue('data-fingerprint', '');
346
-			});
347
-		}
348
-
349
-		if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
350
-			$propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
351
-				/** @var $node \OCA\DAV\Connector\Sabre\File */
352
-				try {
353
-					$directDownloadUrl = $node->getDirectDownload();
354
-					if (isset($directDownloadUrl['url'])) {
355
-						return $directDownloadUrl['url'];
356
-					}
357
-				} catch (StorageNotAvailableException $e) {
358
-					return false;
359
-				} catch (ForbiddenException $e) {
360
-					return false;
361
-				}
362
-				return false;
363
-			});
364
-
365
-			$propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) {
366
-				$checksum = $node->getChecksum();
367
-				if ($checksum === NULL || $checksum === '') {
368
-					return null;
369
-				}
370
-
371
-				return new ChecksumList($checksum);
372
-			});
373
-
374
-		}
375
-
376
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) {
377
-			$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
378
-				return $node->getSize();
379
-			});
380
-		}
381
-	}
382
-
383
-	/**
384
-	 * Update ownCloud-specific properties
385
-	 *
386
-	 * @param string $path
387
-	 * @param PropPatch $propPatch
388
-	 *
389
-	 * @return void
390
-	 */
391
-	public function handleUpdateProperties($path, PropPatch $propPatch) {
392
-		$propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($path) {
393
-			if (empty($time)) {
394
-				return false;
395
-			}
396
-			$node = $this->tree->getNodeForPath($path);
397
-			if (is_null($node)) {
398
-				return 404;
399
-			}
400
-			$node->touch($time);
401
-			return true;
402
-		});
403
-		$propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) {
404
-			if (empty($etag)) {
405
-				return false;
406
-			}
407
-			$node = $this->tree->getNodeForPath($path);
408
-			if (is_null($node)) {
409
-				return 404;
410
-			}
411
-			if ($node->setEtag($etag) !== -1) {
412
-				return true;
413
-			}
414
-			return false;
415
-		});
416
-	}
417
-
418
-	/**
419
-	 * @param string $filePath
420
-	 * @param \Sabre\DAV\INode $node
421
-	 * @throws \Sabre\DAV\Exception\BadRequest
422
-	 */
423
-	public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
424
-		// chunked upload handling
425
-		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
426
-			list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
427
-			$info = \OC_FileChunking::decodeName($name);
428
-			if (!empty($info)) {
429
-				$filePath = $path . '/' . $info['name'];
430
-			}
431
-		}
432
-
433
-		// we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder
434
-		if (!$this->server->tree->nodeExists($filePath)) {
435
-			return;
436
-		}
437
-		$node = $this->server->tree->getNodeForPath($filePath);
438
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
439
-			$fileId = $node->getFileId();
440
-			if (!is_null($fileId)) {
441
-				$this->server->httpResponse->setHeader('OC-FileId', $fileId);
442
-			}
443
-		}
444
-	}
54
+    // namespace
55
+    const NS_OWNCLOUD = 'http://owncloud.org/ns';
56
+    const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
57
+    const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
58
+    const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid';
59
+    const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
60
+    const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions';
61
+    const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
62
+    const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
63
+    const GETETAG_PROPERTYNAME = '{DAV:}getetag';
64
+    const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
65
+    const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
66
+    const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
67
+    const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums';
68
+    const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint';
69
+    const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview';
70
+
71
+    /**
72
+     * Reference to main server object
73
+     *
74
+     * @var \Sabre\DAV\Server
75
+     */
76
+    private $server;
77
+
78
+    /**
79
+     * @var Tree
80
+     */
81
+    private $tree;
82
+
83
+    /**
84
+     * Whether this is public webdav.
85
+     * If true, some returned information will be stripped off.
86
+     *
87
+     * @var bool
88
+     */
89
+    private $isPublic;
90
+
91
+    /**
92
+     * @var View
93
+     */
94
+    private $fileView;
95
+
96
+    /**
97
+     * @var bool
98
+     */
99
+    private $downloadAttachment;
100
+
101
+    /**
102
+     * @var IConfig
103
+     */
104
+    private $config;
105
+
106
+    /**
107
+     * @var IRequest
108
+     */
109
+    private $request;
110
+
111
+    /**
112
+     * @var IPreview
113
+     */
114
+    private $previewManager;
115
+
116
+    /**
117
+     * @param Tree $tree
118
+     * @param IConfig $config
119
+     * @param IRequest $request
120
+     * @param IPreview $previewManager
121
+     * @param bool $isPublic
122
+     * @param bool $downloadAttachment
123
+     */
124
+    public function __construct(Tree $tree,
125
+                                IConfig $config,
126
+                                IRequest $request,
127
+                                IPreview $previewManager,
128
+                                $isPublic = false,
129
+                                $downloadAttachment = true) {
130
+        $this->tree = $tree;
131
+        $this->config = $config;
132
+        $this->request = $request;
133
+        $this->isPublic = $isPublic;
134
+        $this->downloadAttachment = $downloadAttachment;
135
+        $this->previewManager = $previewManager;
136
+    }
137
+
138
+    /**
139
+     * This initializes the plugin.
140
+     *
141
+     * This function is called by \Sabre\DAV\Server, after
142
+     * addPlugin is called.
143
+     *
144
+     * This method should set up the required event subscriptions.
145
+     *
146
+     * @param \Sabre\DAV\Server $server
147
+     * @return void
148
+     */
149
+    public function initialize(\Sabre\DAV\Server $server) {
150
+
151
+        $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
152
+        $server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc';
153
+        $server->protectedProperties[] = self::FILEID_PROPERTYNAME;
154
+        $server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME;
155
+        $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
156
+        $server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME;
157
+        $server->protectedProperties[] = self::SIZE_PROPERTYNAME;
158
+        $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
159
+        $server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
160
+        $server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
161
+        $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME;
162
+        $server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME;
163
+        $server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
164
+
165
+        // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
166
+        $allowedProperties = ['{DAV:}getetag'];
167
+        $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
168
+
169
+        $this->server = $server;
170
+        $this->server->on('propFind', array($this, 'handleGetProperties'));
171
+        $this->server->on('propPatch', array($this, 'handleUpdateProperties'));
172
+        $this->server->on('afterBind', array($this, 'sendFileIdHeader'));
173
+        $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
174
+        $this->server->on('afterMethod:GET', [$this,'httpGet']);
175
+        $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
176
+        $this->server->on('afterResponse', function($request, ResponseInterface $response) {
177
+            $body = $response->getBody();
178
+            if (is_resource($body)) {
179
+                fclose($body);
180
+            }
181
+        });
182
+        $this->server->on('beforeMove', [$this, 'checkMove']);
183
+    }
184
+
185
+    /**
186
+     * Plugin that checks if a move can actually be performed.
187
+     *
188
+     * @param string $source source path
189
+     * @param string $destination destination path
190
+     * @throws Forbidden
191
+     * @throws NotFound
192
+     */
193
+    function checkMove($source, $destination) {
194
+        $sourceNode = $this->tree->getNodeForPath($source);
195
+        if (!$sourceNode instanceof Node) {
196
+            return;
197
+        }
198
+        list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source);
199
+        list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
200
+
201
+        if ($sourceDir !== $destinationDir) {
202
+            $sourceNodeFileInfo = $sourceNode->getFileInfo();
203
+            if (is_null($sourceNodeFileInfo)) {
204
+                throw new NotFound($source . ' does not exist');
205
+            }
206
+
207
+            if (!$sourceNodeFileInfo->isDeletable()) {
208
+                throw new Forbidden($source . " cannot be deleted");
209
+            }
210
+        }
211
+    }
212
+
213
+    /**
214
+     * This sets a cookie to be able to recognize the start of the download
215
+     * the content must not be longer than 32 characters and must only contain
216
+     * alphanumeric characters
217
+     *
218
+     * @param RequestInterface $request
219
+     * @param ResponseInterface $response
220
+     */
221
+    function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
222
+        $queryParams = $request->getQueryParameters();
223
+
224
+        /**
225
+         * this sets a cookie to be able to recognize the start of the download
226
+         * the content must not be longer than 32 characters and must only contain
227
+         * alphanumeric characters
228
+         */
229
+        if (isset($queryParams['downloadStartSecret'])) {
230
+            $token = $queryParams['downloadStartSecret'];
231
+            if (!isset($token[32])
232
+                && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
233
+                // FIXME: use $response->setHeader() instead
234
+                setcookie('ocDownloadStarted', $token, time() + 20, '/');
235
+            }
236
+        }
237
+    }
238
+
239
+    /**
240
+     * Add headers to file download
241
+     *
242
+     * @param RequestInterface $request
243
+     * @param ResponseInterface $response
244
+     */
245
+    function httpGet(RequestInterface $request, ResponseInterface $response) {
246
+        // Only handle valid files
247
+        $node = $this->tree->getNodeForPath($request->getPath());
248
+        if (!($node instanceof IFile)) return;
249
+
250
+        // adds a 'Content-Disposition: attachment' header in case no disposition
251
+        // header has been set before
252
+        if ($this->downloadAttachment &&
253
+            $response->getHeader('Content-Disposition') === null) {
254
+            $filename = $node->getName();
255
+            if ($this->request->isUserAgent(
256
+                [
257
+                    \OC\AppFramework\Http\Request::USER_AGENT_IE,
258
+                    \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
259
+                    \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
260
+                ])) {
261
+                $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
262
+            } else {
263
+                $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
264
+                                                        . '; filename="' . rawurlencode($filename) . '"');
265
+            }
266
+        }
267
+
268
+        if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
269
+            //Add OC-Checksum header
270
+            /** @var $node File */
271
+            $checksum = $node->getChecksum();
272
+            if ($checksum !== null && $checksum !== '') {
273
+                $response->addHeader('OC-Checksum', $checksum);
274
+            }
275
+        }
276
+    }
277
+
278
+    /**
279
+     * Adds all ownCloud-specific properties
280
+     *
281
+     * @param PropFind $propFind
282
+     * @param \Sabre\DAV\INode $node
283
+     * @return void
284
+     */
285
+    public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
286
+
287
+        $httpRequest = $this->server->httpRequest;
288
+
289
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
290
+
291
+            $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
292
+                return $node->getFileId();
293
+            });
294
+
295
+            $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) {
296
+                return $node->getInternalFileId();
297
+            });
298
+
299
+            $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
300
+                $perms = $node->getDavPermissions();
301
+                if ($this->isPublic) {
302
+                    // remove mount information
303
+                    $perms = str_replace(['S', 'M'], '', $perms);
304
+                }
305
+                return $perms;
306
+            });
307
+
308
+            $propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) {
309
+                return $node->getSharePermissions(
310
+                    $httpRequest->getRawServerValue('PHP_AUTH_USER')
311
+                );
312
+            });
313
+
314
+            $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
315
+                return $node->getETag();
316
+            });
317
+
318
+            $propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
319
+                $owner = $node->getOwner();
320
+                if (!$owner) {
321
+                    return null;
322
+                } else {
323
+                    return $owner->getUID();
324
+                }
325
+            });
326
+            $propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
327
+                $owner = $node->getOwner();
328
+                if (!$owner) {
329
+                    return null;
330
+                } else {
331
+                    return $owner->getDisplayName();
332
+                }
333
+            });
334
+
335
+            $propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
336
+                return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
337
+            });
338
+            $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
339
+                return $node->getSize();
340
+            });
341
+        }
342
+
343
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
344
+            $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) {
345
+                return $this->config->getSystemValue('data-fingerprint', '');
346
+            });
347
+        }
348
+
349
+        if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
350
+            $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
351
+                /** @var $node \OCA\DAV\Connector\Sabre\File */
352
+                try {
353
+                    $directDownloadUrl = $node->getDirectDownload();
354
+                    if (isset($directDownloadUrl['url'])) {
355
+                        return $directDownloadUrl['url'];
356
+                    }
357
+                } catch (StorageNotAvailableException $e) {
358
+                    return false;
359
+                } catch (ForbiddenException $e) {
360
+                    return false;
361
+                }
362
+                return false;
363
+            });
364
+
365
+            $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) {
366
+                $checksum = $node->getChecksum();
367
+                if ($checksum === NULL || $checksum === '') {
368
+                    return null;
369
+                }
370
+
371
+                return new ChecksumList($checksum);
372
+            });
373
+
374
+        }
375
+
376
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) {
377
+            $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
378
+                return $node->getSize();
379
+            });
380
+        }
381
+    }
382
+
383
+    /**
384
+     * Update ownCloud-specific properties
385
+     *
386
+     * @param string $path
387
+     * @param PropPatch $propPatch
388
+     *
389
+     * @return void
390
+     */
391
+    public function handleUpdateProperties($path, PropPatch $propPatch) {
392
+        $propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($path) {
393
+            if (empty($time)) {
394
+                return false;
395
+            }
396
+            $node = $this->tree->getNodeForPath($path);
397
+            if (is_null($node)) {
398
+                return 404;
399
+            }
400
+            $node->touch($time);
401
+            return true;
402
+        });
403
+        $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) {
404
+            if (empty($etag)) {
405
+                return false;
406
+            }
407
+            $node = $this->tree->getNodeForPath($path);
408
+            if (is_null($node)) {
409
+                return 404;
410
+            }
411
+            if ($node->setEtag($etag) !== -1) {
412
+                return true;
413
+            }
414
+            return false;
415
+        });
416
+    }
417
+
418
+    /**
419
+     * @param string $filePath
420
+     * @param \Sabre\DAV\INode $node
421
+     * @throws \Sabre\DAV\Exception\BadRequest
422
+     */
423
+    public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
424
+        // chunked upload handling
425
+        if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
426
+            list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
427
+            $info = \OC_FileChunking::decodeName($name);
428
+            if (!empty($info)) {
429
+                $filePath = $path . '/' . $info['name'];
430
+            }
431
+        }
432
+
433
+        // we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder
434
+        if (!$this->server->tree->nodeExists($filePath)) {
435
+            return;
436
+        }
437
+        $node = $this->server->tree->getNodeForPath($filePath);
438
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
439
+            $fileId = $node->getFileId();
440
+            if (!is_null($fileId)) {
441
+                $this->server->httpResponse->setHeader('OC-FileId', $fileId);
442
+            }
443
+        }
444
+    }
445 445
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -171,7 +171,7 @@  discard block
 block discarded – undo
171 171
 		$this->server->on('propPatch', array($this, 'handleUpdateProperties'));
172 172
 		$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
173 173
 		$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
174
-		$this->server->on('afterMethod:GET', [$this,'httpGet']);
174
+		$this->server->on('afterMethod:GET', [$this, 'httpGet']);
175 175
 		$this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
176 176
 		$this->server->on('afterResponse', function($request, ResponseInterface $response) {
177 177
 			$body = $response->getBody();
@@ -201,11 +201,11 @@  discard block
 block discarded – undo
201 201
 		if ($sourceDir !== $destinationDir) {
202 202
 			$sourceNodeFileInfo = $sourceNode->getFileInfo();
203 203
 			if (is_null($sourceNodeFileInfo)) {
204
-				throw new NotFound($source . ' does not exist');
204
+				throw new NotFound($source.' does not exist');
205 205
 			}
206 206
 
207 207
 			if (!$sourceNodeFileInfo->isDeletable()) {
208
-				throw new Forbidden($source . " cannot be deleted");
208
+				throw new Forbidden($source." cannot be deleted");
209 209
 			}
210 210
 		}
211 211
 	}
@@ -258,10 +258,10 @@  discard block
 block discarded – undo
258 258
 					\OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
259 259
 					\OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
260 260
 				])) {
261
-				$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
261
+				$response->addHeader('Content-Disposition', 'attachment; filename="'.rawurlencode($filename).'"');
262 262
 			} else {
263
-				$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
264
-													 . '; filename="' . rawurlencode($filename) . '"');
263
+				$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\''.rawurlencode($filename)
264
+													 . '; filename="'.rawurlencode($filename).'"');
265 265
 			}
266 266
 		}
267 267
 
@@ -332,7 +332,7 @@  discard block
 block discarded – undo
332 332
 				}
333 333
 			});
334 334
 
335
-			$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
335
+			$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function() use ($node) {
336 336
 				return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
337 337
 			});
338 338
 			$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
@@ -426,7 +426,7 @@  discard block
 block discarded – undo
426 426
 			list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
427 427
 			$info = \OC_FileChunking::decodeName($name);
428 428
 			if (!empty($info)) {
429
-				$filePath = $path . '/' . $info['name'];
429
+				$filePath = $path.'/'.$info['name'];
430 430
 			}
431 431
 		}
432 432
 
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/FTP.php 4 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -139,6 +139,9 @@
 block discarded – undo
139 139
 		return false;
140 140
 	}
141 141
 
142
+	/**
143
+	 * @param string $path
144
+	 */
142 145
 	public function writeBack($tmpFile, $path) {
143 146
 		$this->uploadFile($tmpFile, $path);
144 147
 		unlink($tmpFile);
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -37,122 +37,122 @@
 block discarded – undo
37 37
 use Icewind\Streams\RetryWrapper;
38 38
 
39 39
 class FTP extends StreamWrapper{
40
-	private $password;
41
-	private $user;
42
-	private $host;
43
-	private $secure;
44
-	private $root;
40
+    private $password;
41
+    private $user;
42
+    private $host;
43
+    private $secure;
44
+    private $root;
45 45
 
46
-	private static $tempFiles=array();
46
+    private static $tempFiles=array();
47 47
 
48
-	public function __construct($params) {
49
-		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
50
-			$this->host=$params['host'];
51
-			$this->user=$params['user'];
52
-			$this->password=$params['password'];
53
-			if (isset($params['secure'])) {
54
-				$this->secure = $params['secure'];
55
-			} else {
56
-				$this->secure = false;
57
-			}
58
-			$this->root=isset($params['root'])?$params['root']:'/';
59
-			if ( ! $this->root || $this->root[0]!='/') {
60
-				$this->root='/'.$this->root;
61
-			}
62
-			if (substr($this->root, -1) !== '/') {
63
-				$this->root .= '/';
64
-			}
65
-		} else {
66
-			throw new \Exception('Creating FTP storage failed');
67
-		}
48
+    public function __construct($params) {
49
+        if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
50
+            $this->host=$params['host'];
51
+            $this->user=$params['user'];
52
+            $this->password=$params['password'];
53
+            if (isset($params['secure'])) {
54
+                $this->secure = $params['secure'];
55
+            } else {
56
+                $this->secure = false;
57
+            }
58
+            $this->root=isset($params['root'])?$params['root']:'/';
59
+            if ( ! $this->root || $this->root[0]!='/') {
60
+                $this->root='/'.$this->root;
61
+            }
62
+            if (substr($this->root, -1) !== '/') {
63
+                $this->root .= '/';
64
+            }
65
+        } else {
66
+            throw new \Exception('Creating FTP storage failed');
67
+        }
68 68
 		
69
-	}
69
+    }
70 70
 
71
-	public function getId(){
72
-		return 'ftp::' . $this->user . '@' . $this->host . '/' . $this->root;
73
-	}
71
+    public function getId(){
72
+        return 'ftp::' . $this->user . '@' . $this->host . '/' . $this->root;
73
+    }
74 74
 
75
-	/**
76
-	 * construct the ftp url
77
-	 * @param string $path
78
-	 * @return string
79
-	 */
80
-	public function constructUrl($path) {
81
-		$url='ftp';
82
-		if ($this->secure) {
83
-			$url.='s';
84
-		}
85
-		$url.='://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
86
-		return $url;
87
-	}
75
+    /**
76
+     * construct the ftp url
77
+     * @param string $path
78
+     * @return string
79
+     */
80
+    public function constructUrl($path) {
81
+        $url='ftp';
82
+        if ($this->secure) {
83
+            $url.='s';
84
+        }
85
+        $url.='://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
86
+        return $url;
87
+    }
88 88
 
89
-	/**
90
-	 * Unlinks file or directory
91
-	 * @param string $path
92
-	 */
93
-	public function unlink($path) {
94
-		if ($this->is_dir($path)) {
95
-			return $this->rmdir($path);
96
-		}
97
-		else {
98
-			$url = $this->constructUrl($path);
99
-			$result = unlink($url);
100
-			clearstatcache(true, $url);
101
-			return $result;
102
-		}
103
-	}
104
-	public function fopen($path,$mode) {
105
-		switch($mode) {
106
-			case 'r':
107
-			case 'rb':
108
-			case 'w':
109
-			case 'wb':
110
-			case 'a':
111
-			case 'ab':
112
-				//these are supported by the wrapper
113
-				$context = stream_context_create(array('ftp' => array('overwrite' => true)));
114
-				$handle = fopen($this->constructUrl($path), $mode, false, $context);
115
-				return RetryWrapper::wrap($handle);
116
-			case 'r+':
117
-			case 'w+':
118
-			case 'wb+':
119
-			case 'a+':
120
-			case 'x':
121
-			case 'x+':
122
-			case 'c':
123
-			case 'c+':
124
-				//emulate these
125
-				if (strrpos($path, '.')!==false) {
126
-					$ext=substr($path, strrpos($path, '.'));
127
-				} else {
128
-					$ext='';
129
-				}
130
-				$tmpFile=\OCP\Files::tmpFile($ext);
131
-				if ($this->file_exists($path)) {
132
-					$this->getFile($path, $tmpFile);
133
-				}
134
-				$handle = fopen($tmpFile, $mode);
135
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
136
-					$this->writeBack($tmpFile, $path);
137
-				});
138
-		}
139
-		return false;
140
-	}
89
+    /**
90
+     * Unlinks file or directory
91
+     * @param string $path
92
+     */
93
+    public function unlink($path) {
94
+        if ($this->is_dir($path)) {
95
+            return $this->rmdir($path);
96
+        }
97
+        else {
98
+            $url = $this->constructUrl($path);
99
+            $result = unlink($url);
100
+            clearstatcache(true, $url);
101
+            return $result;
102
+        }
103
+    }
104
+    public function fopen($path,$mode) {
105
+        switch($mode) {
106
+            case 'r':
107
+            case 'rb':
108
+            case 'w':
109
+            case 'wb':
110
+            case 'a':
111
+            case 'ab':
112
+                //these are supported by the wrapper
113
+                $context = stream_context_create(array('ftp' => array('overwrite' => true)));
114
+                $handle = fopen($this->constructUrl($path), $mode, false, $context);
115
+                return RetryWrapper::wrap($handle);
116
+            case 'r+':
117
+            case 'w+':
118
+            case 'wb+':
119
+            case 'a+':
120
+            case 'x':
121
+            case 'x+':
122
+            case 'c':
123
+            case 'c+':
124
+                //emulate these
125
+                if (strrpos($path, '.')!==false) {
126
+                    $ext=substr($path, strrpos($path, '.'));
127
+                } else {
128
+                    $ext='';
129
+                }
130
+                $tmpFile=\OCP\Files::tmpFile($ext);
131
+                if ($this->file_exists($path)) {
132
+                    $this->getFile($path, $tmpFile);
133
+                }
134
+                $handle = fopen($tmpFile, $mode);
135
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
136
+                    $this->writeBack($tmpFile, $path);
137
+                });
138
+        }
139
+        return false;
140
+    }
141 141
 
142
-	public function writeBack($tmpFile, $path) {
143
-		$this->uploadFile($tmpFile, $path);
144
-		unlink($tmpFile);
145
-	}
142
+    public function writeBack($tmpFile, $path) {
143
+        $this->uploadFile($tmpFile, $path);
144
+        unlink($tmpFile);
145
+    }
146 146
 
147
-	/**
148
-	 * check if php-ftp is installed
149
-	 */
150
-	public static function checkDependencies() {
151
-		if (function_exists('ftp_login')) {
152
-			return(true);
153
-		} else {
154
-			return array('ftp');
155
-		}
156
-	}
147
+    /**
148
+     * check if php-ftp is installed
149
+     */
150
+    public static function checkDependencies() {
151
+        if (function_exists('ftp_login')) {
152
+            return(true);
153
+        } else {
154
+            return array('ftp');
155
+        }
156
+    }
157 157
 
158 158
 }
Please login to merge, or discard this patch.
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -36,28 +36,28 @@  discard block
 block discarded – undo
36 36
 use Icewind\Streams\CallbackWrapper;
37 37
 use Icewind\Streams\RetryWrapper;
38 38
 
39
-class FTP extends StreamWrapper{
39
+class FTP extends StreamWrapper {
40 40
 	private $password;
41 41
 	private $user;
42 42
 	private $host;
43 43
 	private $secure;
44 44
 	private $root;
45 45
 
46
-	private static $tempFiles=array();
46
+	private static $tempFiles = array();
47 47
 
48 48
 	public function __construct($params) {
49 49
 		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
50
-			$this->host=$params['host'];
51
-			$this->user=$params['user'];
52
-			$this->password=$params['password'];
50
+			$this->host = $params['host'];
51
+			$this->user = $params['user'];
52
+			$this->password = $params['password'];
53 53
 			if (isset($params['secure'])) {
54 54
 				$this->secure = $params['secure'];
55 55
 			} else {
56 56
 				$this->secure = false;
57 57
 			}
58
-			$this->root=isset($params['root'])?$params['root']:'/';
59
-			if ( ! $this->root || $this->root[0]!='/') {
60
-				$this->root='/'.$this->root;
58
+			$this->root = isset($params['root']) ? $params['root'] : '/';
59
+			if (!$this->root || $this->root[0] != '/') {
60
+				$this->root = '/'.$this->root;
61 61
 			}
62 62
 			if (substr($this->root, -1) !== '/') {
63 63
 				$this->root .= '/';
@@ -68,8 +68,8 @@  discard block
 block discarded – undo
68 68
 		
69 69
 	}
70 70
 
71
-	public function getId(){
72
-		return 'ftp::' . $this->user . '@' . $this->host . '/' . $this->root;
71
+	public function getId() {
72
+		return 'ftp::'.$this->user.'@'.$this->host.'/'.$this->root;
73 73
 	}
74 74
 
75 75
 	/**
@@ -78,11 +78,11 @@  discard block
 block discarded – undo
78 78
 	 * @return string
79 79
 	 */
80 80
 	public function constructUrl($path) {
81
-		$url='ftp';
81
+		$url = 'ftp';
82 82
 		if ($this->secure) {
83
-			$url.='s';
83
+			$url .= 's';
84 84
 		}
85
-		$url.='://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
85
+		$url .= '://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
86 86
 		return $url;
87 87
 	}
88 88
 
@@ -101,8 +101,8 @@  discard block
 block discarded – undo
101 101
 			return $result;
102 102
 		}
103 103
 	}
104
-	public function fopen($path,$mode) {
105
-		switch($mode) {
104
+	public function fopen($path, $mode) {
105
+		switch ($mode) {
106 106
 			case 'r':
107 107
 			case 'rb':
108 108
 			case 'w':
@@ -122,17 +122,17 @@  discard block
 block discarded – undo
122 122
 			case 'c':
123 123
 			case 'c+':
124 124
 				//emulate these
125
-				if (strrpos($path, '.')!==false) {
126
-					$ext=substr($path, strrpos($path, '.'));
125
+				if (strrpos($path, '.') !== false) {
126
+					$ext = substr($path, strrpos($path, '.'));
127 127
 				} else {
128
-					$ext='';
128
+					$ext = '';
129 129
 				}
130
-				$tmpFile=\OCP\Files::tmpFile($ext);
130
+				$tmpFile = \OCP\Files::tmpFile($ext);
131 131
 				if ($this->file_exists($path)) {
132 132
 					$this->getFile($path, $tmpFile);
133 133
 				}
134 134
 				$handle = fopen($tmpFile, $mode);
135
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
135
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
136 136
 					$this->writeBack($tmpFile, $path);
137 137
 				});
138 138
 		}
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -93,8 +93,7 @@
 block discarded – undo
93 93
 	public function unlink($path) {
94 94
 		if ($this->is_dir($path)) {
95 95
 			return $this->rmdir($path);
96
-		}
97
-		else {
96
+		} else {
98 97
 			$url = $this->constructUrl($path);
99 98
 			$result = unlink($url);
100 99
 			clearstatcache(true, $url);
Please login to merge, or discard this patch.