Completed
Push — master ( d1daf6...8563ab )
by Morris
33:31 queued 17:44
created

SMB::getFileInfo()   A

Complexity

Conditions 3
Paths 6

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 6
nop 1
dl 0
loc 12
rs 9.8666
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\BasicAuth;
38
use Icewind\SMB\Exception\AlreadyExistsException;
39
use Icewind\SMB\Exception\ConnectException;
40
use Icewind\SMB\Exception\Exception;
41
use Icewind\SMB\Exception\ForbiddenException;
42
use Icewind\SMB\Exception\InvalidArgumentException;
43
use Icewind\SMB\Exception\NotFoundException;
44
use Icewind\SMB\Exception\TimedOutException;
45
use Icewind\SMB\IFileInfo;
46
use Icewind\SMB\Native\NativeServer;
47
use Icewind\SMB\ServerFactory;
48
use Icewind\SMB\System;
49
use Icewind\Streams\CallbackWrapper;
50
use Icewind\Streams\IteratorDirectory;
51
use OC\Cache\CappedMemoryCache;
52
use OC\Files\Filesystem;
53
use OC\Files\Storage\Common;
54
use OCA\Files_External\Lib\Notify\SMBNotifyHandler;
55
use OCP\Files\Notify\IChange;
56
use OCP\Files\Notify\IRenameChange;
57
use OCP\Files\Storage\INotifyStorage;
58
use OCP\Files\StorageNotAvailableException;
59
use OCP\ILogger;
60
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
	public function __construct($params) {
86
		if (!isset($params['host'])) {
87
			throw new \Exception('Invalid configuration, no host provided');
88
		}
89
90
		if (isset($params['auth'])) {
91
			$auth = $params['auth'];
92
		} else if (isset($params['user']) && isset($params['password']) && isset($params['share'])) {
93
			list($workgroup, $user) = $this->splitUser($params['user']);
94
			$auth = new BasicAuth($user, $workgroup, $params['password']);
95
		} else {
96
			throw new \Exception('Invalid configuration, no credentials provided');
97
		}
98
99
		if (isset($params['logger'])) {
100
			$this->logger = $params['logger'];
101
		} else {
102
			$this->logger = \OC::$server->getLogger();
103
		}
104
105
		$serverFactory = new ServerFactory();
106
		$this->server = $serverFactory->createServer($params['host'], $auth);
107
		$this->share = $this->server->getShare(trim($params['share'], '/'));
108
109
		$this->root = $params['root'] ?? '/';
110
		$this->root = '/' . ltrim($this->root, '/');
111
		$this->root = rtrim($this->root, '/') . '/';
112
113
		$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\IFileInfo>> 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...
114
		parent::__construct($params);
115
	}
116
117
	private function splitUser($user) {
118
		if (strpos($user, '/')) {
119
			return explode('/', $user, 2);
120
		} elseif (strpos($user, '\\')) {
121
			return explode('\\', $user);
122
		} else {
123
			return [null, $user];
124
		}
125
	}
126
127
	/**
128
	 * @return string
129
	 */
130
	public function getId() {
131
		// FIXME: double slash to keep compatible with the old storage ids,
132
		// failure to do so will lead to creation of a new storage id and
133
		// loss of shares from the storage
134
		return 'smb::' . $this->server->getAuth()->getUsername() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
135
	}
136
137
	/**
138
	 * @param string $path
139
	 * @return string
140
	 */
141
	protected function buildPath($path) {
142
		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
143
	}
144
145 View Code Duplication
	protected function relativePath($fullPath) {
146
		if ($fullPath === $this->root) {
147
			return '';
148
		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
149
			return substr($fullPath, strlen($this->root));
150
		} else {
151
			return null;
152
		}
153
	}
154
155
	/**
156
	 * @param string $path
157
	 * @return \Icewind\SMB\IFileInfo
158
	 * @throws StorageNotAvailableException
159
	 */
160
	protected function getFileInfo($path) {
161
		try {
162
			$path = $this->buildPath($path);
163
			if (!isset($this->statCache[$path])) {
164
				$this->statCache[$path] = $this->share->stat($path);
165
			}
166
			return $this->statCache[$path];
167
		} 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...
168
			$this->logger->logException($e, ['message' => 'Error while getting file info']);
169
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
170
		}
171
	}
172
173
	/**
174
	 * @param string $path
175
	 * @return \Icewind\SMB\IFileInfo[]
176
	 * @throws StorageNotAvailableException
177
	 */
178
	protected function getFolderContents($path) {
179
		try {
180
			$path = $this->buildPath($path);
181
			$files = $this->share->dir($path);
182
			foreach ($files as $file) {
183
				$this->statCache[$path . '/' . $file->getName()] = $file;
184
			}
185
			return array_filter($files, function (IFileInfo $file) {
186
				try {
187
					if ($file->isHidden()) {
188
						$this->logger->debug('hiding hidden file ' . $file->getName());
189
					}
190
					return !$file->isHidden();
191
				} 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...
192
					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding forbidden entry ' . $file->getName()]);
193
					return false;
194
				} 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...
195
					$this->logger->logException($e, ['level' => ILogger::DEBUG, 'message' => 'Hiding not found entry ' . $file->getName()]);
196
					return false;
197
				}
198
			});
199
		} 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...
200
			$this->logger->logException($e, ['message' => 'Error while getting folder content']);
201
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
202
		}
203
	}
204
205
	/**
206
	 * @param \Icewind\SMB\IFileInfo $info
207
	 * @return array
208
	 */
209
	protected function formatInfo($info) {
210
		$result = [
211
			'size' => $info->getSize(),
212
			'mtime' => $info->getMTime(),
213
		];
214
		if ($info->isDirectory()) {
215
			$result['type'] = 'dir';
216
		} else {
217
			$result['type'] = 'file';
218
		}
219
		return $result;
220
	}
221
222
	/**
223
	 * Rename the files. If the source or the target is the root, the rename won't happen.
224
	 *
225
	 * @param string $source the old name of the path
226
	 * @param string $target the new name of the path
227
	 * @return bool true if the rename is successful, false otherwise
228
	 */
229
	public function rename($source, $target, $retry = true) {
230
		if ($this->isRootDir($source) || $this->isRootDir($target)) {
231
			return false;
232
		}
233
234
		$absoluteSource = $this->buildPath($source);
235
		$absoluteTarget = $this->buildPath($target);
236
		try {
237
			$result = $this->share->rename($absoluteSource, $absoluteTarget);
238
		} 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...
239 View Code Duplication
			if ($retry) {
240
				$this->remove($target);
241
				$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
242
			} else {
243
				$this->logger->logException($e, ['level' => ILogger::WARN]);
244
				return false;
245
			}
246
		} 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...
247 View Code Duplication
			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 (\Exception $e) {
255
			$this->logger->logException($e, ['level' => ILogger::WARN]);
0 ignored issues
show
Documentation introduced by
$e is of type object<Exception>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
256
			return false;
257
		}
258
		unset($this->statCache[$absoluteSource], $this->statCache[$absoluteTarget]);
259
		return $result;
260
	}
261
262
	public function stat($path, $retry = true) {
263
		try {
264
			$result = $this->formatInfo($this->getFileInfo($path));
265
		} 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...
266
			return false;
267
		} 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...
268
			return false;
269
		} catch (TimedOutException $e) {
0 ignored issues
show
Bug introduced by
The class Icewind\SMB\Exception\TimedOutException 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...
270
			if ($retry) {
271
				return $this->stat($path, false);
272
			} else {
273
				throw $e;
274
			}
275
		}
276
		if ($this->remoteIsShare() && $this->isRootDir($path)) {
277
			$result['mtime'] = $this->shareMTime();
278
		}
279
		return $result;
280
	}
281
282
	/**
283
	 * get the best guess for the modification time of the share
284
	 *
285
	 * @return int
286
	 */
287
	private function shareMTime() {
288
		$highestMTime = 0;
289
		$files = $this->share->dir($this->root);
290
		foreach ($files as $fileInfo) {
291
			try {
292
				if ($fileInfo->getMTime() > $highestMTime) {
293
					$highestMTime = $fileInfo->getMTime();
294
				}
295
			} 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...
296
				// Ignore this, can happen on unavailable DFS shares
297
			}
298
		}
299
		return $highestMTime;
300
	}
301
302
	/**
303
	 * Check if the path is our root dir (not the smb one)
304
	 *
305
	 * @param string $path the path
306
	 * @return bool
307
	 */
308
	private function isRootDir($path) {
309
		return $path === '' || $path === '/' || $path === '.';
310
	}
311
312
	/**
313
	 * Check if our root points to a smb share
314
	 *
315
	 * @return bool true if our root points to a share false otherwise
316
	 */
317
	private function remoteIsShare() {
318
		return $this->share->getName() && (!$this->root || $this->root === '/');
319
	}
320
321
	/**
322
	 * @param string $path
323
	 * @return bool
324
	 */
325
	public function unlink($path) {
326
		if ($this->isRootDir($path)) {
327
			return false;
328
		}
329
330
		try {
331
			if ($this->is_dir($path)) {
332
				return $this->rmdir($path);
333
			} else {
334
				$path = $this->buildPath($path);
335
				unset($this->statCache[$path]);
336
				$this->share->del($path);
337
				return true;
338
			}
339
		} 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...
340
			return false;
341
		} 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...
342
			return false;
343
		} 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...
344
			$this->logger->logException($e, ['message' => 'Error while deleting file']);
345
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
346
		}
347
	}
348
349
	/**
350
	 * check if a file or folder has been updated since $time
351
	 *
352
	 * @param string $path
353
	 * @param int $time
354
	 * @return bool
355
	 */
356
	public function hasUpdated($path, $time) {
357
		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...
358
			// mtime doesn't work for shares, but giving the nature of the backend,
359
			// doing a full update is still just fast enough
360
			return true;
361
		} else {
362
			$actualTime = $this->filemtime($path);
363
			return $actualTime > $time;
364
		}
365
	}
366
367
	/**
368
	 * @param string $path
369
	 * @param string $mode
370
	 * @return resource|false
371
	 */
372
	public function fopen($path, $mode) {
373
		$fullPath = $this->buildPath($path);
374
		try {
375
			switch ($mode) {
376
				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...
377
				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...
378
					if (!$this->file_exists($path)) {
379
						return false;
380
					}
381
					return $this->share->read($fullPath);
382
				case 'w':
383
				case 'wb':
384
					$source = $this->share->write($fullPath);
385
					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
386
						unset($this->statCache[$fullPath]);
387
					});
388
				case 'a':
389
				case 'ab':
390
				case 'r+':
391
				case 'w+':
392
				case 'wb+':
393
				case 'a+':
394
				case 'x':
395
				case 'x+':
396
				case 'c':
397
				case 'c+':
398
					//emulate these
399
					if (strrpos($path, '.') !== false) {
400
						$ext = substr($path, strrpos($path, '.'));
401
					} else {
402
						$ext = '';
403
					}
404 View Code Duplication
					if ($this->file_exists($path)) {
405
						if (!$this->isUpdatable($path)) {
406
							return false;
407
						}
408
						$tmpFile = $this->getCachedFile($path);
409
					} else {
410
						if (!$this->isCreatable(dirname($path))) {
411
							return false;
412
						}
413
						$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
414
					}
415
					$source = fopen($tmpFile, $mode);
416
					$share = $this->share;
417
					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
418
						unset($this->statCache[$fullPath]);
419
						$share->put($tmpFile, $fullPath);
420
						unlink($tmpFile);
421
					});
422
			}
423
			return false;
424
		} 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...
425
			return false;
426
		} 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...
427
			return false;
428
		} 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...
429
			$this->logger->logException($e, ['message' => 'Error while opening file']);
430
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
431
		}
432
	}
433
434
	public function rmdir($path) {
435
		if ($this->isRootDir($path)) {
436
			return false;
437
		}
438
439
		try {
440
			$this->statCache = array();
441
			$content = $this->share->dir($this->buildPath($path));
442
			foreach ($content as $file) {
443
				if ($file->isDirectory()) {
444
					$this->rmdir($path . '/' . $file->getName());
445
				} else {
446
					$this->share->del($file->getPath());
447
				}
448
			}
449
			$this->share->rmdir($this->buildPath($path));
450
			return true;
451
		} 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...
452
			return false;
453
		} 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...
454
			return false;
455
		} 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...
456
			$this->logger->logException($e, ['message' => 'Error while removing folder']);
457
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
458
		}
459
	}
460
461 View Code Duplication
	public function touch($path, $time = null) {
462
		try {
463
			if (!$this->file_exists($path)) {
464
				$fh = $this->share->write($this->buildPath($path));
465
				fclose($fh);
466
				return true;
467
			}
468
			return false;
469
		} 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...
470
			$this->logger->logException($e, ['message' => 'Error while creating file']);
471
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
472
		}
473
	}
474
475
	public function opendir($path) {
476
		try {
477
			$files = $this->getFolderContents($path);
478
		} 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...
479
			return false;
480
		} 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...
481
			return false;
482
		}
483
		$names = array_map(function ($info) {
484
			/** @var \Icewind\SMB\IFileInfo $info */
485
			return $info->getName();
486
		}, $files);
487
		return IteratorDirectory::wrap($names);
488
	}
489
490
	public function filetype($path) {
491
		try {
492
			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
493
		} 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...
494
			return false;
495
		} 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...
496
			return false;
497
		}
498
	}
499
500 View Code Duplication
	public function mkdir($path) {
501
		$path = $this->buildPath($path);
502
		try {
503
			$this->share->mkdir($path);
504
			return true;
505
		} 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...
506
			$this->logger->logException($e, ['message' => 'Error while creating folder']);
507
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
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 file_exists($path) {
514
		try {
515
			$this->getFileInfo($path);
516
			return true;
517
		} 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...
518
			return false;
519
		} 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...
520
			return false;
521
		} 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...
522
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
523
		}
524
	}
525
526 View Code Duplication
	public function isReadable($path) {
527
		try {
528
			$info = $this->getFileInfo($path);
529
			return !$info->isHidden();
530
		} 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...
531
			return false;
532
		} 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...
533
			return false;
534
		}
535
	}
536
537 View Code Duplication
	public function isUpdatable($path) {
538
		try {
539
			$info = $this->getFileInfo($path);
540
			// following windows behaviour for read-only folders: they can be written into
541
			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
542
			return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
543
		} 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...
544
			return false;
545
		} 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...
546
			return false;
547
		}
548
	}
549
550 View Code Duplication
	public function isDeletable($path) {
551
		try {
552
			$info = $this->getFileInfo($path);
553
			return !$info->isHidden() && !$info->isReadOnly();
554
		} 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...
555
			return false;
556
		} 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...
557
			return false;
558
		}
559
	}
560
561
	/**
562
	 * check if smbclient is installed
563
	 */
564
	public static function checkDependencies() {
565
		return (
566
			(bool)\OC_Helper::findBinaryPath('smbclient')
567
			|| NativeServer::available(new System())
568
		) ? true : ['smbclient'];
569
	}
570
571
	/**
572
	 * Test a storage for availability
573
	 *
574
	 * @return bool
575
	 */
576
	public function test() {
577
		try {
578
			return parent::test();
579
		} 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...
580
			$this->logger->logException($e);
581
			return false;
582
		}
583
	}
584
585
	public function listen($path, callable $callback) {
586
		$this->notify($path)->listen(function (IChange $change) use ($callback) {
587
			if ($change instanceof IRenameChange) {
588
				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
589
			} else {
590
				return $callback($change->getType(), $change->getPath());
591
			}
592
		});
593
	}
594
595
	public function notify($path) {
596
		$path = '/' . ltrim($path, '/');
597
		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
598
		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
599
	}
600
}
601