Completed
Push — master ( e8bd72...e35451 )
by Morris
24:35
created

SMB::rename()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 32

Duplication

Lines 14
Ratio 43.75 %

Importance

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