Passed
Push — master ( 64fb08...abeea8 )
by Morris
19:26
created

Quota::touch()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Jörn Friedrich Dreyer <[email protected]>
6
 * @author Lukas Reschke <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Robin Appelman <[email protected]>
9
 * @author Robin McCorkell <[email protected]>
10
 * @author Vincent Petry <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OC\Files\Storage\Wrapper;
29
30
use OCP\Files\Cache\ICacheEntry;
31
use OCP\Files\Storage\IStorage;
32
33
class Quota extends Wrapper {
34
35
	/**
36
	 * @var int $quota
37
	 */
38
	protected $quota;
39
40
	/**
41
	 * @var string $sizeRoot
42
	 */
43
	protected $sizeRoot;
44
45
	/**
46
	 * @param array $parameters
47
	 */
48
	public function __construct($parameters) {
49
		parent::__construct($parameters);
50
		$this->quota = $parameters['quota'];
51
		$this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
52
	}
53
54
	/**
55
	 * @return int quota value
56
	 */
57
	public function getQuota() {
58
		return $this->quota;
59
	}
60
61
	/**
62
	 * @param string $path
63
	 * @param \OC\Files\Storage\Storage $storage
64
	 */
65
	protected function getSize($path, $storage = null) {
66
		if (is_null($storage)) {
67
			$cache = $this->getCache();
68
		} else {
69
			$cache = $storage->getCache();
70
		}
71
		$data = $cache->get($path);
72
		if ($data instanceof ICacheEntry and isset($data['size'])) {
73
			return $data['size'];
74
		} else {
75
			return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
76
		}
77
	}
78
79
	/**
80
	 * Get free space as limited by the quota
81
	 *
82
	 * @param string $path
83
	 * @return int
84
	 */
85
	public function free_space($path) {
86
		if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
87
			return $this->storage->free_space($path);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->storage->free_space($path) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
88
		} else {
89
			$used = $this->getSize($this->sizeRoot);
90
			if ($used < 0) {
91
				return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
92
			} else {
93
				$free = $this->storage->free_space($path);
94
				$quotaFree = max($this->quota - $used, 0);
95
				// if free space is known
96
				if ($free >= 0) {
97
					$free = min($free, $quotaFree);
98
				} else {
99
					$free = $quotaFree;
100
				}
101
				return $free;
102
			}
103
		}
104
	}
105
106
	/**
107
	 * see http://php.net/manual/en/function.file_put_contents.php
108
	 *
109
	 * @param string $path
110
	 * @param string $data
111
	 * @return bool
112
	 */
113
	public function file_put_contents($path, $data) {
114
		$free = $this->free_space($path);
115
		if ($free < 0 or strlen($data) < $free) {
116
			return $this->storage->file_put_contents($path, $data);
117
		} else {
118
			return false;
119
		}
120
	}
121
122
	/**
123
	 * see http://php.net/manual/en/function.copy.php
124
	 *
125
	 * @param string $source
126
	 * @param string $target
127
	 * @return bool
128
	 */
129
	public function copy($source, $target) {
130
		$free = $this->free_space($target);
131
		if ($free < 0 or $this->getSize($source) < $free) {
132
			return $this->storage->copy($source, $target);
133
		} else {
134
			return false;
135
		}
136
	}
137
138
	/**
139
	 * see http://php.net/manual/en/function.fopen.php
140
	 *
141
	 * @param string $path
142
	 * @param string $mode
143
	 * @return resource
144
	 */
145
	public function fopen($path, $mode) {
146
		$source = $this->storage->fopen($path, $mode);
147
148
		// don't apply quota for part files
149
		if (!$this->isPartFile($path)) {
150
			$free = $this->free_space($path);
151
			if ($source && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
0 ignored issues
show
introduced by
$source is of type false|resource, thus it always evaluated to false.
Loading history...
152
				// only apply quota for files, not metadata, trash or others
153
				if (strpos(ltrim($path, '/'), 'files/') === 0) {
154
					return \OC\Files\Stream\Quota::wrap($source, $free);
155
				}
156
			}
157
		}
158
		return $source;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $source could also return false which is incompatible with the documented return type resource. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
159
	}
160
161
	/**
162
	 * Checks whether the given path is a part file
163
	 *
164
	 * @param string $path Path that may identify a .part file
165
	 * @return string File path without .part extension
166
	 * @note this is needed for reusing keys
167
	 */
168
	private function isPartFile($path) {
169
		$extension = pathinfo($path, PATHINFO_EXTENSION);
170
171
		return ($extension === 'part');
0 ignored issues
show
Bug Best Practice introduced by
The expression return $extension === 'part' returns the type boolean which is incompatible with the documented return type string.
Loading history...
172
	}
173
174
	/**
175
	 * @param IStorage $sourceStorage
176
	 * @param string $sourceInternalPath
177
	 * @param string $targetInternalPath
178
	 * @return bool
179
	 */
180
	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
181
		$free = $this->free_space($targetInternalPath);
182
		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
183
			return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
184
		} else {
185
			return false;
186
		}
187
	}
188
189
	/**
190
	 * @param IStorage $sourceStorage
191
	 * @param string $sourceInternalPath
192
	 * @param string $targetInternalPath
193
	 * @return bool
194
	 */
195
	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
196
		$free = $this->free_space($targetInternalPath);
197
		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
198
			return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
199
		} else {
200
			return false;
201
		}
202
	}
203
204
	public function mkdir($path) {
205
		$free = $this->free_space($path);
206
		if ($free === 0.0) {
207
			return false;
208
		}
209
210
		return parent::mkdir($path);
211
	}
212
213
	public function touch($path, $mtime = null) {
214
		$free = $this->free_space($path);
215
		if ($free === 0.0) {
216
			return false;
217
		}
218
219
		return parent::touch($path, $mtime);
220
	}
221
222
}
223