Completed
Push — stable8 ( 8f42a1...86a71c )
by Thomas
25:36
created

ObjectTree::copy()   D

Complexity

Conditions 10
Paths 27

Size

Total Lines 38
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 23
c 2
b 0
f 0
nc 27
nop 2
dl 0
loc 38
rs 4.8196

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Copyright (c) 2013 Robin Appelman <[email protected]>
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later.
6
 * See the COPYING-README file.
7
 */
8
9
namespace OC\Connector\Sabre;
10
11
use OC\Files\FileInfo;
12
use OC\Files\Filesystem;
13
use OC\Files\Mount\MoveableMount;
14
use OCP\Files\StorageInvalidException;
15
use OCP\Files\StorageNotAvailableException;
16
17
class ObjectTree extends \Sabre\DAV\ObjectTree {
18
19
	/**
20
	 * @var \OC\Files\View
21
	 */
22
	protected $fileView;
23
24
	/**
25
	 * @var \OC\Files\Mount\Manager
26
	 */
27
	protected $mountManager;
28
29
	/**
30
	 * Creates the object
31
	 *
32
	 * This method expects the rootObject to be passed as a parameter
33
	 */
34
	public function __construct() {
35
	}
36
37
	/**
38
	 * @param \Sabre\DAV\INode $rootNode
39
	 * @param \OC\Files\View $view
40
	 * @param \OC\Files\Mount\Manager $mountManager
41
	 */
42
	public function init(\Sabre\DAV\INode $rootNode, \OC\Files\View $view, \OC\Files\Mount\Manager $mountManager) {
43
		$this->rootNode = $rootNode;
44
		$this->fileView = $view;
45
		$this->mountManager = $mountManager;
46
	}
47
48
	/**
49
	 * Returns the INode object for the requested path
50
	 *
51
	 * @param string $path
52
	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
53
	 * @throws \Sabre\DAV\Exception\NotFound
54
	 * @return \Sabre\DAV\INode
55
	 */
56
	public function getNodeForPath($path) {
57
		if (!$this->fileView) {
58
			throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup');
59
		}
60
61
		$path = trim($path, '/');
62
		if (isset($this->cache[$path])) {
63
			return $this->cache[$path];
64
		}
65
66
		// Is it the root node?
67
		if (!strlen($path)) {
68
			return $this->rootNode;
69
		}
70
71
		if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
72
			// read from storage
73
			$absPath = $this->fileView->getAbsolutePath($path);
74
			$mount = $this->fileView->getMount($path);
75
			$storage = $mount->getStorage();
76
			$internalPath = $mount->getInternalPath($absPath);
77
			if ($storage) {
78
				/**
79
				 * @var \OC\Files\Storage\Storage $storage
80
				 */
81
				$scanner = $storage->getScanner($internalPath);
82
				// get data directly
83
				$data = $scanner->getData($internalPath);
84
				$info = new FileInfo($absPath, $storage, $internalPath, $data, $mount);
0 ignored issues
show
Bug introduced by
It seems like $data defined by $scanner->getData($internalPath) on line 83 can also be of type null; however, OC\Files\FileInfo::__construct() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by
It seems like $mount defined by $this->fileView->getMount($path) on line 74 can be null; however, OC\Files\FileInfo::__construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
85
			} else {
86
				$info = null;
87
			}
88
		} else {
89
			// read from cache
90
			try {
91
				$info = $this->fileView->getFileInfo($path);
92
			} catch (StorageNotAvailableException $e) {
93
				throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available');
94
			} catch (StorageInvalidException $e){
95
				throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid');
96
			}
97
		}
98
99
		if (!$info) {
100
			throw new \Sabre\DAV\Exception\NotFound('File with name ' . $path . ' could not be located');
101
		}
102
103
		if ($info->getType() === 'dir') {
104
			$node = new \OC_Connector_Sabre_Directory($this->fileView, $info);
105
		} else {
106
			$node = new \OC_Connector_Sabre_File($this->fileView, $info);
107
		}
108
109
		$this->cache[$path] = $node;
110
		return $node;
111
112
	}
113
114
	/**
115
	 * Moves a file from one location to another
116
	 *
117
	 * @param string $sourcePath The path to the file which should be moved
118
	 * @param string $destinationPath The full destination path, so not just the destination parent node
119
	 * @throws \Sabre\DAV\Exception\BadRequest
120
	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
121
	 * @throws \Sabre\DAV\Exception\Forbidden
122
	 * @return int
123
	 */
124
	public function move($sourcePath, $destinationPath) {
125
		if (!$this->fileView) {
126
			throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup');
127
		}
128
129
		$targetNodeExists = $this->nodeExists($destinationPath);
130
		$sourceNode = $this->getNodeForPath($sourcePath);
131
		if ($sourceNode instanceof \Sabre\DAV\ICollection && $targetNodeExists) {
0 ignored issues
show
Bug introduced by
The class Sabre\DAV\ICollection does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
132
			throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists');
133
		}
134
		list($sourceDir,) = \Sabre\DAV\URLUtil::splitPath($sourcePath);
135
		list($destinationDir,) = \Sabre\DAV\URLUtil::splitPath($destinationPath);
136
137
		$isMovableMount = false;
138
		$sourceMount = $this->mountManager->find($this->fileView->getAbsolutePath($sourcePath));
139
		$internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath));
140
		if ($sourceMount instanceof MoveableMount && $internalPath === '') {
141
			$isMovableMount = true;
142
		}
143
144
		try {
145
			$sameFolder = ($sourceDir === $destinationDir);
146
			// if we're overwriting or same folder
147
			if ($targetNodeExists || $sameFolder) {
148
				// note that renaming a share mount point is always allowed
149
				if (!$this->fileView->isUpdatable($destinationDir) && !$isMovableMount) {
150
					throw new \Sabre\DAV\Exception\Forbidden();
151
				}
152
			} else {
153
				if (!$this->fileView->isCreatable($destinationDir)) {
154
					throw new \Sabre\DAV\Exception\Forbidden();
155
				}
156
			}
157
158
			if (!$sameFolder) {
159
				// moving to a different folder, source will be gone, like a deletion
160
				// note that moving a share mount point is always allowed
161
				if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) {
162
					throw new \Sabre\DAV\Exception\Forbidden();
163
				}
164
			}
165
166
			$fileName = basename($destinationPath);
167
			if (!\OCP\Util::isValidFileName($fileName)) {
168
				throw new \Sabre\DAV\Exception\BadRequest();
169
			}
170
171
			$renameOkay = $this->fileView->rename($sourcePath, $destinationPath);
172
			if (!$renameOkay) {
173
				throw new \Sabre\DAV\Exception\Forbidden('');
174
			}
175
		} catch (\OCP\Files\StorageNotAvailableException $e) {
176
			throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
177
		}
178
179
		// update properties
180
		$query = \OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?'
181
			. ' WHERE `userid` = ? AND `propertypath` = ?');
182
		$query->execute(array(\OC\Files\Filesystem::normalizePath($destinationPath), \OC_User::getUser(),
183
			\OC\Files\Filesystem::normalizePath($sourcePath)));
184
185
		$this->markDirty($sourceDir);
186
		$this->markDirty($destinationDir);
187
188
	}
189
190
	/**
191
	 * Copies a file or directory.
192
	 *
193
	 * This method must work recursively and delete the destination
194
	 * if it exists
195
	 *
196
	 * @param string $source
197
	 * @param string $destination
198
	 * @throws \Sabre\DAV\Exception\ServiceUnavailable
199
	 * @return void
200
	 */
201
	public function copy($source, $destination) {
202
		if (!$this->fileView) {
203
			throw new \Sabre\DAV\Exception\ServiceUnavailable('filesystem not setup');
204
		}
205
206
		// this will trigger existence check
207
		$this->getNodeForPath($source);
208
209
		$destinationDir = dirname($destination);
210
		if ($destinationDir === '.') {
211
			$destinationDir = '';
212
		}
213
		if (!$this->fileView->isCreatable($destinationDir)) {
214
			throw new \Sabre\DAV\Exception\Forbidden();
215
		}
216
217
		try {
218
			if ($this->fileView->is_file($source)) {
219
				$this->fileView->copy($source, $destination);
220
			} else {
221
				$this->fileView->mkdir($destination);
222
				$dh = $this->fileView->opendir($source);
223
				if (is_resource($dh)) {
224
					while (($subNode = readdir($dh)) !== false) {
225
226
						if ($subNode == '.' || $subNode == '..') continue;
227
						$this->copy($source . '/' . $subNode, $destination . '/' . $subNode);
228
229
					}
230
				}
231
			}
232
		} catch (\OCP\Files\StorageNotAvailableException $e) {
233
			throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
234
		}
235
236
		list($destinationDir,) = \Sabre\DAV\URLUtil::splitPath($destination);
237
		$this->markDirty($destinationDir);
238
	}
239
}
240