Completed
Push — master ( ca493a...4c38d1 )
by Morris
132:28 queued 111:40
created

SMB::hasUpdated()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 2
nop 2
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
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\NotFoundException;
42
use Icewind\SMB\IFileInfo;
43
use Icewind\SMB\NativeServer;
44
use Icewind\SMB\Server;
45
use Icewind\Streams\CallbackWrapper;
46
use Icewind\Streams\IteratorDirectory;
47
use OC\Cache\CappedMemoryCache;
48
use OC\Files\Filesystem;
49
use OC\Files\Storage\Common;
50
use OCA\Files_External\Lib\Notify\SMBNotifyHandler;
51
use OCP\Files\Notify\IChange;
52
use OCP\Files\Notify\IRenameChange;
53
use OCP\Files\Storage\INotifyStorage;
54
use OCP\Files\StorageNotAvailableException;
55
use OCP\Util;
56
57
class SMB extends Common implements INotifyStorage {
58
	/**
59
	 * @var \Icewind\SMB\Server
60
	 */
61
	protected $server;
62
63
	/**
64
	 * @var \Icewind\SMB\Share
65
	 */
66
	protected $share;
67
68
	/**
69
	 * @var string
70
	 */
71
	protected $root;
72
73
	/**
74
	 * @var \Icewind\SMB\FileInfo[]
75
	 */
76
	protected $statCache;
77
78
	public function __construct($params) {
79
		if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
80
			if (Server::NativeAvailable()) {
81
				$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...
82
			} else {
83
				$this->server = new Server($params['host'], $params['user'], $params['password']);
84
			}
85
			$this->share = $this->server->getShare(trim($params['share'], '/'));
86
87
			$this->root = $params['root'] ?? '/';
88
			$this->root = '/' . ltrim($this->root, '/');
89
			$this->root = rtrim($this->root, '/') . '/';
90
		} else {
91
			throw new \Exception('Invalid configuration');
92
		}
93
		$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...
94
		parent::__construct($params);
95
	}
96
97
	/**
98
	 * @return string
99
	 */
100
	public function getId() {
101
		// FIXME: double slash to keep compatible with the old storage ids,
102
		// failure to do so will lead to creation of a new storage id and
103
		// loss of shares from the storage
104
		return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
105
	}
106
107
	/**
108
	 * @param string $path
109
	 * @return string
110
	 */
111
	protected function buildPath($path) {
112
		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
113
	}
114
115 View Code Duplication
	protected function relativePath($fullPath) {
116
		if ($fullPath === $this->root) {
117
			return '';
118
		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
119
			return substr($fullPath, strlen($this->root));
120
		} else {
121
			return null;
122
		}
123
	}
124
125
	/**
126
	 * @param string $path
127
	 * @return \Icewind\SMB\IFileInfo
128
	 * @throws StorageNotAvailableException
129
	 */
130
	protected function getFileInfo($path) {
131
		try {
132
			$path = $this->buildPath($path);
133
			if (!isset($this->statCache[$path])) {
134
				$this->statCache[$path] = $this->share->stat($path);
135
			}
136
			return $this->statCache[$path];
137
		} 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...
138
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
139
		}
140
	}
141
142
	/**
143
	 * @param string $path
144
	 * @return \Icewind\SMB\IFileInfo[]
145
	 * @throws StorageNotAvailableException
146
	 */
147
	protected function getFolderContents($path) {
148
		try {
149
			$path = $this->buildPath($path);
150
			$files = $this->share->dir($path);
151
			foreach ($files as $file) {
152
				$this->statCache[$path . '/' . $file->getName()] = $file;
153
			}
154
			return array_filter($files, function (IFileInfo $file) {
155
				return !$file->isHidden();
156
			});
157
		} 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...
158
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
159
		}
160
	}
161
162
	/**
163
	 * @param \Icewind\SMB\IFileInfo $info
164
	 * @return array
165
	 */
166
	protected function formatInfo($info) {
167
		$result = [
168
			'size' => $info->getSize(),
169
			'mtime' => $info->getMTime(),
170
		];
171
		if ($info->isDirectory()) {
172
			$result['type'] = 'dir';
173
		} else {
174
			$result['type'] = 'file';
175
		}
176
		return $result;
177
	}
178
179
	/**
180
	 * Rename the files. If the source or the target is the root, the rename won't happen.
181
	 *
182
	 * @param string $source the old name of the path
183
	 * @param string $target the new name of the path
184
	 * @return bool true if the rename is successful, false otherwise
185
	 */
186
	public function rename($source, $target) {
187
		if ($this->isRootDir($source) || $this->isRootDir($target)) {
188
			return false;
189
		}
190
191
		$absoluteSource = $this->buildPath($source);
192
		$absoluteTarget = $this->buildPath($target);
193
		try {
194
			$result = $this->share->rename($absoluteSource, $absoluteTarget);
195
		} 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...
196
			$this->remove($target);
197
			$result = $this->share->rename($absoluteSource, $absoluteTarget);
198
		} catch (\Exception $e) {
199
			\OC::$server->getLogger()->logException($e, ['level' => Util::WARN]);
200
			return false;
201
		}
202
		unset($this->statCache[$absoluteSource], $this->statCache[$absoluteTarget]);
203
		return $result;
204
	}
205
206
	public function stat($path) {
207
		try {
208
			$result = $this->formatInfo($this->getFileInfo($path));
209
		} 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...
210
			return false;
211
		} 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...
212
			return false;
213
		}
214
		if ($this->remoteIsShare() && $this->isRootDir($path)) {
215
			$result['mtime'] = $this->shareMTime();
216
		}
217
		return $result;
218
	}
219
220
	/**
221
	 * get the best guess for the modification time of the share
222
	 *
223
	 * @return int
224
	 */
225
	private function shareMTime() {
226
		$highestMTime = 0;
227
		$files = $this->share->dir($this->root);
228
		foreach ($files as $fileInfo) {
229
			if ($fileInfo->getMTime() > $highestMTime) {
230
				$highestMTime = $fileInfo->getMTime();
231
			}
232
		}
233
		return $highestMTime;
234
	}
235
236
	/**
237
	 * Check if the path is our root dir (not the smb one)
238
	 *
239
	 * @param string $path the path
240
	 * @return bool
241
	 */
242
	private function isRootDir($path) {
243
		return $path === '' || $path === '/' || $path === '.';
244
	}
245
246
	/**
247
	 * Check if our root points to a smb share
248
	 *
249
	 * @return bool true if our root points to a share false otherwise
250
	 */
251
	private function remoteIsShare() {
252
		return $this->share->getName() && (!$this->root || $this->root === '/');
253
	}
254
255
	/**
256
	 * @param string $path
257
	 * @return bool
258
	 */
259
	public function unlink($path) {
260
		if ($this->isRootDir($path)) {
261
			return false;
262
		}
263
264
		try {
265
			if ($this->is_dir($path)) {
266
				return $this->rmdir($path);
267
			} else {
268
				$path = $this->buildPath($path);
269
				unset($this->statCache[$path]);
270
				$this->share->del($path);
271
				return true;
272
			}
273
		} 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...
274
			return false;
275
		} 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...
276
			return false;
277
		} 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...
278
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
279
		}
280
	}
281
282
	/**
283
	 * check if a file or folder has been updated since $time
284
	 *
285
	 * @param string $path
286
	 * @param int $time
287
	 * @return bool
288
	 */
289
	public function hasUpdated($path, $time) {
290
		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...
291
			// mtime doesn't work for shares, but giving the nature of the backend,
292
			// doing a full update is still just fast enough
293
			return true;
294
		} else {
295
			$actualTime = $this->filemtime($path);
296
			return $actualTime > $time;
297
		}
298
	}
299
300
	/**
301
	 * @param string $path
302
	 * @param string $mode
303
	 * @return resource|false
304
	 */
305
	public function fopen($path, $mode) {
306
		$fullPath = $this->buildPath($path);
307
		try {
308
			switch ($mode) {
309
				case 'r':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
310
				case 'rb':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
311
					if (!$this->file_exists($path)) {
312
						return false;
313
					}
314
					return $this->share->read($fullPath);
315
				case 'w':
316
				case 'wb':
317
					$source = $this->share->write($fullPath);
318
					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
319
						unset($this->statCache[$fullPath]);
320
					});
321
				case 'a':
322
				case 'ab':
323
				case 'r+':
324
				case 'w+':
325
				case 'wb+':
326
				case 'a+':
327
				case 'x':
328
				case 'x+':
329
				case 'c':
330
				case 'c+':
331
					//emulate these
332
					if (strrpos($path, '.') !== false) {
333
						$ext = substr($path, strrpos($path, '.'));
334
					} else {
335
						$ext = '';
336
					}
337 View Code Duplication
					if ($this->file_exists($path)) {
338
						if (!$this->isUpdatable($path)) {
339
							return false;
340
						}
341
						$tmpFile = $this->getCachedFile($path);
342
					} else {
343
						if (!$this->isCreatable(dirname($path))) {
344
							return false;
345
						}
346
						$tmpFile = \OCP\Files::tmpFile($ext);
347
					}
348
					$source = fopen($tmpFile, $mode);
349
					$share = $this->share;
350
					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
351
						unset($this->statCache[$fullPath]);
352
						$share->put($tmpFile, $fullPath);
353
						unlink($tmpFile);
354
					});
355
			}
356
			return false;
357
		} 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...
358
			return false;
359
		} 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...
360
			return false;
361
		} 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...
362
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
363
		}
364
	}
365
366
	public function rmdir($path) {
367
		if ($this->isRootDir($path)) {
368
			return false;
369
		}
370
371
		try {
372
			$this->statCache = array();
373
			$content = $this->share->dir($this->buildPath($path));
374
			foreach ($content as $file) {
375
				if ($file->isDirectory()) {
376
					$this->rmdir($path . '/' . $file->getName());
377
				} else {
378
					$this->share->del($file->getPath());
379
				}
380
			}
381
			$this->share->rmdir($this->buildPath($path));
382
			return true;
383
		} 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...
384
			return false;
385
		} 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...
386
			return false;
387
		} 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...
388
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
389
		}
390
	}
391
392 View Code Duplication
	public function touch($path, $time = null) {
393
		try {
394
			if (!$this->file_exists($path)) {
395
				$fh = $this->share->write($this->buildPath($path));
396
				fclose($fh);
397
				return true;
398
			}
399
			return false;
400
		} 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...
401
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
402
		}
403
	}
404
405
	public function opendir($path) {
406
		try {
407
			$files = $this->getFolderContents($path);
408
		} 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...
409
			return false;
410
		} 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...
411
			return false;
412
		}
413
		$names = array_map(function ($info) {
414
			/** @var \Icewind\SMB\IFileInfo $info */
415
			return $info->getName();
416
		}, $files);
417
		return IteratorDirectory::wrap($names);
418
	}
419
420
	public function filetype($path) {
421
		try {
422
			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
423
		} 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...
424
			return false;
425
		} 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...
426
			return false;
427
		}
428
	}
429
430 View Code Duplication
	public function mkdir($path) {
431
		$path = $this->buildPath($path);
432
		try {
433
			$this->share->mkdir($path);
434
			return true;
435
		} 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...
436
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
437
		} 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...
438
			return false;
439
		}
440
	}
441
442
	public function file_exists($path) {
443
		try {
444
			$this->getFileInfo($path);
445
			return true;
446
		} 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...
447
			return false;
448
		} 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...
449
			return false;
450
		} 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...
451
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
452
		}
453
	}
454
455 View Code Duplication
	public function isReadable($path) {
456
		try {
457
			$info = $this->getFileInfo($path);
458
			return !$info->isHidden();
459
		} 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...
460
			return false;
461
		} 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...
462
			return false;
463
		}
464
	}
465
466 View Code Duplication
	public function isUpdatable($path) {
467
		try {
468
			$info = $this->getFileInfo($path);
469
			// following windows behaviour for read-only folders: they can be written into
470
			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
471
			return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
472
		} 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...
473
			return false;
474
		} 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...
475
			return false;
476
		}
477
	}
478
479 View Code Duplication
	public function isDeletable($path) {
480
		try {
481
			$info = $this->getFileInfo($path);
482
			return !$info->isHidden() && !$info->isReadOnly();
483
		} 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...
484
			return false;
485
		} 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...
486
			return false;
487
		}
488
	}
489
490
	/**
491
	 * check if smbclient is installed
492
	 */
493
	public static function checkDependencies() {
494
		return (
495
			(bool)\OC_Helper::findBinaryPath('smbclient')
496
			|| Server::NativeAvailable()
497
		) ? true : ['smbclient'];
498
	}
499
500
	/**
501
	 * Test a storage for availability
502
	 *
503
	 * @return bool
504
	 */
505
	public function test() {
506
		try {
507
			return parent::test();
508
		} 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...
509
			return false;
510
		}
511
	}
512
513
	public function listen($path, callable $callback) {
514
		$this->notify($path)->listen(function (IChange $change) use ($callback) {
515
			if ($change instanceof IRenameChange) {
516
				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
517
			} else {
518
				return $callback($change->getType(), $change->getPath());
519
			}
520
		});
521
	}
522
523
	public function notify($path) {
524
		$path = '/' . ltrim($path, '/');
525
		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
526
		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
527
	}
528
}
529