Passed
Push — master ( ccc0a5...5195be )
by Roeland
10:43 queued 11s
created

FileInfo::isDeletable()   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
	 * The size of the file/folder without any sub mount
85
	 *
86
	 * @var int
87
	 */
88
	private $rawSize = 0;
89
90
	/**
91
	 * @param string|boolean $path
92
	 * @param Storage\Storage $storage
93
	 * @param string $internalPath
94
	 * @param array|ICacheEntry $data
95
	 * @param \OCP\Files\Mount\IMountPoint $mount
96
	 * @param \OCP\IUser|null $owner
97
	 */
98
	public function __construct($path, $storage, $internalPath, $data, $mount, $owner= null) {
99
		$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...
100
		$this->storage = $storage;
101
		$this->internalPath = $internalPath;
102
		$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...
103
		$this->mount = $mount;
104
		$this->owner = $owner;
105
		$this->rawSize = $this->data['size'] ?? 0;
106
	}
107
108
	public function offsetSet($offset, $value) {
109
		$this->data[$offset] = $value;
110
	}
111
112
	public function offsetExists($offset) {
113
		return isset($this->data[$offset]);
114
	}
115
116
	public function offsetUnset($offset) {
117
		unset($this->data[$offset]);
118
	}
119
120
	public function offsetGet($offset) {
121
		if ($offset === 'type') {
122
			return $this->getType();
123
		} else if ($offset === 'etag') {
124
			return $this->getEtag();
125
		} else if ($offset === 'size') {
126
			return $this->getSize();
127
		} else if ($offset === 'mtime') {
128
			return $this->getMTime();
129
		} elseif ($offset === 'permissions') {
130
			return $this->getPermissions();
131
		} elseif (isset($this->data[$offset])) {
132
			return $this->data[$offset];
133
		} else {
134
			return null;
135
		}
136
	}
137
138
	/**
139
	 * @return string
140
	 */
141
	public function getPath() {
142
		return $this->path;
143
	}
144
145
	/**
146
	 * @return \OCP\Files\Storage
147
	 */
148
	public function getStorage() {
149
		return $this->storage;
150
	}
151
152
	/**
153
	 * @return string
154
	 */
155
	public function getInternalPath() {
156
		return $this->internalPath;
157
	}
158
159
	/**
160
	 * Get FileInfo ID or null in case of part file
161
	 *
162
	 * @return int|null
163
	 */
164
	public function getId() {
165
		return isset($this->data['fileid']) ? (int)  $this->data['fileid'] : null;
166
	}
167
168
	/**
169
	 * @return string
170
	 */
171
	public function getMimetype() {
172
		return $this->data['mimetype'];
173
	}
174
175
	/**
176
	 * @return string
177
	 */
178
	public function getMimePart() {
179
		return $this->data['mimepart'];
180
	}
181
182
	/**
183
	 * @return string
184
	 */
185
	public function getName() {
186
		return isset($this->data['name']) ? $this->data['name'] : basename($this->getPath());
187
	}
188
189
	/**
190
	 * @return string
191
	 */
192
	public function getEtag() {
193
		$this->updateEntryfromSubMounts();
194
		if (count($this->childEtags) > 0) {
195
			$combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags);
196
			return md5($combinedEtag);
197
		} else {
198
			return $this->data['etag'];
199
		}
200
	}
201
202
	/**
203
	 * @return int
204
	 */
205
	public function getSize($includeMounts = true) {
206
		if ($includeMounts) {
207
			$this->updateEntryfromSubMounts();
208
			return isset($this->data['size']) ? 0 + $this->data['size'] : 0;
209
		} else {
210
			return $this->rawSize;
211
		}
212
	}
213
214
	/**
215
	 * @return int
216
	 */
217
	public function getMTime() {
218
		$this->updateEntryfromSubMounts();
219
		return (int) $this->data['mtime'];
220
	}
221
222
	/**
223
	 * @return bool
224
	 */
225
	public function isEncrypted() {
226
		return $this->data['encrypted'];
227
	}
228
229
	/**
230
	 * Return the currently version used for the HMAC in the encryption app
231
	 *
232
	 * @return int
233
	 */
234
	public function getEncryptedVersion() {
235
		return isset($this->data['encryptedVersion']) ? (int) $this->data['encryptedVersion'] : 1;
236
	}
237
238
	/**
239
	 * @return int
240
	 */
241
	public function getPermissions() {
242
		$perms = (int) $this->data['permissions'];
243
		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

243
		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...
244
			$perms = $perms & ~\OCP\Constants::PERMISSION_SHARE;
245
		}
246
		return (int) $perms;
247
	}
248
249
	/**
250
	 * @return string \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER
251
	 */
252
	public function getType() {
253
		if (!isset($this->data['type'])) {
254
			$this->data['type'] = ($this->getMimetype() === 'httpd/unix-directory') ? self::TYPE_FOLDER : self::TYPE_FILE;
255
		}
256
		return $this->data['type'];
257
	}
258
259
	public function getData() {
260
		return $this->data;
261
	}
262
263
	/**
264
	 * @param int $permissions
265
	 * @return bool
266
	 */
267
	protected function checkPermissions($permissions) {
268
		return ($this->getPermissions() & $permissions) === $permissions;
269
	}
270
271
	/**
272
	 * @return bool
273
	 */
274
	public function isReadable() {
275
		return $this->checkPermissions(\OCP\Constants::PERMISSION_READ);
276
	}
277
278
	/**
279
	 * @return bool
280
	 */
281
	public function isUpdateable() {
282
		return $this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE);
283
	}
284
285
	/**
286
	 * Check whether new files or folders can be created inside this folder
287
	 *
288
	 * @return bool
289
	 */
290
	public function isCreatable() {
291
		return $this->checkPermissions(\OCP\Constants::PERMISSION_CREATE);
292
	}
293
294
	/**
295
	 * @return bool
296
	 */
297
	public function isDeletable() {
298
		return $this->checkPermissions(\OCP\Constants::PERMISSION_DELETE);
299
	}
300
301
	/**
302
	 * @return bool
303
	 */
304
	public function isShareable() {
305
		return $this->checkPermissions(\OCP\Constants::PERMISSION_SHARE);
306
	}
307
308
	/**
309
	 * Check if a file or folder is shared
310
	 *
311
	 * @return bool
312
	 */
313
	public function isShared() {
314
		$sid = $this->getStorage()->getId();
315
		if (!is_null($sid)) {
0 ignored issues
show
introduced by
The condition is_null($sid) is always false.
Loading history...
316
			$sid = explode(':', $sid);
317
			return ($sid[0] === 'shared');
318
		}
319
320
		return false;
321
	}
322
323
	public function isMounted() {
324
		$storage = $this->getStorage();
325
		if ($storage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
326
			return false;
327
		}
328
		$sid = $storage->getId();
329
		if (!is_null($sid)) {
0 ignored issues
show
introduced by
The condition is_null($sid) is always false.
Loading history...
330
			$sid = explode(':', $sid);
331
			return ($sid[0] !== 'home' and $sid[0] !== 'shared');
332
		}
333
334
		return false;
335
	}
336
337
	/**
338
	 * Get the mountpoint the file belongs to
339
	 *
340
	 * @return \OCP\Files\Mount\IMountPoint
341
	 */
342
	public function getMountPoint() {
343
		return $this->mount;
344
	}
345
346
	/**
347
	 * Get the owner of the file
348
	 *
349
	 * @return \OCP\IUser
350
	 */
351
	public function getOwner() {
352
		return $this->owner;
353
	}
354
355
	/**
356
	 * @param IMountPoint[] $mounts
357
	 */
358
	public function setSubMounts(array $mounts) {
359
		$this->subMounts = $mounts;
360
	}
361
362
	private function updateEntryfromSubMounts() {
363
		if ($this->subMountsUsed) {
364
			return;
365
		}
366
		$this->subMountsUsed = true;
367
		foreach ($this->subMounts as $mount) {
368
			$subStorage = $mount->getStorage();
369
			if ($subStorage) {
370
				$subCache = $subStorage->getCache('');
371
				$rootEntry = $subCache->get('');
372
				$this->addSubEntry($rootEntry, $mount->getMountPoint());
373
			}
374
		}
375
	}
376
377
	/**
378
	 * Add a cache entry which is the child of this folder
379
	 *
380
	 * Sets the size, etag and size to for cross-storage childs
381
	 *
382
	 * @param array|ICacheEntry $data cache entry for the child
383
	 * @param string $entryPath full path of the child entry
384
	 */
385
	public function addSubEntry($data, $entryPath) {
386
		$this->data['size'] += isset($data['size']) ? $data['size'] : 0;
387
		if (isset($data['mtime'])) {
388
			$this->data['mtime'] = max($this->data['mtime'], $data['mtime']);
389
		}
390
		if (isset($data['etag'])) {
391
			// prefix the etag with the relative path of the subentry to propagate etag on mount moves
392
			$relativeEntryPath = substr($entryPath, strlen($this->getPath()));
393
			// attach the permissions to propagate etag on permision changes of submounts
394
			$permissions = isset($data['permissions']) ? $data['permissions'] : 0;
395
			$this->childEtags[] = $relativeEntryPath . '/' . $data['etag'] . $permissions;
396
		}
397
	}
398
399
	/**
400
	 * @inheritdoc
401
	 */
402
	public function getChecksum() {
403
		return $this->data['checksum'];
404
	}
405
406
	public function getExtension(): string {
407
		return pathinfo($this->getName(), PATHINFO_EXTENSION);
408
	}
409
410
	public function getCreationTime(): int {
411
		return (int) $this->data['creation_time'];
412
	}
413
414
	public function getUploadTime(): int {
415
		return (int) $this->data['upload_time'];
416
	}
417
}
418