Passed
Push — master ( 96d192...9c7503 )
by Morris
12:50 queued 12s
created
apps/files_external/lib/Lib/Storage/SMB.php 2 patches
Indentation   +546 added lines, -546 removed lines patch added patch discarded remove patch
@@ -59,550 +59,550 @@
 block discarded – undo
59 59
 use OCP\ILogger;
60 60
 
61 61
 class SMB extends Common implements INotifyStorage {
62
-	/**
63
-	 * @var \Icewind\SMB\IServer
64
-	 */
65
-	protected $server;
66
-
67
-	/**
68
-	 * @var \Icewind\SMB\IShare
69
-	 */
70
-	protected $share;
71
-
72
-	/**
73
-	 * @var string
74
-	 */
75
-	protected $root;
76
-
77
-	/**
78
-	 * @var \Icewind\SMB\IFileInfo[]
79
-	 */
80
-	protected $statCache;
81
-
82
-	/** @var ILogger */
83
-	protected $logger;
84
-
85
-	/** @var bool */
86
-	protected $showHidden;
87
-
88
-	public function __construct($params) {
89
-		if (!isset($params['host'])) {
90
-			throw new \Exception('Invalid configuration, no host provided');
91
-		}
92
-
93
-		if (isset($params['auth'])) {
94
-			$auth = $params['auth'];
95
-		} else if (isset($params['user']) && isset($params['password']) && isset($params['share'])) {
96
-			list($workgroup, $user) = $this->splitUser($params['user']);
97
-			$auth = new BasicAuth($user, $workgroup, $params['password']);
98
-		} else {
99
-			throw new \Exception('Invalid configuration, no credentials provided');
100
-		}
101
-
102
-		if (isset($params['logger'])) {
103
-			$this->logger = $params['logger'];
104
-		} else {
105
-			$this->logger = \OC::$server->getLogger();
106
-		}
107
-
108
-		$serverFactory = new ServerFactory();
109
-		$this->server = $serverFactory->createServer($params['host'], $auth);
110
-		$this->share = $this->server->getShare(trim($params['share'], '/'));
111
-
112
-		$this->root = $params['root'] ?? '/';
113
-		$this->root = '/' . ltrim($this->root, '/');
114
-		$this->root = rtrim($this->root, '/') . '/';
115
-
116
-		$this->showHidden = isset($params['show_hidden']) && $params['show_hidden'];
117
-
118
-		$this->statCache = new CappedMemoryCache();
119
-		parent::__construct($params);
120
-	}
121
-
122
-	private function splitUser($user) {
123
-		if (strpos($user, '/')) {
124
-			return explode('/', $user, 2);
125
-		} elseif (strpos($user, '\\')) {
126
-			return explode('\\', $user);
127
-		} else {
128
-			return [null, $user];
129
-		}
130
-	}
131
-
132
-	/**
133
-	 * @return string
134
-	 */
135
-	public function getId() {
136
-		// FIXME: double slash to keep compatible with the old storage ids,
137
-		// failure to do so will lead to creation of a new storage id and
138
-		// loss of shares from the storage
139
-		return 'smb::' . $this->server->getAuth()->getUsername() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
140
-	}
141
-
142
-	/**
143
-	 * @param string $path
144
-	 * @return string
145
-	 */
146
-	protected function buildPath($path) {
147
-		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
148
-	}
149
-
150
-	protected function relativePath($fullPath) {
151
-		if ($fullPath === $this->root) {
152
-			return '';
153
-		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
154
-			return substr($fullPath, strlen($this->root));
155
-		} else {
156
-			return null;
157
-		}
158
-	}
159
-
160
-	/**
161
-	 * @param string $path
162
-	 * @return \Icewind\SMB\IFileInfo
163
-	 * @throws StorageNotAvailableException
164
-	 */
165
-	protected function getFileInfo($path) {
166
-		try {
167
-			$path = $this->buildPath($path);
168
-			if (!isset($this->statCache[$path])) {
169
-				$this->statCache[$path] = $this->share->stat($path);
170
-			}
171
-			return $this->statCache[$path];
172
-		} catch (ConnectException $e) {
173
-			$this->logger->logException($e, ['message' => 'Error while getting file info']);
174
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
175
-		}
176
-	}
177
-
178
-	/**
179
-	 * @param string $path
180
-	 * @return \Icewind\SMB\IFileInfo[]
181
-	 * @throws StorageNotAvailableException
182
-	 */
183
-	protected function getFolderContents($path) {
184
-		try {
185
-			$path = $this->buildPath($path);
186
-			$files = $this->share->dir($path);
187
-			foreach ($files as $file) {
188
-				$this->statCache[$path . '/' . $file->getName()] = $file;
189
-			}
190
-			return array_filter($files, function (IFileInfo $file) {
191
-				try {
192
-					// the isHidden check is done before checking the config boolean to ensure that the metadata is always fetch
193
-					// so we trigger the below exceptions where applicable
194
-					$hide = $file->isHidden() && !$this->showHidden;
195
-					if ($hide) {
196
-						$this->logger->debug('hiding hidden file ' . $file->getName());
197
-					}
198
-					return !$hide;
199
-				} catch (ForbiddenException $e) {
200
-					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding forbidden entry ' . $file->getName()]);
201
-					return false;
202
-				} catch (NotFoundException $e) {
203
-					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding not found entry ' . $file->getName()]);
204
-					return false;
205
-				}
206
-			});
207
-		} catch (ConnectException $e) {
208
-			$this->logger->logException($e, ['message' => 'Error while getting folder content']);
209
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
210
-		}
211
-	}
212
-
213
-	/**
214
-	 * @param \Icewind\SMB\IFileInfo $info
215
-	 * @return array
216
-	 */
217
-	protected function formatInfo($info) {
218
-		$result = [
219
-			'size' => $info->getSize(),
220
-			'mtime' => $info->getMTime(),
221
-		];
222
-		if ($info->isDirectory()) {
223
-			$result['type'] = 'dir';
224
-		} else {
225
-			$result['type'] = 'file';
226
-		}
227
-		return $result;
228
-	}
229
-
230
-	/**
231
-	 * Rename the files. If the source or the target is the root, the rename won't happen.
232
-	 *
233
-	 * @param string $source the old name of the path
234
-	 * @param string $target the new name of the path
235
-	 * @return bool true if the rename is successful, false otherwise
236
-	 */
237
-	public function rename($source, $target, $retry = true) {
238
-		if ($this->isRootDir($source) || $this->isRootDir($target)) {
239
-			return false;
240
-		}
241
-
242
-		$absoluteSource = $this->buildPath($source);
243
-		$absoluteTarget = $this->buildPath($target);
244
-		try {
245
-			$result = $this->share->rename($absoluteSource, $absoluteTarget);
246
-		} catch (AlreadyExistsException $e) {
247
-			if ($retry) {
248
-				$this->remove($target);
249
-				$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
250
-			} else {
251
-				$this->logger->logException($e, ['level' => ILogger::WARN]);
252
-				return false;
253
-			}
254
-		} catch (InvalidArgumentException $e) {
255
-			if ($retry) {
256
-				$this->remove($target);
257
-				$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
258
-			} else {
259
-				$this->logger->logException($e, ['level' => ILogger::WARN]);
260
-				return false;
261
-			}
262
-		} catch (\Exception $e) {
263
-			$this->logger->logException($e, ['level' => ILogger::WARN]);
264
-			return false;
265
-		}
266
-		unset($this->statCache[$absoluteSource], $this->statCache[$absoluteTarget]);
267
-		return $result;
268
-	}
269
-
270
-	public function stat($path, $retry = true) {
271
-		try {
272
-			$result = $this->formatInfo($this->getFileInfo($path));
273
-		} catch (ForbiddenException $e) {
274
-			return false;
275
-		} catch (NotFoundException $e) {
276
-			return false;
277
-		} catch (TimedOutException $e) {
278
-			if ($retry) {
279
-				return $this->stat($path, false);
280
-			} else {
281
-				throw $e;
282
-			}
283
-		}
284
-		if ($this->remoteIsShare() && $this->isRootDir($path)) {
285
-			$result['mtime'] = $this->shareMTime();
286
-		}
287
-		return $result;
288
-	}
289
-
290
-	/**
291
-	 * get the best guess for the modification time of the share
292
-	 *
293
-	 * @return int
294
-	 */
295
-	private function shareMTime() {
296
-		$highestMTime = 0;
297
-		$files = $this->share->dir($this->root);
298
-		foreach ($files as $fileInfo) {
299
-			try {
300
-				if ($fileInfo->getMTime() > $highestMTime) {
301
-					$highestMTime = $fileInfo->getMTime();
302
-				}
303
-			} catch (NotFoundException $e) {
304
-				// Ignore this, can happen on unavailable DFS shares
305
-			}
306
-		}
307
-		return $highestMTime;
308
-	}
309
-
310
-	/**
311
-	 * Check if the path is our root dir (not the smb one)
312
-	 *
313
-	 * @param string $path the path
314
-	 * @return bool
315
-	 */
316
-	private function isRootDir($path) {
317
-		return $path === '' || $path === '/' || $path === '.';
318
-	}
319
-
320
-	/**
321
-	 * Check if our root points to a smb share
322
-	 *
323
-	 * @return bool true if our root points to a share false otherwise
324
-	 */
325
-	private function remoteIsShare() {
326
-		return $this->share->getName() && (!$this->root || $this->root === '/');
327
-	}
328
-
329
-	/**
330
-	 * @param string $path
331
-	 * @return bool
332
-	 */
333
-	public function unlink($path) {
334
-		if ($this->isRootDir($path)) {
335
-			return false;
336
-		}
337
-
338
-		try {
339
-			if ($this->is_dir($path)) {
340
-				return $this->rmdir($path);
341
-			} else {
342
-				$path = $this->buildPath($path);
343
-				unset($this->statCache[$path]);
344
-				$this->share->del($path);
345
-				return true;
346
-			}
347
-		} catch (NotFoundException $e) {
348
-			return false;
349
-		} catch (ForbiddenException $e) {
350
-			return false;
351
-		} catch (ConnectException $e) {
352
-			$this->logger->logException($e, ['message' => 'Error while deleting file']);
353
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
354
-		}
355
-	}
356
-
357
-	/**
358
-	 * check if a file or folder has been updated since $time
359
-	 *
360
-	 * @param string $path
361
-	 * @param int $time
362
-	 * @return bool
363
-	 */
364
-	public function hasUpdated($path, $time) {
365
-		if (!$path and $this->root === '/') {
366
-			// mtime doesn't work for shares, but giving the nature of the backend,
367
-			// doing a full update is still just fast enough
368
-			return true;
369
-		} else {
370
-			$actualTime = $this->filemtime($path);
371
-			return $actualTime > $time;
372
-		}
373
-	}
374
-
375
-	/**
376
-	 * @param string $path
377
-	 * @param string $mode
378
-	 * @return resource|false
379
-	 */
380
-	public function fopen($path, $mode) {
381
-		$fullPath = $this->buildPath($path);
382
-		try {
383
-			switch ($mode) {
384
-				case 'r':
385
-				case 'rb':
386
-					if (!$this->file_exists($path)) {
387
-						return false;
388
-					}
389
-					return $this->share->read($fullPath);
390
-				case 'w':
391
-				case 'wb':
392
-					$source = $this->share->write($fullPath);
393
-					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
394
-						unset($this->statCache[$fullPath]);
395
-					});
396
-				case 'a':
397
-				case 'ab':
398
-				case 'r+':
399
-				case 'w+':
400
-				case 'wb+':
401
-				case 'a+':
402
-				case 'x':
403
-				case 'x+':
404
-				case 'c':
405
-				case 'c+':
406
-					//emulate these
407
-					if (strrpos($path, '.') !== false) {
408
-						$ext = substr($path, strrpos($path, '.'));
409
-					} else {
410
-						$ext = '';
411
-					}
412
-					if ($this->file_exists($path)) {
413
-						if (!$this->isUpdatable($path)) {
414
-							return false;
415
-						}
416
-						$tmpFile = $this->getCachedFile($path);
417
-					} else {
418
-						if (!$this->isCreatable(dirname($path))) {
419
-							return false;
420
-						}
421
-						$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
422
-					}
423
-					$source = fopen($tmpFile, $mode);
424
-					$share = $this->share;
425
-					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
426
-						unset($this->statCache[$fullPath]);
427
-						$share->put($tmpFile, $fullPath);
428
-						unlink($tmpFile);
429
-					});
430
-			}
431
-			return false;
432
-		} catch (NotFoundException $e) {
433
-			return false;
434
-		} catch (ForbiddenException $e) {
435
-			return false;
436
-		} catch (ConnectException $e) {
437
-			$this->logger->logException($e, ['message' => 'Error while opening file']);
438
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
439
-		}
440
-	}
441
-
442
-	public function rmdir($path) {
443
-		if ($this->isRootDir($path)) {
444
-			return false;
445
-		}
446
-
447
-		try {
448
-			$this->statCache = array();
449
-			$content = $this->share->dir($this->buildPath($path));
450
-			foreach ($content as $file) {
451
-				if ($file->isDirectory()) {
452
-					$this->rmdir($path . '/' . $file->getName());
453
-				} else {
454
-					$this->share->del($file->getPath());
455
-				}
456
-			}
457
-			$this->share->rmdir($this->buildPath($path));
458
-			return true;
459
-		} catch (NotFoundException $e) {
460
-			return false;
461
-		} catch (ForbiddenException $e) {
462
-			return false;
463
-		} catch (ConnectException $e) {
464
-			$this->logger->logException($e, ['message' => 'Error while removing folder']);
465
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
466
-		}
467
-	}
468
-
469
-	public function touch($path, $time = null) {
470
-		try {
471
-			if (!$this->file_exists($path)) {
472
-				$fh = $this->share->write($this->buildPath($path));
473
-				fclose($fh);
474
-				return true;
475
-			}
476
-			return false;
477
-		} catch (ConnectException $e) {
478
-			$this->logger->logException($e, ['message' => 'Error while creating file']);
479
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
480
-		}
481
-	}
482
-
483
-	public function opendir($path) {
484
-		try {
485
-			$files = $this->getFolderContents($path);
486
-		} catch (NotFoundException $e) {
487
-			return false;
488
-		} catch (ForbiddenException $e) {
489
-			return false;
490
-		}
491
-		$names = array_map(function ($info) {
492
-			/** @var \Icewind\SMB\IFileInfo $info */
493
-			return $info->getName();
494
-		}, $files);
495
-		return IteratorDirectory::wrap($names);
496
-	}
497
-
498
-	public function filetype($path) {
499
-		try {
500
-			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
501
-		} catch (NotFoundException $e) {
502
-			return false;
503
-		} catch (ForbiddenException $e) {
504
-			return false;
505
-		}
506
-	}
507
-
508
-	public function mkdir($path) {
509
-		$path = $this->buildPath($path);
510
-		try {
511
-			$this->share->mkdir($path);
512
-			return true;
513
-		} catch (ConnectException $e) {
514
-			$this->logger->logException($e, ['message' => 'Error while creating folder']);
515
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
516
-		} catch (Exception $e) {
517
-			return false;
518
-		}
519
-	}
520
-
521
-	public function file_exists($path) {
522
-		try {
523
-			$this->getFileInfo($path);
524
-			return true;
525
-		} catch (NotFoundException $e) {
526
-			return false;
527
-		} catch (ForbiddenException $e) {
528
-			return false;
529
-		} catch (ConnectException $e) {
530
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
531
-		}
532
-	}
533
-
534
-	public function isReadable($path) {
535
-		try {
536
-			$info = $this->getFileInfo($path);
537
-			return $this->showHidden || !$info->isHidden();
538
-		} catch (NotFoundException $e) {
539
-			return false;
540
-		} catch (ForbiddenException $e) {
541
-			return false;
542
-		}
543
-	}
544
-
545
-	public function isUpdatable($path) {
546
-		try {
547
-			$info = $this->getFileInfo($path);
548
-			// following windows behaviour for read-only folders: they can be written into
549
-			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
550
-			return ($this->showHidden || !$info->isHidden()) && (!$info->isReadOnly() || $this->is_dir($path));
551
-		} catch (NotFoundException $e) {
552
-			return false;
553
-		} catch (ForbiddenException $e) {
554
-			return false;
555
-		}
556
-	}
557
-
558
-	public function isDeletable($path) {
559
-		try {
560
-			$info = $this->getFileInfo($path);
561
-			return ($this->showHidden || !$info->isHidden()) && !$info->isReadOnly();
562
-		} catch (NotFoundException $e) {
563
-			return false;
564
-		} catch (ForbiddenException $e) {
565
-			return false;
566
-		}
567
-	}
568
-
569
-	/**
570
-	 * check if smbclient is installed
571
-	 */
572
-	public static function checkDependencies() {
573
-		return (
574
-			(bool)\OC_Helper::findBinaryPath('smbclient')
575
-			|| NativeServer::available(new System())
576
-		) ? true : ['smbclient'];
577
-	}
578
-
579
-	/**
580
-	 * Test a storage for availability
581
-	 *
582
-	 * @return bool
583
-	 */
584
-	public function test() {
585
-		try {
586
-			return parent::test();
587
-		} catch (Exception $e) {
588
-			$this->logger->logException($e);
589
-			return false;
590
-		}
591
-	}
592
-
593
-	public function listen($path, callable $callback) {
594
-		$this->notify($path)->listen(function (IChange $change) use ($callback) {
595
-			if ($change instanceof IRenameChange) {
596
-				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
597
-			} else {
598
-				return $callback($change->getType(), $change->getPath());
599
-			}
600
-		});
601
-	}
602
-
603
-	public function notify($path) {
604
-		$path = '/' . ltrim($path, '/');
605
-		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
606
-		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
607
-	}
62
+    /**
63
+     * @var \Icewind\SMB\IServer
64
+     */
65
+    protected $server;
66
+
67
+    /**
68
+     * @var \Icewind\SMB\IShare
69
+     */
70
+    protected $share;
71
+
72
+    /**
73
+     * @var string
74
+     */
75
+    protected $root;
76
+
77
+    /**
78
+     * @var \Icewind\SMB\IFileInfo[]
79
+     */
80
+    protected $statCache;
81
+
82
+    /** @var ILogger */
83
+    protected $logger;
84
+
85
+    /** @var bool */
86
+    protected $showHidden;
87
+
88
+    public function __construct($params) {
89
+        if (!isset($params['host'])) {
90
+            throw new \Exception('Invalid configuration, no host provided');
91
+        }
92
+
93
+        if (isset($params['auth'])) {
94
+            $auth = $params['auth'];
95
+        } else if (isset($params['user']) && isset($params['password']) && isset($params['share'])) {
96
+            list($workgroup, $user) = $this->splitUser($params['user']);
97
+            $auth = new BasicAuth($user, $workgroup, $params['password']);
98
+        } else {
99
+            throw new \Exception('Invalid configuration, no credentials provided');
100
+        }
101
+
102
+        if (isset($params['logger'])) {
103
+            $this->logger = $params['logger'];
104
+        } else {
105
+            $this->logger = \OC::$server->getLogger();
106
+        }
107
+
108
+        $serverFactory = new ServerFactory();
109
+        $this->server = $serverFactory->createServer($params['host'], $auth);
110
+        $this->share = $this->server->getShare(trim($params['share'], '/'));
111
+
112
+        $this->root = $params['root'] ?? '/';
113
+        $this->root = '/' . ltrim($this->root, '/');
114
+        $this->root = rtrim($this->root, '/') . '/';
115
+
116
+        $this->showHidden = isset($params['show_hidden']) && $params['show_hidden'];
117
+
118
+        $this->statCache = new CappedMemoryCache();
119
+        parent::__construct($params);
120
+    }
121
+
122
+    private function splitUser($user) {
123
+        if (strpos($user, '/')) {
124
+            return explode('/', $user, 2);
125
+        } elseif (strpos($user, '\\')) {
126
+            return explode('\\', $user);
127
+        } else {
128
+            return [null, $user];
129
+        }
130
+    }
131
+
132
+    /**
133
+     * @return string
134
+     */
135
+    public function getId() {
136
+        // FIXME: double slash to keep compatible with the old storage ids,
137
+        // failure to do so will lead to creation of a new storage id and
138
+        // loss of shares from the storage
139
+        return 'smb::' . $this->server->getAuth()->getUsername() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
140
+    }
141
+
142
+    /**
143
+     * @param string $path
144
+     * @return string
145
+     */
146
+    protected function buildPath($path) {
147
+        return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
148
+    }
149
+
150
+    protected function relativePath($fullPath) {
151
+        if ($fullPath === $this->root) {
152
+            return '';
153
+        } else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
154
+            return substr($fullPath, strlen($this->root));
155
+        } else {
156
+            return null;
157
+        }
158
+    }
159
+
160
+    /**
161
+     * @param string $path
162
+     * @return \Icewind\SMB\IFileInfo
163
+     * @throws StorageNotAvailableException
164
+     */
165
+    protected function getFileInfo($path) {
166
+        try {
167
+            $path = $this->buildPath($path);
168
+            if (!isset($this->statCache[$path])) {
169
+                $this->statCache[$path] = $this->share->stat($path);
170
+            }
171
+            return $this->statCache[$path];
172
+        } catch (ConnectException $e) {
173
+            $this->logger->logException($e, ['message' => 'Error while getting file info']);
174
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
175
+        }
176
+    }
177
+
178
+    /**
179
+     * @param string $path
180
+     * @return \Icewind\SMB\IFileInfo[]
181
+     * @throws StorageNotAvailableException
182
+     */
183
+    protected function getFolderContents($path) {
184
+        try {
185
+            $path = $this->buildPath($path);
186
+            $files = $this->share->dir($path);
187
+            foreach ($files as $file) {
188
+                $this->statCache[$path . '/' . $file->getName()] = $file;
189
+            }
190
+            return array_filter($files, function (IFileInfo $file) {
191
+                try {
192
+                    // the isHidden check is done before checking the config boolean to ensure that the metadata is always fetch
193
+                    // so we trigger the below exceptions where applicable
194
+                    $hide = $file->isHidden() && !$this->showHidden;
195
+                    if ($hide) {
196
+                        $this->logger->debug('hiding hidden file ' . $file->getName());
197
+                    }
198
+                    return !$hide;
199
+                } catch (ForbiddenException $e) {
200
+                    $this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding forbidden entry ' . $file->getName()]);
201
+                    return false;
202
+                } catch (NotFoundException $e) {
203
+                    $this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding not found entry ' . $file->getName()]);
204
+                    return false;
205
+                }
206
+            });
207
+        } catch (ConnectException $e) {
208
+            $this->logger->logException($e, ['message' => 'Error while getting folder content']);
209
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
210
+        }
211
+    }
212
+
213
+    /**
214
+     * @param \Icewind\SMB\IFileInfo $info
215
+     * @return array
216
+     */
217
+    protected function formatInfo($info) {
218
+        $result = [
219
+            'size' => $info->getSize(),
220
+            'mtime' => $info->getMTime(),
221
+        ];
222
+        if ($info->isDirectory()) {
223
+            $result['type'] = 'dir';
224
+        } else {
225
+            $result['type'] = 'file';
226
+        }
227
+        return $result;
228
+    }
229
+
230
+    /**
231
+     * Rename the files. If the source or the target is the root, the rename won't happen.
232
+     *
233
+     * @param string $source the old name of the path
234
+     * @param string $target the new name of the path
235
+     * @return bool true if the rename is successful, false otherwise
236
+     */
237
+    public function rename($source, $target, $retry = true) {
238
+        if ($this->isRootDir($source) || $this->isRootDir($target)) {
239
+            return false;
240
+        }
241
+
242
+        $absoluteSource = $this->buildPath($source);
243
+        $absoluteTarget = $this->buildPath($target);
244
+        try {
245
+            $result = $this->share->rename($absoluteSource, $absoluteTarget);
246
+        } catch (AlreadyExistsException $e) {
247
+            if ($retry) {
248
+                $this->remove($target);
249
+                $result = $this->share->rename($absoluteSource, $absoluteTarget, false);
250
+            } else {
251
+                $this->logger->logException($e, ['level' => ILogger::WARN]);
252
+                return false;
253
+            }
254
+        } catch (InvalidArgumentException $e) {
255
+            if ($retry) {
256
+                $this->remove($target);
257
+                $result = $this->share->rename($absoluteSource, $absoluteTarget, false);
258
+            } else {
259
+                $this->logger->logException($e, ['level' => ILogger::WARN]);
260
+                return false;
261
+            }
262
+        } catch (\Exception $e) {
263
+            $this->logger->logException($e, ['level' => ILogger::WARN]);
264
+            return false;
265
+        }
266
+        unset($this->statCache[$absoluteSource], $this->statCache[$absoluteTarget]);
267
+        return $result;
268
+    }
269
+
270
+    public function stat($path, $retry = true) {
271
+        try {
272
+            $result = $this->formatInfo($this->getFileInfo($path));
273
+        } catch (ForbiddenException $e) {
274
+            return false;
275
+        } catch (NotFoundException $e) {
276
+            return false;
277
+        } catch (TimedOutException $e) {
278
+            if ($retry) {
279
+                return $this->stat($path, false);
280
+            } else {
281
+                throw $e;
282
+            }
283
+        }
284
+        if ($this->remoteIsShare() && $this->isRootDir($path)) {
285
+            $result['mtime'] = $this->shareMTime();
286
+        }
287
+        return $result;
288
+    }
289
+
290
+    /**
291
+     * get the best guess for the modification time of the share
292
+     *
293
+     * @return int
294
+     */
295
+    private function shareMTime() {
296
+        $highestMTime = 0;
297
+        $files = $this->share->dir($this->root);
298
+        foreach ($files as $fileInfo) {
299
+            try {
300
+                if ($fileInfo->getMTime() > $highestMTime) {
301
+                    $highestMTime = $fileInfo->getMTime();
302
+                }
303
+            } catch (NotFoundException $e) {
304
+                // Ignore this, can happen on unavailable DFS shares
305
+            }
306
+        }
307
+        return $highestMTime;
308
+    }
309
+
310
+    /**
311
+     * Check if the path is our root dir (not the smb one)
312
+     *
313
+     * @param string $path the path
314
+     * @return bool
315
+     */
316
+    private function isRootDir($path) {
317
+        return $path === '' || $path === '/' || $path === '.';
318
+    }
319
+
320
+    /**
321
+     * Check if our root points to a smb share
322
+     *
323
+     * @return bool true if our root points to a share false otherwise
324
+     */
325
+    private function remoteIsShare() {
326
+        return $this->share->getName() && (!$this->root || $this->root === '/');
327
+    }
328
+
329
+    /**
330
+     * @param string $path
331
+     * @return bool
332
+     */
333
+    public function unlink($path) {
334
+        if ($this->isRootDir($path)) {
335
+            return false;
336
+        }
337
+
338
+        try {
339
+            if ($this->is_dir($path)) {
340
+                return $this->rmdir($path);
341
+            } else {
342
+                $path = $this->buildPath($path);
343
+                unset($this->statCache[$path]);
344
+                $this->share->del($path);
345
+                return true;
346
+            }
347
+        } catch (NotFoundException $e) {
348
+            return false;
349
+        } catch (ForbiddenException $e) {
350
+            return false;
351
+        } catch (ConnectException $e) {
352
+            $this->logger->logException($e, ['message' => 'Error while deleting file']);
353
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
354
+        }
355
+    }
356
+
357
+    /**
358
+     * check if a file or folder has been updated since $time
359
+     *
360
+     * @param string $path
361
+     * @param int $time
362
+     * @return bool
363
+     */
364
+    public function hasUpdated($path, $time) {
365
+        if (!$path and $this->root === '/') {
366
+            // mtime doesn't work for shares, but giving the nature of the backend,
367
+            // doing a full update is still just fast enough
368
+            return true;
369
+        } else {
370
+            $actualTime = $this->filemtime($path);
371
+            return $actualTime > $time;
372
+        }
373
+    }
374
+
375
+    /**
376
+     * @param string $path
377
+     * @param string $mode
378
+     * @return resource|false
379
+     */
380
+    public function fopen($path, $mode) {
381
+        $fullPath = $this->buildPath($path);
382
+        try {
383
+            switch ($mode) {
384
+                case 'r':
385
+                case 'rb':
386
+                    if (!$this->file_exists($path)) {
387
+                        return false;
388
+                    }
389
+                    return $this->share->read($fullPath);
390
+                case 'w':
391
+                case 'wb':
392
+                    $source = $this->share->write($fullPath);
393
+                    return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
394
+                        unset($this->statCache[$fullPath]);
395
+                    });
396
+                case 'a':
397
+                case 'ab':
398
+                case 'r+':
399
+                case 'w+':
400
+                case 'wb+':
401
+                case 'a+':
402
+                case 'x':
403
+                case 'x+':
404
+                case 'c':
405
+                case 'c+':
406
+                    //emulate these
407
+                    if (strrpos($path, '.') !== false) {
408
+                        $ext = substr($path, strrpos($path, '.'));
409
+                    } else {
410
+                        $ext = '';
411
+                    }
412
+                    if ($this->file_exists($path)) {
413
+                        if (!$this->isUpdatable($path)) {
414
+                            return false;
415
+                        }
416
+                        $tmpFile = $this->getCachedFile($path);
417
+                    } else {
418
+                        if (!$this->isCreatable(dirname($path))) {
419
+                            return false;
420
+                        }
421
+                        $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
422
+                    }
423
+                    $source = fopen($tmpFile, $mode);
424
+                    $share = $this->share;
425
+                    return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
426
+                        unset($this->statCache[$fullPath]);
427
+                        $share->put($tmpFile, $fullPath);
428
+                        unlink($tmpFile);
429
+                    });
430
+            }
431
+            return false;
432
+        } catch (NotFoundException $e) {
433
+            return false;
434
+        } catch (ForbiddenException $e) {
435
+            return false;
436
+        } catch (ConnectException $e) {
437
+            $this->logger->logException($e, ['message' => 'Error while opening file']);
438
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
439
+        }
440
+    }
441
+
442
+    public function rmdir($path) {
443
+        if ($this->isRootDir($path)) {
444
+            return false;
445
+        }
446
+
447
+        try {
448
+            $this->statCache = array();
449
+            $content = $this->share->dir($this->buildPath($path));
450
+            foreach ($content as $file) {
451
+                if ($file->isDirectory()) {
452
+                    $this->rmdir($path . '/' . $file->getName());
453
+                } else {
454
+                    $this->share->del($file->getPath());
455
+                }
456
+            }
457
+            $this->share->rmdir($this->buildPath($path));
458
+            return true;
459
+        } catch (NotFoundException $e) {
460
+            return false;
461
+        } catch (ForbiddenException $e) {
462
+            return false;
463
+        } catch (ConnectException $e) {
464
+            $this->logger->logException($e, ['message' => 'Error while removing folder']);
465
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
466
+        }
467
+    }
468
+
469
+    public function touch($path, $time = null) {
470
+        try {
471
+            if (!$this->file_exists($path)) {
472
+                $fh = $this->share->write($this->buildPath($path));
473
+                fclose($fh);
474
+                return true;
475
+            }
476
+            return false;
477
+        } catch (ConnectException $e) {
478
+            $this->logger->logException($e, ['message' => 'Error while creating file']);
479
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
480
+        }
481
+    }
482
+
483
+    public function opendir($path) {
484
+        try {
485
+            $files = $this->getFolderContents($path);
486
+        } catch (NotFoundException $e) {
487
+            return false;
488
+        } catch (ForbiddenException $e) {
489
+            return false;
490
+        }
491
+        $names = array_map(function ($info) {
492
+            /** @var \Icewind\SMB\IFileInfo $info */
493
+            return $info->getName();
494
+        }, $files);
495
+        return IteratorDirectory::wrap($names);
496
+    }
497
+
498
+    public function filetype($path) {
499
+        try {
500
+            return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
501
+        } catch (NotFoundException $e) {
502
+            return false;
503
+        } catch (ForbiddenException $e) {
504
+            return false;
505
+        }
506
+    }
507
+
508
+    public function mkdir($path) {
509
+        $path = $this->buildPath($path);
510
+        try {
511
+            $this->share->mkdir($path);
512
+            return true;
513
+        } catch (ConnectException $e) {
514
+            $this->logger->logException($e, ['message' => 'Error while creating folder']);
515
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
516
+        } catch (Exception $e) {
517
+            return false;
518
+        }
519
+    }
520
+
521
+    public function file_exists($path) {
522
+        try {
523
+            $this->getFileInfo($path);
524
+            return true;
525
+        } catch (NotFoundException $e) {
526
+            return false;
527
+        } catch (ForbiddenException $e) {
528
+            return false;
529
+        } catch (ConnectException $e) {
530
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
531
+        }
532
+    }
533
+
534
+    public function isReadable($path) {
535
+        try {
536
+            $info = $this->getFileInfo($path);
537
+            return $this->showHidden || !$info->isHidden();
538
+        } catch (NotFoundException $e) {
539
+            return false;
540
+        } catch (ForbiddenException $e) {
541
+            return false;
542
+        }
543
+    }
544
+
545
+    public function isUpdatable($path) {
546
+        try {
547
+            $info = $this->getFileInfo($path);
548
+            // following windows behaviour for read-only folders: they can be written into
549
+            // (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
550
+            return ($this->showHidden || !$info->isHidden()) && (!$info->isReadOnly() || $this->is_dir($path));
551
+        } catch (NotFoundException $e) {
552
+            return false;
553
+        } catch (ForbiddenException $e) {
554
+            return false;
555
+        }
556
+    }
557
+
558
+    public function isDeletable($path) {
559
+        try {
560
+            $info = $this->getFileInfo($path);
561
+            return ($this->showHidden || !$info->isHidden()) && !$info->isReadOnly();
562
+        } catch (NotFoundException $e) {
563
+            return false;
564
+        } catch (ForbiddenException $e) {
565
+            return false;
566
+        }
567
+    }
568
+
569
+    /**
570
+     * check if smbclient is installed
571
+     */
572
+    public static function checkDependencies() {
573
+        return (
574
+            (bool)\OC_Helper::findBinaryPath('smbclient')
575
+            || NativeServer::available(new System())
576
+        ) ? true : ['smbclient'];
577
+    }
578
+
579
+    /**
580
+     * Test a storage for availability
581
+     *
582
+     * @return bool
583
+     */
584
+    public function test() {
585
+        try {
586
+            return parent::test();
587
+        } catch (Exception $e) {
588
+            $this->logger->logException($e);
589
+            return false;
590
+        }
591
+    }
592
+
593
+    public function listen($path, callable $callback) {
594
+        $this->notify($path)->listen(function (IChange $change) use ($callback) {
595
+            if ($change instanceof IRenameChange) {
596
+                return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
597
+            } else {
598
+                return $callback($change->getType(), $change->getPath());
599
+            }
600
+        });
601
+    }
602
+
603
+    public function notify($path) {
604
+        $path = '/' . ltrim($path, '/');
605
+        $shareNotifyHandler = $this->share->notify($this->buildPath($path));
606
+        return new SMBNotifyHandler($shareNotifyHandler, $this->root);
607
+    }
608 608
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -110,8 +110,8 @@  discard block
 block discarded – undo
110 110
 		$this->share = $this->server->getShare(trim($params['share'], '/'));
111 111
 
112 112
 		$this->root = $params['root'] ?? '/';
113
-		$this->root = '/' . ltrim($this->root, '/');
114
-		$this->root = rtrim($this->root, '/') . '/';
113
+		$this->root = '/'.ltrim($this->root, '/');
114
+		$this->root = rtrim($this->root, '/').'/';
115 115
 
116 116
 		$this->showHidden = isset($params['show_hidden']) && $params['show_hidden'];
117 117
 
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
 		// FIXME: double slash to keep compatible with the old storage ids,
137 137
 		// failure to do so will lead to creation of a new storage id and
138 138
 		// loss of shares from the storage
139
-		return 'smb::' . $this->server->getAuth()->getUsername() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
139
+		return 'smb::'.$this->server->getAuth()->getUsername().'@'.$this->server->getHost().'//'.$this->share->getName().'/'.$this->root;
140 140
 	}
141 141
 
142 142
 	/**
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 	 * @return string
145 145
 	 */
146 146
 	protected function buildPath($path) {
147
-		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
147
+		return Filesystem::normalizePath($this->root.'/'.$path, true, false, true);
148 148
 	}
149 149
 
150 150
 	protected function relativePath($fullPath) {
@@ -185,22 +185,22 @@  discard block
 block discarded – undo
185 185
 			$path = $this->buildPath($path);
186 186
 			$files = $this->share->dir($path);
187 187
 			foreach ($files as $file) {
188
-				$this->statCache[$path . '/' . $file->getName()] = $file;
188
+				$this->statCache[$path.'/'.$file->getName()] = $file;
189 189
 			}
190
-			return array_filter($files, function (IFileInfo $file) {
190
+			return array_filter($files, function(IFileInfo $file) {
191 191
 				try {
192 192
 					// the isHidden check is done before checking the config boolean to ensure that the metadata is always fetch
193 193
 					// so we trigger the below exceptions where applicable
194 194
 					$hide = $file->isHidden() && !$this->showHidden;
195 195
 					if ($hide) {
196
-						$this->logger->debug('hiding hidden file ' . $file->getName());
196
+						$this->logger->debug('hiding hidden file '.$file->getName());
197 197
 					}
198 198
 					return !$hide;
199 199
 				} catch (ForbiddenException $e) {
200
-					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding forbidden entry ' . $file->getName()]);
200
+					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding forbidden entry '.$file->getName()]);
201 201
 					return false;
202 202
 				} catch (NotFoundException $e) {
203
-					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding not found entry ' . $file->getName()]);
203
+					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding not found entry '.$file->getName()]);
204 204
 					return false;
205 205
 				}
206 206
 			});
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
 				case 'w':
391 391
 				case 'wb':
392 392
 					$source = $this->share->write($fullPath);
393
-					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
393
+					return CallBackWrapper::wrap($source, null, null, function() use ($fullPath) {
394 394
 						unset($this->statCache[$fullPath]);
395 395
 					});
396 396
 				case 'a':
@@ -422,7 +422,7 @@  discard block
 block discarded – undo
422 422
 					}
423 423
 					$source = fopen($tmpFile, $mode);
424 424
 					$share = $this->share;
425
-					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
425
+					return CallbackWrapper::wrap($source, null, null, function() use ($tmpFile, $fullPath, $share) {
426 426
 						unset($this->statCache[$fullPath]);
427 427
 						$share->put($tmpFile, $fullPath);
428 428
 						unlink($tmpFile);
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
 			$content = $this->share->dir($this->buildPath($path));
450 450
 			foreach ($content as $file) {
451 451
 				if ($file->isDirectory()) {
452
-					$this->rmdir($path . '/' . $file->getName());
452
+					$this->rmdir($path.'/'.$file->getName());
453 453
 				} else {
454 454
 					$this->share->del($file->getPath());
455 455
 				}
@@ -488,7 +488,7 @@  discard block
 block discarded – undo
488 488
 		} catch (ForbiddenException $e) {
489 489
 			return false;
490 490
 		}
491
-		$names = array_map(function ($info) {
491
+		$names = array_map(function($info) {
492 492
 			/** @var \Icewind\SMB\IFileInfo $info */
493 493
 			return $info->getName();
494 494
 		}, $files);
@@ -571,7 +571,7 @@  discard block
 block discarded – undo
571 571
 	 */
572 572
 	public static function checkDependencies() {
573 573
 		return (
574
-			(bool)\OC_Helper::findBinaryPath('smbclient')
574
+			(bool) \OC_Helper::findBinaryPath('smbclient')
575 575
 			|| NativeServer::available(new System())
576 576
 		) ? true : ['smbclient'];
577 577
 	}
@@ -591,7 +591,7 @@  discard block
 block discarded – undo
591 591
 	}
592 592
 
593 593
 	public function listen($path, callable $callback) {
594
-		$this->notify($path)->listen(function (IChange $change) use ($callback) {
594
+		$this->notify($path)->listen(function(IChange $change) use ($callback) {
595 595
 			if ($change instanceof IRenameChange) {
596 596
 				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
597 597
 			} else {
@@ -601,7 +601,7 @@  discard block
 block discarded – undo
601 601
 	}
602 602
 
603 603
 	public function notify($path) {
604
-		$path = '/' . ltrim($path, '/');
604
+		$path = '/'.ltrim($path, '/');
605 605
 		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
606 606
 		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
607 607
 	}
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Backend/SMB.php 1 patch
Indentation   +45 added lines, -45 removed lines patch added patch discarded remove patch
@@ -35,53 +35,53 @@
 block discarded – undo
35 35
 
36 36
 class SMB extends Backend {
37 37
 
38
-	use LegacyDependencyCheckPolyfill;
38
+    use LegacyDependencyCheckPolyfill;
39 39
 
40
-	public function __construct(IL10N $l, Password $legacyAuth) {
41
-		$this
42
-			->setIdentifier('smb')
43
-			->addIdentifierAlias('\OC\Files\Storage\SMB')// legacy compat
44
-			->setStorageClass('\OCA\Files_External\Lib\Storage\SMB')
45
-			->setText($l->t('SMB / CIFS'))
46
-			->addParameters([
47
-				new DefinitionParameter('host', $l->t('Host')),
48
-				new DefinitionParameter('share', $l->t('Share')),
49
-				(new DefinitionParameter('root', $l->t('Remote subfolder')))
50
-					->setFlag(DefinitionParameter::FLAG_OPTIONAL),
51
-				(new DefinitionParameter('domain', $l->t('Domain')))
52
-					->setFlag(DefinitionParameter::FLAG_OPTIONAL),
53
-				(new DefinitionParameter('show_hidden', $l->t('Show hidden files')))
54
-					->setType(DefinitionParameter::VALUE_BOOLEAN)
55
-					->setFlag(DefinitionParameter::FLAG_OPTIONAL),
56
-			])
57
-			->addAuthScheme(AuthMechanism::SCHEME_PASSWORD)
58
-			->addAuthScheme(AuthMechanism::SCHEME_SMB)
59
-			->setLegacyAuthMechanism($legacyAuth);
60
-	}
40
+    public function __construct(IL10N $l, Password $legacyAuth) {
41
+        $this
42
+            ->setIdentifier('smb')
43
+            ->addIdentifierAlias('\OC\Files\Storage\SMB')// legacy compat
44
+            ->setStorageClass('\OCA\Files_External\Lib\Storage\SMB')
45
+            ->setText($l->t('SMB / CIFS'))
46
+            ->addParameters([
47
+                new DefinitionParameter('host', $l->t('Host')),
48
+                new DefinitionParameter('share', $l->t('Share')),
49
+                (new DefinitionParameter('root', $l->t('Remote subfolder')))
50
+                    ->setFlag(DefinitionParameter::FLAG_OPTIONAL),
51
+                (new DefinitionParameter('domain', $l->t('Domain')))
52
+                    ->setFlag(DefinitionParameter::FLAG_OPTIONAL),
53
+                (new DefinitionParameter('show_hidden', $l->t('Show hidden files')))
54
+                    ->setType(DefinitionParameter::VALUE_BOOLEAN)
55
+                    ->setFlag(DefinitionParameter::FLAG_OPTIONAL),
56
+            ])
57
+            ->addAuthScheme(AuthMechanism::SCHEME_PASSWORD)
58
+            ->addAuthScheme(AuthMechanism::SCHEME_SMB)
59
+            ->setLegacyAuthMechanism($legacyAuth);
60
+    }
61 61
 
62
-	/**
63
-	 * @param StorageConfig $storage
64
-	 * @param IUser $user
65
-	 */
66
-	public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
67
-		$auth = $storage->getAuthMechanism();
68
-		if ($auth->getScheme() === AuthMechanism::SCHEME_PASSWORD) {
69
-			$smbAuth = new BasicAuth(
70
-				$storage->getBackendOption('user'),
71
-				$storage->getBackendOption('domain'),
72
-				$storage->getBackendOption('password')
73
-			);
74
-		} else {
75
-			switch ($auth->getIdentifier()) {
76
-				case 'smb::kerberos':
77
-					$smbAuth = new KerberosAuth();
78
-					break;
79
-				default:
80
-					throw new \InvalidArgumentException('unknown authentication backend');
81
-			}
82
-		}
62
+    /**
63
+     * @param StorageConfig $storage
64
+     * @param IUser $user
65
+     */
66
+    public function manipulateStorageConfig(StorageConfig &$storage, IUser $user = null) {
67
+        $auth = $storage->getAuthMechanism();
68
+        if ($auth->getScheme() === AuthMechanism::SCHEME_PASSWORD) {
69
+            $smbAuth = new BasicAuth(
70
+                $storage->getBackendOption('user'),
71
+                $storage->getBackendOption('domain'),
72
+                $storage->getBackendOption('password')
73
+            );
74
+        } else {
75
+            switch ($auth->getIdentifier()) {
76
+                case 'smb::kerberos':
77
+                    $smbAuth = new KerberosAuth();
78
+                    break;
79
+                default:
80
+                    throw new \InvalidArgumentException('unknown authentication backend');
81
+            }
82
+        }
83 83
 
84
-		$storage->setBackendOption('auth', $smbAuth);
85
-	}
84
+        $storage->setBackendOption('auth', $smbAuth);
85
+    }
86 86
 
87 87
 }
Please login to merge, or discard this patch.