Passed
Push — master ( 76c318...963d96 )
by Morris
88:25 queued 74:01
created

FileInfo::getData()   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 1 Man Projects <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Julius Härtl <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Piotr M <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Robin McCorkell <[email protected]>
13
 * @author Roeland Jago Douma <[email protected]>
14
 * @author tbartenstein <[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
34
namespace OC\Files;
35
36
use OCP\Files\Cache\ICacheEntry;
37
use OCP\Files\Mount\IMountPoint;
38
use OCP\IUser;
39
40
class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess {
41
	/**
42
	 * @var array $data
43
	 */
44
	private $data;
45
46
	/**
47
	 * @var string $path
48
	 */
49
	private $path;
50
51
	/**
52
	 * @var \OC\Files\Storage\Storage $storage
53
	 */
54
	private $storage;
55
56
	/**
57
	 * @var string $internalPath
58
	 */
59
	private $internalPath;
60
61
	/**
62
	 * @var \OCP\Files\Mount\IMountPoint
63
	 */
64
	private $mount;
65
66
	/**
67
	 * @var IUser
68
	 */
69
	private $owner;
70
71
	/**
72
	 * @var string[]
73
	 */
74
	private $childEtags = [];
75
76
	/**
77
	 * @var IMountPoint[]
78
	 */
79
	private $subMounts = [];
80
81
	private $subMountsUsed = false;
82
83
	/**
84
	 * @param string|boolean $path
85
	 * @param Storage\Storage $storage
86
	 * @param string $internalPath
87
	 * @param array|ICacheEntry $data
88
	 * @param \OCP\Files\Mount\IMountPoint $mount
89
	 * @param \OCP\IUser|null $owner
90
	 */
91
	public function __construct($path, $storage, $internalPath, $data, $mount, $owner= null) {
92
		$this->path = $path;
0 ignored issues
show
Documentation Bug introduced by
It seems like $path can also be of type boolean. However, the property $path is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
93
		$this->storage = $storage;
94
		$this->internalPath = $internalPath;
95
		$this->data = $data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $data can also be of type OCP\Files\Cache\ICacheEntry. However, the property $data is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
96
		$this->mount = $mount;
97
		$this->owner = $owner;
98
	}
99
100
	public function offsetSet($offset, $value) {
101
		$this->data[$offset] = $value;
102
	}
103
104
	public function offsetExists($offset) {
105
		return isset($this->data[$offset]);
106
	}
107
108
	public function offsetUnset($offset) {
109
		unset($this->data[$offset]);
110
	}
111
112
	public function offsetGet($offset) {
113
		if ($offset === 'type') {
114
			return $this->getType();
115
		} else if ($offset === 'etag') {
116
			return $this->getEtag();
117
		} else if ($offset === 'size') {
118
			return $this->getSize();
119
		} else if ($offset === 'mtime') {
120
			return $this->getMTime();
121
		} elseif ($offset === 'permissions') {
122
			return $this->getPermissions();
123
		} elseif (isset($this->data[$offset])) {
124
			return $this->data[$offset];
125
		} else {
126
			return null;
127
		}
128
	}
129
130
	/**
131
	 * @return string
132
	 */
133
	public function getPath() {
134
		return $this->path;
135
	}
136
137
	/**
138
	 * @return \OCP\Files\Storage
139
	 */
140
	public function getStorage() {
141
		return $this->storage;
142
	}
143
144
	/**
145
	 * @return string
146
	 */
147
	public function getInternalPath() {
148
		return $this->internalPath;
149
	}
150
151
	/**
152
	 * Get FileInfo ID or null in case of part file
153
	 *
154
	 * @return int|null
155
	 */
156
	public function getId() {
157
		return isset($this->data['fileid']) ? (int)  $this->data['fileid'] : null;
158
	}
159
160
	/**
161
	 * @return string
162
	 */
163
	public function getMimetype() {
164
		return $this->data['mimetype'];
165
	}
166
167
	/**
168
	 * @return string
169
	 */
170
	public function getMimePart() {
171
		return $this->data['mimepart'];
172
	}
173
174
	/**
175
	 * @return string
176
	 */
177
	public function getName() {
178
		return isset($this->data['name']) ? $this->data['name'] : basename($this->getPath());
179
	}
180
181
	/**
182
	 * @return string
183
	 */
184
	public function getEtag() {
185
		$this->updateEntryfromSubMounts();
186
		if (count($this->childEtags) > 0) {
187
			$combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags);
188
			return md5($combinedEtag);
189
		} else {
190
			return $this->data['etag'];
191
		}
192
	}
193
194
	/**
195
	 * @return int
196
	 */
197
	public function getSize() {
198
		$this->updateEntryfromSubMounts();
199
		return isset($this->data['size']) ? 0 + $this->data['size'] : 0;
200
	}
201
202
	/**
203
	 * @return int
204
	 */
205
	public function getMTime() {
206
		$this->updateEntryfromSubMounts();
207
		return (int) $this->data['mtime'];
208
	}
209
210
	/**
211
	 * @return bool
212
	 */
213
	public function isEncrypted() {
214
		return $this->data['encrypted'];
215
	}
216
217
	/**
218
	 * Return the currently version used for the HMAC in the encryption app
219
	 *
220
	 * @return int
221
	 */
222
	public function getEncryptedVersion() {
223
		return isset($this->data['encryptedVersion']) ? (int) $this->data['encryptedVersion'] : 1;
224
	}
225
226
	/**
227
	 * @return int
228
	 */
229
	public function getPermissions() {
230
		$perms = (int) $this->data['permissions'];
231
		if (\OCP\Util::isSharingDisabledForUser() || ($this->isShared() && !\OC\Share\Share::isResharingAllowed())) {
0 ignored issues
show
Deprecated Code introduced by
The function OCP\Util::isSharingDisabledForUser() has been deprecated: 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

231
		if (/** @scrutinizer ignore-deprecated */ \OCP\Util::isSharingDisabledForUser() || ($this->isShared() && !\OC\Share\Share::isResharingAllowed())) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
232
			$perms = $perms & ~\OCP\Constants::PERMISSION_SHARE;
233
		}
234
		return (int) $perms;
235
	}
236
237
	/**
238
	 * @return string \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER
239
	 */
240
	public function getType() {
241
		if (!isset($this->data['type'])) {
242
			$this->data['type'] = ($this->getMimetype() === 'httpd/unix-directory') ? self::TYPE_FOLDER : self::TYPE_FILE;
243
		}
244
		return $this->data['type'];
245
	}
246
247
	public function getData() {
248
		return $this->data;
249
	}
250
251
	/**
252
	 * @param int $permissions
253
	 * @return bool
254
	 */
255
	protected function checkPermissions($permissions) {
256
		return ($this->getPermissions() & $permissions) === $permissions;
257
	}
258
259
	/**
260
	 * @return bool
261
	 */
262
	public function isReadable() {
263
		return $this->checkPermissions(\OCP\Constants::PERMISSION_READ);
264
	}
265
266
	/**
267
	 * @return bool
268
	 */
269
	public function isUpdateable() {
270
		return $this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE);
271
	}
272
273
	/**
274
	 * Check whether new files or folders can be created inside this folder
275
	 *
276
	 * @return bool
277
	 */
278
	public function isCreatable() {
279
		return $this->checkPermissions(\OCP\Constants::PERMISSION_CREATE);
280
	}
281
282
	/**
283
	 * @return bool
284
	 */
285
	public function isDeletable() {
286
		return $this->checkPermissions(\OCP\Constants::PERMISSION_DELETE);
287
	}
288
289
	/**
290
	 * @return bool
291
	 */
292
	public function isShareable() {
293
		return $this->checkPermissions(\OCP\Constants::PERMISSION_SHARE);
294
	}
295
296
	/**
297
	 * Check if a file or folder is shared
298
	 *
299
	 * @return bool
300
	 */
301
	public function isShared() {
302
		$sid = $this->getStorage()->getId();
303
		if (!is_null($sid)) {
0 ignored issues
show
introduced by
The condition is_null($sid) is always false.
Loading history...
304
			$sid = explode(':', $sid);
305
			return ($sid[0] === 'shared');
306
		}
307
308
		return false;
309
	}
310
311
	public function isMounted() {
312
		$storage = $this->getStorage();
313
		if ($storage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
314
			return false;
315
		}
316
		$sid = $storage->getId();
317
		if (!is_null($sid)) {
0 ignored issues
show
introduced by
The condition is_null($sid) is always false.
Loading history...
318
			$sid = explode(':', $sid);
319
			return ($sid[0] !== 'home' and $sid[0] !== 'shared');
320
		}
321
322
		return false;
323
	}
324
325
	/**
326
	 * Get the mountpoint the file belongs to
327
	 *
328
	 * @return \OCP\Files\Mount\IMountPoint
329
	 */
330
	public function getMountPoint() {
331
		return $this->mount;
332
	}
333
334
	/**
335
	 * Get the owner of the file
336
	 *
337
	 * @return \OCP\IUser
338
	 */
339
	public function getOwner() {
340
		return $this->owner;
341
	}
342
343
	/**
344
	 * @param IMountPoint[] $mounts
345
	 */
346
	public function setSubMounts(array $mounts) {
347
		$this->subMounts = $mounts;
348
	}
349
350
	private function updateEntryfromSubMounts() {
351
		if ($this->subMountsUsed) {
352
			return;
353
		}
354
		$this->subMountsUsed = true;
355
		foreach ($this->subMounts as $mount) {
356
			$subStorage = $mount->getStorage();
357
			if ($subStorage) {
358
				$subCache = $subStorage->getCache('');
359
				$rootEntry = $subCache->get('');
360
				$this->addSubEntry($rootEntry, $mount->getMountPoint());
0 ignored issues
show
Bug introduced by
It seems like $rootEntry can also be of type false; however, parameter $data of OC\Files\FileInfo::addSubEntry() does only seem to accept OCP\Files\Cache\ICacheEntry|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

360
				$this->addSubEntry(/** @scrutinizer ignore-type */ $rootEntry, $mount->getMountPoint());
Loading history...
361
			}
362
		}
363
	}
364
365
	/**
366
	 * Add a cache entry which is the child of this folder
367
	 *
368
	 * Sets the size, etag and size to for cross-storage childs
369
	 *
370
	 * @param array|ICacheEntry $data cache entry for the child
371
	 * @param string $entryPath full path of the child entry
372
	 */
373
	public function addSubEntry($data, $entryPath) {
374
		$this->data['size'] += isset($data['size']) ? $data['size'] : 0;
375
		if (isset($data['mtime'])) {
376
			$this->data['mtime'] = max($this->data['mtime'], $data['mtime']);
377
		}
378
		if (isset($data['etag'])) {
379
			// prefix the etag with the relative path of the subentry to propagate etag on mount moves
380
			$relativeEntryPath = substr($entryPath, strlen($this->getPath()));
381
			// attach the permissions to propagate etag on permision changes of submounts
382
			$permissions = isset($data['permissions']) ? $data['permissions'] : 0;
383
			$this->childEtags[] = $relativeEntryPath . '/' . $data['etag'] . $permissions;
384
		}
385
	}
386
387
	/**
388
	 * @inheritdoc
389
	 */
390
	public function getChecksum() {
391
		return $this->data['checksum'];
392
	}
393
394
	public function getExtension(): string {
395
		return pathinfo($this->getName(), PATHINFO_EXTENSION);
396
	}
397
}
398