This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * @author Arthur Schiwon <[email protected]> |
||
4 | * @author Jesús Macias <[email protected]> |
||
5 | * @author Jörn Friedrich Dreyer <[email protected]> |
||
6 | * @author Juan Pablo Villafañez <[email protected]> |
||
7 | * @author Michael Gapczynski <[email protected]> |
||
8 | * @author Morris Jobke <[email protected]> |
||
9 | * @author Philipp Kapfer <[email protected]> |
||
10 | * @author Robin Appelman <[email protected]> |
||
11 | * @author Robin McCorkell <[email protected]> |
||
12 | * @author Thomas Müller <[email protected]> |
||
13 | * @author Vincent Petry <[email protected]> |
||
14 | * |
||
15 | * @copyright Copyright (c) 2018, ownCloud GmbH |
||
16 | * @license AGPL-3.0 |
||
17 | * |
||
18 | * This code is free software: you can redistribute it and/or modify |
||
19 | * it under the terms of the GNU Affero General Public License, version 3, |
||
20 | * as published by the Free Software Foundation. |
||
21 | * |
||
22 | * This program is distributed in the hope that it will be useful, |
||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
25 | * GNU Affero General Public License for more details. |
||
26 | * |
||
27 | * You should have received a copy of the GNU Affero General Public License, version 3, |
||
28 | * along with this program. If not, see <http://www.gnu.org/licenses/> |
||
29 | * |
||
30 | */ |
||
31 | |||
32 | namespace OCA\Files_External\Lib\Storage; |
||
33 | |||
34 | use Icewind\SMB\Exception\AlreadyExistsException; |
||
35 | use Icewind\SMB\Exception\ConnectException; |
||
36 | use Icewind\SMB\Exception\Exception; |
||
37 | use Icewind\SMB\Exception\ForbiddenException; |
||
38 | use Icewind\SMB\Exception\NotFoundException; |
||
39 | use Icewind\SMB\BasicAuth; |
||
40 | use Icewind\SMB\IFileInfo; |
||
41 | use Icewind\SMB\Native\NativeServer; |
||
42 | use Icewind\SMB\Wrapped\FileInfo; |
||
43 | use Icewind\SMB\ServerFactory; |
||
44 | use Icewind\SMB\System; |
||
45 | use Icewind\SMB\IShare; |
||
46 | use Icewind\Streams\CallbackWrapper; |
||
47 | use Icewind\Streams\IteratorDirectory; |
||
48 | use OC\Cache\CappedMemoryCache; |
||
49 | use OC\Files\Filesystem; |
||
50 | use OCP\Files\Cache\ICache; |
||
51 | use OCP\Files\StorageNotAvailableException; |
||
52 | use OCP\Util; |
||
53 | |||
54 | class SMB extends \OCP\Files\Storage\StorageAdapter { |
||
55 | /** |
||
56 | * @var \Icewind\SMB\IServer |
||
57 | */ |
||
58 | protected $server; |
||
59 | |||
60 | /** |
||
61 | * @var \Icewind\SMB\IShare |
||
62 | */ |
||
63 | protected $share; |
||
64 | |||
65 | /** |
||
66 | * @var string |
||
67 | */ |
||
68 | protected $root; |
||
69 | |||
70 | /** |
||
71 | * @var ICache |
||
72 | */ |
||
73 | protected $statCache; |
||
74 | |||
75 | public function __construct($params) { |
||
76 | $loggedParams = $params; |
||
77 | // remove password from log if it is set |
||
78 | if (!empty($loggedParams['password'])) { |
||
79 | $loggedParams['password'] = '***removed***'; |
||
80 | } |
||
81 | $this->log('enter: '.__FUNCTION__.'('.\json_encode($loggedParams).')'); |
||
82 | |||
83 | if (isset($params['host'], $params['user'], $params['password'], $params['share'])) { |
||
84 | $auth = new BasicAuth($params['user'], '', $params['password']); |
||
85 | $serverFactory = new ServerFactory(); |
||
86 | $this->server = $serverFactory->createServer($params['host'], $auth); |
||
87 | $this->share = $this->server->getShare(\trim($params['share'], '/')); |
||
88 | |||
89 | $shareClass = \get_class($this->share); |
||
90 | $this->log("using $shareClass for the connection"); |
||
91 | |||
92 | $this->root = isset($params['root']) ? $params['root'] : '/'; |
||
93 | View Code Duplication | if (!$this->root || $this->root[0] != '/') { |
|
94 | $this->root = '/' . $this->root; |
||
95 | } |
||
96 | if (\substr($this->root, -1, 1) != '/') { |
||
97 | $this->root .= '/'; |
||
98 | } |
||
99 | } else { |
||
100 | $ex = new \Exception('Invalid configuration'); |
||
101 | $this->leave(__FUNCTION__, $ex); |
||
102 | throw $ex; |
||
103 | } |
||
104 | $this->statCache = new CappedMemoryCache(); |
||
105 | $this->log('leave: '.__FUNCTION__.', getId:'.$this->getId()); |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * @return string |
||
110 | */ |
||
111 | public function getId() { |
||
112 | // FIXME: double slash to keep compatible with the old storage ids, |
||
113 | // failure to do so will lead to creation of a new storage id and |
||
114 | // loss of shares from the storage |
||
115 | return 'smb::' . $this->server->getAuth()->getUsername() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root; |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * @param string $path |
||
120 | * @return string |
||
121 | */ |
||
122 | protected function buildPath($path) { |
||
123 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
124 | $result = Filesystem::normalizePath($this->root . '/' . $path, true, false, true); |
||
125 | return $this->leave(__FUNCTION__, $result); |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * @param string $path |
||
130 | * @return \Icewind\SMB\IFileInfo |
||
131 | * @throws StorageNotAvailableException |
||
132 | * @throws ForbiddenException |
||
133 | * @throws NotFoundException |
||
134 | */ |
||
135 | protected function getFileInfo($path) { |
||
136 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
137 | $path = $this->buildPath($path); |
||
138 | if (!isset($this->statCache[$path])) { |
||
139 | try { |
||
140 | $this->log("stat fetching '$path'"); |
||
141 | try { |
||
142 | $this->statCache[$path] = $this->share->stat($path); |
||
143 | } catch (NotFoundException $e) { |
||
144 | if ($this->share instanceof IShare) { |
||
145 | // smbclient may have problems with the allinfo cmd |
||
146 | $this->log("stat for '$path' failed, trying to read parent dir"); |
||
147 | $infos = $this->share->dir(\dirname($path)); |
||
148 | foreach ($infos as $fileInfo) { |
||
149 | if ($fileInfo->getName() === \basename($path)) { |
||
150 | $this->statCache[$path] = $fileInfo; |
||
151 | break; |
||
152 | } |
||
153 | } |
||
154 | if (empty($this->statCache[$path])) { |
||
155 | $this->leave(__FUNCTION__, $e); |
||
156 | throw $e; |
||
157 | } |
||
158 | } else { |
||
159 | // trust the results of libsmb |
||
160 | $this->leave(__FUNCTION__, $e); |
||
161 | throw $e; |
||
162 | } |
||
163 | } |
||
164 | if ($this->isRootDir($path) && $this->statCache[$path]->isHidden()) { |
||
165 | $this->log("unhiding stat for '$path'"); |
||
166 | // make root never hidden, may happen when accessing a shared drive (mode is 22, archived and readonly - neither is true ... whatever) |
||
167 | if ($this->statCache[$path]->isReadOnly()) { |
||
168 | $mode = IFileInfo::MODE_DIRECTORY & IFileInfo::MODE_READONLY; |
||
169 | } else { |
||
170 | $mode = IFileInfo::MODE_DIRECTORY; |
||
171 | } |
||
172 | $this->statCache[$path] = new FileInfo($path, '', 0, $this->statCache[$path]->getMTime(), $mode); |
||
173 | } |
||
174 | } catch (ConnectException $e) { |
||
175 | $ex = new StorageNotAvailableException( |
||
176 | $e->getMessage(), $e->getCode(), $e); |
||
177 | $this->leave(__FUNCTION__, $ex); |
||
178 | throw $ex; |
||
179 | } catch (ForbiddenException $e) { |
||
180 | if ($this->remoteIsShare() && $this->isRootDir($path)) { //mtime may not work for share root |
||
181 | $this->log("faking stat for forbidden '$path'"); |
||
182 | $this->statCache[$path] = new FileInfo($path, '', 0, $this->shareMTime(), IFileInfo::MODE_DIRECTORY); |
||
183 | } else { |
||
184 | $this->leave(__FUNCTION__, $e); |
||
185 | throw $e; |
||
186 | } |
||
187 | } |
||
188 | } else { |
||
189 | $this->log("stat cache hit for '$path'"); |
||
190 | } |
||
191 | $result = $this->statCache[$path]; |
||
192 | return $this->leave(__FUNCTION__, $result); |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * @param string $path |
||
197 | * @return \Icewind\SMB\IFileInfo[] |
||
198 | * @throws StorageNotAvailableException |
||
199 | */ |
||
200 | protected function getFolderContents($path) { |
||
201 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
202 | try { |
||
203 | $path = $this->buildPath($path); |
||
204 | $result = []; |
||
205 | $children = $this->share->dir($path); |
||
206 | foreach ($children as $fileInfo) { |
||
207 | // check if the file is readable before adding it to the list |
||
208 | // can't use "isReadable" function here, use smb internals instead |
||
209 | try { |
||
210 | if ($fileInfo->isHidden()) { |
||
211 | $this->log("{$fileInfo->getName()} isn't readable, skipping", Util::DEBUG); |
||
212 | } else { |
||
213 | $result[] = $fileInfo; |
||
214 | //remember entry so we can answer file_exists and filetype without a full stat |
||
215 | $this->statCache[$path . '/' . $fileInfo->getName()] = $fileInfo; |
||
216 | } |
||
217 | } catch (NotFoundException $e) { |
||
218 | $this->swallow(__FUNCTION__, $e); |
||
219 | } |
||
220 | } |
||
221 | } catch (ConnectException $e) { |
||
222 | $ex = new StorageNotAvailableException( |
||
223 | $e->getMessage(), $e->getCode(), $e); |
||
224 | $this->leave(__FUNCTION__, $ex); |
||
225 | throw $ex; |
||
226 | } |
||
227 | return $this->leave(__FUNCTION__, $result); |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * @param \Icewind\SMB\IFileInfo $info |
||
232 | * @return array |
||
233 | */ |
||
234 | protected function formatInfo($info) { |
||
235 | $result = [ |
||
236 | 'size' => $info->getSize(), |
||
237 | 'mtime' => $info->getMTime(), |
||
238 | ]; |
||
239 | if ($info->isDirectory()) { |
||
240 | $result['type'] = 'dir'; |
||
241 | } else { |
||
242 | $result['type'] = 'file'; |
||
243 | } |
||
244 | return $result; |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Rename the files. If the source or the target is the root, the rename won't happen. |
||
249 | * |
||
250 | * @param string $source the old name of the path |
||
251 | * @param string $target the new name of the path |
||
252 | * @return bool true if the rename is successful, false otherwise |
||
253 | */ |
||
254 | public function rename($source, $target) { |
||
255 | $this->log("enter: rename('$source', '$target')", Util::DEBUG); |
||
256 | |||
257 | if ($this->isRootDir($source) || $this->isRootDir($target)) { |
||
258 | $this->log("refusing to rename \"$source\" to \"$target\""); |
||
259 | return $this->leave(__FUNCTION__, false); |
||
260 | } |
||
261 | |||
262 | try { |
||
263 | $result = $this->share->rename($this->root . $source, $this->root . $target); |
||
264 | if ($result) { |
||
265 | $this->removeFromCache($this->root . $source); |
||
266 | $this->removeFromCache($this->root . $target); |
||
267 | } |
||
268 | } catch (AlreadyExistsException $e) { |
||
269 | $this->swallow(__FUNCTION__, $e); |
||
270 | View Code Duplication | if ($this->unlink($target)) { |
|
0 ignored issues
–
show
|
|||
271 | $result = $this->share->rename($this->root . $source, $this->root . $target); |
||
272 | if ($result) { |
||
273 | $this->removeFromCache($this->root . $source); |
||
274 | $this->removeFromCache($this->root . $target); |
||
275 | } |
||
276 | } else { |
||
277 | $result = false; |
||
278 | } |
||
279 | } catch (Exception $e) { |
||
280 | $this->swallow(__FUNCTION__, $e); |
||
281 | // Icewind\SMB\Exception\Exception, not a plain exception |
||
282 | if ($e->getCode() === 22) { |
||
283 | View Code Duplication | if ($this->unlink($target)) { |
|
0 ignored issues
–
show
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...
|
|||
284 | $result = $this->share->rename($this->root . $source, $this->root . $target); |
||
285 | if ($result) { |
||
286 | $this->removeFromCache($this->root . $source); |
||
287 | $this->removeFromCache($this->root . $target); |
||
288 | } |
||
289 | } else { |
||
290 | $result = false; |
||
291 | } |
||
292 | } elseif ($e->getCode() === 16) { |
||
293 | $this->swallow(__FUNCTION__, $e); |
||
294 | $result = false; |
||
295 | } else { |
||
296 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
297 | $this->leave(__FUNCTION__, $ex); |
||
298 | throw $ex; |
||
299 | } |
||
300 | } catch (\Exception $e) { |
||
301 | $this->swallow(__FUNCTION__, $e); |
||
302 | $result = false; |
||
303 | } |
||
304 | return $this->leave(__FUNCTION__, $result); |
||
305 | } |
||
306 | |||
307 | private function removeFromCache($path) { |
||
308 | $path = \trim($path, '/'); |
||
309 | // TODO The CappedCache does not really clear by prefix. It just clears all. |
||
310 | //$this->dirCache->clear($path); |
||
311 | $this->statCache->clear($path); |
||
312 | //$this->xattrCache->clear($path); |
||
313 | } |
||
314 | /** |
||
315 | * @param string $path |
||
316 | * @return array |
||
317 | */ |
||
318 | public function stat($path) { |
||
319 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
320 | try { |
||
321 | $result = $this->formatInfo($this->getFileInfo($path)); |
||
322 | } catch (NotFoundException $e) { |
||
323 | $this->swallow(__FUNCTION__, $e); |
||
324 | $result = false; |
||
325 | } catch (Exception $e) { |
||
326 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
327 | $this->leave(__FUNCTION__, $ex); |
||
328 | throw $ex; |
||
329 | } |
||
330 | return $this->leave(__FUNCTION__, $result); |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * get the best guess for the modification time of the share |
||
335 | * NOTE: modification times do not bubble up the directory tree, basically |
||
336 | * we are just guessing a time |
||
337 | * |
||
338 | * @return int the calculated mtime for the folder |
||
339 | */ |
||
340 | private function shareMTime() { |
||
341 | $this->log('enter: '.__FUNCTION__, Util::DEBUG); |
||
342 | $files = $this->share->dir($this->root); |
||
343 | $result = 0; |
||
344 | foreach ($files as $fileInfo) { |
||
345 | if ($fileInfo->getMTime() > $result) { |
||
346 | $result = $fileInfo->getMTime(); |
||
347 | } |
||
348 | } |
||
349 | return $this->leave(__FUNCTION__, $result); |
||
350 | } |
||
351 | /** |
||
352 | * Check if the path is our root dir (not the smb one) |
||
353 | * |
||
354 | * @param string $path the path |
||
355 | * @return bool true if it's root, false if not |
||
356 | */ |
||
357 | private function isRootDir($path) { |
||
358 | $this->log('enter: '.__FUNCTION__."($path)", Util::DEBUG); |
||
359 | $result = $path === '' || $path === '/' || $path === '.'; |
||
360 | return $this->leave(__FUNCTION__, $result); |
||
361 | } |
||
362 | /** |
||
363 | * Check if our root points to a smb share |
||
364 | * |
||
365 | * @return bool true if our root points to a share false otherwise |
||
366 | */ |
||
367 | private function remoteIsShare() { |
||
368 | $this->log('enter: '.__FUNCTION__, Util::DEBUG); |
||
369 | $result = $this->share->getName() && (!$this->root || $this->root === '/'); |
||
370 | return $this->leave(__FUNCTION__, $result); |
||
371 | } |
||
372 | /** |
||
373 | * @param string $path |
||
374 | * @return bool |
||
375 | * @throws StorageNotAvailableException |
||
376 | */ |
||
377 | public function unlink($path) { |
||
378 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
379 | |||
380 | if ($this->isRootDir($path)) { |
||
381 | $this->log("refusing to unlink \"$path\""); |
||
382 | return $this->leave(__FUNCTION__, false); |
||
383 | } |
||
384 | |||
385 | $result = false; |
||
386 | try { |
||
387 | if ($this->is_dir($path)) { |
||
388 | $result = $this->rmdir($path); |
||
389 | } else { |
||
390 | $path = $this->buildPath($path); |
||
391 | $this->share->del($path); |
||
392 | unset($this->statCache[$path]); |
||
393 | $result = true; |
||
394 | } |
||
395 | } catch (NotFoundException $e) { |
||
396 | $this->swallow(__FUNCTION__, $e); |
||
397 | } catch (ForbiddenException $e) { |
||
398 | $this->swallow(__FUNCTION__, $e); |
||
399 | } catch (Exception $e) { |
||
400 | View Code Duplication | if ($e->getCode() === 16) { |
|
0 ignored issues
–
show
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...
|
|||
401 | $this->swallow(__FUNCTION__, $e); |
||
402 | } else { |
||
403 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
404 | $this->leave(__FUNCTION__, $ex); |
||
405 | throw $ex; |
||
406 | } |
||
407 | } |
||
408 | return $this->leave(__FUNCTION__, $result); |
||
409 | } |
||
410 | |||
411 | /** |
||
412 | * check if a file or folder has been updated since $time |
||
413 | * |
||
414 | * @param string $path |
||
415 | * @param int $time |
||
416 | * @return bool |
||
417 | */ |
||
418 | public function hasUpdated($path, $time) { |
||
419 | $this->log('enter: '.__FUNCTION__."($path, $time)"); |
||
420 | $actualTime = $this->filemtime($path); |
||
421 | $result = $actualTime > $time; |
||
422 | return $this->leave(__FUNCTION__, $result); |
||
423 | } |
||
424 | |||
425 | /** |
||
426 | * @param string $path |
||
427 | * @param string $mode |
||
428 | * @return resource |
||
429 | * @throws StorageNotAvailableException |
||
430 | */ |
||
431 | public function fopen($path, $mode) { |
||
432 | $this->log('enter: '.__FUNCTION__."($path, $mode)"); |
||
433 | $fullPath = $this->buildPath($path); |
||
434 | $result = false; |
||
435 | try { |
||
436 | switch ($mode) { |
||
437 | case 'r': |
||
438 | case 'rb': |
||
439 | if ($this->file_exists($path)) { |
||
440 | $result = $this->share->read($fullPath); |
||
441 | } |
||
442 | break; |
||
443 | case 'w': |
||
444 | case 'wb': |
||
445 | $source = $this->share->write($fullPath); |
||
446 | $result = CallBackWrapper::wrap($source, null, null, function () use ($fullPath) { |
||
447 | unset($this->statCache[$fullPath]); |
||
448 | }); |
||
449 | break; |
||
450 | case 'a': |
||
451 | case 'ab': |
||
452 | case 'r+': |
||
453 | case 'w+': |
||
454 | case 'wb+': |
||
455 | case 'a+': |
||
456 | case 'x': |
||
457 | case 'x+': |
||
458 | case 'c': |
||
459 | case 'c+': |
||
460 | //emulate these |
||
461 | if (\strrpos($path, '.') !== false) { |
||
462 | $ext = \substr($path, \strrpos($path, '.')); |
||
463 | } else { |
||
464 | $ext = ''; |
||
465 | } |
||
466 | if ($this->file_exists($path)) { |
||
467 | if (!$this->isUpdatable($path)) { |
||
468 | break; |
||
469 | } |
||
470 | $tmpFile = $this->getCachedFile($path); |
||
471 | } else { |
||
472 | if (!$this->isCreatable(\dirname($path))) { |
||
473 | break; |
||
474 | } |
||
475 | $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext); |
||
476 | } |
||
477 | $source = \fopen($tmpFile, $mode); |
||
478 | $share = $this->share; |
||
479 | $result = CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) { |
||
480 | unset($this->statCache[$fullPath]); |
||
481 | $share->put($tmpFile, $fullPath); |
||
482 | \unlink($tmpFile); |
||
483 | }); |
||
484 | } |
||
485 | } catch (NotFoundException $e) { |
||
486 | $this->swallow(__FUNCTION__, $e); |
||
487 | } catch (ForbiddenException $e) { |
||
488 | $this->swallow(__FUNCTION__, $e); |
||
489 | } catch (Exception $e) { |
||
490 | View Code Duplication | if ($e->getCode() === 16) { |
|
0 ignored issues
–
show
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...
|
|||
491 | $this->swallow(__FUNCTION__, $e); |
||
492 | } else { |
||
493 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
494 | $this->leave(__FUNCTION__, $ex); |
||
495 | throw $ex; |
||
496 | } |
||
497 | } |
||
498 | return $this->leave(__FUNCTION__, $result); |
||
499 | } |
||
500 | |||
501 | public function rmdir($path) { |
||
502 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
503 | |||
504 | if ($this->isRootDir($path)) { |
||
505 | $this->log("refusing to delete \"$path\""); |
||
506 | return $this->leave(__FUNCTION__, false); |
||
507 | } |
||
508 | |||
509 | $result = false; |
||
510 | try { |
||
511 | $this->removeFromCache($path); |
||
512 | $content = $this->share->dir($this->buildPath($path)); |
||
513 | foreach ($content as $file) { |
||
514 | if ($file->isDirectory()) { |
||
515 | $this->rmdir($path . '/' . $file->getName()); |
||
516 | } else { |
||
517 | $this->share->del($file->getPath()); |
||
518 | } |
||
519 | } |
||
520 | $this->share->rmdir($this->buildPath($path)); |
||
521 | $result = true; |
||
522 | } catch (NotFoundException $e) { |
||
523 | $this->swallow(__FUNCTION__, $e); |
||
524 | } catch (ForbiddenException $e) { |
||
525 | $this->swallow(__FUNCTION__, $e); |
||
526 | } catch (Exception $e) { |
||
527 | View Code Duplication | if ($e->getCode() === 16) { |
|
0 ignored issues
–
show
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...
|
|||
528 | $this->swallow(__FUNCTION__, $e); |
||
529 | } else { |
||
530 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
531 | $this->leave(__FUNCTION__, $ex); |
||
532 | throw $ex; |
||
533 | } |
||
534 | } |
||
535 | return $this->leave(__FUNCTION__, $result); |
||
536 | } |
||
537 | |||
538 | public function touch($path, $time = null) { |
||
539 | $this->log('enter: '.__FUNCTION__."($path, $time)"); |
||
540 | $result = false; |
||
541 | try { |
||
542 | if (!$this->file_exists($path)) { |
||
543 | $fh = $this->share->write($this->buildPath($path)); |
||
544 | \fclose($fh); |
||
545 | $result = true; |
||
546 | } |
||
547 | } catch (Exception $e) { |
||
548 | View Code Duplication | if ($e->getCode() === 16) { |
|
0 ignored issues
–
show
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...
|
|||
549 | $this->swallow(__FUNCTION__, $e); |
||
550 | } else { |
||
551 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
552 | $this->leave(__FUNCTION__, $ex); |
||
553 | throw $ex; |
||
554 | } |
||
555 | } |
||
556 | return $this->leave(__FUNCTION__, $result); |
||
557 | } |
||
558 | |||
559 | public function opendir($path) { |
||
560 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
561 | $result = false; |
||
562 | try { |
||
563 | $files = $this->getFolderContents($path); |
||
564 | $names = \array_map(function ($info) { |
||
565 | /** @var \Icewind\SMB\IFileInfo $info */ |
||
566 | return $info->getName(); |
||
567 | }, $files); |
||
568 | $result = IteratorDirectory::wrap($names); |
||
569 | } catch (NotFoundException $e) { |
||
570 | $this->swallow(__FUNCTION__, $e); |
||
571 | } catch (ForbiddenException $e) { |
||
572 | $this->swallow(__FUNCTION__, $e); |
||
573 | } catch (Exception $e) { |
||
574 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
575 | $this->leave(__FUNCTION__, $ex); |
||
576 | throw $ex; |
||
577 | } |
||
578 | return $this->leave(__FUNCTION__, $result); |
||
579 | } |
||
580 | |||
581 | public function filetype($path) { |
||
582 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
583 | $result = false; |
||
584 | try { |
||
585 | $result = $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file'; |
||
586 | } catch (NotFoundException $e) { |
||
587 | $this->swallow(__FUNCTION__, $e); |
||
588 | } catch (ForbiddenException $e) { |
||
589 | $this->swallow(__FUNCTION__, $e); |
||
590 | } catch (Exception $e) { |
||
591 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
592 | $this->leave(__FUNCTION__, $ex); |
||
593 | throw $ex; |
||
594 | } |
||
595 | return $this->leave(__FUNCTION__, $result); |
||
596 | } |
||
597 | |||
598 | public function mkdir($path) { |
||
599 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
600 | $result = false; |
||
601 | $path = $this->buildPath($path); |
||
602 | try { |
||
603 | $result = $this->share->mkdir($path); |
||
604 | } catch (ForbiddenException $e) { |
||
605 | $this->swallow(__FUNCTION__, $e); |
||
606 | } catch (AlreadyExistsException $e) { |
||
0 ignored issues
–
show
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 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...
|
|||
607 | $this->swallow(__FUNCTION__, $e); |
||
608 | } catch (Exception $e) { |
||
609 | View Code Duplication | if ($e->getCode() === 16) { |
|
0 ignored issues
–
show
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...
|
|||
610 | $this->swallow(__FUNCTION__, $e); |
||
611 | } else { |
||
612 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
613 | $this->leave(__FUNCTION__, $ex); |
||
614 | throw $ex; |
||
615 | } |
||
616 | } |
||
617 | return $this->leave(__FUNCTION__, $result); |
||
618 | } |
||
619 | |||
620 | public function file_exists($path) { |
||
621 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
622 | $result = false; |
||
623 | try { |
||
624 | $this->getFileInfo($path); |
||
625 | $result = true; |
||
626 | } catch (NotFoundException $e) { |
||
627 | $this->swallow(__FUNCTION__, $e); |
||
628 | } catch (ForbiddenException $e) { |
||
629 | $this->swallow(__FUNCTION__, $e); |
||
630 | } catch (Exception $e) { |
||
631 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
632 | $this->leave(__FUNCTION__, $ex); |
||
633 | throw $ex; |
||
634 | } |
||
635 | return $this->leave(__FUNCTION__, $result); |
||
636 | } |
||
637 | |||
638 | public function isReadable($path) { |
||
639 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
640 | $result = false; |
||
641 | try { |
||
642 | $info = $this->getFileInfo($path); |
||
643 | $result = !$info->isHidden(); |
||
644 | } catch (NotFoundException $e) { |
||
645 | $this->swallow(__FUNCTION__, $e); |
||
646 | } catch (ForbiddenException $e) { |
||
647 | $this->swallow(__FUNCTION__, $e); |
||
648 | } catch (Exception $e) { |
||
649 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
650 | $this->leave(__FUNCTION__, $ex); |
||
651 | throw $ex; |
||
652 | } |
||
653 | return $this->leave(__FUNCTION__, $result); |
||
654 | } |
||
655 | |||
656 | View Code Duplication | public function isUpdatable($path) { |
|
657 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
658 | $result = false; |
||
659 | try { |
||
660 | $info = $this->getFileInfo($path); |
||
661 | // following windows behaviour for read-only folders: they can be written into |
||
662 | // (https://support.microsoft.com/en-us/kb/326549 - "cause" section) |
||
663 | $result = !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path)); |
||
664 | } catch (NotFoundException $e) { |
||
665 | $this->swallow(__FUNCTION__, $e); |
||
666 | } catch (ForbiddenException $e) { |
||
667 | $this->swallow(__FUNCTION__, $e); |
||
668 | } catch (Exception $e) { |
||
669 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
670 | $this->leave(__FUNCTION__, $ex); |
||
671 | throw $ex; |
||
672 | } |
||
673 | return $this->leave(__FUNCTION__, $result); |
||
674 | } |
||
675 | |||
676 | View Code Duplication | public function isDeletable($path) { |
|
677 | $this->log('enter: '.__FUNCTION__."($path)"); |
||
678 | $result = false; |
||
679 | try { |
||
680 | $info = $this->getFileInfo($path); |
||
681 | $result = !$info->isHidden() && !$info->isReadOnly(); |
||
682 | } catch (NotFoundException $e) { |
||
683 | $this->swallow(__FUNCTION__, $e); |
||
684 | } catch (ForbiddenException $e) { |
||
685 | $this->swallow(__FUNCTION__, $e); |
||
686 | } catch (Exception $e) { |
||
687 | $ex = new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e); |
||
688 | $this->leave(__FUNCTION__, $ex); |
||
689 | throw $ex; |
||
690 | } |
||
691 | return $this->leave(__FUNCTION__, $result); |
||
692 | } |
||
693 | |||
694 | /** |
||
695 | * check if smbclient is installed |
||
696 | */ |
||
697 | public static function checkDependencies() { |
||
698 | return ( |
||
699 | (bool)\OC_Helper::findBinaryPath('smbclient') |
||
700 | || NativeServer::available(new System()) |
||
701 | ) ? true : ['smbclient']; |
||
702 | } |
||
703 | |||
704 | /** |
||
705 | * Test a storage for availability |
||
706 | * |
||
707 | * @return bool |
||
708 | */ |
||
709 | public function test() { |
||
710 | $this->log('enter: '.__FUNCTION__."()"); |
||
711 | $result = false; |
||
712 | try { |
||
713 | $result = parent::test(); |
||
714 | } catch (Exception $e) { |
||
715 | $this->swallow(__FUNCTION__, $e); |
||
716 | } |
||
717 | return $this->leave(__FUNCTION__, $result); |
||
718 | } |
||
719 | |||
720 | /** |
||
721 | * @param string $message |
||
722 | * @param int $level |
||
723 | * @param string $from |
||
724 | */ |
||
725 | private function log($message, $level = Util::DEBUG, $from = 'smb') { |
||
726 | if (\OC::$server->getConfig()->getSystemValue('smb.logging.enable', false) === true) { |
||
727 | Util::writeLog($from, $message, $level); |
||
728 | } |
||
729 | } |
||
730 | |||
731 | /** |
||
732 | * if smb.logging.enable is set to true in the config will log a leave line |
||
733 | * with the given function, the return value or the exception |
||
734 | * |
||
735 | * @param $function |
||
736 | * @param mixed $result an exception will be logged and then returned |
||
737 | * @return mixed |
||
738 | */ |
||
739 | private function leave($function, $result) { |
||
740 | if (\OC::$server->getConfig()->getSystemValue('smb.logging.enable', false) === false) { |
||
741 | //don't bother building log strings |
||
742 | return $result; |
||
743 | } elseif ($result === true) { |
||
744 | Util::writeLog('smb', "leave: $function, return true", Util::DEBUG); |
||
745 | } elseif ($result === false) { |
||
746 | Util::writeLog('smb', "leave: $function, return false", Util::DEBUG); |
||
747 | } elseif (\is_string($result)) { |
||
748 | Util::writeLog('smb', "leave: $function, return '$result'", Util::DEBUG); |
||
749 | } elseif (\is_resource($result)) { |
||
750 | Util::writeLog('smb', "leave: $function, return resource", Util::DEBUG); |
||
751 | } elseif ($result instanceof \Exception) { |
||
752 | Util::writeLog('smb', "leave: $function, throw ".\get_class($result) |
||
753 | .' - code: '.$result->getCode() |
||
754 | .' message: '.$result->getMessage() |
||
755 | .' trace: '.$result->getTraceAsString(), Util::DEBUG); |
||
756 | } else { |
||
757 | Util::writeLog('smb', "leave: $function, return ".\json_encode($result, true), Util::DEBUG); |
||
758 | } |
||
759 | return $result; |
||
760 | } |
||
761 | |||
762 | private function swallow($function, \Exception $exception) { |
||
763 | if (\OC::$server->getConfig()->getSystemValue('smb.logging.enable', false) === true) { |
||
764 | Util::writeLog('smb', "$function swallowing ".\get_class($exception) |
||
765 | .' - code: '.$exception->getCode() |
||
766 | .' message: '.$exception->getMessage() |
||
767 | .' trace: '.$exception->getTraceAsString(), Util::DEBUG); |
||
768 | } |
||
769 | } |
||
770 | |||
771 | /** |
||
772 | * immediately close / free connection |
||
773 | */ |
||
774 | public function __destruct() { |
||
775 | unset($this->share); |
||
776 | } |
||
777 | } |
||
778 |
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.