Completed
Push — stable10 ( 72d31a...5e7973 )
by Lukas
39:36 queued 28:45
created

SharedMount::getNumericStorageId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 9
rs 9.6666
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Björn Schießle <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 * @author Robin Appelman <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 * @author Vincent Petry <[email protected]>
11
 *
12
 * @license AGPL-3.0
13
 *
14
 * This code is free software: you can redistribute it and/or modify
15
 * it under the terms of the GNU Affero General Public License, version 3,
16
 * as published by the Free Software Foundation.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * GNU Affero General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU Affero General Public License, version 3,
24
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
25
 *
26
 */
27
28
namespace OCA\Files_Sharing;
29
30
use OC\Files\Filesystem;
31
use OC\Files\Mount\MountPoint;
32
use OC\Files\Mount\MoveableMount;
33
use OC\Files\View;
34
35
/**
36
 * Shared mount points can be moved by the user
37
 */
38
class SharedMount extends MountPoint implements MoveableMount {
39
	/**
40
	 * @var \OC\Files\Storage\Shared $storage
41
	 */
42
	protected $storage = null;
43
44
	/**
45
	 * @var \OC\Files\View
46
	 */
47
	private $recipientView;
48
49
	/**
50
	 * @var string
51
	 */
52
	private $user;
53
54
	/** @var \OCP\Share\IShare */
55
	private $superShare;
56
57
	/** @var \OCP\Share\IShare[] */
58
	private $groupedShares;
59
60
	/**
61
	 * @param string $storage
62
	 * @param SharedMount[] $mountpoints
63
	 * @param array|null $arguments
64
	 * @param \OCP\Files\Storage\IStorageFactory $loader
65
	 */
66
	public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) {
67
		$this->user = $arguments['user'];
68
		$this->recipientView = new View('/' . $this->user . '/files');
69
70
		$this->superShare = $arguments['superShare'];
71
		$this->groupedShares = $arguments['groupedShares'];
72
73
		$newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints);
74
		$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
75
		$arguments['ownerView'] = new View('/' . $this->superShare->getShareOwner() . '/files');
76
		parent::__construct($storage, $absMountPoint, $arguments, $loader);
77
	}
78
79
	/**
80
	 * check if the parent folder exists otherwise move the mount point up
81
	 *
82
	 * @param \OCP\Share\IShare $share
83
	 * @param SharedMount[] $mountpoints
84
	 * @return string
85
	 */
86
	private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints) {
87
88
		$mountPoint = basename($share->getTarget());
89
		$parent = dirname($share->getTarget());
90
91
		if (!$this->recipientView->is_dir($parent)) {
92
			$parent = Helper::getShareFolder($this->recipientView);
93
		}
94
95
		$newMountPoint = $this->generateUniqueTarget(
96
			\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
97
			$this->recipientView,
98
			$mountpoints
99
		);
100
101
		if ($newMountPoint !== $share->getTarget()) {
102
			$this->updateFileTarget($newMountPoint, $share);
103
		}
104
105
		return $newMountPoint;
106
	}
107
108
	/**
109
	 * update fileTarget in the database if the mount point changed
110
	 *
111
	 * @param string $newPath
112
	 * @param \OCP\Share\IShare $share
113
	 * @return bool
114
	 */
115
	private function updateFileTarget($newPath, &$share) {
116
		$share->setTarget($newPath);
117
118
		foreach ($this->groupedShares as $share) {
119
			$share->setTarget($newPath);
120
			\OC::$server->getShareManager()->moveShare($share, $this->user);
121
		}
122
	}
123
124
125
	/**
126
	 * @param string $path
127
	 * @param View $view
128
	 * @param SharedMount[] $mountpoints
129
	 * @return mixed
130
	 */
131
	private function generateUniqueTarget($path, $view, array $mountpoints) {
132
		$pathinfo = pathinfo($path);
133
		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
134
		$name = $pathinfo['filename'];
135
		$dir = $pathinfo['dirname'];
136
137
		// Helper function to find existing mount points
138
		$mountpointExists = function($path) use ($mountpoints) {
139
			foreach ($mountpoints as $mountpoint) {
140
				if ($mountpoint->getShare()->getTarget() === $path) {
141
					return true;
142
				}
143
			}
144
			return false;
145
		};
146
147
		$i = 2;
148 View Code Duplication
		while ($view->file_exists($path) || $mountpointExists($path)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
149
			$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
150
			$i++;
151
		}
152
153
		return $path;
154
	}
155
156
	/**
157
	 * Format a path to be relative to the /user/files/ directory
158
	 *
159
	 * @param string $path the absolute path
160
	 * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
161
	 * @throws \OCA\Files_Sharing\Exceptions\BrokenPath
162
	 */
163
	protected function stripUserFilesPath($path) {
164
		$trimmed = ltrim($path, '/');
165
		$split = explode('/', $trimmed);
166
167
		// it is not a file relative to data/user/files
168
		if (count($split) < 3 || $split[1] !== 'files') {
169
			\OCP\Util::writeLog('file sharing',
170
				'Can not strip userid and "files/" from path: ' . $path,
171
				\OCP\Util::ERROR);
172
			throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
173
		}
174
175
		// skip 'user' and 'files'
176
		$sliced = array_slice($split, 2);
177
		$relPath = implode('/', $sliced);
178
179
		return '/' . $relPath;
180
	}
181
182
	/**
183
	 * Move the mount point to $target
184
	 *
185
	 * @param string $target the target mount point
186
	 * @return bool
187
	 */
188
	public function moveMount($target) {
189
190
		$relTargetPath = $this->stripUserFilesPath($target);
191
		$share = $this->storage->getShare();
192
193
		$result = true;
194
195
		try {
196
			$this->updateFileTarget($relTargetPath, $share);
197
			$this->setMountPoint($target);
198
			$this->storage->setMountPoint($relTargetPath);
199
		} catch (\Exception $e) {
200
			\OCP\Util::writeLog('file sharing',
201
				'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
202
				\OCP\Util::ERROR);
203
		}
204
205
		return $result;
206
	}
207
208
	/**
209
	 * Remove the mount points
210
	 *
211
	 * @return bool
212
	 */
213
	public function removeMount() {
214
		$mountManager = \OC\Files\Filesystem::getMountManager();
215
		/** @var $storage \OC\Files\Storage\Shared */
216
		$storage = $this->getStorage();
217
		$result = $storage->unshareStorage();
218
		$mountManager->removeMount($this->mountPoint);
219
220
		return $result;
221
	}
222
223
	/**
224
	 * @return \OCP\Share\IShare
225
	 */
226
	public function getShare() {
227
		return $this->superShare;
228
	}
229
230
	/**
231
	 * Get the file id of the root of the storage
232
	 *
233
	 * @return int
234
	 */
235
	public function getStorageRootId() {
236
		return $this->getShare()->getNodeId();
237
	}
238
239
	/**
240
	 * @return int
241
	 */
242
	public function getNumericStorageId() {
243
		$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
244
245
		$query = $builder->select('storage')
246
			->from('filecache')
247
			->where($builder->expr()->eq('fileid', $builder->createNamedParameter($this->getShare()->getNodeId())));
248
249
		return $query->execute()->fetchColumn();
250
	}
251
}
252