Passed
Push — master ( b88dc5...9f34d1 )
by Robin
14:21 queued 11s
created

Directory::getNode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bart Visscher <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Jakob Sack <[email protected]>
10
 * @author Joas Schilling <[email protected]>
11
 * @author Julius Härtl <[email protected]>
12
 * @author Morris Jobke <[email protected]>
13
 * @author Robin Appelman <[email protected]>
14
 * @author Roeland Jago Douma <[email protected]>
15
 * @author Thomas Müller <[email protected]>
16
 * @author Vincent Petry <[email protected]>
17
 *
18
 * @license AGPL-3.0
19
 *
20
 * This code is free software: you can redistribute it and/or modify
21
 * it under the terms of the GNU Affero General Public License, version 3,
22
 * as published by the Free Software Foundation.
23
 *
24
 * This program is distributed in the hope that it will be useful,
25
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
 * GNU Affero General Public License for more details.
28
 *
29
 * You should have received a copy of the GNU Affero General Public License, version 3,
30
 * along with this program. If not, see <http://www.gnu.org/licenses/>
31
 *
32
 */
33
namespace OCA\DAV\Connector\Sabre;
34
35
use OC\Files\Mount\MoveableMount;
36
use OC\Files\View;
37
use OCA\DAV\Connector\Sabre\Exception\FileLocked;
38
use OCA\DAV\Connector\Sabre\Exception\Forbidden;
39
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
40
use OCP\Files\FileInfo;
41
use OCP\Files\Folder;
42
use OCP\Files\ForbiddenException;
43
use OCP\Files\InvalidPathException;
44
use OCP\Files\NotPermittedException;
45
use OCP\Files\StorageNotAvailableException;
46
use OCP\Lock\ILockingProvider;
47
use OCP\Lock\LockedException;
48
use Sabre\DAV\Exception\BadRequest;
49
use Sabre\DAV\Exception\Locked;
50
use Sabre\DAV\Exception\NotFound;
51
use Sabre\DAV\Exception\ServiceUnavailable;
52
use Sabre\DAV\IFile;
53
use Sabre\DAV\INode;
54
55
class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota, \Sabre\DAV\IMoveTarget, \Sabre\DAV\ICopyTarget {
56
57
	/**
58
	 * Cached directory content
59
	 *
60
	 * @var \OCP\Files\FileInfo[]
61
	 */
62
	private $dirContent;
63
64
	/**
65
	 * Cached quota info
66
	 *
67
	 * @var array
68
	 */
69
	private $quotaInfo;
70
71
	/**
72
	 * @var ObjectTree|null
73
	 */
74
	private $tree;
75
76
	/**
77
	 * Sets up the node, expects a full path name
78
	 *
79
	 * @param \OC\Files\View $view
80
	 * @param \OCP\Files\FileInfo $info
81
	 * @param ObjectTree|null $tree
82
	 * @param \OCP\Share\IManager $shareManager
83
	 */
84
	public function __construct(View $view, FileInfo $info, $tree = null, $shareManager = null) {
85
		parent::__construct($view, $info, $shareManager);
86
		$this->tree = $tree;
87
	}
88
89
	/**
90
	 * Creates a new file in the directory
91
	 *
92
	 * Data will either be supplied as a stream resource, or in certain cases
93
	 * as a string. Keep in mind that you may have to support either.
94
	 *
95
	 * After successful creation of the file, you may choose to return the ETag
96
	 * of the new file here.
97
	 *
98
	 * The returned ETag must be surrounded by double-quotes (The quotes should
99
	 * be part of the actual string).
100
	 *
101
	 * If you cannot accurately determine the ETag, you should not return it.
102
	 * If you don't store the file exactly as-is (you're transforming it
103
	 * somehow) you should also not return an ETag.
104
	 *
105
	 * This means that if a subsequent GET to this new file does not exactly
106
	 * return the same contents of what was submitted here, you are strongly
107
	 * recommended to omit the ETag.
108
	 *
109
	 * @param string $name Name of the file
110
	 * @param resource|string $data Initial payload
111
	 * @return null|string
112
	 * @throws Exception\EntityTooLarge
113
	 * @throws Exception\UnsupportedMediaType
114
	 * @throws FileLocked
115
	 * @throws InvalidPath
116
	 * @throws \Sabre\DAV\Exception
117
	 * @throws \Sabre\DAV\Exception\BadRequest
118
	 * @throws \Sabre\DAV\Exception\Forbidden
119
	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
120
	 */
121
	public function createFile($name, $data = null) {
122
		try {
123
			// for chunked upload also updating a existing file is a "createFile"
124
			// because we create all the chunks before re-assemble them to the existing file.
125
			if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
126
127
				// exit if we can't create a new file and we don't updatable existing file
128
				$chunkInfo = \OC_FileChunking::decodeName($name);
129
				if (!$this->fileView->isCreatable($this->path) &&
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->isCreatable($this->path) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
130
					!$this->fileView->isUpdatable($this->path . '/' . $chunkInfo['name'])
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->isUpdat...' . $chunkInfo['name']) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
131
				) {
132
					throw new \Sabre\DAV\Exception\Forbidden();
133
				}
134
			} else {
135
				// For non-chunked upload it is enough to check if we can create a new file
136
				if (!$this->fileView->isCreatable($this->path)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->isCreatable($this->path) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
137
					throw new \Sabre\DAV\Exception\Forbidden();
138
				}
139
			}
140
141
			$this->fileView->verifyPath($this->path, $name);
142
143
			$path = $this->fileView->getAbsolutePath($this->path) . '/' . $name;
144
			// in case the file already exists/overwriting
145
			$info = $this->fileView->getFileInfo($this->path . '/' . $name);
146
			if (!$info) {
147
				// use a dummy FileInfo which is acceptable here since it will be refreshed after the put is complete
148
				$info = new \OC\Files\FileInfo($path, null, null, [
149
					'type' => FileInfo::TYPE_FILE
150
				], null);
151
			}
152
			$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info);
153
154
			// only allow 1 process to upload a file at once but still allow reading the file while writing the part file
155
			$node->acquireLock(ILockingProvider::LOCK_SHARED);
156
			$this->fileView->lockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
157
158
			$result = $node->put($data);
159
160
			$this->fileView->unlockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
161
			$node->releaseLock(ILockingProvider::LOCK_SHARED);
162
			return $result;
163
		} catch (\OCP\Files\StorageNotAvailableException $e) {
164
			throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage(), $e->getCode(), $e);
165
		} catch (InvalidPathException $ex) {
166
			throw new InvalidPath($ex->getMessage(), false, $ex);
167
		} catch (ForbiddenException $ex) {
168
			throw new Forbidden($ex->getMessage(), $ex->getRetry(), $ex);
169
		} catch (LockedException $e) {
170
			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
171
		}
172
	}
173
174
	/**
175
	 * Creates a new subdirectory
176
	 *
177
	 * @param string $name
178
	 * @throws FileLocked
179
	 * @throws InvalidPath
180
	 * @throws \Sabre\DAV\Exception\Forbidden
181
	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
182
	 */
183
	public function createDirectory($name) {
184
		try {
185
			if (!$this->info->isCreatable()) {
186
				throw new \Sabre\DAV\Exception\Forbidden();
187
			}
188
189
			$this->fileView->verifyPath($this->path, $name);
190
			$newPath = $this->path . '/' . $name;
191
			if (!$this->fileView->mkdir($newPath)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->mkdir($newPath) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
192
				throw new \Sabre\DAV\Exception\Forbidden('Could not create directory ' . $newPath);
193
			}
194
		} catch (\OCP\Files\StorageNotAvailableException $e) {
195
			throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
196
		} catch (InvalidPathException $ex) {
197
			throw new InvalidPath($ex->getMessage());
198
		} catch (ForbiddenException $ex) {
199
			throw new Forbidden($ex->getMessage(), $ex->getRetry());
200
		} catch (LockedException $e) {
201
			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
202
		}
203
	}
204
205
	/**
206
	 * Returns a specific child node, referenced by its name
207
	 *
208
	 * @param string $name
209
	 * @param \OCP\Files\FileInfo $info
210
	 * @return \Sabre\DAV\INode
211
	 * @throws InvalidPath
212
	 * @throws \Sabre\DAV\Exception\NotFound
213
	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
214
	 */
215
	public function getChild($name, $info = null) {
216
		if (!$this->info->isReadable()) {
217
			// avoid detecting files through this way
218
			throw new NotFound();
219
		}
220
221
		$path = $this->path . '/' . $name;
222
		if (is_null($info)) {
223
			try {
224
				$this->fileView->verifyPath($this->path, $name);
225
				$info = $this->fileView->getFileInfo($path);
226
			} catch (\OCP\Files\StorageNotAvailableException $e) {
227
				throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
228
			} catch (InvalidPathException $ex) {
229
				throw new InvalidPath($ex->getMessage());
230
			} catch (ForbiddenException $e) {
231
				throw new \Sabre\DAV\Exception\Forbidden();
232
			}
233
		}
234
235
		if (!$info) {
236
			throw new \Sabre\DAV\Exception\NotFound('File with name ' . $path . ' could not be located');
237
		}
238
239
		if ($info->getMimeType() === FileInfo::MIMETYPE_FOLDER) {
240
			$node = new \OCA\DAV\Connector\Sabre\Directory($this->fileView, $info, $this->tree, $this->shareManager);
241
		} else {
242
			$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info, $this->shareManager);
243
		}
244
		if ($this->tree) {
245
			$this->tree->cacheNode($node);
246
		}
247
		return $node;
248
	}
249
250
	/**
251
	 * Returns an array with all the child nodes
252
	 *
253
	 * @return \Sabre\DAV\INode[]
254
	 * @throws \Sabre\DAV\Exception\Locked
255
	 * @throws \OCA\DAV\Connector\Sabre\Exception\Forbidden
256
	 */
257
	public function getChildren() {
258
		if (!is_null($this->dirContent)) {
0 ignored issues
show
introduced by
The condition is_null($this->dirContent) is always false.
Loading history...
259
			return $this->dirContent;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->dirContent returns the type OCP\Files\FileInfo[] which is incompatible with the documented return type Sabre\DAV\INode[].
Loading history...
260
		}
261
		try {
262
			if (!$this->info->isReadable()) {
263
				// return 403 instead of 404 because a 404 would make
264
				// the caller believe that the collection itself does not exist
265
				throw new Forbidden('No read permissions');
266
			}
267
			$folderContent = $this->getNode()->getDirectoryListing();
268
		} catch (LockedException $e) {
269
			throw new Locked();
270
		}
271
272
		$nodes = [];
273
		foreach ($folderContent as $info) {
274
			$node = $this->getChild($info->getName(), $info);
275
			$nodes[] = $node;
276
		}
277
		$this->dirContent = $nodes;
278
		return $this->dirContent;
279
	}
280
281
	/**
282
	 * Checks if a child exists.
283
	 *
284
	 * @param string $name
285
	 * @return bool
286
	 */
287
	public function childExists($name) {
288
		// note: here we do NOT resolve the chunk file name to the real file name
289
		// to make sure we return false when checking for file existence with a chunk
290
		// file name.
291
		// This is to make sure that "createFile" is still triggered
292
		// (required old code) instead of "updateFile".
293
		//
294
		// TODO: resolve chunk file name here and implement "updateFile"
295
		$path = $this->path . '/' . $name;
296
		return $this->fileView->file_exists($path);
297
	}
298
299
	/**
300
	 * Deletes all files in this directory, and then itself
301
	 *
302
	 * @return void
303
	 * @throws FileLocked
304
	 * @throws \Sabre\DAV\Exception\Forbidden
305
	 */
306
	public function delete() {
307
		if ($this->path === '' || $this->path === '/' || !$this->info->isDeletable()) {
308
			throw new \Sabre\DAV\Exception\Forbidden();
309
		}
310
311
		try {
312
			if (!$this->fileView->rmdir($this->path)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->rmdir($this->path) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
313
				// assume it wasn't possible to remove due to permission issue
314
				throw new \Sabre\DAV\Exception\Forbidden();
315
			}
316
		} catch (ForbiddenException $ex) {
317
			throw new Forbidden($ex->getMessage(), $ex->getRetry());
318
		} catch (LockedException $e) {
319
			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
320
		}
321
	}
322
323
	/**
324
	 * Returns available diskspace information
325
	 *
326
	 * @return array
327
	 */
328
	public function getQuotaInfo() {
329
		if ($this->quotaInfo) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->quotaInfo of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
330
			return $this->quotaInfo;
331
		}
332
		try {
333
			$storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $this->info, false);
334
			if ($storageInfo['quota'] === \OCP\Files\FileInfo::SPACE_UNLIMITED) {
335
				$free = \OCP\Files\FileInfo::SPACE_UNLIMITED;
336
			} else {
337
				$free = $storageInfo['free'];
338
			}
339
			$this->quotaInfo = [
340
				$storageInfo['used'],
341
				$free
342
			];
343
			return $this->quotaInfo;
344
		} catch (\OCP\Files\NotFoundException $e) {
345
			return [0, 0];
346
		} catch (\OCP\Files\StorageNotAvailableException $e) {
347
			return [0, 0];
348
		} catch (NotPermittedException $e) {
349
			return [0, 0];
350
		}
351
	}
352
353
	/**
354
	 * Moves a node into this collection.
355
	 *
356
	 * It is up to the implementors to:
357
	 *   1. Create the new resource.
358
	 *   2. Remove the old resource.
359
	 *   3. Transfer any properties or other data.
360
	 *
361
	 * Generally you should make very sure that your collection can easily move
362
	 * the move.
363
	 *
364
	 * If you don't, just return false, which will trigger sabre/dav to handle
365
	 * the move itself. If you return true from this function, the assumption
366
	 * is that the move was successful.
367
	 *
368
	 * @param string $targetName New local file/collection name.
369
	 * @param string $fullSourcePath Full path to source node
370
	 * @param INode $sourceNode Source node itself
371
	 * @return bool
372
	 * @throws BadRequest
373
	 * @throws ServiceUnavailable
374
	 * @throws Forbidden
375
	 * @throws FileLocked
376
	 * @throws \Sabre\DAV\Exception\Forbidden
377
	 */
378
	public function moveInto($targetName, $fullSourcePath, INode $sourceNode) {
379
		if (!$sourceNode instanceof Node) {
380
			// it's a file of another kind, like FutureFile
381
			if ($sourceNode instanceof IFile) {
382
				// fallback to default copy+delete handling
383
				return false;
384
			}
385
			throw new BadRequest('Incompatible node types');
386
		}
387
388
		if (!$this->fileView) {
389
			throw new ServiceUnavailable('filesystem not setup');
390
		}
391
392
		$destinationPath = $this->getPath() . '/' . $targetName;
393
394
395
		$targetNodeExists = $this->childExists($targetName);
396
397
		// at getNodeForPath we also check the path for isForbiddenFileOrDir
398
		// with that we have covered both source and destination
399
		if ($sourceNode instanceof Directory && $targetNodeExists) {
400
			throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode->getName() . ', target exists');
401
		}
402
403
		[$sourceDir,] = \Sabre\Uri\split($sourceNode->getPath());
404
		$destinationDir = $this->getPath();
405
406
		$sourcePath = $sourceNode->getPath();
407
408
		$isMovableMount = false;
409
		$sourceMount = \OC::$server->getMountManager()->find($this->fileView->getAbsolutePath($sourcePath));
410
		$internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath));
411
		if ($sourceMount instanceof MoveableMount && $internalPath === '') {
412
			$isMovableMount = true;
413
		}
414
415
		try {
416
			$sameFolder = ($sourceDir === $destinationDir);
417
			// if we're overwriting or same folder
418
			if ($targetNodeExists || $sameFolder) {
419
				// note that renaming a share mount point is always allowed
420
				if (!$this->fileView->isUpdatable($destinationDir) && !$isMovableMount) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->isUpdatable($destinationDir) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
421
					throw new \Sabre\DAV\Exception\Forbidden();
422
				}
423
			} else {
424
				if (!$this->fileView->isCreatable($destinationDir)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->isCreatable($destinationDir) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
425
					throw new \Sabre\DAV\Exception\Forbidden();
426
				}
427
			}
428
429
			if (!$sameFolder) {
430
				// moving to a different folder, source will be gone, like a deletion
431
				// note that moving a share mount point is always allowed
432
				if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->isDeletable($sourcePath) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
433
					throw new \Sabre\DAV\Exception\Forbidden();
434
				}
435
			}
436
437
			$fileName = basename($destinationPath);
438
			try {
439
				$this->fileView->verifyPath($destinationDir, $fileName);
440
			} catch (InvalidPathException $ex) {
441
				throw new InvalidPath($ex->getMessage());
442
			}
443
444
			$renameOkay = $this->fileView->rename($sourcePath, $destinationPath);
445
			if (!$renameOkay) {
446
				throw new \Sabre\DAV\Exception\Forbidden('');
447
			}
448
		} catch (StorageNotAvailableException $e) {
449
			throw new ServiceUnavailable($e->getMessage());
450
		} catch (ForbiddenException $ex) {
451
			throw new Forbidden($ex->getMessage(), $ex->getRetry());
452
		} catch (LockedException $e) {
453
			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
454
		}
455
456
		return true;
457
	}
458
459
460
	public function copyInto($targetName, $sourcePath, INode $sourceNode) {
461
		if ($sourceNode instanceof File || $sourceNode instanceof Directory) {
462
			$destinationPath = $this->getPath() . '/' . $targetName;
463
			$sourcePath = $sourceNode->getPath();
464
465
			if (!$this->fileView->isCreatable($this->getPath())) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fileView->isCreatable($this->getPath()) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
466
				throw new \Sabre\DAV\Exception\Forbidden();
467
			}
468
469
			try {
470
				$this->fileView->verifyPath($this->getPath(), $targetName);
471
			} catch (InvalidPathException $ex) {
472
				throw new InvalidPath($ex->getMessage());
473
			}
474
475
			return $this->fileView->copy($sourcePath, $destinationPath);
476
		}
477
478
		return false;
479
	}
480
481
	public function getNode(): Folder {
482
		return $this->node;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->node returns the type OCP\Files\Node which includes types incompatible with the type-hinted return OCP\Files\Folder.
Loading history...
483
	}
484
}
485