Completed
Push — stable13 ( dc0fd5...263953 )
by Roeland
23:29
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\Exception\AlreadyExistsException;
38
use Icewind\SMB\Exception\ConnectException;
39
use Icewind\SMB\Exception\Exception;
40
use Icewind\SMB\Exception\ForbiddenException;
41
use Icewind\SMB\Exception\InvalidArgumentException;
42
use Icewind\SMB\Exception\NotFoundException;
43
use Icewind\SMB\IFileInfo;
44
use Icewind\SMB\NativeServer;
45
use Icewind\SMB\Server;
46
use Icewind\Streams\CallbackWrapper;
47
use Icewind\Streams\IteratorDirectory;
48
use OC\Cache\CappedMemoryCache;
49
use OC\Files\Filesystem;
50
use OC\Files\Storage\Common;
51
use OCA\Files_External\Lib\Notify\SMBNotifyHandler;
52
use OCP\Files\Notify\IChange;
53
use OCP\Files\Notify\IRenameChange;
54
use OCP\Files\Storage\INotifyStorage;
55
use OCP\Files\StorageNotAvailableException;
56
use OCP\ILogger;
57
use OCP\Util;
58
59
class SMB extends Common implements INotifyStorage {
60
	/**
61
	 * @var \Icewind\SMB\Server
62
	 */
63
	protected $server;
64
65
	/**
66
	 * @var \Icewind\SMB\Share
67
	 */
68
	protected $share;
69
70
	/**
71
	 * @var string
72
	 */
73
	protected $root;
74
75
	/**
76
	 * @var \Icewind\SMB\FileInfo[]
77
	 */
78
	protected $statCache;
79
80
	public function __construct($params) {
81
		if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
82
			if (Server::NativeAvailable()) {
83
				$this->server = new NativeServer($params['host'], $params['user'], $params['password']);
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Icewind\SMB\NativeS...], $params['password']) of type object<Icewind\SMB\NativeServer> is incompatible with the declared type object<Icewind\SMB\Server> of property $server.

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

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

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

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

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

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

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

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

Loading history...
144
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while getting file info']);
145
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
146
		}
147
	}
148
149
	/**
150
	 * @param string $path
151
	 * @return \Icewind\SMB\IFileInfo[]
152
	 * @throws StorageNotAvailableException
153
	 */
154
	protected function getFolderContents($path) {
155
		try {
156
			$path = $this->buildPath($path);
157
			$files = $this->share->dir($path);
158
			foreach ($files as $file) {
159
				$this->statCache[$path . '/' . $file->getName()] = $file;
160
			}
161
			return array_filter($files, function (IFileInfo $file) {
162
				try {
163
					return !$file->isHidden();
164
				} 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...
165
					return false;
166
				} 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...
167
					return false;
168
				}
169
			});
170
		} 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...
171
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while getting folder content']);
172
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
173
		}
174
	}
175
176
	/**
177
	 * @param \Icewind\SMB\IFileInfo $info
178
	 * @return array
179
	 */
180
	protected function formatInfo($info) {
181
		$result = [
182
			'size' => $info->getSize(),
183
			'mtime' => $info->getMTime(),
184
		];
185
		if ($info->isDirectory()) {
186
			$result['type'] = 'dir';
187
		} else {
188
			$result['type'] = 'file';
189
		}
190
		return $result;
191
	}
192
193
	/**
194
	 * Rename the files. If the source or the target is the root, the rename won't happen.
195
	 *
196
	 * @param string $source the old name of the path
197
	 * @param string $target the new name of the path
198
	 * @return bool true if the rename is successful, false otherwise
199
	 */
200
	public function rename($source, $target, $retry = true) {
201
		if ($this->isRootDir($source) || $this->isRootDir($target)) {
202
			return false;
203
		}
204
205
		$absoluteSource = $this->buildPath($source);
206
		$absoluteTarget = $this->buildPath($target);
207
		try {
208
			$result = $this->share->rename($absoluteSource, $absoluteTarget);
209
		} 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...
210 View Code Duplication
			if ($retry) {
211
				$this->remove($target);
212
				$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
213
			} else {
214
				\OC::$server->getLogger()->logException($e, ['level' => ILogger::WARN]);
215
				return false;
216
			}
217
		} 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...
218 View Code Duplication
			if ($retry) {
219
				$this->remove($target);
220
				$result = $this->share->rename($absoluteSource, $absoluteTarget, false);
221
			} else {
222
				\OC::$server->getLogger()->logException($e, ['level' => ILogger::WARN]);
223
				return false;
224
			}
225
		} catch (\Exception $e) {
226
			\OC::$server->getLogger()->logException($e, ['level' => Util::WARN]);
227
			return false;
228
		}
229
		unset($this->statCache[$absoluteSource], $this->statCache[$absoluteTarget]);
230
		return $result;
231
	}
232
233
	public function stat($path) {
234
		try {
235
			$result = $this->formatInfo($this->getFileInfo($path));
236
		} 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...
237
			return false;
238
		} 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...
239
			return false;
240
		}
241
		if ($this->remoteIsShare() && $this->isRootDir($path)) {
242
			$result['mtime'] = $this->shareMTime();
243
		}
244
		return $result;
245
	}
246
247
	/**
248
	 * get the best guess for the modification time of the share
249
	 *
250
	 * @return int
251
	 */
252
	private function shareMTime() {
253
		$highestMTime = 0;
254
		$files = $this->share->dir($this->root);
255
		foreach ($files as $fileInfo) {
256
			try {
257
				if ($fileInfo->getMTime() > $highestMTime) {
258
					$highestMTime = $fileInfo->getMTime();
259
				}
260
			} 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...
261
				// Ignore this, can happen on unavailable DFS shares
262
			}
263
		}
264
		return $highestMTime;
265
	}
266
267
	/**
268
	 * Check if the path is our root dir (not the smb one)
269
	 *
270
	 * @param string $path the path
271
	 * @return bool
272
	 */
273
	private function isRootDir($path) {
274
		return $path === '' || $path === '/' || $path === '.';
275
	}
276
277
	/**
278
	 * Check if our root points to a smb share
279
	 *
280
	 * @return bool true if our root points to a share false otherwise
281
	 */
282
	private function remoteIsShare() {
283
		return $this->share->getName() && (!$this->root || $this->root === '/');
284
	}
285
286
	/**
287
	 * @param string $path
288
	 * @return bool
289
	 */
290
	public function unlink($path) {
291
		if ($this->isRootDir($path)) {
292
			return false;
293
		}
294
295
		try {
296
			if ($this->is_dir($path)) {
297
				return $this->rmdir($path);
298
			} else {
299
				$path = $this->buildPath($path);
300
				unset($this->statCache[$path]);
301
				$this->share->del($path);
302
				return true;
303
			}
304
		} 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...
305
			return false;
306
		} 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...
307
			return false;
308
		} 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...
309
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while deleting file']);
310
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
311
		}
312
	}
313
314
	/**
315
	 * check if a file or folder has been updated since $time
316
	 *
317
	 * @param string $path
318
	 * @param int $time
319
	 * @return bool
320
	 */
321
	public function hasUpdated($path, $time) {
322
		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...
323
			// mtime doesn't work for shares, but giving the nature of the backend,
324
			// doing a full update is still just fast enough
325
			return true;
326
		} else {
327
			$actualTime = $this->filemtime($path);
328
			return $actualTime > $time;
329
		}
330
	}
331
332
	/**
333
	 * @param string $path
334
	 * @param string $mode
335
	 * @return resource|false
336
	 */
337
	public function fopen($path, $mode) {
338
		$fullPath = $this->buildPath($path);
339
		try {
340
			switch ($mode) {
341
				case 'r':
342
				case 'rb':
343
					if (!$this->file_exists($path)) {
344
						return false;
345
					}
346
					return $this->share->read($fullPath);
347
				case 'w':
348
				case 'wb':
349
					$source = $this->share->write($fullPath);
350
					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
351
						unset($this->statCache[$fullPath]);
352
					});
353
				case 'a':
354
				case 'ab':
355
				case 'r+':
356
				case 'w+':
357
				case 'wb+':
358
				case 'a+':
359
				case 'x':
360
				case 'x+':
361
				case 'c':
362
				case 'c+':
363
					//emulate these
364
					if (strrpos($path, '.') !== false) {
365
						$ext = substr($path, strrpos($path, '.'));
366
					} else {
367
						$ext = '';
368
					}
369 View Code Duplication
					if ($this->file_exists($path)) {
370
						if (!$this->isUpdatable($path)) {
371
							return false;
372
						}
373
						$tmpFile = $this->getCachedFile($path);
374
					} else {
375
						if (!$this->isCreatable(dirname($path))) {
376
							return false;
377
						}
378
						$tmpFile = \OCP\Files::tmpFile($ext);
379
					}
380
					$source = fopen($tmpFile, $mode);
381
					$share = $this->share;
382
					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
383
						unset($this->statCache[$fullPath]);
384
						$share->put($tmpFile, $fullPath);
385
						unlink($tmpFile);
386
					});
387
			}
388
			return false;
389
		} 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...
390
			return false;
391
		} 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...
392
			return false;
393
		} 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...
394
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while opening file']);
395
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
396
		}
397
	}
398
399
	public function rmdir($path) {
400
		if ($this->isRootDir($path)) {
401
			return false;
402
		}
403
404
		try {
405
			$this->statCache = array();
406
			$content = $this->share->dir($this->buildPath($path));
407
			foreach ($content as $file) {
408
				if ($file->isDirectory()) {
409
					$this->rmdir($path . '/' . $file->getName());
410
				} else {
411
					$this->share->del($file->getPath());
412
				}
413
			}
414
			$this->share->rmdir($this->buildPath($path));
415
			return true;
416
		} 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...
417
			return false;
418
		} 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...
419
			return false;
420
		} 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...
421
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while removing folder']);
422
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
423
		}
424
	}
425
426 View Code Duplication
	public function touch($path, $time = null) {
427
		try {
428
			if (!$this->file_exists($path)) {
429
				$fh = $this->share->write($this->buildPath($path));
430
				fclose($fh);
431
				return true;
432
			}
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 creating file']);
436
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
437
		}
438
	}
439
440
	public function opendir($path) {
441
		try {
442
			$files = $this->getFolderContents($path);
443
		} 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...
444
			return false;
445
		} 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...
446
			return false;
447
		}
448
		$names = array_map(function ($info) {
449
			/** @var \Icewind\SMB\IFileInfo $info */
450
			return $info->getName();
451
		}, $files);
452
		return IteratorDirectory::wrap($names);
453
	}
454
455
	public function filetype($path) {
456
		try {
457
			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
458
		} 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...
459
			return false;
460
		} 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...
461
			return false;
462
		}
463
	}
464
465 View Code Duplication
	public function mkdir($path) {
466
		$path = $this->buildPath($path);
467
		try {
468
			$this->share->mkdir($path);
469
			return true;
470
		} 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...
471
			\OC::$server->getLogger()->logException($e, ['message' => 'Error while creating folder']);
472
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
473
		} 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...
474
			return false;
475
		}
476
	}
477
478
	public function file_exists($path) {
479
		try {
480
			$this->getFileInfo($path);
481
			return true;
482
		} 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...
483
			return false;
484
		} 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...
485
			return false;
486
		} 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...
487
			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
488
		}
489
	}
490
491 View Code Duplication
	public function isReadable($path) {
492
		try {
493
			$info = $this->getFileInfo($path);
494
			return !$info->isHidden();
495
		} 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...
496
			return false;
497
		} 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...
498
			return false;
499
		}
500
	}
501
502 View Code Duplication
	public function isUpdatable($path) {
503
		try {
504
			$info = $this->getFileInfo($path);
505
			// following windows behaviour for read-only folders: they can be written into
506
			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
507
			return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
508
		} 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...
509
			return false;
510
		} 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...
511
			return false;
512
		}
513
	}
514
515 View Code Duplication
	public function isDeletable($path) {
516
		try {
517
			$info = $this->getFileInfo($path);
518
			return !$info->isHidden() && !$info->isReadOnly();
519
		} 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...
520
			return false;
521
		} 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...
522
			return false;
523
		}
524
	}
525
526
	/**
527
	 * check if smbclient is installed
528
	 */
529
	public static function checkDependencies() {
530
		return (
531
			(bool)\OC_Helper::findBinaryPath('smbclient')
532
			|| Server::NativeAvailable()
533
		) ? true : ['smbclient'];
534
	}
535
536
	/**
537
	 * Test a storage for availability
538
	 *
539
	 * @return bool
540
	 */
541
	public function test() {
542
		try {
543
			return parent::test();
544
		} 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...
545
			\OC::$server->getLogger()->logException($e);
546
			return false;
547
		}
548
	}
549
550
	public function listen($path, callable $callback) {
551
		$this->notify($path)->listen(function (IChange $change) use ($callback) {
552
			if ($change instanceof IRenameChange) {
553
				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
554
			} else {
555
				return $callback($change->getType(), $change->getPath());
556
			}
557
		});
558
	}
559
560
	public function notify($path) {
561
		$path = '/' . ltrim($path, '/');
562
		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
563
		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
564
	}
565
}
566