Passed
Push — master ( 4bdb47...6c7738 )
by Daniel
25:23 queued 10s
created

AbstractLocalNode::getParentFolder()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
cc 2
nc 2
nop 0
crap 2
1
<?php
2
/**
3
 * CMS Pico - Create websites using Pico CMS for Nextcloud.
4
 *
5
 * @copyright Copyright (c) 2019, Daniel Rudolf (<[email protected]>)
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
declare(strict_types=1);
24
25
namespace OCA\CMSPico\Files;
26
27
use OCP\Constants;
28
use OCP\Files\AlreadyExistsException;
29
use OCP\Files\GenericFileException;
30
use OCP\Files\InvalidPathException;
31
use OCP\Files\NotFoundException;
32
use OCP\Files\NotPermittedException;
33
34
abstract class AbstractLocalNode extends AbstractNode implements NodeInterface
35
{
36
	/** @var string */
37
	protected $path;
38
39
	/** @var LocalFolder|null */
40
	protected $parentFolder;
41
42
	/** @var string */
43
	protected $rootPath;
44
45
	/** @var int|null */
46
	protected $permissions;
47
48
	/**
49
	 * AbstractLocalNode constructor.
50
	 *
51
	 * @param string      $path
52
	 * @param string|null $rootPath
53
	 *
54
	 * @throws InvalidPathException
55
	 * @throws NotFoundException
56
	 */
57 16
	public function __construct(string $path, string $rootPath = null)
58
	{
59 16
		parent::__construct();
60
61 16
		$this->path = $this->normalizePath($path);
62 16
		$this->rootPath = realpath($rootPath ?? \OC::$SERVERROOT);
63
64 16
		if (!file_exists($this->getLocalPath())) {
65
			throw new NotFoundException();
66
		}
67 16
	}
68
69
	/**
70
	 * {@inheritDoc}
71
	 */
72
	public function rename(string $name): NodeInterface
73
	{
74
		$this->assertValidFileName($name);
75
76
		if (!$this->isDeletable()) {
77
			throw new NotPermittedException();
78
		}
79
80
		$parentNode = $this->getParentFolder();
81
		if ($parentNode->exists($name)) {
82
			throw new AlreadyExistsException();
83
		}
84
		if (!$parentNode->isCreatable()) {
85
			throw new NotPermittedException();
86
		}
87
88
		if (!rename($this->getLocalPath(), dirname($this->getLocalPath()) . '/' . $name)) {
89
			throw new GenericFileException();
90
		}
91
92
		$parentPath = dirname($this->path);
93
		$this->path = (($parentPath !== '/') ? $parentPath : '') . '/' . $name;
94
95
		return $this;
96
	}
97
98
	/**
99
	 * {@inheritDoc}
100
	 */
101 2
	public function copy(FolderInterface $targetPath, string $name = null): NodeInterface
102
	{
103 2
		if (($targetPath instanceof LocalFolder) && $this->isFile()) {
104
			if ($name !== null) {
105
				$this->assertValidFileName($name);
106
			} else {
107
				$name = $this->getName();
108
			}
109
110
			if ($targetPath->exists($name)) {
111
				throw new AlreadyExistsException();
112
			}
113
			if (!$targetPath->isCreatable()) {
114
				throw new NotPermittedException();
115
			}
116
117
			if (!@copy($this->getLocalPath(), $targetPath->getLocalPath() . '/' . $name)) {
118
				throw new GenericFileException();
119
			}
120
121
			return new LocalFile($targetPath->getPath() . '/' . $name, $targetPath->getRootPath());
122
		} else {
123 2
			return parent::copy($targetPath, $name);
124
		}
125
	}
126
127
	/**
128
	 * {@inheritDoc}
129
	 */
130
	public function move(FolderInterface $targetPath, string $name = null): NodeInterface
131
	{
132
		if (($targetPath instanceof LocalFolder) && $this->isFile()) {
133
			if ($name !== null) {
134
				$this->assertValidFileName($name);
135
			} else {
136
				$name = $this->getName();
137
			}
138
139
			if (!$this->isDeletable()) {
140
				throw new NotPermittedException();
141
			}
142
143
			if ($targetPath->exists($name)) {
144
				throw new AlreadyExistsException();
145
			}
146
			if (!$targetPath->isCreatable()) {
147
				throw new NotPermittedException();
148
			}
149
150
			if (!@rename($this->getLocalPath(), $targetPath->getLocalPath() . '/' . $name)) {
151
				throw new GenericFileException();
152
			}
153
154
			return new LocalFile($targetPath->getPath() . '/' . $name, $targetPath->getRootPath());
155
		} else {
156
			return parent::move($targetPath, $name);
157
		}
158
	}
159
160
	/**
161
	 * {@inheritDoc}
162
	 */
163
	public function getPath(): string
164
	{
165
		return $this->path;
166
	}
167
168
	/**
169
	 * {@inheritDoc}
170
	 */
171 16
	public function getLocalPath(): string
172
	{
173 16
		return $this->rootPath . (($this->path !== '/') ? $this->path : '');
174
	}
175
176
	/**
177
	 * {@inheritDoc}
178
	 */
179 11
	public function getName(): string
180
	{
181 11
		return basename($this->path);
182
	}
183
184
	/**
185
	 * {@inheritDoc}
186
	 */
187 13
	public function getParentPath(): string
188
	{
189 13
		if ($this->path === '/') {
190 11
			throw new InvalidPathException();
191
		}
192
193 13
		return dirname($this->path);
194
	}
195
196
	/**
197
	 * {@inheritDoc}
198
	 */
199 13
	public function getParentFolder(): FolderInterface
200
	{
201 13
		if ($this->parentFolder === null) {
202 13
			$this->parentFolder = new LocalFolder($this->getParentPath(), $this->rootPath);
203
		}
204
205 13
		return $this->parentFolder;
206
	}
207
208
	/**
209
	 * @return string
210
	 */
211
	public function getRootPath(): string
212
	{
213
		return $this->rootPath;
214
	}
215
216
	/**
217
	 * {@inheritDoc}
218
	 */
219 7
	public function isFile(): bool
220
	{
221 7
		return is_file($this->getLocalPath());
222
	}
223
224
	/**
225
	 * {@inheritDoc}
226
	 */
227 16
	public function isFolder(): bool
228
	{
229 16
		return is_dir($this->getLocalPath());
230
	}
231
232
	/**
233
	 * {@inheritDoc}
234
	 */
235
	public function isLocal(): bool
236
	{
237
		return true;
238
	}
239
240
	/**
241
	 * {@inheritDoc}
242
	 */
243 13
	public function getPermissions(): int
244
	{
245 13
		if ($this->permissions === null) {
246 13
			$this->permissions = 0;
247
248
			try {
249 13
				$localPath = $this->getLocalPath();
250
			} catch (\Exception $e) {
251
				// can't read a node's permissions without its local path
252
				return $this->permissions;
253
			}
254
255 13
			if (is_readable($localPath)) {
256 13
				$this->permissions |= Constants::PERMISSION_READ;
257
			}
258
259 13
			if (is_writable($localPath)) {
260 13
				$this->permissions |= Constants::PERMISSION_UPDATE;
261
262 13
				if ($this->isFolder() && is_executable($localPath)) {
263 13
					$this->permissions |= Constants::PERMISSION_CREATE;
264
				}
265
			}
266
267
			try {
268 13
				if (is_writable($this->getParentFolder()->getLocalPath())) {
269 13
					$this->permissions |= Constants::PERMISSION_DELETE;
270
				}
271 11
			} catch (\Exception $e) {
272
				// this is either the root folder or we can't read the parent folder's local path
273
				// in neither case we can delete this node
274
			}
275
		}
276
277 13
		return $this->permissions;
278
	}
279
}
280