Completed
Push — master ( bca165...f347e2 )
by Björn
15:51
created

Node::getFileInfo()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Bart Visscher <[email protected]>
7
 * @author Björn Schießle <[email protected]>
8
 * @author Jakob Sack <[email protected]>
9
 * @author Joas Schilling <[email protected]>
10
 * @author Jörn Friedrich Dreyer <[email protected]>
11
 * @author Klaas Freitag <[email protected]>
12
 * @author Markus Goetz <[email protected]>
13
 * @author Morris Jobke <[email protected]>
14
 * @author Robin Appelman <[email protected]>
15
 * @author Roeland Jago Douma <[email protected]>
16
 * @author Thomas Müller <[email protected]>
17
 * @author Vincent Petry <[email protected]>
18
 *
19
 * @license AGPL-3.0
20
 *
21
 * This code is free software: you can redistribute it and/or modify
22
 * it under the terms of the GNU Affero General Public License, version 3,
23
 * as published by the Free Software Foundation.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
 * GNU Affero General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Affero General Public License, version 3,
31
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
32
 *
33
 */
34
35
namespace OCA\DAV\Connector\Sabre;
36
37
use OC\Files\Mount\MoveableMount;
38
use OC\Files\View;
39
use OCA\DAV\Connector\Sabre\Exception\InvalidPath;
40
use OCP\Files\FileInfo;
41
use OCP\Share\Exceptions\ShareNotFound;
42
use OCP\Share\IManager;
43
44
45
abstract class Node implements \Sabre\DAV\INode {
46
47
	/**
48
	 * @var \OC\Files\View
49
	 */
50
	protected $fileView;
51
52
	/**
53
	 * The path to the current node
54
	 *
55
	 * @var string
56
	 */
57
	protected $path;
58
59
	/**
60
	 * node properties cache
61
	 *
62
	 * @var array
63
	 */
64
	protected $property_cache = null;
65
66
	/**
67
	 * @var \OCP\Files\FileInfo
68
	 */
69
	protected $info;
70
71
	/**
72
	 * @var IManager
73
	 */
74
	protected $shareManager;
75
76
	/**
77
	 * Sets up the node, expects a full path name
78
	 *
79
	 * @param \OC\Files\View $view
80
	 * @param \OCP\Files\FileInfo $info
81
	 * @param IManager $shareManager
82
	 */
83
	public function __construct(View $view, FileInfo $info, IManager $shareManager = null) {
84
		$this->fileView = $view;
85
		$this->path = $this->fileView->getRelativePath($info->getPath());
86
		$this->info = $info;
87
		if ($shareManager) {
88
			$this->shareManager = $shareManager;
89
		} else {
90
			$this->shareManager = \OC::$server->getShareManager();
91
		}
92
	}
93
94
	protected function refreshInfo() {
95
		$this->info = $this->fileView->getFileInfo($this->path);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->fileView->getFileInfo($this->path) can also be of type false. However, the property $info is declared as type object<OCP\Files\FileInfo>. 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
	}
97
98
	/**
99
	 *  Returns the name of the node
100
	 *
101
	 * @return string
102
	 */
103
	public function getName() {
104
		return $this->info->getName();
105
	}
106
107
	/**
108
	 * Returns the full path
109
	 *
110
	 * @return string
111
	 */
112
	public function getPath() {
113
		return $this->path;
114
	}
115
116
	/**
117
	 * Renames the node
118
	 *
119
	 * @param string $name The new name
120
	 * @throws \Sabre\DAV\Exception\BadRequest
121
	 * @throws \Sabre\DAV\Exception\Forbidden
122
	 */
123
	public function setName($name) {
124
125
		// rename is only allowed if the update privilege is granted
126
		if (!$this->info->isUpdateable()) {
127
			throw new \Sabre\DAV\Exception\Forbidden();
128
		}
129
130
		list($parentPath,) = \Sabre\Uri\split($this->path);
131
		list(, $newName) = \Sabre\Uri\split($name);
132
133
		// verify path of the target
134
		$this->verifyPath();
135
136
		$newPath = $parentPath . '/' . $newName;
137
138
		$this->fileView->rename($this->path, $newPath);
139
140
		$this->path = $newPath;
141
142
		$this->refreshInfo();
143
	}
144
145
	public function setPropertyCache($property_cache) {
146
		$this->property_cache = $property_cache;
147
	}
148
149
	/**
150
	 * Returns the last modification time, as a unix timestamp
151
	 *
152
	 * @return int timestamp as integer
153
	 */
154
	public function getLastModified() {
155
		$timestamp = $this->info->getMtime();
156
		if (!empty($timestamp)) {
157
			return (int)$timestamp;
158
		}
159
		return $timestamp;
160
	}
161
162
	/**
163
	 *  sets the last modification time of the file (mtime) to the value given
164
	 *  in the second parameter or to now if the second param is empty.
165
	 *  Even if the modification time is set to a custom value the access time is set to now.
166
	 */
167
	public function touch($mtime) {
168
		$this->fileView->touch($this->path, $mtime);
169
		$this->refreshInfo();
170
	}
171
172
	/**
173
	 * Returns the ETag for a file
174
	 *
175
	 * An ETag is a unique identifier representing the current version of the
176
	 * file. If the file changes, the ETag MUST change.  The ETag is an
177
	 * arbitrary string, but MUST be surrounded by double-quotes.
178
	 *
179
	 * Return null if the ETag can not effectively be determined
180
	 *
181
	 * @return string
182
	 */
183
	public function getETag() {
184
		return '"' . $this->info->getEtag() . '"';
185
	}
186
187
	/**
188
	 * Sets the ETag
189
	 *
190
	 * @param string $etag
191
	 *
192
	 * @return int file id of updated file or -1 on failure
193
	 */
194
	public function setETag($etag) {
195
		return $this->fileView->putFileInfo($this->path, array('etag' => $etag));
196
	}
197
198
	/**
199
	 * Returns the size of the node, in bytes
200
	 *
201
	 * @return integer
202
	 */
203
	public function getSize() {
204
		return $this->info->getSize();
205
	}
206
207
	/**
208
	 * Returns the cache's file id
209
	 *
210
	 * @return int
211
	 */
212
	public function getId() {
213
		return $this->info->getId();
214
	}
215
216
	/**
217
	 * @return string|null
218
	 */
219
	public function getFileId() {
220
		if ($this->info->getId()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->info->getId() of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
221
			$instanceId = \OC_Util::getInstanceId();
222
			$id = sprintf('%08d', $this->info->getId());
223
			return $id . $instanceId;
224
		}
225
226
		return null;
227
	}
228
229
	/**
230
	 * @return integer
231
	 */
232
	public function getInternalFileId() {
233
		return $this->info->getId();
234
	}
235
236
	/**
237
	 * @param string $user
238
	 * @return int
239
	 */
240
	public function getSharePermissions($user) {
241
242
		// check of we access a federated share
243
		if ($user !== null) {
244
			try {
245
				$share = $this->shareManager->getShareByToken($user);
246
				return $share->getPermissions();
247
			} catch (ShareNotFound $e) {
248
				// ignore
249
			}
250
		}
251
252
		$storage = $this->info->getStorage();
253
254
		$path = $this->info->getInternalPath();
255
256
		if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
257
			/** @var \OCA\Files_Sharing\SharedStorage $storage */
258
			$permissions = (int)$storage->getShare()->getPermissions();
259
		} else {
260
			$permissions = $storage->getPermissions($path);
261
		}
262
263
		/*
264
		 * We can always share non moveable mount points with DELETE and UPDATE
265
		 * Eventually we need to do this properly
266
		 */
267
		$mountpoint = $this->info->getMountPoint();
268
		if (!($mountpoint instanceof MoveableMount)) {
269
			$mountpointpath = $mountpoint->getMountPoint();
270
			if (substr($mountpointpath, -1) === '/') {
271
				$mountpointpath = substr($mountpointpath, 0, -1);
272
			}
273
274
			if ($mountpointpath === $this->info->getPath()) {
275
				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
276
			}
277
		}
278
279
		/*
280
		 * Files can't have create or delete permissions
281
		 */
282
		if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
283
			$permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE);
284
		}
285
286
		return $permissions;
287
	}
288
289
	/**
290
	 * @return string
291
	 */
292
	public function getDavPermissions() {
293
		$p = '';
294
		if ($this->info->isShared()) {
295
			$p .= 'S';
296
		}
297
		if ($this->info->isShareable()) {
298
			$p .= 'R';
299
		}
300
		if ($this->info->isMounted()) {
301
			$p .= 'M';
302
		}
303
		if ($this->info->isReadable()) {
304
			$p .= 'G';
305
		}
306
		if ($this->info->isDeletable()) {
307
			$p .= 'D';
308
		}
309
		if ($this->info->isUpdateable()) {
310
			$p .= 'NV'; // Renameable, Moveable
311
		}
312
		if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
313
			if ($this->info->isUpdateable()) {
314
				$p .= 'W';
315
			}
316
		} else {
317
			if ($this->info->isCreatable()) {
318
				$p .= 'CK';
319
			}
320
		}
321
		return $p;
322
	}
323
324
	public function getOwner() {
325
		return $this->info->getOwner();
326
	}
327
328
	protected function verifyPath() {
329
		try {
330
			$fileName = basename($this->info->getPath());
331
			$this->fileView->verifyPath($this->path, $fileName);
332
		} catch (\OCP\Files\InvalidPathException $ex) {
333
			throw new InvalidPath($ex->getMessage());
334
		}
335
	}
336
337
	/**
338
	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
339
	 */
340
	public function acquireLock($type) {
341
		$this->fileView->lockFile($this->path, $type);
342
	}
343
344
	/**
345
	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
346
	 */
347
	public function releaseLock($type) {
348
		$this->fileView->unlockFile($this->path, $type);
349
	}
350
351
	/**
352
	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
353
	 */
354
	public function changeLock($type) {
355
		$this->fileView->changeLock($this->path, $type);
356
	}
357
358
	public function getFileInfo() {
359
		return $this->info;
360
	}
361
}
362