Completed
Push — stable8.2 ( 54f8ec...bbfc5b )
by Morris
66:52
created

Updater::rename()   C

Complexity

Conditions 11
Paths 13

Size

Total Lines 46
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 11.0036

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 46
ccs 31
cts 32
cp 0.9688
rs 5.2653
cc 11
eloc 27
nc 13
nop 2
crap 11.0036

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
 * @author Björn Schießle <[email protected]>
4
 * @author Michael Gapczynski <[email protected]>
5
 * @author Morris Jobke <[email protected]>
6
 * @author Robin Appelman <[email protected]>
7
 * @author Vincent Petry <[email protected]>
8
 *
9
 * @copyright Copyright (c) 2015, ownCloud, Inc.
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OC\Files\Cache;
27
use OC\Files\View;
28
29
/**
30
 * Update the cache and propagate changes
31
 *
32
 * Unlike most other classes an Updater is not related to a specific storage but handles updates for all storages in a users filesystem.
33
 * This is needed because the propagation of mtime and etags need to cross storage boundaries
34
 */
35
class Updater {
36
	/**
37
	 * @var bool
38
	 */
39
	protected $enabled = true;
40
41
	/**
42
	 * @var \OC\Files\View
43
	 */
44
	protected $view;
45
46
	/**
47
	 * @var \OC\Files\Cache\ChangePropagator
48
	 */
49
	protected $propagator;
50
51
	/**
52
	 * @var null|View
53
	 */
54
	protected $propagatorView;
55
56
	/**
57
	 * @param \OC\Files\View $view the view the updater works on, usually the view of the logged in user
58
	 * @param View | null $userView
59
	 */
60 1421
	public function __construct(View $view, $userView = null) {
61 1421
		$this->view = $view;
62
63
		// use the userview if the view is a subfolder
64 1421
		if ($userView && $userView->getRelativePath($view->getRoot())) {
65 578
			$this->propagatorView = $userView;
66 578
			$this->propagator = new ChangePropagator($userView);
67 578
		} else {
68 1421
			$this->propagatorView = $view;
69 1421
			$this->propagator = new ChangePropagator($view);
70
		}
71 1421
	}
72
73 824
	protected function getPropagatorPath($path) {
74 824
		return $this->propagatorView->getRelativePath($this->view->getAbsolutePath($path));
75
	}
76
77
	/**
78
	 * Disable updating the cache trough this updater
79
	 */
80 6
	public function disable() {
81 6
		$this->enabled = false;
82 6
	}
83
84
	/**
85
	 * Re-enable the updating of the cache trough this updater
86
	 */
87
	public function enable() {
88
		$this->enabled = true;
89
	}
90
91
	/**
92
	 * Get the propagator for etags and mtime for the view the updater works on
93
	 *
94
	 * @return ChangePropagator
95
	 */
96 418
	public function getPropagator() {
97 418
		return $this->propagator;
98
	}
99
100
	/**
101
	 * Propagate etag and mtime changes for the parent folders of $path up to the root of the filesystem
102
	 *
103
	 * @param string $path the path of the file to propagate the changes for
104
	 * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used
105
	 */
106 3
	public function propagate($path, $time = null) {
107 3
		if (Scanner::isPartialFile($path)) {
108
			return;
109
		}
110 3
		$this->propagator->addChange($this->getPropagatorPath($path));
111 3
		$this->propagator->propagateChanges($time);
112 3
	}
113
114
	/**
115
	 * Update the cache for $path and update the size, etag and mtime of the parent folders
116
	 *
117
	 * @param string $path
118
	 * @param int $time
119
	 */
120 823
	public function update($path, $time = null) {
121 823
		if (!$this->enabled or Scanner::isPartialFile($path)) {
122 30
			return;
123
		}
124
		/**
125
		 * @var \OC\Files\Storage\Storage $storage
126
		 * @var string $internalPath
127
		 */
128 822
		list($storage, $internalPath) = $this->view->resolvePath($path);
129 822
		if ($storage) {
130 822
			$this->propagator->addChange($this->getPropagatorPath($path));
131 822
			$cache = $storage->getCache($internalPath);
132 822
			$scanner = $storage->getScanner($internalPath);
133 822
			$data = $scanner->scan($internalPath, Scanner::SCAN_SHALLOW, -1, false);
134 822
			$this->correctParentStorageMtime($storage, $internalPath);
135 822
			$cache->correctFolderSize($internalPath, $data);
136 822
			$this->propagator->propagateChanges($time);
137 822
		}
138 822
	}
139
140
	/**
141
	 * Remove $path from the cache and update the size, etag and mtime of the parent folders
142
	 *
143
	 * @param string $path
144
	 */
145 273
	public function remove($path) {
146 273
		if (!$this->enabled or Scanner::isPartialFile($path)) {
147
			return;
148
		}
149
		/**
150
		 * @var \OC\Files\Storage\Storage $storage
151
		 * @var string $internalPath
152
		 */
153 273
		list($storage, $internalPath) = $this->view->resolvePath($path);
154 273
		if ($storage) {
155 273
			$parent = dirname($internalPath);
156 273
			if ($parent === '.') {
157 51
				$parent = '';
158 51
			}
159 273
			$this->propagator->addChange($this->getPropagatorPath($path));
160 273
			$cache = $storage->getCache($internalPath);
161 273
			$cache->remove($internalPath);
162 273
			$cache->correctFolderSize($parent);
163 273
			$this->correctParentStorageMtime($storage, $internalPath);
164 273
			$this->propagator->propagateChanges();
165 273
		}
166 273
	}
167
168
	/**
169
	 * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders
170
	 *
171
	 * @param string $source
172
	 * @param string $target
173
	 */
174 89
	public function rename($source, $target) {
175 89
		if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) {
176 2
			return;
177
		}
178
		/**
179
		 * @var \OC\Files\Storage\Storage $sourceStorage
180
		 * @var \OC\Files\Storage\Storage $targetStorage
181
		 * @var string $sourceInternalPath
182
		 * @var string $targetInternalPath
183
		 */
184 87
		list($sourceStorage, $sourceInternalPath) = $this->view->resolvePath($source);
185
		// if it's a moved mountpoint we dont need to do anything
186 87
		if ($sourceInternalPath === '') {
187
			return;
188
		}
189 87
		list($targetStorage, $targetInternalPath) = $this->view->resolvePath($target);
190
191 87
		if ($sourceStorage && $targetStorage) {
192 87
			$targetCache = $targetStorage->getCache($sourceInternalPath);
193 87
			if ($sourceStorage->getCache($sourceInternalPath)->inCache($sourceInternalPath)) {
194 86
				if ($targetCache->inCache($targetInternalPath)) {
195 11
					$targetCache->remove($targetInternalPath);
196 11
				}
197 86
				if ($sourceStorage === $targetStorage) {
198 75
					$targetCache->move($sourceInternalPath, $targetInternalPath);
199 75
				} else {
200 17
					$targetCache->moveFromCache($sourceStorage->getCache(), $sourceInternalPath, $targetInternalPath);
201
				}
202 86
			}
203
204 87
			if (pathinfo($sourceInternalPath, PATHINFO_EXTENSION) !== pathinfo($targetInternalPath, PATHINFO_EXTENSION)) {
205
				// handle mime type change
206 55
				$mimeType = $targetStorage->getMimeType($targetInternalPath);
207 55
				$fileId = $targetCache->getId($targetInternalPath);
208 55
				$targetCache->update($fileId, array('mimetype' => $mimeType));
209 55
			}
210
211 87
			$targetCache->correctFolderSize($sourceInternalPath);
212 87
			$targetCache->correctFolderSize($targetInternalPath);
213 87
			$this->correctParentStorageMtime($sourceStorage, $sourceInternalPath);
214 87
			$this->correctParentStorageMtime($targetStorage, $targetInternalPath);
215 87
			$this->propagator->addChange($this->getPropagatorPath($source));
216 87
			$this->propagator->addChange($this->getPropagatorPath($target));
217 87
			$this->propagator->propagateChanges();
218 87
		}
219 87
	}
220
221
	/**
222
	 * update the storage_mtime of the direct parent in the cache to the mtime from the storage
223
	 *
224
	 * @param \OC\Files\Storage\Storage $storage
225
	 * @param string $internalPath
226
	 */
227 824
	private function correctParentStorageMtime($storage, $internalPath) {
228 824
		$cache = $storage->getCache();
229 824
		$parentId = $cache->getParentId($internalPath);
230 824
		$parent = dirname($internalPath);
231 824
		if ($parentId != -1) {
232 823
			$cache->update($parentId, array('storage_mtime' => $storage->filemtime($parent)));
233 823
		}
234 824
	}
235
236 211
	public function __destruct() {
237
		// propagate any leftover changes
238 211
		$this->propagator->propagateChanges();
239 211
	}
240
}
241