Completed
Push — master ( 76ba1c...91e148 )
by Thomas
23:00 queued 09:19
created

Node::setName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 1
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Arthur Schiwon <[email protected]>
4
 * @author Bart Visscher <[email protected]>
5
 * @author Björn Schießle <[email protected]>
6
 * @author Jakob Sack <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Jörn Friedrich Dreyer <[email protected]>
9
 * @author Klaas Freitag <[email protected]>
10
 * @author Markus Goetz <[email protected]>
11
 * @author Martin Mattel <[email protected]>
12
 * @author Morris Jobke <[email protected]>
13
 * @author Robin Appelman <[email protected]>
14
 * @author Roeland Jago Douma <[email protected]>
15
 * @author Thomas Müller <[email protected]>
16
 * @author Vincent Petry <[email protected]>
17
 *
18
 * @copyright Copyright (c) 2017, ownCloud GmbH
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 OCA\DAV\Connector\Sabre\Exception\InvalidPath;
39
use OCP\Share\Exceptions\ShareNotFound;
40
use OCP\Share\IManager;
41
42
43
abstract class Node implements \Sabre\DAV\INode {
44
45
	/**
46
	 * @var \OC\Files\View
47
	 */
48
	protected $fileView;
49
50
	/**
51
	 * The path to the current node
52
	 *
53
	 * @var string
54
	 */
55
	protected $path;
56
57
	/**
58
	 * node properties cache
59
	 *
60
	 * @var array
61
	 */
62
	protected $property_cache = null;
63
64
	/**
65
	 * @var \OCP\Files\FileInfo
66
	 */
67
	protected $info;
68
69
	/**
70
	 * @var IManager
71
	 */
72
	protected $shareManager;
73
74
	/**
75
	 * Sets up the node, expects a full path name
76
	 *
77
	 * @param \OC\Files\View $view
78
	 * @param \OCP\Files\FileInfo $info
79
	 * @param IManager $shareManager
80
	 */
81
	public function __construct($view, $info, IManager $shareManager = null) {
82
		$this->fileView = $view;
83
		$this->path = $this->fileView->getRelativePath($info->getPath());
84
		$this->info = $info;
85
		if ($shareManager) {
86
			$this->shareManager = $shareManager;
87
		} else {
88
			$this->shareManager = \OC::$server->getShareManager();
89
		}
90
	}
91
92
	protected function refreshInfo() {
93
		$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...
94
	}
95
96
	/**
97
	 *  Returns the name of the node
98
	 *
99
	 * @return string
100
	 */
101
	public function getName() {
102
		return $this->info->getName();
103
	}
104
105
	/**
106
	 * Returns the full path
107
	 *
108
	 * @return string
109
	 */
110
	public function getPath() {
111
		return $this->path;
112
	}
113
114
	/**
115
	 * Renames the node
116
	 *
117
	 * @param string $name The new name
118
	 * @throws \Sabre\DAV\Exception\BadRequest
119
	 * @throws \Sabre\DAV\Exception\Forbidden
120
	 * @throws InvalidPath
121
	 */
122
	public function setName($name) {
123
124
		// rename is only allowed if the update privilege is granted
125
		if (!$this->info->isUpdateable()) {
126
			throw new \Sabre\DAV\Exception\Forbidden();
127
		}
128
129
		list($parentPath,) = \Sabre\HTTP\URLUtil::splitPath($this->path);
130
		list(, $newName) = \Sabre\HTTP\URLUtil::splitPath($name);
131
132
		// verify path of the target
133
		$this->verifyPath();
134
135
		$newPath = $parentPath . '/' . $newName;
136
137
		$this->fileView->rename($this->path, $newPath);
138
139
		$this->path = $newPath;
140
141
		$this->refreshInfo();
142
	}
143
144
	public function setPropertyCache($property_cache) {
145
		$this->property_cache = $property_cache;
146
	}
147
148
	/**
149
	 * Returns the last modification time, as a unix timestamp
150
	 *
151
	 * @return int timestamp as integer
152
	 */
153
	public function getLastModified() {
154
		$timestamp = $this->info->getMtime();
155
		if (!empty($timestamp)) {
156
			return (int)$timestamp;
157
		}
158
		return $timestamp;
159
	}
160
161
	/**
162
	 *  sets the last modification time of the file (mtime) to the value given
163
	 *  in the second parameter or to now if the second param is empty.
164
	 *  Even if the modification time is set to a custom value the access time is set to now.
165
	 */
166
	public function touch($mtime) {
167
		$mtime = $this->sanitizeMtime($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, ['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
	 * Returns the node's full id
218
	 *
219
	 * The full id is the numerical id padded with zeroes concatenated with
220
	 * the instance id.
221
	 *
222
	 * Warning: Users of the full id may depend on its particular format, be
223
	 * careful about changes.
224
	 *
225
	 * The contract is that taking the substring up until the first character
226
	 * and converting to an integer yields the numerical id.
227
	 *
228
	 * @return string|null
229
	 */
230
	public function getFileId() {
231
		if ($this->info->getId()) {
232
			$instanceId = \OC_Util::getInstanceId();
233
			$id = sprintf('%08d', $this->info->getId());
234
			return $id . $instanceId;
235
		}
236
237
		return null;
238
	}
239
240
	/**
241
	 * @return integer
242
	 */
243
	public function getInternalFileId() {
244
		return $this->info->getId();
245
	}
246
247
	/**
248
	 * @param string $user
249
	 * @return int
250
	 */
251
	public function getSharePermissions($user) {
252
253
		// check of we access a federated share
254
		if ($user !== null) {
255
			try {
256
				$share = $this->shareManager->getShareByToken($user);
257
				return $share->getPermissions();
258
			} catch (ShareNotFound $e) {
259
				// ignore
260
			}
261
		}
262
263
		$storage = $this->info->getStorage();
264
265
		$path = $this->info->getInternalPath();
266
267
		if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
268
			/** @var \OCA\Files_Sharing\SharedStorage $storage */
269
			$permissions = (int)$storage->getShare()->getPermissions();
270
		} else {
271
			$permissions = $storage->getPermissions($path);
272
		}
273
274
		/*
275
		 * We can always share non moveable mount points with DELETE and UPDATE
276
		 * Eventually we need to do this properly
277
		 */
278
		$mountpoint = $this->info->getMountPoint();
279
		if (!($mountpoint instanceof MoveableMount)) {
280
			$mountpointpath = $mountpoint->getMountPoint();
281
			if (substr($mountpointpath, -1) === '/') {
282
				$mountpointpath = substr($mountpointpath, 0, -1);
283
			}
284
285
			if ($mountpointpath === $this->info->getPath()) {
286
				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
287
			}
288
		}
289
290
		/*
291
		 * Files can't have create or delete permissions
292
		 */
293
		if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
294
			$permissions &= ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_DELETE);
295
		}
296
297
		return $permissions;
298
	}
299
300
	/**
301
	 * @return string
302
	 */
303
	public function getDavPermissions() {
304
		$p = '';
305
		if ($this->info->isShared()) {
306
			$p .= 'S';
307
		}
308
		if ($this->info->isShareable()) {
309
			$p .= 'R';
310
		}
311
		if ($this->info->isMounted()) {
312
			$p .= 'M';
313
		}
314
		if ($this->info->isDeletable()) {
315
			$p .= 'D';
316
		}
317
		if ($this->info->isUpdateable()) {
318
			$p .= 'NV'; // Renameable, Moveable
319
		}
320
		if ($this->info->getType() === \OCP\Files\FileInfo::TYPE_FILE) {
321
			if ($this->info->isUpdateable()) {
322
				$p .= 'W';
323
			}
324
		} else {
325
			if ($this->info->isCreatable()) {
326
				$p .= 'CK';
327
			}
328
		}
329
		return $p;
330
	}
331
332
	public function getOwner() {
333
		return $this->info->getOwner();
334
	}
335
336
	protected function verifyPath() {
337
		if (\OC\Files\Filesystem::isForbiddenFileOrDir($this->info->getPath())) {
338
			throw new \Sabre\DAV\Exception\Forbidden();
339
		}
340
341
		try {
342
			$fileName = basename($this->info->getPath());
343
			$this->fileView->verifyPath($this->path, $fileName);
344
		} catch (\OCP\Files\InvalidPathException $ex) {
345
			throw new InvalidPath($ex->getMessage());
346
		}
347
	}
348
349
	/**
350
	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
351
	 */
352
	public function acquireLock($type) {
353
		$this->fileView->lockFile($this->path, $type);
354
	}
355
356
	/**
357
	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
358
	 */
359
	public function releaseLock($type) {
360
		$this->fileView->unlockFile($this->path, $type);
361
	}
362
363
	/**
364
	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
365
	 */
366
	public function changeLock($type) {
367
		$this->fileView->changeLock($this->path, $type);
368
	}
369
370
	public function getFileInfo() {
371
		return $this->info;
372
	}
373
374
	protected function sanitizeMtime ($mtimeFromRequest) {
375
		$mtime = (float) $mtimeFromRequest;
376
		if ($mtime >= PHP_INT_MAX) {
377
			$mtime = PHP_INT_MAX;
378
		} elseif ($mtime <= (PHP_INT_MAX*-1)) {
379
			$mtime = (PHP_INT_MAX*-1);
380
		} else {
381
			$mtime = (int) $mtimeFromRequest;
382
		}
383
		return $mtime;
384
	}
385
386
}
387