Completed
Pull Request — stable8.2 (#23481)
by Robin
12:39
created

SMB::hasUpdated()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 10
rs 9.4285
cc 3
eloc 6
nc 2
nop 2
1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Jörn Friedrich Dreyer <[email protected]>
5
 * @author Michael Gapczynski <[email protected]>
6
 * @author Morris Jobke <[email protected]>
7
 * @author Philipp Kapfer <[email protected]>
8
 * @author Robin Appelman <[email protected]>
9
 * @author Robin McCorkell <[email protected]>
10
 * @author Thomas Müller <[email protected]>
11
 * @author Vincent Petry <[email protected]>
12
 *
13
 * @copyright Copyright (c) 2015, ownCloud, Inc.
14
 * @license AGPL-3.0
15
 *
16
 * This code is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License, version 3,
18
 * as published by the Free Software Foundation.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License, version 3,
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
27
 *
28
 */
29
30
namespace OC\Files\Storage;
31
32
use Icewind\SMB\Exception\Exception;
33
use Icewind\SMB\Exception\ForbiddenException;
34
use Icewind\SMB\Exception\NotFoundException;
35
use Icewind\SMB\NativeServer;
36
use Icewind\SMB\Server;
37
use Icewind\Streams\CallbackWrapper;
38
use Icewind\Streams\IteratorDirectory;
39
use OC\Cache\CappedMemoryCache;
40
use OC\Files\Filesystem;
41
42
class SMB extends Common {
43
	/**
44
	 * @var \Icewind\SMB\Server
45
	 */
46
	protected $server;
47
48
	/**
49
	 * @var \Icewind\SMB\Share
50
	 */
51
	protected $share;
52
53
	/**
54
	 * @var string
55
	 */
56
	protected $root;
57
58
	/**
59
	 * @var \Icewind\SMB\FileInfo[]
60
	 */
61
	protected $statCache;
62
63
	public function __construct($params) {
64
		if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
65
			if (Server::NativeAvailable()) {
66
				$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...
67
			} else {
68
				$this->server = new Server($params['host'], $params['user'], $params['password']);
69
			}
70
			$this->share = $this->server->getShare(trim($params['share'], '/'));
71
72
			$this->root = isset($params['root']) ? $params['root'] : '/';
73 View Code Duplication
			if (!$this->root || $this->root[0] != '/') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
74
				$this->root = '/' . $this->root;
75
			}
76
			if (substr($this->root, -1, 1) != '/') {
77
				$this->root .= '/';
78
			}
79
		} else {
80
			throw new \Exception('Invalid configuration');
81
		}
82
		$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...
83
	}
84
85
	/**
86
	 * @return string
87
	 */
88
	public function getId() {
89
		// FIXME: double slash to keep compatible with the old storage ids,
90
		// failure to do so will lead to creation of a new storage id and
91
		// loss of shares from the storage
92
		return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
93
	}
94
95
	/**
96
	 * @param string $path
97
	 * @return string
98
	 */
99
	protected function buildPath($path) {
100
		return Filesystem::normalizePath($this->root . '/' . $path);
101
	}
102
103
	/**
104
	 * @param string $path
105
	 * @return \Icewind\SMB\IFileInfo
106
	 */
107
	protected function getFileInfo($path) {
108
		$path = $this->buildPath($path);
109
		if (!isset($this->statCache[$path])) {
110
			$this->statCache[$path] = $this->share->stat($path);
111
		}
112
		return $this->statCache[$path];
113
	}
114
115
	/**
116
	 * @param string $path
117
	 * @return \Icewind\SMB\IFileInfo[]
118
	 */
119
	protected function getFolderContents($path) {
120
		$path = $this->buildPath($path);
121
		$files = $this->share->dir($path);
122
		foreach ($files as $file) {
123
			$this->statCache[$path . '/' . $file->getName()] = $file;
124
		}
125
		return $files;
126
	}
127
128
	/**
129
	 * @param \Icewind\SMB\IFileInfo $info
130
	 * @return array
131
	 */
132
	protected function formatInfo($info) {
133
		return array(
134
			'size' => $info->getSize(),
135
			'mtime' => $info->getMTime()
136
		);
137
	}
138
139
	/**
140
	 * @param string $path
141
	 * @return array
142
	 */
143
	public function stat($path) {
144
		return $this->formatInfo($this->getFileInfo($path));
145
	}
146
147
	/**
148
	 * @param string $path
149
	 * @return bool
150
	 */
151
	public function unlink($path) {
152
		try {
153
			if ($this->is_dir($path)) {
154
				return $this->rmdir($path);
155
			} else {
156
				$path = $this->buildPath($path);
157
				unset($this->statCache[$path]);
158
				$this->share->del($path);
159
				return true;
160
			}
161
		} catch (NotFoundException $e) {
1 ignored issue
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...
162
			return false;
163
		} catch (ForbiddenException $e) {
1 ignored issue
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...
164
			return false;
165
		}
166
	}
167
168
	/**
169
	 * check if a file or folder has been updated since $time
170
	 *
171
	 * @param string $path
172
	 * @param int $time
173
	 * @return bool
174
	 */
175
	public function hasUpdated($path, $time) {
176
		if (!$path and $this->root == '/') {
177
			// mtime doesn't work for shares, but giving the nature of the backend,
178
			// doing a full update is still just fast enough
179
			return true;
180
		} else {
181
			$actualTime = $this->filemtime($path);
182
			return $actualTime > $time;
183
		}
184
	}
185
186
	/**
187
	 * @param string $path
188
	 * @param string $mode
189
	 * @return resource
190
	 */
191
	public function fopen($path, $mode) {
192
		$fullPath = $this->buildPath($path);
193
		try {
194
			switch ($mode) {
195
				case 'r':
196
				case 'rb':
197
					if (!$this->file_exists($path)) {
198
						return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OC\Files\Storage\SMB::fopen of type resource.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
199
					}
200
					return $this->share->read($fullPath);
201
				case 'w':
202
				case 'wb':
203
					return $this->share->write($fullPath);
204
				case 'a':
205
				case 'ab':
206
				case 'r+':
207
				case 'w+':
208
				case 'wb+':
209
				case 'a+':
210
				case 'x':
211
				case 'x+':
212
				case 'c':
213
				case 'c+':
214
					//emulate these
215
					if (strrpos($path, '.') !== false) {
216
						$ext = substr($path, strrpos($path, '.'));
217
					} else {
218
						$ext = '';
219
					}
220 View Code Duplication
					if ($this->file_exists($path)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221
						if (!$this->isUpdatable($path)) {
222
							return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OC\Files\Storage\SMB::fopen of type resource.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
223
						}
224
						$tmpFile = $this->getCachedFile($path);
225
					} else {
226
						if (!$this->isCreatable(dirname($path))) {
227
							return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OC\Files\Storage\SMB::fopen of type resource.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
228
						}
229
						$tmpFile = \OCP\Files::tmpFile($ext);
230
					}
231
					$source = fopen($tmpFile, $mode);
232
					$share = $this->share;
233
					return CallBackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
234
						$share->put($tmpFile, $fullPath);
235
						unlink($tmpFile);
236
					});
237
			}
238
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OC\Files\Storage\SMB::fopen of type resource.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
239
		} catch (NotFoundException $e) {
1 ignored issue
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...
240
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OC\Files\Storage\SMB::fopen of type resource.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
241
		} catch (ForbiddenException $e) {
1 ignored issue
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...
242
			return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OC\Files\Storage\SMB::fopen of type resource.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
243
		}
244
	}
245
246
	public function rmdir($path) {
247
		try {
248
			$this->statCache = array();
249
			$content = $this->share->dir($this->buildPath($path));
250
			foreach ($content as $file) {
251
				if ($file->isDirectory()) {
252
					$this->rmdir($path . '/' . $file->getName());
253
				} else {
254
					$this->share->del($file->getPath());
255
				}
256
			}
257
			$this->share->rmdir($this->buildPath($path));
258
			return true;
259
		} catch (NotFoundException $e) {
1 ignored issue
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...
260
			return false;
261
		} catch (ForbiddenException $e) {
1 ignored issue
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...
262
			return false;
263
		}
264
	}
265
266
	public function touch($path, $time = null) {
267
		if (!$this->file_exists($path)) {
268
			$fh = $this->share->write($this->buildPath($path));
269
			fclose($fh);
270
			return true;
271
		}
272
		return false;
273
	}
274
275
	public function opendir($path) {
276
		try {
277
			$files = $this->getFolderContents($path);
278
		} catch (NotFoundException $e) {
1 ignored issue
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...
279
			return false;
280
		} catch (ForbiddenException $e) {
1 ignored issue
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...
281
			return false;
282
		}
283
		$names = array_map(function ($info) {
284
			/** @var \Icewind\SMB\IFileInfo $info */
285
			return $info->getName();
286
		}, $files);
287
		return IteratorDirectory::wrap($names);
288
	}
289
290 View Code Duplication
	public function filetype($path) {
291
		try {
292
			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
293
		} catch (NotFoundException $e) {
1 ignored issue
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...
294
			return false;
295
		} catch (ForbiddenException $e) {
1 ignored issue
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...
296
			return false;
297
		}
298
	}
299
300
	public function mkdir($path) {
301
		$path = $this->buildPath($path);
302
		try {
303
			$this->share->mkdir($path);
304
			return true;
305
		} catch (Exception $e) {
1 ignored issue
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...
306
			return false;
307
		}
308
	}
309
310 View Code Duplication
	public function file_exists($path) {
311
		try {
312
			$this->getFileInfo($path);
313
			return true;
314
		} catch (NotFoundException $e) {
1 ignored issue
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...
315
			return false;
316
		} catch (ForbiddenException $e) {
1 ignored issue
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...
317
			return false;
318
		}
319
	}
320
321
	/**
322
	 * check if smbclient is installed
323
	 */
324
	public static function checkDependencies() {
325
		return (
326
			(bool)\OC_Helper::findBinaryPath('smbclient')
327
			|| Server::NativeAvailable()
328
		) ? true : ['smbclient'];
329
	}
330
}
331