Completed
Push — master ( c4ef8a...3281c7 )
by Robin
259:46 queued 234:25
created

SMB::checkDependencies()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 4
nop 0
dl 0
loc 6
rs 10
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\NotFoundException;
43
use Icewind\SMB\IFileInfo;
44
use Icewind\SMB\Native\NativeServer;
45
use Icewind\SMB\ServerFactory;
46
use Icewind\SMB\System;
47
use Icewind\Streams\CallbackWrapper;
48
use Icewind\Streams\IteratorDirectory;
49
use OC\Cache\CappedMemoryCache;
50
use OC\Files\Filesystem;
51
use OC\Files\Storage\Common;
52
use OCA\Files_External\Lib\Notify\SMBNotifyHandler;
53
use OCP\Files\Notify\IChange;
54
use OCP\Files\Notify\IRenameChange;
55
use OCP\Files\Storage\INotifyStorage;
56
use OCP\Files\StorageNotAvailableException;
57
use OCP\ILogger;
58
59
class SMB extends Common implements INotifyStorage {
60
	/**
61
	 * @var \Icewind\SMB\IServer
62
	 */
63
	protected $server;
64
65
	/**
66
	 * @var \Icewind\SMB\IShare
67
	 */
68
	protected $share;
69
70
	/**
71
	 * @var string
72
	 */
73
	protected $root;
74
75
	/**
76
	 * @var \Icewind\SMB\IFileInfo[]
77
	 */
78
	protected $statCache;
79
80
	public function __construct($params) {
81
		if (!isset($params['host'])) {
82
			throw new \Exception('Invalid configuration, no host provided');
83
		}
84
85
		if (isset($params['auth'])) {
86
			$auth = $params['auth'];
87
		} else if (isset($params['user']) && isset($params['password']) && isset($params['share'])) {
88
			list($workgroup, $user) = $this->splitUser($params['user']);
89
			$auth = new BasicAuth($user, $workgroup, $params['password']);
90
		} else {
91
			throw new \Exception('Invalid configuration, no credentials provided');
92
		}
93
94
		$serverFactory = new ServerFactory();
95
		$this->server = $serverFactory->createServer($params['host'], $auth);
96
		$this->share = $this->server->getShare(trim($params['share'], '/'));
97
98
		$this->root = $params['root'] ?? '/';
99
		$this->root = '/' . ltrim($this->root, '/');
100
		$this->root = rtrim($this->root, '/') . '/';
101
102
		$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...
103
		parent::__construct($params);
104
	}
105
106
	private function splitUser($user) {
107
		if (strpos($user, '/')) {
108
			return explode('/', $user, 2);
109
		} elseif (strpos($user, '\\')) {
110
			return explode('\\', $user);
111
		} else {
112
			return [null, $user];
113
		}
114
	}
115
116
	/**
117
	 * @return string
118
	 */
119
	public function getId() {
120
		// FIXME: double slash to keep compatible with the old storage ids,
121
		// failure to do so will lead to creation of a new storage id and
122
		// loss of shares from the storage
123
		return 'smb::' . $this->server->getAuth()->getUsername() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
124
	}
125
126
	/**
127
	 * @param string $path
128
	 * @return string
129
	 */
130
	protected function buildPath($path) {
131
		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
132
	}
133
134 View Code Duplication
	protected function relativePath($fullPath) {
135
		if ($fullPath === $this->root) {
136
			return '';
137
		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
138
			return substr($fullPath, strlen($this->root));
139
		} else {
140
			return null;
141
		}
142
	}
143
144
	/**
145
	 * @param string $path
146
	 * @return \Icewind\SMB\IFileInfo
147
	 * @throws StorageNotAvailableException
148
	 */
149
	protected function getFileInfo($path) {
150
		try {
151
			$path = $this->buildPath($path);
152
			if (!isset($this->statCache[$path])) {
153
				$this->statCache[$path] = $this->share->stat($path);
154
			}
155
			return $this->statCache[$path];
156
		} 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...
157
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
158
		}
159
	}
160
161
	/**
162
	 * @param string $path
163
	 * @return \Icewind\SMB\IFileInfo[]
164
	 * @throws StorageNotAvailableException
165
	 */
166
	protected function getFolderContents($path) {
167
		try {
168
			$path = $this->buildPath($path);
169
			$files = $this->share->dir($path);
170
			foreach ($files as $file) {
171
				$this->statCache[$path . '/' . $file->getName()] = $file;
172
			}
173
			return array_filter($files, function (IFileInfo $file) {
174
				try {
175
					return !$file->isHidden();
176
				} 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...
177
					return false;
178
				} 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...
179
					return false;
180
				}
181
			});
182
		} 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...
183
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
184
		}
185
	}
186
187
	/**
188
	 * @param \Icewind\SMB\IFileInfo $info
189
	 * @return array
190
	 */
191
	protected function formatInfo($info) {
192
		$result = [
193
			'size' => $info->getSize(),
194
			'mtime' => $info->getMTime(),
195
		];
196
		if ($info->isDirectory()) {
197
			$result['type'] = 'dir';
198
		} else {
199
			$result['type'] = 'file';
200
		}
201
		return $result;
202
	}
203
204
	/**
205
	 * Rename the files. If the source or the target is the root, the rename won't happen.
206
	 *
207
	 * @param string $source the old name of the path
208
	 * @param string $target the new name of the path
209
	 * @return bool true if the rename is successful, false otherwise
210
	 */
211
	public function rename($source, $target) {
212
		if ($this->isRootDir($source) || $this->isRootDir($target)) {
213
			return false;
214
		}
215
216
		$absoluteSource = $this->buildPath($source);
217
		$absoluteTarget = $this->buildPath($target);
218
		try {
219
			$result = $this->share->rename($absoluteSource, $absoluteTarget);
220
		} 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...
221
			$this->remove($target);
222
			$result = $this->share->rename($absoluteSource, $absoluteTarget);
223
		} catch (\Exception $e) {
224
			\OC::$server->getLogger()->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...
225
			return false;
226
		}
227
		unset($this->statCache[$absoluteSource], $this->statCache[$absoluteTarget]);
228
		return $result;
229
	}
230
231
	public function stat($path) {
232
		try {
233
			$result = $this->formatInfo($this->getFileInfo($path));
234
		} 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...
235
			return false;
236
		} 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...
237
			return false;
238
		}
239
		if ($this->remoteIsShare() && $this->isRootDir($path)) {
240
			$result['mtime'] = $this->shareMTime();
241
		}
242
		return $result;
243
	}
244
245
	/**
246
	 * get the best guess for the modification time of the share
247
	 *
248
	 * @return int
249
	 */
250
	private function shareMTime() {
251
		$highestMTime = 0;
252
		$files = $this->share->dir($this->root);
253
		foreach ($files as $fileInfo) {
254
			try {
255
				if ($fileInfo->getMTime() > $highestMTime) {
256
					$highestMTime = $fileInfo->getMTime();
257
				}
258
			} 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...
259
				// Ignore this, can happen on unavailable DFS shares
260
			}
261
		}
262
		return $highestMTime;
263
	}
264
265
	/**
266
	 * Check if the path is our root dir (not the smb one)
267
	 *
268
	 * @param string $path the path
269
	 * @return bool
270
	 */
271
	private function isRootDir($path) {
272
		return $path === '' || $path === '/' || $path === '.';
273
	}
274
275
	/**
276
	 * Check if our root points to a smb share
277
	 *
278
	 * @return bool true if our root points to a share false otherwise
279
	 */
280
	private function remoteIsShare() {
281
		return $this->share->getName() && (!$this->root || $this->root === '/');
282
	}
283
284
	/**
285
	 * @param string $path
286
	 * @return bool
287
	 */
288
	public function unlink($path) {
289
		if ($this->isRootDir($path)) {
290
			return false;
291
		}
292
293
		try {
294
			if ($this->is_dir($path)) {
295
				return $this->rmdir($path);
296
			} else {
297
				$path = $this->buildPath($path);
298
				unset($this->statCache[$path]);
299
				$this->share->del($path);
300
				return true;
301
			}
302
		} 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...
303
			return false;
304
		} 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...
305
			return false;
306
		} 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...
307
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
308
		}
309
	}
310
311
	/**
312
	 * check if a file or folder has been updated since $time
313
	 *
314
	 * @param string $path
315
	 * @param int $time
316
	 * @return bool
317
	 */
318
	public function hasUpdated($path, $time) {
319
		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...
320
			// mtime doesn't work for shares, but giving the nature of the backend,
321
			// doing a full update is still just fast enough
322
			return true;
323
		} else {
324
			$actualTime = $this->filemtime($path);
325
			return $actualTime > $time;
326
		}
327
	}
328
329
	/**
330
	 * @param string $path
331
	 * @param string $mode
332
	 * @return resource|false
333
	 */
334
	public function fopen($path, $mode) {
335
		$fullPath = $this->buildPath($path);
336
		try {
337
			switch ($mode) {
338
				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...
339
				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...
340
					if (!$this->file_exists($path)) {
341
						return false;
342
					}
343
					return $this->share->read($fullPath);
344
				case 'w':
345
				case 'wb':
346
					$source = $this->share->write($fullPath);
347
					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
348
						unset($this->statCache[$fullPath]);
349
					});
350
				case 'a':
351
				case 'ab':
352
				case 'r+':
353
				case 'w+':
354
				case 'wb+':
355
				case 'a+':
356
				case 'x':
357
				case 'x+':
358
				case 'c':
359
				case 'c+':
360
					//emulate these
361
					if (strrpos($path, '.') !== false) {
362
						$ext = substr($path, strrpos($path, '.'));
363
					} else {
364
						$ext = '';
365
					}
366 View Code Duplication
					if ($this->file_exists($path)) {
367
						if (!$this->isUpdatable($path)) {
368
							return false;
369
						}
370
						$tmpFile = $this->getCachedFile($path);
371
					} else {
372
						if (!$this->isCreatable(dirname($path))) {
373
							return false;
374
						}
375
						$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
376
					}
377
					$source = fopen($tmpFile, $mode);
378
					$share = $this->share;
379
					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
380
						unset($this->statCache[$fullPath]);
381
						$share->put($tmpFile, $fullPath);
382
						unlink($tmpFile);
383
					});
384
			}
385
			return false;
386
		} 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...
387
			return false;
388
		} 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...
389
			return false;
390
		} 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...
391
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
392
		}
393
	}
394
395
	public function rmdir($path) {
396
		if ($this->isRootDir($path)) {
397
			return false;
398
		}
399
400
		try {
401
			$this->statCache = array();
402
			$content = $this->share->dir($this->buildPath($path));
403
			foreach ($content as $file) {
404
				if ($file->isDirectory()) {
405
					$this->rmdir($path . '/' . $file->getName());
406
				} else {
407
					$this->share->del($file->getPath());
408
				}
409
			}
410
			$this->share->rmdir($this->buildPath($path));
411
			return true;
412
		} 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...
413
			return false;
414
		} 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...
415
			return false;
416
		} 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...
417
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
418
		}
419
	}
420
421 View Code Duplication
	public function touch($path, $time = null) {
422
		try {
423
			if (!$this->file_exists($path)) {
424
				$fh = $this->share->write($this->buildPath($path));
425
				fclose($fh);
426
				return true;
427
			}
428
			return false;
429
		} 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...
430
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
431
		}
432
	}
433
434
	public function opendir($path) {
435
		try {
436
			$files = $this->getFolderContents($path);
437
		} 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...
438
			return false;
439
		} 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...
440
			return false;
441
		}
442
		$names = array_map(function ($info) {
443
			/** @var \Icewind\SMB\IFileInfo $info */
444
			return $info->getName();
445
		}, $files);
446
		return IteratorDirectory::wrap($names);
447
	}
448
449
	public function filetype($path) {
450
		try {
451
			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
452
		} 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...
453
			return false;
454
		} 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...
455
			return false;
456
		}
457
	}
458
459 View Code Duplication
	public function mkdir($path) {
460
		$path = $this->buildPath($path);
461
		try {
462
			$this->share->mkdir($path);
463
			return true;
464
		} 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...
465
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
466
		} 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...
467
			return false;
468
		}
469
	}
470
471
	public function file_exists($path) {
472
		try {
473
			$this->getFileInfo($path);
474
			return true;
475
		} 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...
476
			return false;
477
		} 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...
478
			return false;
479
		} 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...
480
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
481
		}
482
	}
483
484 View Code Duplication
	public function isReadable($path) {
485
		try {
486
			$info = $this->getFileInfo($path);
487
			return !$info->isHidden();
488
		} 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...
489
			return false;
490
		} 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...
491
			return false;
492
		}
493
	}
494
495 View Code Duplication
	public function isUpdatable($path) {
496
		try {
497
			$info = $this->getFileInfo($path);
498
			// following windows behaviour for read-only folders: they can be written into
499
			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
500
			return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
501
		} 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...
502
			return false;
503
		} 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...
504
			return false;
505
		}
506
	}
507
508 View Code Duplication
	public function isDeletable($path) {
509
		try {
510
			$info = $this->getFileInfo($path);
511
			return !$info->isHidden() && !$info->isReadOnly();
512
		} 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...
513
			return false;
514
		} 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...
515
			return false;
516
		}
517
	}
518
519
	/**
520
	 * check if smbclient is installed
521
	 */
522
	public static function checkDependencies() {
523
		return (
524
			(bool)\OC_Helper::findBinaryPath('smbclient')
525
			|| NativeServer::available(new System())
526
		) ? true : ['smbclient'];
527
	}
528
529
	/**
530
	 * Test a storage for availability
531
	 *
532
	 * @return bool
533
	 */
534
	public function test() {
535
		try {
536
			return parent::test();
537
		} 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...
538
			return false;
539
		}
540
	}
541
542
	public function listen($path, callable $callback) {
543
		$this->notify($path)->listen(function (IChange $change) use ($callback) {
544
			if ($change instanceof IRenameChange) {
545
				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
546
			} else {
547
				return $callback($change->getType(), $change->getPath());
548
			}
549
		});
550
	}
551
552
	public function notify($path) {
553
		$path = '/' . ltrim($path, '/');
554
		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
555
		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
556
	}
557
}
558