Passed
Push — master ( 927582...173f8a )
by Morris
11:22 queued 17s
created

Updater::disable()   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 Björn Schießle <[email protected]>
6
 * @author Christoph Wurst <[email protected]>
7
 * @author Daniel Jagszent <[email protected]>
8
 * @author Michael Gapczynski <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Vincent Petry <[email protected]>
12
 *
13
 * @license AGPL-3.0
14
 *
15
 * This code is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License, version 3,
17
 * as published by the Free Software Foundation.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public License, version 3,
25
 * along with this program. If not, see <http://www.gnu.org/licenses/>
26
 *
27
 */
28
29
namespace OC\Files\Cache;
30
31
use OC\Files\FileInfo;
32
use OCP\Files\Cache\ICacheEntry;
33
use OCP\Files\Cache\IUpdater;
34
use OCP\Files\Storage\IStorage;
35
36
/**
37
 * Update the cache and propagate changes
38
 *
39
 */
40
class Updater implements IUpdater {
41
	/**
42
	 * @var bool
43
	 */
44
	protected $enabled = true;
45
46
	/**
47
	 * @var \OC\Files\Storage\Storage
48
	 */
49
	protected $storage;
50
51
	/**
52
	 * @var \OC\Files\Cache\Propagator
53
	 */
54
	protected $propagator;
55
56
	/**
57
	 * @var Scanner
58
	 */
59
	protected $scanner;
60
61
	/**
62
	 * @var Cache
63
	 */
64
	protected $cache;
65
66
	/**
67
	 * @param \OC\Files\Storage\Storage $storage
68
	 */
69
	public function __construct(\OC\Files\Storage\Storage $storage) {
70
		$this->storage = $storage;
71
		$this->propagator = $storage->getPropagator();
72
		$this->scanner = $storage->getScanner();
73
		$this->cache = $storage->getCache();
74
	}
75
76
	/**
77
	 * Disable updating the cache trough this updater
78
	 */
79
	public function disable() {
80
		$this->enabled = false;
81
	}
82
83
	/**
84
	 * Re-enable the updating of the cache trough this updater
85
	 */
86
	public function enable() {
87
		$this->enabled = true;
88
	}
89
90
	/**
91
	 * Get the propagator for etags and mtime for the view the updater works on
92
	 *
93
	 * @return Propagator
94
	 */
95
	public function getPropagator() {
96
		return $this->propagator;
97
	}
98
99
	/**
100
	 * Propagate etag and mtime changes for the parent folders of $path up to the root of the filesystem
101
	 *
102
	 * @param string $path the path of the file to propagate the changes for
103
	 * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used
104
	 */
105
	public function propagate($path, $time = null) {
106
		if (Scanner::isPartialFile($path)) {
107
			return;
108
		}
109
		$this->propagator->propagateChange($path, $time);
110
	}
111
112
	/**
113
	 * Update the cache for $path and update the size, etag and mtime of the parent folders
114
	 *
115
	 * @param string $path
116
	 * @param int $time
117
	 */
118
	public function update($path, $time = null) {
119
		if (!$this->enabled or Scanner::isPartialFile($path)) {
120
			return;
121
		}
122
		if (is_null($time)) {
123
			$time = time();
124
		}
125
126
		$data = $this->scanner->scan($path, Scanner::SCAN_SHALLOW, -1, false);
127
		if (
128
			isset($data['oldSize']) && isset($data['size']) &&
129
			!$data['encrypted'] // encryption is a pita and touches the cache itself
130
		) {
131
			$sizeDifference = $data['size'] - $data['oldSize'];
132
		} else {
133
			// scanner didn't provide size info, fallback to full size calculation
134
			$sizeDifference = 0;
135
			if ($this->cache instanceof Cache) {
0 ignored issues
show
introduced by
$this->cache is always a sub-type of OC\Files\Cache\Cache.
Loading history...
136
				$this->cache->correctFolderSize($path, $data);
137
			}
138
		}
139
		$this->correctParentStorageMtime($path);
140
		$this->propagator->propagateChange($path, $time, $sizeDifference);
141
	}
142
143
	/**
144
	 * Remove $path from the cache and update the size, etag and mtime of the parent folders
145
	 *
146
	 * @param string $path
147
	 */
148
	public function remove($path) {
149
		if (!$this->enabled or Scanner::isPartialFile($path)) {
150
			return;
151
		}
152
153
		$parent = dirname($path);
154
		if ($parent === '.') {
155
			$parent = '';
156
		}
157
158
		$entry = $this->cache->get($path);
159
160
		$this->cache->remove($path);
161
162
		$this->correctParentStorageMtime($path);
163
		if ($entry instanceof ICacheEntry) {
164
			$this->propagator->propagateChange($path, time(), -$entry->getSize());
165
		} else {
166
			$this->propagator->propagateChange($path, time());
167
			if ($this->cache instanceof Cache) {
0 ignored issues
show
introduced by
$this->cache is always a sub-type of OC\Files\Cache\Cache.
Loading history...
168
				$this->cache->correctFolderSize($parent);
169
			}
170
		}
171
	}
172
173
	/**
174
	 * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders
175
	 *
176
	 * @param IStorage $sourceStorage
177
	 * @param string $source
178
	 * @param string $target
179
	 */
180
	public function renameFromStorage(IStorage $sourceStorage, $source, $target) {
181
		if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) {
182
			return;
183
		}
184
185
		$time = time();
186
187
		$sourceCache = $sourceStorage->getCache();
188
		$sourceUpdater = $sourceStorage->getUpdater();
189
		$sourcePropagator = $sourceStorage->getPropagator();
190
191
		$sourceInfo = $sourceCache->get($source);
192
193
		if ($sourceInfo !== false) {
194
			if ($this->cache->inCache($target)) {
195
				$this->cache->remove($target);
196
			}
197
198
			if ($sourceStorage === $this->storage) {
0 ignored issues
show
introduced by
The condition $sourceStorage === $this->storage is always false.
Loading history...
199
				$this->cache->move($source, $target);
200
			} else {
201
				$this->cache->moveFromCache($sourceCache, $source, $target);
202
			}
203
204
			if (pathinfo($source, PATHINFO_EXTENSION) !== pathinfo($target, PATHINFO_EXTENSION) && $sourceInfo->getMimeType() !== FileInfo::MIMETYPE_FOLDER) {
205
				// handle mime type change
206
				$mimeType = $this->storage->getMimeType($target);
207
				$fileId = $this->cache->getId($target);
208
				$this->cache->update($fileId, ['mimetype' => $mimeType]);
209
			}
210
		}
211
212
		if ($sourceCache instanceof Cache) {
213
			$sourceCache->correctFolderSize($source);
214
		}
215
		if ($this->cache instanceof Cache) {
0 ignored issues
show
introduced by
$this->cache is always a sub-type of OC\Files\Cache\Cache.
Loading history...
216
			$this->cache->correctFolderSize($target);
217
		}
218
		if ($sourceUpdater instanceof Updater) {
219
			$sourceUpdater->correctParentStorageMtime($source);
220
		}
221
		$this->correctParentStorageMtime($target);
222
		$this->updateStorageMTimeOnly($target);
223
		$sourcePropagator->propagateChange($source, $time);
224
		$this->propagator->propagateChange($target, $time);
225
	}
226
227
	private function updateStorageMTimeOnly($internalPath) {
228
		$fileId = $this->cache->getId($internalPath);
229
		if ($fileId !== -1) {
230
			$mtime = $this->storage->filemtime($internalPath);
231
			if ($mtime !== false) {
232
				$this->cache->update(
233
					$fileId, [
234
						'mtime' => null, // this magic tells it to not overwrite mtime
235
						'storage_mtime' => $mtime
236
					]
237
				);
238
			}
239
		}
240
	}
241
242
	/**
243
	 * update the storage_mtime of the direct parent in the cache to the mtime from the storage
244
	 *
245
	 * @param string $internalPath
246
	 */
247
	private function correctParentStorageMtime($internalPath) {
248
		$parentId = $this->cache->getParentId($internalPath);
249
		$parent = dirname($internalPath);
250
		if ($parentId != -1) {
251
			$mtime = $this->storage->filemtime($parent);
252
			if ($mtime !== false) {
253
				$this->cache->update($parentId, ['storage_mtime' => $mtime]);
254
			}
255
		}
256
	}
257
}
258