Completed
Push — stable13 ( eea151...ace570 )
by Blizzz
127:50 queued 105:16
created

SMB   F

Complexity

Total Complexity 125

Size/Duplication

Total Lines 512
Duplicated Lines 18.36 %

Coupling/Cohesion

Components 1
Dependencies 13

Importance

Changes 0
Metric Value
wmc 125
lcom 1
cbo 13
dl 94
loc 512
rs 2
c 0
b 0
f 0

28 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 3 22 10
A getId() 0 6 1
A buildPath() 0 3 1
A relativePath() 9 9 3
A getFileInfo() 0 12 3
B getFolderContents() 0 26 6
A formatInfo() 0 12 2
B rename() 14 32 8
A stat() 0 13 5
A shareMTime() 0 14 4
A isRootDir() 0 3 3
A remoteIsShare() 0 3 3
B unlink() 0 23 6
A hasUpdated() 0 10 3
F fopen() 11 61 23
B rmdir() 0 26 7
A touch() 13 13 3
A opendir() 0 14 3
A filetype() 0 9 4
A mkdir() 12 12 3
A file_exists() 0 12 4
A isReadable() 10 10 3
A isUpdatable() 12 12 5
A isDeletable() 10 10 4
A checkDependencies() 0 6 3
A test() 0 8 2
A listen() 0 9 2
A notify() 0 5 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like SMB often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SMB, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Jesús Macias <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Juan Pablo Villafañez <[email protected]>
9
 * @author Juan Pablo Villafáñez <[email protected]>
10
 * @author Jörn Friedrich Dreyer <[email protected]>
11
 * @author Michael Gapczynski <[email protected]>
12
 * @author Morris Jobke <[email protected]>
13
 * @author Philipp Kapfer <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 * @author Robin McCorkell <[email protected]>
16
 * @author Thomas Müller <[email protected]>
17
 * @author Vincent Petry <[email protected]>
18
 *
19
 * @license AGPL-3.0
20
 *
21
 * This code is free software: you can redistribute it and/or modify
22
 * it under the terms of the GNU Affero General Public License, version 3,
23
 * as published by the Free Software Foundation.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
 * GNU Affero General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Affero General Public License, version 3,
31
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
32
 *
33
 */
34
35
namespace OCA\Files_External\Lib\Storage;
36
37
use Icewind\SMB\Exception\AlreadyExistsException;
38
use Icewind\SMB\Exception\ConnectException;
39
use Icewind\SMB\Exception\Exception;
40
use Icewind\SMB\Exception\ForbiddenException;
41
use Icewind\SMB\Exception\InvalidArgumentException;
42
use Icewind\SMB\Exception\NotFoundException;
43
use Icewind\SMB\IFileInfo;
44
use Icewind\SMB\NativeServer;
45
use Icewind\SMB\Server;
46
use Icewind\Streams\CallbackWrapper;
47
use Icewind\Streams\IteratorDirectory;
48
use OC\Cache\CappedMemoryCache;
49
use OC\Files\Filesystem;
50
use OC\Files\Storage\Common;
51
use OCA\Files_External\Lib\Notify\SMBNotifyHandler;
52
use OCP\Files\Notify\IChange;
53
use OCP\Files\Notify\IRenameChange;
54
use OCP\Files\Storage\INotifyStorage;
55
use OCP\Files\StorageNotAvailableException;
56
use OCP\ILogger;
57
use OCP\Util;
58
59
class SMB extends Common implements INotifyStorage {
60
	/**
61
	 * @var \Icewind\SMB\Server
62
	 */
63
	protected $server;
64
65
	/**
66
	 * @var \Icewind\SMB\Share
67
	 */
68
	protected $share;
69
70
	/**
71
	 * @var string
72
	 */
73
	protected $root;
74
75
	/**
76
	 * @var \Icewind\SMB\FileInfo[]
77
	 */
78
	protected $statCache;
79
80
	public function __construct($params) {
81
		if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
82
			if (Server::NativeAvailable()) {
83
				$this->server = new NativeServer($params['host'], $params['user'], $params['password']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Icewind\SMB\NativeS...], $params['password']) of type object<Icewind\SMB\NativeServer> is incompatible with the declared type object<Icewind\SMB\Server> of property $server.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
84
			} else {
85
				$this->server = new Server($params['host'], $params['user'], $params['password']);
86
			}
87
			$this->share = $this->server->getShare(trim($params['share'], '/'));
88
89
			$this->root = isset($params['root']) ? $params['root'] : '/';
90 View Code Duplication
			if (!$this->root || $this->root[0] !== '/') {
91
				$this->root = '/' . $this->root;
92
			}
93
			if (substr($this->root, -1, 1) !== '/') {
94
				$this->root .= '/';
95
			}
96
		} else {
97
			throw new \Exception('Invalid configuration');
98
		}
99
		$this->statCache = new CappedMemoryCache();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \OC\Cache\CappedMemoryCache() of type object<OC\Cache\CappedMemoryCache> is incompatible with the declared type array<integer,object<Icewind\SMB\FileInfo>> of property $statCache.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
100
		parent::__construct($params);
101
	}
102
103
	/**
104
	 * @return string
105
	 */
106
	public function getId() {
107
		// FIXME: double slash to keep compatible with the old storage ids,
108
		// failure to do so will lead to creation of a new storage id and
109
		// loss of shares from the storage
110
		return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
111
	}
112
113
	/**
114
	 * @param string $path
115
	 * @return string
116
	 */
117
	protected function buildPath($path) {
118
		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
119
	}
120
121 View Code Duplication
	protected function relativePath($fullPath) {
122
		if ($fullPath === $this->root) {
123
			return '';
124
		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
125
			return substr($fullPath, strlen($this->root));
126
		} else {
127
			return null;
128
		}
129
	}
130
131
	/**
132
	 * @param string $path
133
	 * @return \Icewind\SMB\IFileInfo
134
	 * @throws StorageNotAvailableException
135
	 */
136
	protected function getFileInfo($path) {
137
		try {
138
			$path = $this->buildPath($path);
139
			if (!isset($this->statCache[$path])) {
140
				$this->statCache[$path] = $this->share->stat($path);
141
			}
142
			return $this->statCache[$path];
143
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
144
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while getting file info']);
145
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
146
		}
147
	}
148
149
	/**
150
	 * @param string $path
151
	 * @return \Icewind\SMB\IFileInfo[]
152
	 * @throws StorageNotAvailableException
153
	 */
154
	protected function getFolderContents($path) {
155
		try {
156
			$path = $this->buildPath($path);
157
			$files = $this->share->dir($path);
158
			foreach ($files as $file) {
159
				$this->statCache[$path . '/' . $file->getName()] = $file;
160
			}
161
			return array_filter($files, function (IFileInfo $file) {
162
				try {
163
					if ($file->isHidden()) {
164
						\OC::$server->getLogger()->debug('hiding hidden file ' . $file->getName());
165
					}
166
					return !$file->isHidden();
167
				} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
168
					\OC::$server->getLogger()->logException($e, ['level' => Util::DEBUG, 'message' => 'Hiding forbidden entry ' . $file->getName()]);
169
					return false;
170
				} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
171
					\OC::$server->getLogger()->logException($e, ['level' => Util::DEBUG, 'message' => 'Hiding not found entry ' . $file->getName()]);
172
					return false;
173
				}
174
			});
175
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
176
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while getting folder content']);
177
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
178
		}
179
	}
180
181
	/**
182
	 * @param \Icewind\SMB\IFileInfo $info
183
	 * @return array
184
	 */
185
	protected function formatInfo($info) {
186
		$result = [
187
			'size' => $info->getSize(),
188
			'mtime' => $info->getMTime(),
189
		];
190
		if ($info->isDirectory()) {
191
			$result['type'] = 'dir';
192
		} else {
193
			$result['type'] = 'file';
194
		}
195
		return $result;
196
	}
197
198
	/**
199
	 * Rename the files. If the source or the target is the root, the rename won't happen.
200
	 *
201
	 * @param string $source the old name of the path
202
	 * @param string $target the new name of the path
203
	 * @return bool true if the rename is successful, false otherwise
204
	 */
205
	public function rename($source, $target, $retry = true) {
206
		if ($this->isRootDir($source) || $this->isRootDir($target)) {
207
			return false;
208
		}
209
210
		$absoluteSource = $this->buildPath($source);
211
		$absoluteTarget = $this->buildPath($target);
212
		try {
213
			$result = $this->share->rename($absoluteSource, $absoluteTarget);
214
		} catch (AlreadyExistsException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\AlreadyExistsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
215 View Code Duplication
			if ($retry) {
216
				$this->remove($target);
217
				$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
218
			} else {
219
				\OC::$server->getLogger()->logException($e, ['level' => ILogger::WARN]);
220
				return false;
221
			}
222
		} catch (InvalidArgumentException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\InvalidArgumentException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
223 View Code Duplication
			if ($retry) {
224
				$this->remove($target);
225
				$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
226
			} else {
227
				\OC::$server->getLogger()->logException($e, ['level' => ILogger::WARN]);
228
				return false;
229
			}
230
		} catch (\Exception $e) {
231
			\OC::$server->getLogger()->logException($e, ['level' => Util::WARN]);
232
			return false;
233
		}
234
		unset($this->statCache[$absoluteSource], $this->statCache[$absoluteTarget]);
235
		return $result;
236
	}
237
238
	public function stat($path) {
239
		try {
240
			$result = $this->formatInfo($this->getFileInfo($path));
241
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
242
			return false;
243
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
244
			return false;
245
		}
246
		if ($this->remoteIsShare() && $this->isRootDir($path)) {
247
			$result['mtime'] = $this->shareMTime();
248
		}
249
		return $result;
250
	}
251
252
	/**
253
	 * get the best guess for the modification time of the share
254
	 *
255
	 * @return int
256
	 */
257
	private function shareMTime() {
258
		$highestMTime = 0;
259
		$files = $this->share->dir($this->root);
260
		foreach ($files as $fileInfo) {
261
			try {
262
				if ($fileInfo->getMTime() > $highestMTime) {
263
					$highestMTime = $fileInfo->getMTime();
264
				}
265
			} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
266
				// Ignore this, can happen on unavailable DFS shares
267
			}
268
		}
269
		return $highestMTime;
270
	}
271
272
	/**
273
	 * Check if the path is our root dir (not the smb one)
274
	 *
275
	 * @param string $path the path
276
	 * @return bool
277
	 */
278
	private function isRootDir($path) {
279
		return $path === '' || $path === '/' || $path === '.';
280
	}
281
282
	/**
283
	 * Check if our root points to a smb share
284
	 *
285
	 * @return bool true if our root points to a share false otherwise
286
	 */
287
	private function remoteIsShare() {
288
		return $this->share->getName() && (!$this->root || $this->root === '/');
289
	}
290
291
	/**
292
	 * @param string $path
293
	 * @return bool
294
	 */
295
	public function unlink($path) {
296
		if ($this->isRootDir($path)) {
297
			return false;
298
		}
299
300
		try {
301
			if ($this->is_dir($path)) {
302
				return $this->rmdir($path);
303
			} else {
304
				$path = $this->buildPath($path);
305
				unset($this->statCache[$path]);
306
				$this->share->del($path);
307
				return true;
308
			}
309
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
310
			return false;
311
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
312
			return false;
313
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
314
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while deleting file']);
315
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
316
		}
317
	}
318
319
	/**
320
	 * check if a file or folder has been updated since $time
321
	 *
322
	 * @param string $path
323
	 * @param int $time
324
	 * @return bool
325
	 */
326
	public function hasUpdated($path, $time) {
327
		if (!$path and $this->root === '/') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
328
			// mtime doesn't work for shares, but giving the nature of the backend,
329
			// doing a full update is still just fast enough
330
			return true;
331
		} else {
332
			$actualTime = $this->filemtime($path);
333
			return $actualTime > $time;
334
		}
335
	}
336
337
	/**
338
	 * @param string $path
339
	 * @param string $mode
340
	 * @return resource|false
341
	 */
342
	public function fopen($path, $mode) {
343
		$fullPath = $this->buildPath($path);
344
		try {
345
			switch ($mode) {
346
				case 'r':
347
				case 'rb':
348
					if (!$this->file_exists($path)) {
349
						return false;
350
					}
351
					return $this->share->read($fullPath);
352
				case 'w':
353
				case 'wb':
354
					$source = $this->share->write($fullPath);
355
					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
356
						unset($this->statCache[$fullPath]);
357
					});
358
				case 'a':
359
				case 'ab':
360
				case 'r+':
361
				case 'w+':
362
				case 'wb+':
363
				case 'a+':
364
				case 'x':
365
				case 'x+':
366
				case 'c':
367
				case 'c+':
368
					//emulate these
369
					if (strrpos($path, '.') !== false) {
370
						$ext = substr($path, strrpos($path, '.'));
371
					} else {
372
						$ext = '';
373
					}
374 View Code Duplication
					if ($this->file_exists($path)) {
375
						if (!$this->isUpdatable($path)) {
376
							return false;
377
						}
378
						$tmpFile = $this->getCachedFile($path);
379
					} else {
380
						if (!$this->isCreatable(dirname($path))) {
381
							return false;
382
						}
383
						$tmpFile = \OCP\Files::tmpFile($ext);
384
					}
385
					$source = fopen($tmpFile, $mode);
386
					$share = $this->share;
387
					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
388
						unset($this->statCache[$fullPath]);
389
						$share->put($tmpFile, $fullPath);
390
						unlink($tmpFile);
391
					});
392
			}
393
			return false;
394
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
395
			return false;
396
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
397
			return false;
398
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
399
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while opening file']);
400
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
401
		}
402
	}
403
404
	public function rmdir($path) {
405
		if ($this->isRootDir($path)) {
406
			return false;
407
		}
408
409
		try {
410
			$this->statCache = array();
411
			$content = $this->share->dir($this->buildPath($path));
412
			foreach ($content as $file) {
413
				if ($file->isDirectory()) {
414
					$this->rmdir($path . '/' . $file->getName());
415
				} else {
416
					$this->share->del($file->getPath());
417
				}
418
			}
419
			$this->share->rmdir($this->buildPath($path));
420
			return true;
421
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
422
			return false;
423
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
424
			return false;
425
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
426
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while removing folder']);
427
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
428
		}
429
	}
430
431 View Code Duplication
	public function touch($path, $time = null) {
432
		try {
433
			if (!$this->file_exists($path)) {
434
				$fh = $this->share->write($this->buildPath($path));
435
				fclose($fh);
436
				return true;
437
			}
438
			return false;
439
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
440
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while creating file']);
441
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
442
		}
443
	}
444
445
	public function opendir($path) {
446
		try {
447
			$files = $this->getFolderContents($path);
448
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
449
			return false;
450
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
451
			return false;
452
		}
453
		$names = array_map(function ($info) {
454
			/** @var \Icewind\SMB\IFileInfo $info */
455
			return $info->getName();
456
		}, $files);
457
		return IteratorDirectory::wrap($names);
458
	}
459
460
	public function filetype($path) {
461
		try {
462
			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
463
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
464
			return false;
465
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
466
			return false;
467
		}
468
	}
469
470 View Code Duplication
	public function mkdir($path) {
471
		$path = $this->buildPath($path);
472
		try {
473
			$this->share->mkdir($path);
474
			return true;
475
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
476
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while creating folder']);
477
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
478
		} catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
479
			return false;
480
		}
481
	}
482
483
	public function file_exists($path) {
484
		try {
485
			$this->getFileInfo($path);
486
			return true;
487
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
488
			return false;
489
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
490
			return false;
491
		} catch (ConnectException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ConnectException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
492
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
493
		}
494
	}
495
496 View Code Duplication
	public function isReadable($path) {
497
		try {
498
			$info = $this->getFileInfo($path);
499
			return !$info->isHidden();
500
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
501
			return false;
502
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
503
			return false;
504
		}
505
	}
506
507 View Code Duplication
	public function isUpdatable($path) {
508
		try {
509
			$info = $this->getFileInfo($path);
510
			// following windows behaviour for read-only folders: they can be written into
511
			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
512
			return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
513
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
514
			return false;
515
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
516
			return false;
517
		}
518
	}
519
520 View Code Duplication
	public function isDeletable($path) {
521
		try {
522
			$info = $this->getFileInfo($path);
523
			return !$info->isHidden() && !$info->isReadOnly();
524
		} catch (NotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
525
			return false;
526
		} catch (ForbiddenException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\ForbiddenException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
527
			return false;
528
		}
529
	}
530
531
	/**
532
	 * check if smbclient is installed
533
	 */
534
	public static function checkDependencies() {
535
		return (
536
			(bool)\OC_Helper::findBinaryPath('smbclient')
537
			|| Server::NativeAvailable()
538
		) ? true : ['smbclient'];
539
	}
540
541
	/**
542
	 * Test a storage for availability
543
	 *
544
	 * @return bool
545
	 */
546
	public function test() {
547
		try {
548
			return parent::test();
549
		} catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
550
			\OC::$server->getLogger()->logException($e);
551
			return false;
552
		}
553
	}
554
555
	public function listen($path, callable $callback) {
556
		$this->notify($path)->listen(function (IChange $change) use ($callback) {
557
			if ($change instanceof IRenameChange) {
558
				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
559
			} else {
560
				return $callback($change->getType(), $change->getPath());
561
			}
562
		});
563
	}
564
565
	public function notify($path) {
566
		$path = '/' . ltrim($path, '/');
567
		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
568
		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
569
	}
570
}
571