Completed
Pull Request — master (#7363)
by Björn
14:32
created
lib/public/Migration/IOutput.php 2 patches
Doc Comments   +5 added lines, -1 removed lines patch added patch discarded remove patch
@@ -32,18 +32,21 @@  discard block
 block discarded – undo
32 32
 	/**
33 33
 	 * @param string $message
34 34
 	 * @since 9.1.0
35
+	 * @return void
35 36
 	 */
36 37
 	public function info($message);
37 38
 
38 39
 	/**
39 40
 	 * @param string $message
40 41
 	 * @since 9.1.0
42
+	 * @return void
41 43
 	 */
42 44
 	public function warning($message);
43 45
 
44 46
 	/**
45 47
 	 * @param int $max
46 48
 	 * @since 9.1.0
49
+	 * @return void
47 50
 	 */
48 51
 	public function startProgress($max = 0);
49 52
 
@@ -51,12 +54,13 @@  discard block
 block discarded – undo
51 54
 	 * @param int $step
52 55
 	 * @param string $description
53 56
 	 * @since 9.1.0
57
+	 * @return void
54 58
 	 */
55 59
 	public function advance($step = 1, $description = '');
56 60
 
57 61
 	/**
58
-	 * @param int $max
59 62
 	 * @since 9.1.0
63
+	 * @return void
60 64
 	 */
61 65
 	public function finishProgress();
62 66
 
Please login to merge, or discard this patch.
Indentation   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -30,35 +30,35 @@
 block discarded – undo
30 30
  */
31 31
 interface IOutput {
32 32
 
33
-	/**
34
-	 * @param string $message
35
-	 * @since 9.1.0
36
-	 */
37
-	public function info($message);
33
+    /**
34
+     * @param string $message
35
+     * @since 9.1.0
36
+     */
37
+    public function info($message);
38 38
 
39
-	/**
40
-	 * @param string $message
41
-	 * @since 9.1.0
42
-	 */
43
-	public function warning($message);
39
+    /**
40
+     * @param string $message
41
+     * @since 9.1.0
42
+     */
43
+    public function warning($message);
44 44
 
45
-	/**
46
-	 * @param int $max
47
-	 * @since 9.1.0
48
-	 */
49
-	public function startProgress($max = 0);
45
+    /**
46
+     * @param int $max
47
+     * @since 9.1.0
48
+     */
49
+    public function startProgress($max = 0);
50 50
 
51
-	/**
52
-	 * @param int $step
53
-	 * @param string $description
54
-	 * @since 9.1.0
55
-	 */
56
-	public function advance($step = 1, $description = '');
51
+    /**
52
+     * @param int $step
53
+     * @param string $description
54
+     * @since 9.1.0
55
+     */
56
+    public function advance($step = 1, $description = '');
57 57
 
58
-	/**
59
-	 * @param int $max
60
-	 * @since 9.1.0
61
-	 */
62
-	public function finishProgress();
58
+    /**
59
+     * @param int $max
60
+     * @since 9.1.0
61
+     */
62
+    public function finishProgress();
63 63
 
64 64
 }
Please login to merge, or discard this patch.
lib/public/SystemTag/ISystemTagManager.php 2 patches
Doc Comments   +7 added lines, -4 removed lines patch added patch discarded remove patch
@@ -102,17 +102,19 @@  discard block
 block discarded – undo
102 102
 	 * with the same attributes
103 103
 	 *
104 104
 	 * @since 9.0.0
105
+	 * @return void
105 106
 	 */
106 107
 	public function updateTag($tagId, $newName, $userVisible, $userAssignable);
107 108
 
108 109
 	/**
109 110
 	 * Delete the given tags from the database and all their relationships.
110 111
 	 *
111
-	 * @param string|array $tagIds array of tag ids
112
+	 * @param string $tagIds array of tag ids
112 113
 	 *
113 114
 	 * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist
114 115
 	 *
115 116
 	 * @since 9.0.0
117
+	 * @return void
116 118
 	 */
117 119
 	public function deleteTags($tagIds);
118 120
 
@@ -123,7 +125,7 @@  discard block
 block discarded – undo
123 125
 	 * @param ISystemTag $tag tag to check permission for
124 126
 	 * @param IUser $user user to check permission for
125 127
 	 *
126
-	 * @return true if the user is allowed to assign/unassign the tag, false otherwise
128
+	 * @return boolean if the user is allowed to assign/unassign the tag, false otherwise
127 129
 	 *
128 130
 	 * @since 9.1.0
129 131
 	 */
@@ -133,9 +135,9 @@  discard block
 block discarded – undo
133 135
 	 * Checks whether the given user is allowed to see the tag with the given id.
134 136
 	 *
135 137
 	 * @param ISystemTag $tag tag to check permission for
136
-	 * @param IUser $user user to check permission for
138
+	 * @param IUser $userId user to check permission for
137 139
 	 *
138
-	 * @return true if the user can see the tag, false otherwise
140
+	 * @return boolean if the user can see the tag, false otherwise
139 141
 	 *
140 142
 	 * @since 9.1.0
141 143
 	 */
@@ -148,6 +150,7 @@  discard block
 block discarded – undo
148 150
 	 * @param string[] $groupIds group ids of groups that can assign/unassign the tag
149 151
 	 *
150 152
 	 * @since 9.1.0
153
+	 * @return void
151 154
 	 */
152 155
 	public function setTagGroups(ISystemTag $tag, $groupIds);
153 156
 
Please login to merge, or discard this patch.
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -33,133 +33,133 @@
 block discarded – undo
33 33
  */
34 34
 interface ISystemTagManager {
35 35
 
36
-	/**
37
-	 * Returns the tag objects matching the given tag ids.
38
-	 *
39
-	 * @param array|string $tagIds id or array of unique ids of the tag to retrieve
40
-	 *
41
-	 * @return \OCP\SystemTag\ISystemTag[] array of system tags with tag id as key
42
-	 *
43
-	 * @throws \InvalidArgumentException if at least one given tag ids is invalid (string instead of integer, etc.)
44
-	 * @throws \OCP\SystemTag\TagNotFoundException if at least one given tag ids did no exist
45
-	 * 			The message contains a json_encoded array of the ids that could not be found
46
-	 *
47
-	 * @since 9.0.0
48
-	 */
49
-	public function getTagsByIds($tagIds);
36
+    /**
37
+     * Returns the tag objects matching the given tag ids.
38
+     *
39
+     * @param array|string $tagIds id or array of unique ids of the tag to retrieve
40
+     *
41
+     * @return \OCP\SystemTag\ISystemTag[] array of system tags with tag id as key
42
+     *
43
+     * @throws \InvalidArgumentException if at least one given tag ids is invalid (string instead of integer, etc.)
44
+     * @throws \OCP\SystemTag\TagNotFoundException if at least one given tag ids did no exist
45
+     * 			The message contains a json_encoded array of the ids that could not be found
46
+     *
47
+     * @since 9.0.0
48
+     */
49
+    public function getTagsByIds($tagIds);
50 50
 
51
-	/**
52
-	 * Returns the tag object matching the given attributes.
53
-	 *
54
-	 * @param string $tagName tag name
55
-	 * @param bool $userVisible whether the tag is visible by users
56
-	 * @param bool $userAssignable whether the tag is assignable by users
57
-	 *
58
-	 * @return \OCP\SystemTag\ISystemTag system tag
59
-	 *
60
-	 * @throws \OCP\SystemTag\TagNotFoundException if tag does not exist
61
-	 *
62
-	 * @since 9.0.0
63
-	 */
64
-	public function getTag($tagName, $userVisible, $userAssignable);
51
+    /**
52
+     * Returns the tag object matching the given attributes.
53
+     *
54
+     * @param string $tagName tag name
55
+     * @param bool $userVisible whether the tag is visible by users
56
+     * @param bool $userAssignable whether the tag is assignable by users
57
+     *
58
+     * @return \OCP\SystemTag\ISystemTag system tag
59
+     *
60
+     * @throws \OCP\SystemTag\TagNotFoundException if tag does not exist
61
+     *
62
+     * @since 9.0.0
63
+     */
64
+    public function getTag($tagName, $userVisible, $userAssignable);
65 65
 
66
-	/**
67
-	 * Creates the tag object using the given attributes.
68
-	 *
69
-	 * @param string $tagName tag name
70
-	 * @param bool $userVisible whether the tag is visible by users
71
-	 * @param bool $userAssignable whether the tag is assignable by users
72
-	 *
73
-	 * @return \OCP\SystemTag\ISystemTag system tag
74
-	 *
75
-	 * @throws \OCP\SystemTag\TagAlreadyExistsException if tag already exists
76
-	 *
77
-	 * @since 9.0.0
78
-	 */
79
-	public function createTag($tagName, $userVisible, $userAssignable);
66
+    /**
67
+     * Creates the tag object using the given attributes.
68
+     *
69
+     * @param string $tagName tag name
70
+     * @param bool $userVisible whether the tag is visible by users
71
+     * @param bool $userAssignable whether the tag is assignable by users
72
+     *
73
+     * @return \OCP\SystemTag\ISystemTag system tag
74
+     *
75
+     * @throws \OCP\SystemTag\TagAlreadyExistsException if tag already exists
76
+     *
77
+     * @since 9.0.0
78
+     */
79
+    public function createTag($tagName, $userVisible, $userAssignable);
80 80
 
81
-	/**
82
-	 * Returns all known tags, optionally filtered by visibility.
83
-	 *
84
-	 * @param bool|null $visibilityFilter filter by visibility if non-null
85
-	 * @param string $nameSearchPattern optional search pattern for the tag name
86
-	 *
87
-	 * @return \OCP\SystemTag\ISystemTag[] array of system tags or empty array if none found
88
-	 *
89
-	 * @since 9.0.0
90
-	 */
91
-	public function getAllTags($visibilityFilter = null, $nameSearchPattern = null);
81
+    /**
82
+     * Returns all known tags, optionally filtered by visibility.
83
+     *
84
+     * @param bool|null $visibilityFilter filter by visibility if non-null
85
+     * @param string $nameSearchPattern optional search pattern for the tag name
86
+     *
87
+     * @return \OCP\SystemTag\ISystemTag[] array of system tags or empty array if none found
88
+     *
89
+     * @since 9.0.0
90
+     */
91
+    public function getAllTags($visibilityFilter = null, $nameSearchPattern = null);
92 92
 
93
-	/**
94
-	 * Updates the given tag
95
-	 *
96
-	 * @param string $tagId tag id
97
-	 * @param string $newName the new tag name
98
-	 * @param bool $userVisible whether the tag is visible by users
99
-	 * @param bool $userAssignable whether the tag is assignable by users
100
-	 *
101
-	 * @throws \OCP\SystemTag\TagNotFoundException if tag with the given id does not exist
102
-	 * @throws \OCP\SystemTag\TagAlreadyExistsException if there is already another tag
103
-	 * with the same attributes
104
-	 *
105
-	 * @since 9.0.0
106
-	 */
107
-	public function updateTag($tagId, $newName, $userVisible, $userAssignable);
93
+    /**
94
+     * Updates the given tag
95
+     *
96
+     * @param string $tagId tag id
97
+     * @param string $newName the new tag name
98
+     * @param bool $userVisible whether the tag is visible by users
99
+     * @param bool $userAssignable whether the tag is assignable by users
100
+     *
101
+     * @throws \OCP\SystemTag\TagNotFoundException if tag with the given id does not exist
102
+     * @throws \OCP\SystemTag\TagAlreadyExistsException if there is already another tag
103
+     * with the same attributes
104
+     *
105
+     * @since 9.0.0
106
+     */
107
+    public function updateTag($tagId, $newName, $userVisible, $userAssignable);
108 108
 
109
-	/**
110
-	 * Delete the given tags from the database and all their relationships.
111
-	 *
112
-	 * @param string|array $tagIds array of tag ids
113
-	 *
114
-	 * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist
115
-	 *
116
-	 * @since 9.0.0
117
-	 */
118
-	public function deleteTags($tagIds);
109
+    /**
110
+     * Delete the given tags from the database and all their relationships.
111
+     *
112
+     * @param string|array $tagIds array of tag ids
113
+     *
114
+     * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist
115
+     *
116
+     * @since 9.0.0
117
+     */
118
+    public function deleteTags($tagIds);
119 119
 
120
-	/**
121
-	 * Checks whether the given user is allowed to assign/unassign the tag with the
122
-	 * given id.
123
-	 *
124
-	 * @param ISystemTag $tag tag to check permission for
125
-	 * @param IUser $user user to check permission for
126
-	 *
127
-	 * @return true if the user is allowed to assign/unassign the tag, false otherwise
128
-	 *
129
-	 * @since 9.1.0
130
-	 */
131
-	public function canUserAssignTag(ISystemTag $tag, IUser $user);
120
+    /**
121
+     * Checks whether the given user is allowed to assign/unassign the tag with the
122
+     * given id.
123
+     *
124
+     * @param ISystemTag $tag tag to check permission for
125
+     * @param IUser $user user to check permission for
126
+     *
127
+     * @return true if the user is allowed to assign/unassign the tag, false otherwise
128
+     *
129
+     * @since 9.1.0
130
+     */
131
+    public function canUserAssignTag(ISystemTag $tag, IUser $user);
132 132
 
133
-	/**
134
-	 * Checks whether the given user is allowed to see the tag with the given id.
135
-	 *
136
-	 * @param ISystemTag $tag tag to check permission for
137
-	 * @param IUser $user user to check permission for
138
-	 *
139
-	 * @return true if the user can see the tag, false otherwise
140
-	 *
141
-	 * @since 9.1.0
142
-	 */
143
-	public function canUserSeeTag(ISystemTag $tag, IUser $userId);
133
+    /**
134
+     * Checks whether the given user is allowed to see the tag with the given id.
135
+     *
136
+     * @param ISystemTag $tag tag to check permission for
137
+     * @param IUser $user user to check permission for
138
+     *
139
+     * @return true if the user can see the tag, false otherwise
140
+     *
141
+     * @since 9.1.0
142
+     */
143
+    public function canUserSeeTag(ISystemTag $tag, IUser $userId);
144 144
 
145
-	/**
146
-	 * Set groups that can assign a given tag.
147
-	 *
148
-	 * @param ISystemTag $tag tag for group assignment
149
-	 * @param string[] $groupIds group ids of groups that can assign/unassign the tag
150
-	 *
151
-	 * @since 9.1.0
152
-	 */
153
-	public function setTagGroups(ISystemTag $tag, $groupIds);
145
+    /**
146
+     * Set groups that can assign a given tag.
147
+     *
148
+     * @param ISystemTag $tag tag for group assignment
149
+     * @param string[] $groupIds group ids of groups that can assign/unassign the tag
150
+     *
151
+     * @since 9.1.0
152
+     */
153
+    public function setTagGroups(ISystemTag $tag, $groupIds);
154 154
 
155
-	/**
156
-	 * Get groups that can assign a given tag.
157
-	 *
158
-	 * @param ISystemTag $tag tag for group assignment
159
-	 *
160
-	 * @return string[] group ids of groups that can assign/unassign the tag
161
-	 *
162
-	 * @since 9.1.0
163
-	 */
164
-	public function getTagGroups(ISystemTag $tag);
155
+    /**
156
+     * Get groups that can assign a given tag.
157
+     *
158
+     * @param ISystemTag $tag tag for group assignment
159
+     *
160
+     * @return string[] group ids of groups that can assign/unassign the tag
161
+     *
162
+     * @since 9.1.0
163
+     */
164
+    public function getTagGroups(ISystemTag $tag);
165 165
 }
Please login to merge, or discard this patch.
lib/private/Files/View.php 3 patches
Doc Comments   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -200,7 +200,7 @@  discard block
 block discarded – undo
200 200
 	 * and does not take the chroot into account )
201 201
 	 *
202 202
 	 * @param string $path
203
-	 * @return \OCP\Files\Mount\IMountPoint
203
+	 * @return Mount\MountPoint|null
204 204
 	 */
205 205
 	public function getMount($path) {
206 206
 		return Filesystem::getMountManager()->find($this->getAbsolutePath($path));
@@ -963,7 +963,7 @@  discard block
 block discarded – undo
963 963
 
964 964
 	/**
965 965
 	 * @param string $path
966
-	 * @return bool|string
966
+	 * @return string|false
967 967
 	 * @throws \OCP\Files\InvalidPathException
968 968
 	 */
969 969
 	public function toTmpFile($path) {
@@ -1078,7 +1078,7 @@  discard block
 block discarded – undo
1078 1078
 	 * @param string $path
1079 1079
 	 * @param array $hooks (optional)
1080 1080
 	 * @param mixed $extraParam (optional)
1081
-	 * @return mixed
1081
+	 * @return string
1082 1082
 	 * @throws \Exception
1083 1083
 	 *
1084 1084
 	 * This method takes requests for basic filesystem functions (e.g. reading & writing
@@ -2086,7 +2086,7 @@  discard block
 block discarded – undo
2086 2086
 
2087 2087
 	/**
2088 2088
 	 * @param string $filename
2089
-	 * @return array
2089
+	 * @return string[]
2090 2090
 	 * @throws \OC\User\NoUserException
2091 2091
 	 * @throws NotFoundException
2092 2092
 	 */
Please login to merge, or discard this patch.
Spacing   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -126,9 +126,9 @@  discard block
 block discarded – undo
126 126
 			$path = '/';
127 127
 		}
128 128
 		if ($path[0] !== '/') {
129
-			$path = '/' . $path;
129
+			$path = '/'.$path;
130 130
 		}
131
-		return $this->fakeRoot . $path;
131
+		return $this->fakeRoot.$path;
132 132
 	}
133 133
 
134 134
 	/**
@@ -140,7 +140,7 @@  discard block
 block discarded – undo
140 140
 	public function chroot($fakeRoot) {
141 141
 		if (!$fakeRoot == '') {
142 142
 			if ($fakeRoot[0] !== '/') {
143
-				$fakeRoot = '/' . $fakeRoot;
143
+				$fakeRoot = '/'.$fakeRoot;
144 144
 			}
145 145
 		}
146 146
 		$this->fakeRoot = $fakeRoot;
@@ -172,7 +172,7 @@  discard block
 block discarded – undo
172 172
 		}
173 173
 
174 174
 		// missing slashes can cause wrong matches!
175
-		$root = rtrim($this->fakeRoot, '/') . '/';
175
+		$root = rtrim($this->fakeRoot, '/').'/';
176 176
 
177 177
 		if (strpos($path, $root) !== 0) {
178 178
 			return null;
@@ -278,7 +278,7 @@  discard block
 block discarded – undo
278 278
 		if ($mount instanceof MoveableMount) {
279 279
 			// cut of /user/files to get the relative path to data/user/files
280 280
 			$pathParts = explode('/', $path, 4);
281
-			$relPath = '/' . $pathParts[3];
281
+			$relPath = '/'.$pathParts[3];
282 282
 			$this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
283 283
 			\OC_Hook::emit(
284 284
 				Filesystem::CLASSNAME, "umount",
@@ -698,7 +698,7 @@  discard block
 block discarded – undo
698 698
 		}
699 699
 		$postFix = (substr($path, -1) === '/') ? '/' : '';
700 700
 		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
701
-		$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
701
+		$mount = Filesystem::getMountManager()->find($absolutePath.$postFix);
702 702
 		if ($mount and $mount->getInternalPath($absolutePath) === '') {
703 703
 			return $this->removeMount($mount, $absolutePath);
704 704
 		}
@@ -818,7 +818,7 @@  discard block
 block discarded – undo
818 818
 								$this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
819 819
 							}
820 820
 						}
821
-					} catch(\Exception $e) {
821
+					} catch (\Exception $e) {
822 822
 						throw $e;
823 823
 					} finally {
824 824
 						$this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
@@ -842,7 +842,7 @@  discard block
 block discarded – undo
842 842
 						}
843 843
 					}
844 844
 				}
845
-			} catch(\Exception $e) {
845
+			} catch (\Exception $e) {
846 846
 				throw $e;
847 847
 			} finally {
848 848
 				$this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
@@ -975,7 +975,7 @@  discard block
 block discarded – undo
975 975
 				$hooks[] = 'write';
976 976
 				break;
977 977
 			default:
978
-				\OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR);
978
+				\OCP\Util::writeLog('core', 'invalid mode ('.$mode.') for '.$path, \OCP\Util::ERROR);
979 979
 		}
980 980
 
981 981
 		if ($mode !== 'r' && $mode !== 'w') {
@@ -1079,7 +1079,7 @@  discard block
 block discarded – undo
1079 1079
 					array(Filesystem::signal_param_path => $this->getHookPath($path))
1080 1080
 				);
1081 1081
 			}
1082
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1082
+			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath.$postFix);
1083 1083
 			if ($storage) {
1084 1084
 				return $storage->hash($type, $internalPath, $raw);
1085 1085
 			}
@@ -1133,7 +1133,7 @@  discard block
 block discarded – undo
1133 1133
 
1134 1134
 			$run = $this->runHooks($hooks, $path);
1135 1135
 			/** @var \OC\Files\Storage\Storage $storage */
1136
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1136
+			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath.$postFix);
1137 1137
 			if ($run and $storage) {
1138 1138
 				if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1139 1139
 					$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
@@ -1172,7 +1172,7 @@  discard block
 block discarded – undo
1172 1172
 					$unlockLater = true;
1173 1173
 					// make sure our unlocking callback will still be called if connection is aborted
1174 1174
 					ignore_user_abort(true);
1175
-					$result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1175
+					$result = CallbackWrapper::wrap($result, null, null, function() use ($hooks, $path) {
1176 1176
 						if (in_array('write', $hooks)) {
1177 1177
 							$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1178 1178
 						} else if (in_array('read', $hooks)) {
@@ -1233,7 +1233,7 @@  discard block
 block discarded – undo
1233 1233
 			return true;
1234 1234
 		}
1235 1235
 
1236
-		return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1236
+		return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot.'/');
1237 1237
 	}
1238 1238
 
1239 1239
 	/**
@@ -1252,7 +1252,7 @@  discard block
 block discarded – undo
1252 1252
 				if ($hook != 'read') {
1253 1253
 					\OC_Hook::emit(
1254 1254
 						Filesystem::CLASSNAME,
1255
-						$prefix . $hook,
1255
+						$prefix.$hook,
1256 1256
 						array(
1257 1257
 							Filesystem::signal_param_run => &$run,
1258 1258
 							Filesystem::signal_param_path => $path
@@ -1261,7 +1261,7 @@  discard block
 block discarded – undo
1261 1261
 				} elseif (!$post) {
1262 1262
 					\OC_Hook::emit(
1263 1263
 						Filesystem::CLASSNAME,
1264
-						$prefix . $hook,
1264
+						$prefix.$hook,
1265 1265
 						array(
1266 1266
 							Filesystem::signal_param_path => $path
1267 1267
 						)
@@ -1356,7 +1356,7 @@  discard block
 block discarded – undo
1356 1356
 			return $this->getPartFileInfo($path);
1357 1357
 		}
1358 1358
 		$relativePath = $path;
1359
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1359
+		$path = Filesystem::normalizePath($this->fakeRoot.'/'.$path);
1360 1360
 
1361 1361
 		$mount = Filesystem::getMountManager()->find($path);
1362 1362
 		if (!$mount) {
@@ -1383,7 +1383,7 @@  discard block
 block discarded – undo
1383 1383
 					//add the sizes of other mount points to the folder
1384 1384
 					$extOnly = ($includeMountPoints === 'ext');
1385 1385
 					$mounts = Filesystem::getMountManager()->findIn($path);
1386
-					$info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1386
+					$info->setSubMounts(array_filter($mounts, function(IMountPoint $mount) use ($extOnly) {
1387 1387
 						$subStorage = $mount->getStorage();
1388 1388
 						return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1389 1389
 					}));
@@ -1433,12 +1433,12 @@  discard block
 block discarded – undo
1433 1433
 			/**
1434 1434
 			 * @var \OC\Files\FileInfo[] $files
1435 1435
 			 */
1436
-			$files = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1436
+			$files = array_map(function(ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1437 1437
 				if ($sharingDisabled) {
1438 1438
 					$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1439 1439
 				}
1440 1440
 				$owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1441
-				return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1441
+				return new FileInfo($path.'/'.$content['name'], $storage, $content['path'], $content, $mount, $owner);
1442 1442
 			}, $contents);
1443 1443
 
1444 1444
 			//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
@@ -1462,7 +1462,7 @@  discard block
 block discarded – undo
1462 1462
 						} catch (\Exception $e) {
1463 1463
 							// sometimes when the storage is not available it can be any exception
1464 1464
 							\OC::$server->getLogger()->logException($e, [
1465
-								'message' => 'Exception while scanning storage "' . $subStorage->getId() . '"',
1465
+								'message' => 'Exception while scanning storage "'.$subStorage->getId().'"',
1466 1466
 								'level' => \OCP\Util::ERROR,
1467 1467
 								'app' => 'lib',
1468 1468
 							]);
@@ -1500,7 +1500,7 @@  discard block
 block discarded – undo
1500 1500
 									break;
1501 1501
 								}
1502 1502
 							}
1503
-							$rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1503
+							$rootEntry['path'] = substr(Filesystem::normalizePath($path.'/'.$rootEntry['name']), strlen($user) + 2); // full path without /$user/
1504 1504
 
1505 1505
 							// if sharing was disabled for the user we remove the share permissions
1506 1506
 							if (\OCP\Util::isSharingDisabledForUser()) {
@@ -1508,14 +1508,14 @@  discard block
 block discarded – undo
1508 1508
 							}
1509 1509
 
1510 1510
 							$owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1511
-							$files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1511
+							$files[] = new FileInfo($path.'/'.$rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1512 1512
 						}
1513 1513
 					}
1514 1514
 				}
1515 1515
 			}
1516 1516
 
1517 1517
 			if ($mimetype_filter) {
1518
-				$files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1518
+				$files = array_filter($files, function(FileInfo $file) use ($mimetype_filter) {
1519 1519
 					if (strpos($mimetype_filter, '/')) {
1520 1520
 						return $file->getMimetype() === $mimetype_filter;
1521 1521
 					} else {
@@ -1544,7 +1544,7 @@  discard block
 block discarded – undo
1544 1544
 		if ($data instanceof FileInfo) {
1545 1545
 			$data = $data->getData();
1546 1546
 		}
1547
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1547
+		$path = Filesystem::normalizePath($this->fakeRoot.'/'.$path);
1548 1548
 		/**
1549 1549
 		 * @var \OC\Files\Storage\Storage $storage
1550 1550
 		 * @var string $internalPath
@@ -1571,7 +1571,7 @@  discard block
 block discarded – undo
1571 1571
 	 * @return FileInfo[]
1572 1572
 	 */
1573 1573
 	public function search($query) {
1574
-		return $this->searchCommon('search', array('%' . $query . '%'));
1574
+		return $this->searchCommon('search', array('%'.$query.'%'));
1575 1575
 	}
1576 1576
 
1577 1577
 	/**
@@ -1622,10 +1622,10 @@  discard block
 block discarded – undo
1622 1622
 
1623 1623
 			$results = call_user_func_array(array($cache, $method), $args);
1624 1624
 			foreach ($results as $result) {
1625
-				if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1625
+				if (substr($mountPoint.$result['path'], 0, $rootLength + 1) === $this->fakeRoot.'/') {
1626 1626
 					$internalPath = $result['path'];
1627
-					$path = $mountPoint . $result['path'];
1628
-					$result['path'] = substr($mountPoint . $result['path'], $rootLength);
1627
+					$path = $mountPoint.$result['path'];
1628
+					$result['path'] = substr($mountPoint.$result['path'], $rootLength);
1629 1629
 					$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1630 1630
 					$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1631 1631
 				}
@@ -1643,8 +1643,8 @@  discard block
 block discarded – undo
1643 1643
 					if ($results) {
1644 1644
 						foreach ($results as $result) {
1645 1645
 							$internalPath = $result['path'];
1646
-							$result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1647
-							$path = rtrim($mountPoint . $internalPath, '/');
1646
+							$result['path'] = rtrim($relativeMountPoint.$result['path'], '/');
1647
+							$path = rtrim($mountPoint.$internalPath, '/');
1648 1648
 							$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1649 1649
 							$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1650 1650
 						}
@@ -1665,7 +1665,7 @@  discard block
 block discarded – undo
1665 1665
 	public function getOwner($path) {
1666 1666
 		$info = $this->getFileInfo($path);
1667 1667
 		if (!$info) {
1668
-			throw new NotFoundException($path . ' not found while trying to get owner');
1668
+			throw new NotFoundException($path.' not found while trying to get owner');
1669 1669
 		}
1670 1670
 		return $info->getOwner()->getUID();
1671 1671
 	}
@@ -1699,7 +1699,7 @@  discard block
 block discarded – undo
1699 1699
 	 * @return string
1700 1700
 	 */
1701 1701
 	public function getPath($id) {
1702
-		$id = (int)$id;
1702
+		$id = (int) $id;
1703 1703
 		$manager = Filesystem::getMountManager();
1704 1704
 		$mounts = $manager->findIn($this->fakeRoot);
1705 1705
 		$mounts[] = $manager->find($this->fakeRoot);
@@ -1714,7 +1714,7 @@  discard block
 block discarded – undo
1714 1714
 				$cache = $mount->getStorage()->getCache();
1715 1715
 				$internalPath = $cache->getPathById($id);
1716 1716
 				if (is_string($internalPath)) {
1717
-					$fullPath = $mount->getMountPoint() . $internalPath;
1717
+					$fullPath = $mount->getMountPoint().$internalPath;
1718 1718
 					if (!is_null($path = $this->getRelativePath($fullPath))) {
1719 1719
 						return $path;
1720 1720
 					}
@@ -1757,10 +1757,10 @@  discard block
 block discarded – undo
1757 1757
 		}
1758 1758
 
1759 1759
 		// note: cannot use the view because the target is already locked
1760
-		$fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1760
+		$fileId = (int) $targetStorage->getCache()->getId($targetInternalPath);
1761 1761
 		if ($fileId === -1) {
1762 1762
 			// target might not exist, need to check parent instead
1763
-			$fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1763
+			$fileId = (int) $targetStorage->getCache()->getId(dirname($targetInternalPath));
1764 1764
 		}
1765 1765
 
1766 1766
 		// check if any of the parents were shared by the current owner (include collections)
@@ -1860,7 +1860,7 @@  discard block
 block discarded – undo
1860 1860
 		$resultPath = '';
1861 1861
 		foreach ($parts as $part) {
1862 1862
 			if ($part) {
1863
-				$resultPath .= '/' . $part;
1863
+				$resultPath .= '/'.$part;
1864 1864
 				$result[] = $resultPath;
1865 1865
 			}
1866 1866
 		}
@@ -2123,16 +2123,16 @@  discard block
 block discarded – undo
2123 2123
 	public function getUidAndFilename($filename) {
2124 2124
 		$info = $this->getFileInfo($filename);
2125 2125
 		if (!$info instanceof \OCP\Files\FileInfo) {
2126
-			throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2126
+			throw new NotFoundException($this->getAbsolutePath($filename).' not found');
2127 2127
 		}
2128 2128
 		$uid = $info->getOwner()->getUID();
2129 2129
 		if ($uid != \OCP\User::getUser()) {
2130 2130
 			Filesystem::initMountPoints($uid);
2131
-			$ownerView = new View('/' . $uid . '/files');
2131
+			$ownerView = new View('/'.$uid.'/files');
2132 2132
 			try {
2133 2133
 				$filename = $ownerView->getPath($info['fileid']);
2134 2134
 			} catch (NotFoundException $e) {
2135
-				throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2135
+				throw new NotFoundException('File with id '.$info['fileid'].' not found for user '.$uid);
2136 2136
 			}
2137 2137
 		}
2138 2138
 		return [$uid, $filename];
@@ -2149,7 +2149,7 @@  discard block
 block discarded – undo
2149 2149
 		$directoryParts = array_filter($directoryParts);
2150 2150
 		foreach ($directoryParts as $key => $part) {
2151 2151
 			$currentPathElements = array_slice($directoryParts, 0, $key);
2152
-			$currentPath = '/' . implode('/', $currentPathElements);
2152
+			$currentPath = '/'.implode('/', $currentPathElements);
2153 2153
 			if ($this->is_file($currentPath)) {
2154 2154
 				return false;
2155 2155
 			}
Please login to merge, or discard this patch.
Indentation   +2080 added lines, -2080 removed lines patch added patch discarded remove patch
@@ -80,2084 +80,2084 @@
 block discarded – undo
80 80
  * \OC\Files\Storage\Storage object
81 81
  */
82 82
 class View {
83
-	/** @var string */
84
-	private $fakeRoot = '';
85
-
86
-	/**
87
-	 * @var \OCP\Lock\ILockingProvider
88
-	 */
89
-	protected $lockingProvider;
90
-
91
-	private $lockingEnabled;
92
-
93
-	private $updaterEnabled = true;
94
-
95
-	/** @var \OC\User\Manager */
96
-	private $userManager;
97
-
98
-	/** @var \OCP\ILogger */
99
-	private $logger;
100
-
101
-	/**
102
-	 * @param string $root
103
-	 * @throws \Exception If $root contains an invalid path
104
-	 */
105
-	public function __construct($root = '') {
106
-		if (is_null($root)) {
107
-			throw new \InvalidArgumentException('Root can\'t be null');
108
-		}
109
-		if (!Filesystem::isValidPath($root)) {
110
-			throw new \Exception();
111
-		}
112
-
113
-		$this->fakeRoot = $root;
114
-		$this->lockingProvider = \OC::$server->getLockingProvider();
115
-		$this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
116
-		$this->userManager = \OC::$server->getUserManager();
117
-		$this->logger = \OC::$server->getLogger();
118
-	}
119
-
120
-	public function getAbsolutePath($path = '/') {
121
-		if ($path === null) {
122
-			return null;
123
-		}
124
-		$this->assertPathLength($path);
125
-		if ($path === '') {
126
-			$path = '/';
127
-		}
128
-		if ($path[0] !== '/') {
129
-			$path = '/' . $path;
130
-		}
131
-		return $this->fakeRoot . $path;
132
-	}
133
-
134
-	/**
135
-	 * change the root to a fake root
136
-	 *
137
-	 * @param string $fakeRoot
138
-	 * @return boolean|null
139
-	 */
140
-	public function chroot($fakeRoot) {
141
-		if (!$fakeRoot == '') {
142
-			if ($fakeRoot[0] !== '/') {
143
-				$fakeRoot = '/' . $fakeRoot;
144
-			}
145
-		}
146
-		$this->fakeRoot = $fakeRoot;
147
-	}
148
-
149
-	/**
150
-	 * get the fake root
151
-	 *
152
-	 * @return string
153
-	 */
154
-	public function getRoot() {
155
-		return $this->fakeRoot;
156
-	}
157
-
158
-	/**
159
-	 * get path relative to the root of the view
160
-	 *
161
-	 * @param string $path
162
-	 * @return string
163
-	 */
164
-	public function getRelativePath($path) {
165
-		$this->assertPathLength($path);
166
-		if ($this->fakeRoot == '') {
167
-			return $path;
168
-		}
169
-
170
-		if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) {
171
-			return '/';
172
-		}
173
-
174
-		// missing slashes can cause wrong matches!
175
-		$root = rtrim($this->fakeRoot, '/') . '/';
176
-
177
-		if (strpos($path, $root) !== 0) {
178
-			return null;
179
-		} else {
180
-			$path = substr($path, strlen($this->fakeRoot));
181
-			if (strlen($path) === 0) {
182
-				return '/';
183
-			} else {
184
-				return $path;
185
-			}
186
-		}
187
-	}
188
-
189
-	/**
190
-	 * get the mountpoint of the storage object for a path
191
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
192
-	 * returned mountpoint is relative to the absolute root of the filesystem
193
-	 * and does not take the chroot into account )
194
-	 *
195
-	 * @param string $path
196
-	 * @return string
197
-	 */
198
-	public function getMountPoint($path) {
199
-		return Filesystem::getMountPoint($this->getAbsolutePath($path));
200
-	}
201
-
202
-	/**
203
-	 * get the mountpoint of the storage object for a path
204
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
205
-	 * returned mountpoint is relative to the absolute root of the filesystem
206
-	 * and does not take the chroot into account )
207
-	 *
208
-	 * @param string $path
209
-	 * @return \OCP\Files\Mount\IMountPoint
210
-	 */
211
-	public function getMount($path) {
212
-		return Filesystem::getMountManager()->find($this->getAbsolutePath($path));
213
-	}
214
-
215
-	/**
216
-	 * resolve a path to a storage and internal path
217
-	 *
218
-	 * @param string $path
219
-	 * @return array an array consisting of the storage and the internal path
220
-	 */
221
-	public function resolvePath($path) {
222
-		$a = $this->getAbsolutePath($path);
223
-		$p = Filesystem::normalizePath($a);
224
-		return Filesystem::resolvePath($p);
225
-	}
226
-
227
-	/**
228
-	 * return the path to a local version of the file
229
-	 * we need this because we can't know if a file is stored local or not from
230
-	 * outside the filestorage and for some purposes a local file is needed
231
-	 *
232
-	 * @param string $path
233
-	 * @return string
234
-	 */
235
-	public function getLocalFile($path) {
236
-		$parent = substr($path, 0, strrpos($path, '/'));
237
-		$path = $this->getAbsolutePath($path);
238
-		list($storage, $internalPath) = Filesystem::resolvePath($path);
239
-		if (Filesystem::isValidPath($parent) and $storage) {
240
-			return $storage->getLocalFile($internalPath);
241
-		} else {
242
-			return null;
243
-		}
244
-	}
245
-
246
-	/**
247
-	 * @param string $path
248
-	 * @return string
249
-	 */
250
-	public function getLocalFolder($path) {
251
-		$parent = substr($path, 0, strrpos($path, '/'));
252
-		$path = $this->getAbsolutePath($path);
253
-		list($storage, $internalPath) = Filesystem::resolvePath($path);
254
-		if (Filesystem::isValidPath($parent) and $storage) {
255
-			return $storage->getLocalFolder($internalPath);
256
-		} else {
257
-			return null;
258
-		}
259
-	}
260
-
261
-	/**
262
-	 * the following functions operate with arguments and return values identical
263
-	 * to those of their PHP built-in equivalents. Mostly they are merely wrappers
264
-	 * for \OC\Files\Storage\Storage via basicOperation().
265
-	 */
266
-	public function mkdir($path) {
267
-		return $this->basicOperation('mkdir', $path, array('create', 'write'));
268
-	}
269
-
270
-	/**
271
-	 * remove mount point
272
-	 *
273
-	 * @param \OC\Files\Mount\MoveableMount $mount
274
-	 * @param string $path relative to data/
275
-	 * @return boolean
276
-	 */
277
-	protected function removeMount($mount, $path) {
278
-		if ($mount instanceof MoveableMount) {
279
-			// cut of /user/files to get the relative path to data/user/files
280
-			$pathParts = explode('/', $path, 4);
281
-			$relPath = '/' . $pathParts[3];
282
-			$this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
283
-			\OC_Hook::emit(
284
-				Filesystem::CLASSNAME, "umount",
285
-				array(Filesystem::signal_param_path => $relPath)
286
-			);
287
-			$this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true);
288
-			$result = $mount->removeMount();
289
-			$this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true);
290
-			if ($result) {
291
-				\OC_Hook::emit(
292
-					Filesystem::CLASSNAME, "post_umount",
293
-					array(Filesystem::signal_param_path => $relPath)
294
-				);
295
-			}
296
-			$this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true);
297
-			return $result;
298
-		} else {
299
-			// do not allow deleting the storage's root / the mount point
300
-			// because for some storages it might delete the whole contents
301
-			// but isn't supposed to work that way
302
-			return false;
303
-		}
304
-	}
305
-
306
-	public function disableCacheUpdate() {
307
-		$this->updaterEnabled = false;
308
-	}
309
-
310
-	public function enableCacheUpdate() {
311
-		$this->updaterEnabled = true;
312
-	}
313
-
314
-	protected function writeUpdate(Storage $storage, $internalPath, $time = null) {
315
-		if ($this->updaterEnabled) {
316
-			if (is_null($time)) {
317
-				$time = time();
318
-			}
319
-			$storage->getUpdater()->update($internalPath, $time);
320
-		}
321
-	}
322
-
323
-	protected function removeUpdate(Storage $storage, $internalPath) {
324
-		if ($this->updaterEnabled) {
325
-			$storage->getUpdater()->remove($internalPath);
326
-		}
327
-	}
328
-
329
-	protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) {
330
-		if ($this->updaterEnabled) {
331
-			$targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
332
-		}
333
-	}
334
-
335
-	/**
336
-	 * @param string $path
337
-	 * @return bool|mixed
338
-	 */
339
-	public function rmdir($path) {
340
-		$absolutePath = $this->getAbsolutePath($path);
341
-		$mount = Filesystem::getMountManager()->find($absolutePath);
342
-		if ($mount->getInternalPath($absolutePath) === '') {
343
-			return $this->removeMount($mount, $absolutePath);
344
-		}
345
-		if ($this->is_dir($path)) {
346
-			$result = $this->basicOperation('rmdir', $path, array('delete'));
347
-		} else {
348
-			$result = false;
349
-		}
350
-
351
-		if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
352
-			$storage = $mount->getStorage();
353
-			$internalPath = $mount->getInternalPath($absolutePath);
354
-			$storage->getUpdater()->remove($internalPath);
355
-		}
356
-		return $result;
357
-	}
358
-
359
-	/**
360
-	 * @param string $path
361
-	 * @return resource
362
-	 */
363
-	public function opendir($path) {
364
-		return $this->basicOperation('opendir', $path, array('read'));
365
-	}
366
-
367
-	/**
368
-	 * @param string $path
369
-	 * @return bool|mixed
370
-	 */
371
-	public function is_dir($path) {
372
-		if ($path == '/') {
373
-			return true;
374
-		}
375
-		return $this->basicOperation('is_dir', $path);
376
-	}
377
-
378
-	/**
379
-	 * @param string $path
380
-	 * @return bool|mixed
381
-	 */
382
-	public function is_file($path) {
383
-		if ($path == '/') {
384
-			return false;
385
-		}
386
-		return $this->basicOperation('is_file', $path);
387
-	}
388
-
389
-	/**
390
-	 * @param string $path
391
-	 * @return mixed
392
-	 */
393
-	public function stat($path) {
394
-		return $this->basicOperation('stat', $path);
395
-	}
396
-
397
-	/**
398
-	 * @param string $path
399
-	 * @return mixed
400
-	 */
401
-	public function filetype($path) {
402
-		return $this->basicOperation('filetype', $path);
403
-	}
404
-
405
-	/**
406
-	 * @param string $path
407
-	 * @return mixed
408
-	 */
409
-	public function filesize($path) {
410
-		return $this->basicOperation('filesize', $path);
411
-	}
412
-
413
-	/**
414
-	 * @param string $path
415
-	 * @return bool|mixed
416
-	 * @throws \OCP\Files\InvalidPathException
417
-	 */
418
-	public function readfile($path) {
419
-		$this->assertPathLength($path);
420
-		@ob_end_clean();
421
-		$handle = $this->fopen($path, 'rb');
422
-		if ($handle) {
423
-			$chunkSize = 8192; // 8 kB chunks
424
-			while (!feof($handle)) {
425
-				echo fread($handle, $chunkSize);
426
-				flush();
427
-			}
428
-			fclose($handle);
429
-			return $this->filesize($path);
430
-		}
431
-		return false;
432
-	}
433
-
434
-	/**
435
-	 * @param string $path
436
-	 * @param int $from
437
-	 * @param int $to
438
-	 * @return bool|mixed
439
-	 * @throws \OCP\Files\InvalidPathException
440
-	 * @throws \OCP\Files\UnseekableException
441
-	 */
442
-	public function readfilePart($path, $from, $to) {
443
-		$this->assertPathLength($path);
444
-		@ob_end_clean();
445
-		$handle = $this->fopen($path, 'rb');
446
-		if ($handle) {
447
-			$chunkSize = 8192; // 8 kB chunks
448
-			$startReading = true;
449
-
450
-			if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) {
451
-				// forward file handle via chunked fread because fseek seem to have failed
452
-
453
-				$end = $from + 1;
454
-				while (!feof($handle) && ftell($handle) < $end) {
455
-					$len = $from - ftell($handle);
456
-					if ($len > $chunkSize) {
457
-						$len = $chunkSize;
458
-					}
459
-					$result = fread($handle, $len);
460
-
461
-					if ($result === false) {
462
-						$startReading = false;
463
-						break;
464
-					}
465
-				}
466
-			}
467
-
468
-			if ($startReading) {
469
-				$end = $to + 1;
470
-				while (!feof($handle) && ftell($handle) < $end) {
471
-					$len = $end - ftell($handle);
472
-					if ($len > $chunkSize) {
473
-						$len = $chunkSize;
474
-					}
475
-					echo fread($handle, $len);
476
-					flush();
477
-				}
478
-				return ftell($handle) - $from;
479
-			}
480
-
481
-			throw new \OCP\Files\UnseekableException('fseek error');
482
-		}
483
-		return false;
484
-	}
485
-
486
-	/**
487
-	 * @param string $path
488
-	 * @return mixed
489
-	 */
490
-	public function isCreatable($path) {
491
-		return $this->basicOperation('isCreatable', $path);
492
-	}
493
-
494
-	/**
495
-	 * @param string $path
496
-	 * @return mixed
497
-	 */
498
-	public function isReadable($path) {
499
-		return $this->basicOperation('isReadable', $path);
500
-	}
501
-
502
-	/**
503
-	 * @param string $path
504
-	 * @return mixed
505
-	 */
506
-	public function isUpdatable($path) {
507
-		return $this->basicOperation('isUpdatable', $path);
508
-	}
509
-
510
-	/**
511
-	 * @param string $path
512
-	 * @return bool|mixed
513
-	 */
514
-	public function isDeletable($path) {
515
-		$absolutePath = $this->getAbsolutePath($path);
516
-		$mount = Filesystem::getMountManager()->find($absolutePath);
517
-		if ($mount->getInternalPath($absolutePath) === '') {
518
-			return $mount instanceof MoveableMount;
519
-		}
520
-		return $this->basicOperation('isDeletable', $path);
521
-	}
522
-
523
-	/**
524
-	 * @param string $path
525
-	 * @return mixed
526
-	 */
527
-	public function isSharable($path) {
528
-		return $this->basicOperation('isSharable', $path);
529
-	}
530
-
531
-	/**
532
-	 * @param string $path
533
-	 * @return bool|mixed
534
-	 */
535
-	public function file_exists($path) {
536
-		if ($path == '/') {
537
-			return true;
538
-		}
539
-		return $this->basicOperation('file_exists', $path);
540
-	}
541
-
542
-	/**
543
-	 * @param string $path
544
-	 * @return mixed
545
-	 */
546
-	public function filemtime($path) {
547
-		return $this->basicOperation('filemtime', $path);
548
-	}
549
-
550
-	/**
551
-	 * @param string $path
552
-	 * @param int|string $mtime
553
-	 * @return bool
554
-	 */
555
-	public function touch($path, $mtime = null) {
556
-		if (!is_null($mtime) and !is_numeric($mtime)) {
557
-			$mtime = strtotime($mtime);
558
-		}
559
-
560
-		$hooks = array('touch');
561
-
562
-		if (!$this->file_exists($path)) {
563
-			$hooks[] = 'create';
564
-			$hooks[] = 'write';
565
-		}
566
-		$result = $this->basicOperation('touch', $path, $hooks, $mtime);
567
-		if (!$result) {
568
-			// If create file fails because of permissions on external storage like SMB folders,
569
-			// check file exists and return false if not.
570
-			if (!$this->file_exists($path)) {
571
-				return false;
572
-			}
573
-			if (is_null($mtime)) {
574
-				$mtime = time();
575
-			}
576
-			//if native touch fails, we emulate it by changing the mtime in the cache
577
-			$this->putFileInfo($path, array('mtime' => floor($mtime)));
578
-		}
579
-		return true;
580
-	}
581
-
582
-	/**
583
-	 * @param string $path
584
-	 * @return mixed
585
-	 */
586
-	public function file_get_contents($path) {
587
-		return $this->basicOperation('file_get_contents', $path, array('read'));
588
-	}
589
-
590
-	/**
591
-	 * @param bool $exists
592
-	 * @param string $path
593
-	 * @param bool $run
594
-	 */
595
-	protected function emit_file_hooks_pre($exists, $path, &$run) {
596
-		if (!$exists) {
597
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, array(
598
-				Filesystem::signal_param_path => $this->getHookPath($path),
599
-				Filesystem::signal_param_run => &$run,
600
-			));
601
-		} else {
602
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, array(
603
-				Filesystem::signal_param_path => $this->getHookPath($path),
604
-				Filesystem::signal_param_run => &$run,
605
-			));
606
-		}
607
-		\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, array(
608
-			Filesystem::signal_param_path => $this->getHookPath($path),
609
-			Filesystem::signal_param_run => &$run,
610
-		));
611
-	}
612
-
613
-	/**
614
-	 * @param bool $exists
615
-	 * @param string $path
616
-	 */
617
-	protected function emit_file_hooks_post($exists, $path) {
618
-		if (!$exists) {
619
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, array(
620
-				Filesystem::signal_param_path => $this->getHookPath($path),
621
-			));
622
-		} else {
623
-			\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, array(
624
-				Filesystem::signal_param_path => $this->getHookPath($path),
625
-			));
626
-		}
627
-		\OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, array(
628
-			Filesystem::signal_param_path => $this->getHookPath($path),
629
-		));
630
-	}
631
-
632
-	/**
633
-	 * @param string $path
634
-	 * @param mixed $data
635
-	 * @return bool|mixed
636
-	 * @throws \Exception
637
-	 */
638
-	public function file_put_contents($path, $data) {
639
-		if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
640
-			$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
641
-			if (Filesystem::isValidPath($path)
642
-				and !Filesystem::isFileBlacklisted($path)
643
-			) {
644
-				$path = $this->getRelativePath($absolutePath);
645
-
646
-				$this->lockFile($path, ILockingProvider::LOCK_SHARED);
647
-
648
-				$exists = $this->file_exists($path);
649
-				$run = true;
650
-				if ($this->shouldEmitHooks($path)) {
651
-					$this->emit_file_hooks_pre($exists, $path, $run);
652
-				}
653
-				if (!$run) {
654
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
655
-					return false;
656
-				}
657
-
658
-				$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
659
-
660
-				/** @var \OC\Files\Storage\Storage $storage */
661
-				list($storage, $internalPath) = $this->resolvePath($path);
662
-				$target = $storage->fopen($internalPath, 'w');
663
-				if ($target) {
664
-					list (, $result) = \OC_Helper::streamCopy($data, $target);
665
-					fclose($target);
666
-					fclose($data);
667
-
668
-					$this->writeUpdate($storage, $internalPath);
669
-
670
-					$this->changeLock($path, ILockingProvider::LOCK_SHARED);
671
-
672
-					if ($this->shouldEmitHooks($path) && $result !== false) {
673
-						$this->emit_file_hooks_post($exists, $path);
674
-					}
675
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
676
-					return $result;
677
-				} else {
678
-					$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
679
-					return false;
680
-				}
681
-			} else {
682
-				return false;
683
-			}
684
-		} else {
685
-			$hooks = $this->file_exists($path) ? array('update', 'write') : array('create', 'write');
686
-			return $this->basicOperation('file_put_contents', $path, $hooks, $data);
687
-		}
688
-	}
689
-
690
-	/**
691
-	 * @param string $path
692
-	 * @return bool|mixed
693
-	 */
694
-	public function unlink($path) {
695
-		if ($path === '' || $path === '/') {
696
-			// do not allow deleting the root
697
-			return false;
698
-		}
699
-		$postFix = (substr($path, -1) === '/') ? '/' : '';
700
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
701
-		$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
702
-		if ($mount and $mount->getInternalPath($absolutePath) === '') {
703
-			return $this->removeMount($mount, $absolutePath);
704
-		}
705
-		if ($this->is_dir($path)) {
706
-			$result = $this->basicOperation('rmdir', $path, ['delete']);
707
-		} else {
708
-			$result = $this->basicOperation('unlink', $path, ['delete']);
709
-		}
710
-		if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
711
-			$storage = $mount->getStorage();
712
-			$internalPath = $mount->getInternalPath($absolutePath);
713
-			$storage->getUpdater()->remove($internalPath);
714
-			return true;
715
-		} else {
716
-			return $result;
717
-		}
718
-	}
719
-
720
-	/**
721
-	 * @param string $directory
722
-	 * @return bool|mixed
723
-	 */
724
-	public function deleteAll($directory) {
725
-		return $this->rmdir($directory);
726
-	}
727
-
728
-	/**
729
-	 * Rename/move a file or folder from the source path to target path.
730
-	 *
731
-	 * @param string $path1 source path
732
-	 * @param string $path2 target path
733
-	 *
734
-	 * @return bool|mixed
735
-	 */
736
-	public function rename($path1, $path2) {
737
-		$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
738
-		$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
739
-		$result = false;
740
-		if (
741
-			Filesystem::isValidPath($path2)
742
-			and Filesystem::isValidPath($path1)
743
-			and !Filesystem::isFileBlacklisted($path2)
744
-		) {
745
-			$path1 = $this->getRelativePath($absolutePath1);
746
-			$path2 = $this->getRelativePath($absolutePath2);
747
-			$exists = $this->file_exists($path2);
748
-
749
-			if ($path1 == null or $path2 == null) {
750
-				return false;
751
-			}
752
-
753
-			$this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
754
-			try {
755
-				$this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
756
-
757
-				$run = true;
758
-				if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
759
-					// if it was a rename from a part file to a regular file it was a write and not a rename operation
760
-					$this->emit_file_hooks_pre($exists, $path2, $run);
761
-				} elseif ($this->shouldEmitHooks($path1)) {
762
-					\OC_Hook::emit(
763
-						Filesystem::CLASSNAME, Filesystem::signal_rename,
764
-						array(
765
-							Filesystem::signal_param_oldpath => $this->getHookPath($path1),
766
-							Filesystem::signal_param_newpath => $this->getHookPath($path2),
767
-							Filesystem::signal_param_run => &$run
768
-						)
769
-					);
770
-				}
771
-				if ($run) {
772
-					$this->verifyPath(dirname($path2), basename($path2));
773
-
774
-					$manager = Filesystem::getMountManager();
775
-					$mount1 = $this->getMount($path1);
776
-					$mount2 = $this->getMount($path2);
777
-					$storage1 = $mount1->getStorage();
778
-					$storage2 = $mount2->getStorage();
779
-					$internalPath1 = $mount1->getInternalPath($absolutePath1);
780
-					$internalPath2 = $mount2->getInternalPath($absolutePath2);
781
-
782
-					$this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
783
-					try {
784
-						$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
785
-
786
-						if ($internalPath1 === '') {
787
-							if ($mount1 instanceof MoveableMount) {
788
-								if ($this->isTargetAllowed($absolutePath2)) {
789
-									/**
790
-									 * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
791
-									 */
792
-									$sourceMountPoint = $mount1->getMountPoint();
793
-									$result = $mount1->moveMount($absolutePath2);
794
-									$manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
795
-								} else {
796
-									$result = false;
797
-								}
798
-							} else {
799
-								$result = false;
800
-							}
801
-							// moving a file/folder within the same mount point
802
-						} elseif ($storage1 === $storage2) {
803
-							if ($storage1) {
804
-								$result = $storage1->rename($internalPath1, $internalPath2);
805
-							} else {
806
-								$result = false;
807
-							}
808
-							// moving a file/folder between storages (from $storage1 to $storage2)
809
-						} else {
810
-							$result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
811
-						}
812
-
813
-						if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
814
-							// if it was a rename from a part file to a regular file it was a write and not a rename operation
815
-							$this->writeUpdate($storage2, $internalPath2);
816
-						} else if ($result) {
817
-							if ($internalPath1 !== '') { // don't do a cache update for moved mounts
818
-								$this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
819
-							}
820
-						}
821
-					} catch(\Exception $e) {
822
-						throw $e;
823
-					} finally {
824
-						$this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
825
-						$this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
826
-					}
827
-
828
-					if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
829
-						if ($this->shouldEmitHooks()) {
830
-							$this->emit_file_hooks_post($exists, $path2);
831
-						}
832
-					} elseif ($result) {
833
-						if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) {
834
-							\OC_Hook::emit(
835
-								Filesystem::CLASSNAME,
836
-								Filesystem::signal_post_rename,
837
-								array(
838
-									Filesystem::signal_param_oldpath => $this->getHookPath($path1),
839
-									Filesystem::signal_param_newpath => $this->getHookPath($path2)
840
-								)
841
-							);
842
-						}
843
-					}
844
-				}
845
-			} catch(\Exception $e) {
846
-				throw $e;
847
-			} finally {
848
-				$this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
849
-				$this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
850
-			}
851
-		}
852
-		return $result;
853
-	}
854
-
855
-	/**
856
-	 * Copy a file/folder from the source path to target path
857
-	 *
858
-	 * @param string $path1 source path
859
-	 * @param string $path2 target path
860
-	 * @param bool $preserveMtime whether to preserve mtime on the copy
861
-	 *
862
-	 * @return bool|mixed
863
-	 */
864
-	public function copy($path1, $path2, $preserveMtime = false) {
865
-		$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
866
-		$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
867
-		$result = false;
868
-		if (
869
-			Filesystem::isValidPath($path2)
870
-			and Filesystem::isValidPath($path1)
871
-			and !Filesystem::isFileBlacklisted($path2)
872
-		) {
873
-			$path1 = $this->getRelativePath($absolutePath1);
874
-			$path2 = $this->getRelativePath($absolutePath2);
875
-
876
-			if ($path1 == null or $path2 == null) {
877
-				return false;
878
-			}
879
-			$run = true;
880
-
881
-			$this->lockFile($path2, ILockingProvider::LOCK_SHARED);
882
-			$this->lockFile($path1, ILockingProvider::LOCK_SHARED);
883
-			$lockTypePath1 = ILockingProvider::LOCK_SHARED;
884
-			$lockTypePath2 = ILockingProvider::LOCK_SHARED;
885
-
886
-			try {
887
-
888
-				$exists = $this->file_exists($path2);
889
-				if ($this->shouldEmitHooks()) {
890
-					\OC_Hook::emit(
891
-						Filesystem::CLASSNAME,
892
-						Filesystem::signal_copy,
893
-						array(
894
-							Filesystem::signal_param_oldpath => $this->getHookPath($path1),
895
-							Filesystem::signal_param_newpath => $this->getHookPath($path2),
896
-							Filesystem::signal_param_run => &$run
897
-						)
898
-					);
899
-					$this->emit_file_hooks_pre($exists, $path2, $run);
900
-				}
901
-				if ($run) {
902
-					$mount1 = $this->getMount($path1);
903
-					$mount2 = $this->getMount($path2);
904
-					$storage1 = $mount1->getStorage();
905
-					$internalPath1 = $mount1->getInternalPath($absolutePath1);
906
-					$storage2 = $mount2->getStorage();
907
-					$internalPath2 = $mount2->getInternalPath($absolutePath2);
908
-
909
-					$this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE);
910
-					$lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE;
911
-
912
-					if ($mount1->getMountPoint() == $mount2->getMountPoint()) {
913
-						if ($storage1) {
914
-							$result = $storage1->copy($internalPath1, $internalPath2);
915
-						} else {
916
-							$result = false;
917
-						}
918
-					} else {
919
-						$result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
920
-					}
921
-
922
-					$this->writeUpdate($storage2, $internalPath2);
923
-
924
-					$this->changeLock($path2, ILockingProvider::LOCK_SHARED);
925
-					$lockTypePath2 = ILockingProvider::LOCK_SHARED;
926
-
927
-					if ($this->shouldEmitHooks() && $result !== false) {
928
-						\OC_Hook::emit(
929
-							Filesystem::CLASSNAME,
930
-							Filesystem::signal_post_copy,
931
-							array(
932
-								Filesystem::signal_param_oldpath => $this->getHookPath($path1),
933
-								Filesystem::signal_param_newpath => $this->getHookPath($path2)
934
-							)
935
-						);
936
-						$this->emit_file_hooks_post($exists, $path2);
937
-					}
938
-
939
-				}
940
-			} catch (\Exception $e) {
941
-				$this->unlockFile($path2, $lockTypePath2);
942
-				$this->unlockFile($path1, $lockTypePath1);
943
-				throw $e;
944
-			}
945
-
946
-			$this->unlockFile($path2, $lockTypePath2);
947
-			$this->unlockFile($path1, $lockTypePath1);
948
-
949
-		}
950
-		return $result;
951
-	}
952
-
953
-	/**
954
-	 * @param string $path
955
-	 * @param string $mode 'r' or 'w'
956
-	 * @return resource
957
-	 */
958
-	public function fopen($path, $mode) {
959
-		$mode = str_replace('b', '', $mode); // the binary flag is a windows only feature which we do not support
960
-		$hooks = array();
961
-		switch ($mode) {
962
-			case 'r':
963
-				$hooks[] = 'read';
964
-				break;
965
-			case 'r+':
966
-			case 'w+':
967
-			case 'x+':
968
-			case 'a+':
969
-				$hooks[] = 'read';
970
-				$hooks[] = 'write';
971
-				break;
972
-			case 'w':
973
-			case 'x':
974
-			case 'a':
975
-				$hooks[] = 'write';
976
-				break;
977
-			default:
978
-				\OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR);
979
-		}
980
-
981
-		if ($mode !== 'r' && $mode !== 'w') {
982
-			\OC::$server->getLogger()->info('Trying to open a file with a mode other than "r" or "w" can cause severe performance issues with some backends');
983
-		}
984
-
985
-		return $this->basicOperation('fopen', $path, $hooks, $mode);
986
-	}
987
-
988
-	/**
989
-	 * @param string $path
990
-	 * @return bool|string
991
-	 * @throws \OCP\Files\InvalidPathException
992
-	 */
993
-	public function toTmpFile($path) {
994
-		$this->assertPathLength($path);
995
-		if (Filesystem::isValidPath($path)) {
996
-			$source = $this->fopen($path, 'r');
997
-			if ($source) {
998
-				$extension = pathinfo($path, PATHINFO_EXTENSION);
999
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
1000
-				file_put_contents($tmpFile, $source);
1001
-				return $tmpFile;
1002
-			} else {
1003
-				return false;
1004
-			}
1005
-		} else {
1006
-			return false;
1007
-		}
1008
-	}
1009
-
1010
-	/**
1011
-	 * @param string $tmpFile
1012
-	 * @param string $path
1013
-	 * @return bool|mixed
1014
-	 * @throws \OCP\Files\InvalidPathException
1015
-	 */
1016
-	public function fromTmpFile($tmpFile, $path) {
1017
-		$this->assertPathLength($path);
1018
-		if (Filesystem::isValidPath($path)) {
1019
-
1020
-			// Get directory that the file is going into
1021
-			$filePath = dirname($path);
1022
-
1023
-			// Create the directories if any
1024
-			if (!$this->file_exists($filePath)) {
1025
-				$result = $this->createParentDirectories($filePath);
1026
-				if ($result === false) {
1027
-					return false;
1028
-				}
1029
-			}
1030
-
1031
-			$source = fopen($tmpFile, 'r');
1032
-			if ($source) {
1033
-				$result = $this->file_put_contents($path, $source);
1034
-				// $this->file_put_contents() might have already closed
1035
-				// the resource, so we check it, before trying to close it
1036
-				// to avoid messages in the error log.
1037
-				if (is_resource($source)) {
1038
-					fclose($source);
1039
-				}
1040
-				unlink($tmpFile);
1041
-				return $result;
1042
-			} else {
1043
-				return false;
1044
-			}
1045
-		} else {
1046
-			return false;
1047
-		}
1048
-	}
1049
-
1050
-
1051
-	/**
1052
-	 * @param string $path
1053
-	 * @return mixed
1054
-	 * @throws \OCP\Files\InvalidPathException
1055
-	 */
1056
-	public function getMimeType($path) {
1057
-		$this->assertPathLength($path);
1058
-		return $this->basicOperation('getMimeType', $path);
1059
-	}
1060
-
1061
-	/**
1062
-	 * @param string $type
1063
-	 * @param string $path
1064
-	 * @param bool $raw
1065
-	 * @return bool|null|string
1066
-	 */
1067
-	public function hash($type, $path, $raw = false) {
1068
-		$postFix = (substr($path, -1) === '/') ? '/' : '';
1069
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1070
-		if (Filesystem::isValidPath($path)) {
1071
-			$path = $this->getRelativePath($absolutePath);
1072
-			if ($path == null) {
1073
-				return false;
1074
-			}
1075
-			if ($this->shouldEmitHooks($path)) {
1076
-				\OC_Hook::emit(
1077
-					Filesystem::CLASSNAME,
1078
-					Filesystem::signal_read,
1079
-					array(Filesystem::signal_param_path => $this->getHookPath($path))
1080
-				);
1081
-			}
1082
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1083
-			if ($storage) {
1084
-				return $storage->hash($type, $internalPath, $raw);
1085
-			}
1086
-		}
1087
-		return null;
1088
-	}
1089
-
1090
-	/**
1091
-	 * @param string $path
1092
-	 * @return mixed
1093
-	 * @throws \OCP\Files\InvalidPathException
1094
-	 */
1095
-	public function free_space($path = '/') {
1096
-		$this->assertPathLength($path);
1097
-		$result = $this->basicOperation('free_space', $path);
1098
-		if ($result === null) {
1099
-			throw new InvalidPathException();
1100
-		}
1101
-		return $result;
1102
-	}
1103
-
1104
-	/**
1105
-	 * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage
1106
-	 *
1107
-	 * @param string $operation
1108
-	 * @param string $path
1109
-	 * @param array $hooks (optional)
1110
-	 * @param mixed $extraParam (optional)
1111
-	 * @return mixed
1112
-	 * @throws \Exception
1113
-	 *
1114
-	 * This method takes requests for basic filesystem functions (e.g. reading & writing
1115
-	 * files), processes hooks and proxies, sanitises paths, and finally passes them on to
1116
-	 * \OC\Files\Storage\Storage for delegation to a storage backend for execution
1117
-	 */
1118
-	private function basicOperation($operation, $path, $hooks = [], $extraParam = null) {
1119
-		$postFix = (substr($path, -1) === '/') ? '/' : '';
1120
-		$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1121
-		if (Filesystem::isValidPath($path)
1122
-			and !Filesystem::isFileBlacklisted($path)
1123
-		) {
1124
-			$path = $this->getRelativePath($absolutePath);
1125
-			if ($path == null) {
1126
-				return false;
1127
-			}
1128
-
1129
-			if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) {
1130
-				// always a shared lock during pre-hooks so the hook can read the file
1131
-				$this->lockFile($path, ILockingProvider::LOCK_SHARED);
1132
-			}
1133
-
1134
-			$run = $this->runHooks($hooks, $path);
1135
-			/** @var \OC\Files\Storage\Storage $storage */
1136
-			list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1137
-			if ($run and $storage) {
1138
-				if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1139
-					$this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
1140
-				}
1141
-				try {
1142
-					if (!is_null($extraParam)) {
1143
-						$result = $storage->$operation($internalPath, $extraParam);
1144
-					} else {
1145
-						$result = $storage->$operation($internalPath);
1146
-					}
1147
-				} catch (\Exception $e) {
1148
-					if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1149
-						$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1150
-					} else if (in_array('read', $hooks)) {
1151
-						$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1152
-					}
1153
-					throw $e;
1154
-				}
1155
-
1156
-				if ($result && in_array('delete', $hooks) and $result) {
1157
-					$this->removeUpdate($storage, $internalPath);
1158
-				}
1159
-				if ($result && in_array('write', $hooks) and $operation !== 'fopen') {
1160
-					$this->writeUpdate($storage, $internalPath);
1161
-				}
1162
-				if ($result && in_array('touch', $hooks)) {
1163
-					$this->writeUpdate($storage, $internalPath, $extraParam);
1164
-				}
1165
-
1166
-				if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
1167
-					$this->changeLock($path, ILockingProvider::LOCK_SHARED);
1168
-				}
1169
-
1170
-				$unlockLater = false;
1171
-				if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) {
1172
-					$unlockLater = true;
1173
-					// make sure our unlocking callback will still be called if connection is aborted
1174
-					ignore_user_abort(true);
1175
-					$result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1176
-						if (in_array('write', $hooks)) {
1177
-							$this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1178
-						} else if (in_array('read', $hooks)) {
1179
-							$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1180
-						}
1181
-					});
1182
-				}
1183
-
1184
-				if ($this->shouldEmitHooks($path) && $result !== false) {
1185
-					if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
1186
-						$this->runHooks($hooks, $path, true);
1187
-					}
1188
-				}
1189
-
1190
-				if (!$unlockLater
1191
-					&& (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks))
1192
-				) {
1193
-					$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1194
-				}
1195
-				return $result;
1196
-			} else {
1197
-				$this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1198
-			}
1199
-		}
1200
-		return null;
1201
-	}
1202
-
1203
-	/**
1204
-	 * get the path relative to the default root for hook usage
1205
-	 *
1206
-	 * @param string $path
1207
-	 * @return string
1208
-	 */
1209
-	private function getHookPath($path) {
1210
-		if (!Filesystem::getView()) {
1211
-			return $path;
1212
-		}
1213
-		return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path));
1214
-	}
1215
-
1216
-	private function shouldEmitHooks($path = '') {
1217
-		if ($path && Cache\Scanner::isPartialFile($path)) {
1218
-			return false;
1219
-		}
1220
-		if (!Filesystem::$loaded) {
1221
-			return false;
1222
-		}
1223
-		$defaultRoot = Filesystem::getRoot();
1224
-		if ($defaultRoot === null) {
1225
-			return false;
1226
-		}
1227
-		if ($this->fakeRoot === $defaultRoot) {
1228
-			return true;
1229
-		}
1230
-		$fullPath = $this->getAbsolutePath($path);
1231
-
1232
-		if ($fullPath === $defaultRoot) {
1233
-			return true;
1234
-		}
1235
-
1236
-		return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1237
-	}
1238
-
1239
-	/**
1240
-	 * @param string[] $hooks
1241
-	 * @param string $path
1242
-	 * @param bool $post
1243
-	 * @return bool
1244
-	 */
1245
-	private function runHooks($hooks, $path, $post = false) {
1246
-		$relativePath = $path;
1247
-		$path = $this->getHookPath($path);
1248
-		$prefix = $post ? 'post_' : '';
1249
-		$run = true;
1250
-		if ($this->shouldEmitHooks($relativePath)) {
1251
-			foreach ($hooks as $hook) {
1252
-				if ($hook != 'read') {
1253
-					\OC_Hook::emit(
1254
-						Filesystem::CLASSNAME,
1255
-						$prefix . $hook,
1256
-						array(
1257
-							Filesystem::signal_param_run => &$run,
1258
-							Filesystem::signal_param_path => $path
1259
-						)
1260
-					);
1261
-				} elseif (!$post) {
1262
-					\OC_Hook::emit(
1263
-						Filesystem::CLASSNAME,
1264
-						$prefix . $hook,
1265
-						array(
1266
-							Filesystem::signal_param_path => $path
1267
-						)
1268
-					);
1269
-				}
1270
-			}
1271
-		}
1272
-		return $run;
1273
-	}
1274
-
1275
-	/**
1276
-	 * check if a file or folder has been updated since $time
1277
-	 *
1278
-	 * @param string $path
1279
-	 * @param int $time
1280
-	 * @return bool
1281
-	 */
1282
-	public function hasUpdated($path, $time) {
1283
-		return $this->basicOperation('hasUpdated', $path, array(), $time);
1284
-	}
1285
-
1286
-	/**
1287
-	 * @param string $ownerId
1288
-	 * @return \OC\User\User
1289
-	 */
1290
-	private function getUserObjectForOwner($ownerId) {
1291
-		$owner = $this->userManager->get($ownerId);
1292
-		if ($owner instanceof IUser) {
1293
-			return $owner;
1294
-		} else {
1295
-			return new User($ownerId, null);
1296
-		}
1297
-	}
1298
-
1299
-	/**
1300
-	 * Get file info from cache
1301
-	 *
1302
-	 * If the file is not in cached it will be scanned
1303
-	 * If the file has changed on storage the cache will be updated
1304
-	 *
1305
-	 * @param \OC\Files\Storage\Storage $storage
1306
-	 * @param string $internalPath
1307
-	 * @param string $relativePath
1308
-	 * @return ICacheEntry|bool
1309
-	 */
1310
-	private function getCacheEntry($storage, $internalPath, $relativePath) {
1311
-		$cache = $storage->getCache($internalPath);
1312
-		$data = $cache->get($internalPath);
1313
-		$watcher = $storage->getWatcher($internalPath);
1314
-
1315
-		try {
1316
-			// if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
1317
-			if (!$data || $data['size'] === -1) {
1318
-				$this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1319
-				if (!$storage->file_exists($internalPath)) {
1320
-					$this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1321
-					return false;
1322
-				}
1323
-				$scanner = $storage->getScanner($internalPath);
1324
-				$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1325
-				$data = $cache->get($internalPath);
1326
-				$this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1327
-			} else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
1328
-				$this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1329
-				$watcher->update($internalPath, $data);
1330
-				$storage->getPropagator()->propagateChange($internalPath, time());
1331
-				$data = $cache->get($internalPath);
1332
-				$this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1333
-			}
1334
-		} catch (LockedException $e) {
1335
-			// if the file is locked we just use the old cache info
1336
-		}
1337
-
1338
-		return $data;
1339
-	}
1340
-
1341
-	/**
1342
-	 * get the filesystem info
1343
-	 *
1344
-	 * @param string $path
1345
-	 * @param boolean|string $includeMountPoints true to add mountpoint sizes,
1346
-	 * 'ext' to add only ext storage mount point sizes. Defaults to true.
1347
-	 * defaults to true
1348
-	 * @return \OC\Files\FileInfo|false False if file does not exist
1349
-	 */
1350
-	public function getFileInfo($path, $includeMountPoints = true) {
1351
-		$this->assertPathLength($path);
1352
-		if (!Filesystem::isValidPath($path)) {
1353
-			return false;
1354
-		}
1355
-		if (Cache\Scanner::isPartialFile($path)) {
1356
-			return $this->getPartFileInfo($path);
1357
-		}
1358
-		$relativePath = $path;
1359
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1360
-
1361
-		$mount = Filesystem::getMountManager()->find($path);
1362
-		if (!$mount) {
1363
-			return false;
1364
-		}
1365
-		$storage = $mount->getStorage();
1366
-		$internalPath = $mount->getInternalPath($path);
1367
-		if ($storage) {
1368
-			$data = $this->getCacheEntry($storage, $internalPath, $relativePath);
1369
-
1370
-			if (!$data instanceof ICacheEntry) {
1371
-				return false;
1372
-			}
1373
-
1374
-			if ($mount instanceof MoveableMount && $internalPath === '') {
1375
-				$data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
1376
-			}
1377
-
1378
-			$owner = $this->getUserObjectForOwner($storage->getOwner($internalPath));
1379
-			$info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
1380
-
1381
-			if ($data and isset($data['fileid'])) {
1382
-				if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
1383
-					//add the sizes of other mount points to the folder
1384
-					$extOnly = ($includeMountPoints === 'ext');
1385
-					$mounts = Filesystem::getMountManager()->findIn($path);
1386
-					$info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1387
-						$subStorage = $mount->getStorage();
1388
-						return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1389
-					}));
1390
-				}
1391
-			}
1392
-
1393
-			return $info;
1394
-		}
1395
-
1396
-		return false;
1397
-	}
1398
-
1399
-	/**
1400
-	 * get the content of a directory
1401
-	 *
1402
-	 * @param string $directory path under datadirectory
1403
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
1404
-	 * @return FileInfo[]
1405
-	 */
1406
-	public function getDirectoryContent($directory, $mimetype_filter = '') {
1407
-		$this->assertPathLength($directory);
1408
-		if (!Filesystem::isValidPath($directory)) {
1409
-			return [];
1410
-		}
1411
-		$path = $this->getAbsolutePath($directory);
1412
-		$path = Filesystem::normalizePath($path);
1413
-		$mount = $this->getMount($directory);
1414
-		if (!$mount) {
1415
-			return [];
1416
-		}
1417
-		$storage = $mount->getStorage();
1418
-		$internalPath = $mount->getInternalPath($path);
1419
-		if ($storage) {
1420
-			$cache = $storage->getCache($internalPath);
1421
-			$user = \OC_User::getUser();
1422
-
1423
-			$data = $this->getCacheEntry($storage, $internalPath, $directory);
1424
-
1425
-			if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
1426
-				return [];
1427
-			}
1428
-
1429
-			$folderId = $data['fileid'];
1430
-			$contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
1431
-
1432
-			$sharingDisabled = \OCP\Util::isSharingDisabledForUser();
1433
-			/**
1434
-			 * @var \OC\Files\FileInfo[] $files
1435
-			 */
1436
-			$files = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1437
-				if ($sharingDisabled) {
1438
-					$content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1439
-				}
1440
-				$owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1441
-				return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1442
-			}, $contents);
1443
-
1444
-			//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
1445
-			$mounts = Filesystem::getMountManager()->findIn($path);
1446
-			$dirLength = strlen($path);
1447
-			foreach ($mounts as $mount) {
1448
-				$mountPoint = $mount->getMountPoint();
1449
-				$subStorage = $mount->getStorage();
1450
-				if ($subStorage) {
1451
-					$subCache = $subStorage->getCache('');
1452
-
1453
-					$rootEntry = $subCache->get('');
1454
-					if (!$rootEntry) {
1455
-						$subScanner = $subStorage->getScanner('');
1456
-						try {
1457
-							$subScanner->scanFile('');
1458
-						} catch (\OCP\Files\StorageNotAvailableException $e) {
1459
-							continue;
1460
-						} catch (\OCP\Files\StorageInvalidException $e) {
1461
-							continue;
1462
-						} catch (\Exception $e) {
1463
-							// sometimes when the storage is not available it can be any exception
1464
-							\OC::$server->getLogger()->logException($e, [
1465
-								'message' => 'Exception while scanning storage "' . $subStorage->getId() . '"',
1466
-								'level' => \OCP\Util::ERROR,
1467
-								'app' => 'lib',
1468
-							]);
1469
-							continue;
1470
-						}
1471
-						$rootEntry = $subCache->get('');
1472
-					}
1473
-
1474
-					if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
1475
-						$relativePath = trim(substr($mountPoint, $dirLength), '/');
1476
-						if ($pos = strpos($relativePath, '/')) {
1477
-							//mountpoint inside subfolder add size to the correct folder
1478
-							$entryName = substr($relativePath, 0, $pos);
1479
-							foreach ($files as &$entry) {
1480
-								if ($entry->getName() === $entryName) {
1481
-									$entry->addSubEntry($rootEntry, $mountPoint);
1482
-								}
1483
-							}
1484
-						} else { //mountpoint in this folder, add an entry for it
1485
-							$rootEntry['name'] = $relativePath;
1486
-							$rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
1487
-							$permissions = $rootEntry['permissions'];
1488
-							// do not allow renaming/deleting the mount point if they are not shared files/folders
1489
-							// for shared files/folders we use the permissions given by the owner
1490
-							if ($mount instanceof MoveableMount) {
1491
-								$rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
1492
-							} else {
1493
-								$rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
1494
-							}
1495
-
1496
-							//remove any existing entry with the same name
1497
-							foreach ($files as $i => $file) {
1498
-								if ($file['name'] === $rootEntry['name']) {
1499
-									unset($files[$i]);
1500
-									break;
1501
-								}
1502
-							}
1503
-							$rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1504
-
1505
-							// if sharing was disabled for the user we remove the share permissions
1506
-							if (\OCP\Util::isSharingDisabledForUser()) {
1507
-								$rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1508
-							}
1509
-
1510
-							$owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1511
-							$files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1512
-						}
1513
-					}
1514
-				}
1515
-			}
1516
-
1517
-			if ($mimetype_filter) {
1518
-				$files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1519
-					if (strpos($mimetype_filter, '/')) {
1520
-						return $file->getMimetype() === $mimetype_filter;
1521
-					} else {
1522
-						return $file->getMimePart() === $mimetype_filter;
1523
-					}
1524
-				});
1525
-			}
1526
-
1527
-			return $files;
1528
-		} else {
1529
-			return [];
1530
-		}
1531
-	}
1532
-
1533
-	/**
1534
-	 * change file metadata
1535
-	 *
1536
-	 * @param string $path
1537
-	 * @param array|\OCP\Files\FileInfo $data
1538
-	 * @return int
1539
-	 *
1540
-	 * returns the fileid of the updated file
1541
-	 */
1542
-	public function putFileInfo($path, $data) {
1543
-		$this->assertPathLength($path);
1544
-		if ($data instanceof FileInfo) {
1545
-			$data = $data->getData();
1546
-		}
1547
-		$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1548
-		/**
1549
-		 * @var \OC\Files\Storage\Storage $storage
1550
-		 * @var string $internalPath
1551
-		 */
1552
-		list($storage, $internalPath) = Filesystem::resolvePath($path);
1553
-		if ($storage) {
1554
-			$cache = $storage->getCache($path);
1555
-
1556
-			if (!$cache->inCache($internalPath)) {
1557
-				$scanner = $storage->getScanner($internalPath);
1558
-				$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1559
-			}
1560
-
1561
-			return $cache->put($internalPath, $data);
1562
-		} else {
1563
-			return -1;
1564
-		}
1565
-	}
1566
-
1567
-	/**
1568
-	 * search for files with the name matching $query
1569
-	 *
1570
-	 * @param string $query
1571
-	 * @return FileInfo[]
1572
-	 */
1573
-	public function search($query) {
1574
-		return $this->searchCommon('search', array('%' . $query . '%'));
1575
-	}
1576
-
1577
-	/**
1578
-	 * search for files with the name matching $query
1579
-	 *
1580
-	 * @param string $query
1581
-	 * @return FileInfo[]
1582
-	 */
1583
-	public function searchRaw($query) {
1584
-		return $this->searchCommon('search', array($query));
1585
-	}
1586
-
1587
-	/**
1588
-	 * search for files by mimetype
1589
-	 *
1590
-	 * @param string $mimetype
1591
-	 * @return FileInfo[]
1592
-	 */
1593
-	public function searchByMime($mimetype) {
1594
-		return $this->searchCommon('searchByMime', array($mimetype));
1595
-	}
1596
-
1597
-	/**
1598
-	 * search for files by tag
1599
-	 *
1600
-	 * @param string|int $tag name or tag id
1601
-	 * @param string $userId owner of the tags
1602
-	 * @return FileInfo[]
1603
-	 */
1604
-	public function searchByTag($tag, $userId) {
1605
-		return $this->searchCommon('searchByTag', array($tag, $userId));
1606
-	}
1607
-
1608
-	/**
1609
-	 * @param string $method cache method
1610
-	 * @param array $args
1611
-	 * @return FileInfo[]
1612
-	 */
1613
-	private function searchCommon($method, $args) {
1614
-		$files = array();
1615
-		$rootLength = strlen($this->fakeRoot);
1616
-
1617
-		$mount = $this->getMount('');
1618
-		$mountPoint = $mount->getMountPoint();
1619
-		$storage = $mount->getStorage();
1620
-		if ($storage) {
1621
-			$cache = $storage->getCache('');
1622
-
1623
-			$results = call_user_func_array(array($cache, $method), $args);
1624
-			foreach ($results as $result) {
1625
-				if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1626
-					$internalPath = $result['path'];
1627
-					$path = $mountPoint . $result['path'];
1628
-					$result['path'] = substr($mountPoint . $result['path'], $rootLength);
1629
-					$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1630
-					$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1631
-				}
1632
-			}
1633
-
1634
-			$mounts = Filesystem::getMountManager()->findIn($this->fakeRoot);
1635
-			foreach ($mounts as $mount) {
1636
-				$mountPoint = $mount->getMountPoint();
1637
-				$storage = $mount->getStorage();
1638
-				if ($storage) {
1639
-					$cache = $storage->getCache('');
1640
-
1641
-					$relativeMountPoint = substr($mountPoint, $rootLength);
1642
-					$results = call_user_func_array(array($cache, $method), $args);
1643
-					if ($results) {
1644
-						foreach ($results as $result) {
1645
-							$internalPath = $result['path'];
1646
-							$result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1647
-							$path = rtrim($mountPoint . $internalPath, '/');
1648
-							$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1649
-							$files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1650
-						}
1651
-					}
1652
-				}
1653
-			}
1654
-		}
1655
-		return $files;
1656
-	}
1657
-
1658
-	/**
1659
-	 * Get the owner for a file or folder
1660
-	 *
1661
-	 * @param string $path
1662
-	 * @return string the user id of the owner
1663
-	 * @throws NotFoundException
1664
-	 */
1665
-	public function getOwner($path) {
1666
-		$info = $this->getFileInfo($path);
1667
-		if (!$info) {
1668
-			throw new NotFoundException($path . ' not found while trying to get owner');
1669
-		}
1670
-		return $info->getOwner()->getUID();
1671
-	}
1672
-
1673
-	/**
1674
-	 * get the ETag for a file or folder
1675
-	 *
1676
-	 * @param string $path
1677
-	 * @return string
1678
-	 */
1679
-	public function getETag($path) {
1680
-		/**
1681
-		 * @var Storage\Storage $storage
1682
-		 * @var string $internalPath
1683
-		 */
1684
-		list($storage, $internalPath) = $this->resolvePath($path);
1685
-		if ($storage) {
1686
-			return $storage->getETag($internalPath);
1687
-		} else {
1688
-			return null;
1689
-		}
1690
-	}
1691
-
1692
-	/**
1693
-	 * Get the path of a file by id, relative to the view
1694
-	 *
1695
-	 * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
1696
-	 *
1697
-	 * @param int $id
1698
-	 * @throws NotFoundException
1699
-	 * @return string
1700
-	 */
1701
-	public function getPath($id) {
1702
-		$id = (int)$id;
1703
-		$manager = Filesystem::getMountManager();
1704
-		$mounts = $manager->findIn($this->fakeRoot);
1705
-		$mounts[] = $manager->find($this->fakeRoot);
1706
-		// reverse the array so we start with the storage this view is in
1707
-		// which is the most likely to contain the file we're looking for
1708
-		$mounts = array_reverse($mounts);
1709
-		foreach ($mounts as $mount) {
1710
-			/**
1711
-			 * @var \OC\Files\Mount\MountPoint $mount
1712
-			 */
1713
-			if ($mount->getStorage()) {
1714
-				$cache = $mount->getStorage()->getCache();
1715
-				$internalPath = $cache->getPathById($id);
1716
-				if (is_string($internalPath)) {
1717
-					$fullPath = $mount->getMountPoint() . $internalPath;
1718
-					if (!is_null($path = $this->getRelativePath($fullPath))) {
1719
-						return $path;
1720
-					}
1721
-				}
1722
-			}
1723
-		}
1724
-		throw new NotFoundException(sprintf('File with id "%s" has not been found.', $id));
1725
-	}
1726
-
1727
-	/**
1728
-	 * @param string $path
1729
-	 * @throws InvalidPathException
1730
-	 */
1731
-	private function assertPathLength($path) {
1732
-		$maxLen = min(PHP_MAXPATHLEN, 4000);
1733
-		// Check for the string length - performed using isset() instead of strlen()
1734
-		// because isset() is about 5x-40x faster.
1735
-		if (isset($path[$maxLen])) {
1736
-			$pathLen = strlen($path);
1737
-			throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path");
1738
-		}
1739
-	}
1740
-
1741
-	/**
1742
-	 * check if it is allowed to move a mount point to a given target.
1743
-	 * It is not allowed to move a mount point into a different mount point or
1744
-	 * into an already shared folder
1745
-	 *
1746
-	 * @param string $target path
1747
-	 * @return boolean
1748
-	 */
1749
-	private function isTargetAllowed($target) {
1750
-
1751
-		list($targetStorage, $targetInternalPath) = \OC\Files\Filesystem::resolvePath($target);
1752
-		if (!$targetStorage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
1753
-			\OCP\Util::writeLog('files',
1754
-				'It is not allowed to move one mount point into another one',
1755
-				\OCP\Util::DEBUG);
1756
-			return false;
1757
-		}
1758
-
1759
-		// note: cannot use the view because the target is already locked
1760
-		$fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1761
-		if ($fileId === -1) {
1762
-			// target might not exist, need to check parent instead
1763
-			$fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1764
-		}
1765
-
1766
-		// check if any of the parents were shared by the current owner (include collections)
1767
-		$shares = \OCP\Share::getItemShared(
1768
-			'folder',
1769
-			$fileId,
1770
-			\OCP\Share::FORMAT_NONE,
1771
-			null,
1772
-			true
1773
-		);
1774
-
1775
-		if (count($shares) > 0) {
1776
-			\OCP\Util::writeLog('files',
1777
-				'It is not allowed to move one mount point into a shared folder',
1778
-				\OCP\Util::DEBUG);
1779
-			return false;
1780
-		}
1781
-
1782
-		return true;
1783
-	}
1784
-
1785
-	/**
1786
-	 * Get a fileinfo object for files that are ignored in the cache (part files)
1787
-	 *
1788
-	 * @param string $path
1789
-	 * @return \OCP\Files\FileInfo
1790
-	 */
1791
-	private function getPartFileInfo($path) {
1792
-		$mount = $this->getMount($path);
1793
-		$storage = $mount->getStorage();
1794
-		$internalPath = $mount->getInternalPath($this->getAbsolutePath($path));
1795
-		$owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1796
-		return new FileInfo(
1797
-			$this->getAbsolutePath($path),
1798
-			$storage,
1799
-			$internalPath,
1800
-			[
1801
-				'fileid' => null,
1802
-				'mimetype' => $storage->getMimeType($internalPath),
1803
-				'name' => basename($path),
1804
-				'etag' => null,
1805
-				'size' => $storage->filesize($internalPath),
1806
-				'mtime' => $storage->filemtime($internalPath),
1807
-				'encrypted' => false,
1808
-				'permissions' => \OCP\Constants::PERMISSION_ALL
1809
-			],
1810
-			$mount,
1811
-			$owner
1812
-		);
1813
-	}
1814
-
1815
-	/**
1816
-	 * @param string $path
1817
-	 * @param string $fileName
1818
-	 * @throws InvalidPathException
1819
-	 */
1820
-	public function verifyPath($path, $fileName) {
1821
-		try {
1822
-			/** @type \OCP\Files\Storage $storage */
1823
-			list($storage, $internalPath) = $this->resolvePath($path);
1824
-			$storage->verifyPath($internalPath, $fileName);
1825
-		} catch (ReservedWordException $ex) {
1826
-			$l = \OC::$server->getL10N('lib');
1827
-			throw new InvalidPathException($l->t('File name is a reserved word'));
1828
-		} catch (InvalidCharacterInPathException $ex) {
1829
-			$l = \OC::$server->getL10N('lib');
1830
-			throw new InvalidPathException($l->t('File name contains at least one invalid character'));
1831
-		} catch (FileNameTooLongException $ex) {
1832
-			$l = \OC::$server->getL10N('lib');
1833
-			throw new InvalidPathException($l->t('File name is too long'));
1834
-		} catch (InvalidDirectoryException $ex) {
1835
-			$l = \OC::$server->getL10N('lib');
1836
-			throw new InvalidPathException($l->t('Dot files are not allowed'));
1837
-		} catch (EmptyFileNameException $ex) {
1838
-			$l = \OC::$server->getL10N('lib');
1839
-			throw new InvalidPathException($l->t('Empty filename is not allowed'));
1840
-		}
1841
-	}
1842
-
1843
-	/**
1844
-	 * get all parent folders of $path
1845
-	 *
1846
-	 * @param string $path
1847
-	 * @return string[]
1848
-	 */
1849
-	private function getParents($path) {
1850
-		$path = trim($path, '/');
1851
-		if (!$path) {
1852
-			return [];
1853
-		}
1854
-
1855
-		$parts = explode('/', $path);
1856
-
1857
-		// remove the single file
1858
-		array_pop($parts);
1859
-		$result = array('/');
1860
-		$resultPath = '';
1861
-		foreach ($parts as $part) {
1862
-			if ($part) {
1863
-				$resultPath .= '/' . $part;
1864
-				$result[] = $resultPath;
1865
-			}
1866
-		}
1867
-		return $result;
1868
-	}
1869
-
1870
-	/**
1871
-	 * Returns the mount point for which to lock
1872
-	 *
1873
-	 * @param string $absolutePath absolute path
1874
-	 * @param bool $useParentMount true to return parent mount instead of whatever
1875
-	 * is mounted directly on the given path, false otherwise
1876
-	 * @return \OC\Files\Mount\MountPoint mount point for which to apply locks
1877
-	 */
1878
-	private function getMountForLock($absolutePath, $useParentMount = false) {
1879
-		$results = [];
1880
-		$mount = Filesystem::getMountManager()->find($absolutePath);
1881
-		if (!$mount) {
1882
-			return $results;
1883
-		}
1884
-
1885
-		if ($useParentMount) {
1886
-			// find out if something is mounted directly on the path
1887
-			$internalPath = $mount->getInternalPath($absolutePath);
1888
-			if ($internalPath === '') {
1889
-				// resolve the parent mount instead
1890
-				$mount = Filesystem::getMountManager()->find(dirname($absolutePath));
1891
-			}
1892
-		}
1893
-
1894
-		return $mount;
1895
-	}
1896
-
1897
-	/**
1898
-	 * Lock the given path
1899
-	 *
1900
-	 * @param string $path the path of the file to lock, relative to the view
1901
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1902
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1903
-	 *
1904
-	 * @return bool False if the path is excluded from locking, true otherwise
1905
-	 * @throws \OCP\Lock\LockedException if the path is already locked
1906
-	 */
1907
-	private function lockPath($path, $type, $lockMountPoint = false) {
1908
-		$absolutePath = $this->getAbsolutePath($path);
1909
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1910
-		if (!$this->shouldLockFile($absolutePath)) {
1911
-			return false;
1912
-		}
1913
-
1914
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1915
-		if ($mount) {
1916
-			try {
1917
-				$storage = $mount->getStorage();
1918
-				if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1919
-					$storage->acquireLock(
1920
-						$mount->getInternalPath($absolutePath),
1921
-						$type,
1922
-						$this->lockingProvider
1923
-					);
1924
-				}
1925
-			} catch (\OCP\Lock\LockedException $e) {
1926
-				// rethrow with the a human-readable path
1927
-				throw new \OCP\Lock\LockedException(
1928
-					$this->getPathRelativeToFiles($absolutePath),
1929
-					$e
1930
-				);
1931
-			}
1932
-		}
1933
-
1934
-		return true;
1935
-	}
1936
-
1937
-	/**
1938
-	 * Change the lock type
1939
-	 *
1940
-	 * @param string $path the path of the file to lock, relative to the view
1941
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1942
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1943
-	 *
1944
-	 * @return bool False if the path is excluded from locking, true otherwise
1945
-	 * @throws \OCP\Lock\LockedException if the path is already locked
1946
-	 */
1947
-	public function changeLock($path, $type, $lockMountPoint = false) {
1948
-		$path = Filesystem::normalizePath($path);
1949
-		$absolutePath = $this->getAbsolutePath($path);
1950
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1951
-		if (!$this->shouldLockFile($absolutePath)) {
1952
-			return false;
1953
-		}
1954
-
1955
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1956
-		if ($mount) {
1957
-			try {
1958
-				$storage = $mount->getStorage();
1959
-				if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1960
-					$storage->changeLock(
1961
-						$mount->getInternalPath($absolutePath),
1962
-						$type,
1963
-						$this->lockingProvider
1964
-					);
1965
-				}
1966
-			} catch (\OCP\Lock\LockedException $e) {
1967
-				try {
1968
-					// rethrow with the a human-readable path
1969
-					throw new \OCP\Lock\LockedException(
1970
-						$this->getPathRelativeToFiles($absolutePath),
1971
-						$e
1972
-					);
1973
-				} catch (\InvalidArgumentException $e) {
1974
-					throw new \OCP\Lock\LockedException(
1975
-						$absolutePath,
1976
-						$e
1977
-					);
1978
-				}
1979
-			}
1980
-		}
1981
-
1982
-		return true;
1983
-	}
1984
-
1985
-	/**
1986
-	 * Unlock the given path
1987
-	 *
1988
-	 * @param string $path the path of the file to unlock, relative to the view
1989
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1990
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1991
-	 *
1992
-	 * @return bool False if the path is excluded from locking, true otherwise
1993
-	 */
1994
-	private function unlockPath($path, $type, $lockMountPoint = false) {
1995
-		$absolutePath = $this->getAbsolutePath($path);
1996
-		$absolutePath = Filesystem::normalizePath($absolutePath);
1997
-		if (!$this->shouldLockFile($absolutePath)) {
1998
-			return false;
1999
-		}
2000
-
2001
-		$mount = $this->getMountForLock($absolutePath, $lockMountPoint);
2002
-		if ($mount) {
2003
-			$storage = $mount->getStorage();
2004
-			if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2005
-				$storage->releaseLock(
2006
-					$mount->getInternalPath($absolutePath),
2007
-					$type,
2008
-					$this->lockingProvider
2009
-				);
2010
-			}
2011
-		}
2012
-
2013
-		return true;
2014
-	}
2015
-
2016
-	/**
2017
-	 * Lock a path and all its parents up to the root of the view
2018
-	 *
2019
-	 * @param string $path the path of the file to lock relative to the view
2020
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2021
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2022
-	 *
2023
-	 * @return bool False if the path is excluded from locking, true otherwise
2024
-	 */
2025
-	public function lockFile($path, $type, $lockMountPoint = false) {
2026
-		$absolutePath = $this->getAbsolutePath($path);
2027
-		$absolutePath = Filesystem::normalizePath($absolutePath);
2028
-		if (!$this->shouldLockFile($absolutePath)) {
2029
-			return false;
2030
-		}
2031
-
2032
-		$this->lockPath($path, $type, $lockMountPoint);
2033
-
2034
-		$parents = $this->getParents($path);
2035
-		foreach ($parents as $parent) {
2036
-			$this->lockPath($parent, ILockingProvider::LOCK_SHARED);
2037
-		}
2038
-
2039
-		return true;
2040
-	}
2041
-
2042
-	/**
2043
-	 * Unlock a path and all its parents up to the root of the view
2044
-	 *
2045
-	 * @param string $path the path of the file to lock relative to the view
2046
-	 * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2047
-	 * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2048
-	 *
2049
-	 * @return bool False if the path is excluded from locking, true otherwise
2050
-	 */
2051
-	public function unlockFile($path, $type, $lockMountPoint = false) {
2052
-		$absolutePath = $this->getAbsolutePath($path);
2053
-		$absolutePath = Filesystem::normalizePath($absolutePath);
2054
-		if (!$this->shouldLockFile($absolutePath)) {
2055
-			return false;
2056
-		}
2057
-
2058
-		$this->unlockPath($path, $type, $lockMountPoint);
2059
-
2060
-		$parents = $this->getParents($path);
2061
-		foreach ($parents as $parent) {
2062
-			$this->unlockPath($parent, ILockingProvider::LOCK_SHARED);
2063
-		}
2064
-
2065
-		return true;
2066
-	}
2067
-
2068
-	/**
2069
-	 * Only lock files in data/user/files/
2070
-	 *
2071
-	 * @param string $path Absolute path to the file/folder we try to (un)lock
2072
-	 * @return bool
2073
-	 */
2074
-	protected function shouldLockFile($path) {
2075
-		$path = Filesystem::normalizePath($path);
2076
-
2077
-		$pathSegments = explode('/', $path);
2078
-		if (isset($pathSegments[2])) {
2079
-			// E.g.: /username/files/path-to-file
2080
-			return ($pathSegments[2] === 'files') && (count($pathSegments) > 3);
2081
-		}
2082
-
2083
-		return strpos($path, '/appdata_') !== 0;
2084
-	}
2085
-
2086
-	/**
2087
-	 * Shortens the given absolute path to be relative to
2088
-	 * "$user/files".
2089
-	 *
2090
-	 * @param string $absolutePath absolute path which is under "files"
2091
-	 *
2092
-	 * @return string path relative to "files" with trimmed slashes or null
2093
-	 * if the path was NOT relative to files
2094
-	 *
2095
-	 * @throws \InvalidArgumentException if the given path was not under "files"
2096
-	 * @since 8.1.0
2097
-	 */
2098
-	public function getPathRelativeToFiles($absolutePath) {
2099
-		$path = Filesystem::normalizePath($absolutePath);
2100
-		$parts = explode('/', trim($path, '/'), 3);
2101
-		// "$user", "files", "path/to/dir"
2102
-		if (!isset($parts[1]) || $parts[1] !== 'files') {
2103
-			$this->logger->error(
2104
-				'$absolutePath must be relative to "files", value is "%s"',
2105
-				[
2106
-					$absolutePath
2107
-				]
2108
-			);
2109
-			throw new \InvalidArgumentException('$absolutePath must be relative to "files"');
2110
-		}
2111
-		if (isset($parts[2])) {
2112
-			return $parts[2];
2113
-		}
2114
-		return '';
2115
-	}
2116
-
2117
-	/**
2118
-	 * @param string $filename
2119
-	 * @return array
2120
-	 * @throws \OC\User\NoUserException
2121
-	 * @throws NotFoundException
2122
-	 */
2123
-	public function getUidAndFilename($filename) {
2124
-		$info = $this->getFileInfo($filename);
2125
-		if (!$info instanceof \OCP\Files\FileInfo) {
2126
-			throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2127
-		}
2128
-		$uid = $info->getOwner()->getUID();
2129
-		if ($uid != \OCP\User::getUser()) {
2130
-			Filesystem::initMountPoints($uid);
2131
-			$ownerView = new View('/' . $uid . '/files');
2132
-			try {
2133
-				$filename = $ownerView->getPath($info['fileid']);
2134
-			} catch (NotFoundException $e) {
2135
-				throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2136
-			}
2137
-		}
2138
-		return [$uid, $filename];
2139
-	}
2140
-
2141
-	/**
2142
-	 * Creates parent non-existing folders
2143
-	 *
2144
-	 * @param string $filePath
2145
-	 * @return bool
2146
-	 */
2147
-	private function createParentDirectories($filePath) {
2148
-		$directoryParts = explode('/', $filePath);
2149
-		$directoryParts = array_filter($directoryParts);
2150
-		foreach ($directoryParts as $key => $part) {
2151
-			$currentPathElements = array_slice($directoryParts, 0, $key);
2152
-			$currentPath = '/' . implode('/', $currentPathElements);
2153
-			if ($this->is_file($currentPath)) {
2154
-				return false;
2155
-			}
2156
-			if (!$this->file_exists($currentPath)) {
2157
-				$this->mkdir($currentPath);
2158
-			}
2159
-		}
2160
-
2161
-		return true;
2162
-	}
83
+    /** @var string */
84
+    private $fakeRoot = '';
85
+
86
+    /**
87
+     * @var \OCP\Lock\ILockingProvider
88
+     */
89
+    protected $lockingProvider;
90
+
91
+    private $lockingEnabled;
92
+
93
+    private $updaterEnabled = true;
94
+
95
+    /** @var \OC\User\Manager */
96
+    private $userManager;
97
+
98
+    /** @var \OCP\ILogger */
99
+    private $logger;
100
+
101
+    /**
102
+     * @param string $root
103
+     * @throws \Exception If $root contains an invalid path
104
+     */
105
+    public function __construct($root = '') {
106
+        if (is_null($root)) {
107
+            throw new \InvalidArgumentException('Root can\'t be null');
108
+        }
109
+        if (!Filesystem::isValidPath($root)) {
110
+            throw new \Exception();
111
+        }
112
+
113
+        $this->fakeRoot = $root;
114
+        $this->lockingProvider = \OC::$server->getLockingProvider();
115
+        $this->lockingEnabled = !($this->lockingProvider instanceof \OC\Lock\NoopLockingProvider);
116
+        $this->userManager = \OC::$server->getUserManager();
117
+        $this->logger = \OC::$server->getLogger();
118
+    }
119
+
120
+    public function getAbsolutePath($path = '/') {
121
+        if ($path === null) {
122
+            return null;
123
+        }
124
+        $this->assertPathLength($path);
125
+        if ($path === '') {
126
+            $path = '/';
127
+        }
128
+        if ($path[0] !== '/') {
129
+            $path = '/' . $path;
130
+        }
131
+        return $this->fakeRoot . $path;
132
+    }
133
+
134
+    /**
135
+     * change the root to a fake root
136
+     *
137
+     * @param string $fakeRoot
138
+     * @return boolean|null
139
+     */
140
+    public function chroot($fakeRoot) {
141
+        if (!$fakeRoot == '') {
142
+            if ($fakeRoot[0] !== '/') {
143
+                $fakeRoot = '/' . $fakeRoot;
144
+            }
145
+        }
146
+        $this->fakeRoot = $fakeRoot;
147
+    }
148
+
149
+    /**
150
+     * get the fake root
151
+     *
152
+     * @return string
153
+     */
154
+    public function getRoot() {
155
+        return $this->fakeRoot;
156
+    }
157
+
158
+    /**
159
+     * get path relative to the root of the view
160
+     *
161
+     * @param string $path
162
+     * @return string
163
+     */
164
+    public function getRelativePath($path) {
165
+        $this->assertPathLength($path);
166
+        if ($this->fakeRoot == '') {
167
+            return $path;
168
+        }
169
+
170
+        if (rtrim($path, '/') === rtrim($this->fakeRoot, '/')) {
171
+            return '/';
172
+        }
173
+
174
+        // missing slashes can cause wrong matches!
175
+        $root = rtrim($this->fakeRoot, '/') . '/';
176
+
177
+        if (strpos($path, $root) !== 0) {
178
+            return null;
179
+        } else {
180
+            $path = substr($path, strlen($this->fakeRoot));
181
+            if (strlen($path) === 0) {
182
+                return '/';
183
+            } else {
184
+                return $path;
185
+            }
186
+        }
187
+    }
188
+
189
+    /**
190
+     * get the mountpoint of the storage object for a path
191
+     * ( note: because a storage is not always mounted inside the fakeroot, the
192
+     * returned mountpoint is relative to the absolute root of the filesystem
193
+     * and does not take the chroot into account )
194
+     *
195
+     * @param string $path
196
+     * @return string
197
+     */
198
+    public function getMountPoint($path) {
199
+        return Filesystem::getMountPoint($this->getAbsolutePath($path));
200
+    }
201
+
202
+    /**
203
+     * get the mountpoint of the storage object for a path
204
+     * ( note: because a storage is not always mounted inside the fakeroot, the
205
+     * returned mountpoint is relative to the absolute root of the filesystem
206
+     * and does not take the chroot into account )
207
+     *
208
+     * @param string $path
209
+     * @return \OCP\Files\Mount\IMountPoint
210
+     */
211
+    public function getMount($path) {
212
+        return Filesystem::getMountManager()->find($this->getAbsolutePath($path));
213
+    }
214
+
215
+    /**
216
+     * resolve a path to a storage and internal path
217
+     *
218
+     * @param string $path
219
+     * @return array an array consisting of the storage and the internal path
220
+     */
221
+    public function resolvePath($path) {
222
+        $a = $this->getAbsolutePath($path);
223
+        $p = Filesystem::normalizePath($a);
224
+        return Filesystem::resolvePath($p);
225
+    }
226
+
227
+    /**
228
+     * return the path to a local version of the file
229
+     * we need this because we can't know if a file is stored local or not from
230
+     * outside the filestorage and for some purposes a local file is needed
231
+     *
232
+     * @param string $path
233
+     * @return string
234
+     */
235
+    public function getLocalFile($path) {
236
+        $parent = substr($path, 0, strrpos($path, '/'));
237
+        $path = $this->getAbsolutePath($path);
238
+        list($storage, $internalPath) = Filesystem::resolvePath($path);
239
+        if (Filesystem::isValidPath($parent) and $storage) {
240
+            return $storage->getLocalFile($internalPath);
241
+        } else {
242
+            return null;
243
+        }
244
+    }
245
+
246
+    /**
247
+     * @param string $path
248
+     * @return string
249
+     */
250
+    public function getLocalFolder($path) {
251
+        $parent = substr($path, 0, strrpos($path, '/'));
252
+        $path = $this->getAbsolutePath($path);
253
+        list($storage, $internalPath) = Filesystem::resolvePath($path);
254
+        if (Filesystem::isValidPath($parent) and $storage) {
255
+            return $storage->getLocalFolder($internalPath);
256
+        } else {
257
+            return null;
258
+        }
259
+    }
260
+
261
+    /**
262
+     * the following functions operate with arguments and return values identical
263
+     * to those of their PHP built-in equivalents. Mostly they are merely wrappers
264
+     * for \OC\Files\Storage\Storage via basicOperation().
265
+     */
266
+    public function mkdir($path) {
267
+        return $this->basicOperation('mkdir', $path, array('create', 'write'));
268
+    }
269
+
270
+    /**
271
+     * remove mount point
272
+     *
273
+     * @param \OC\Files\Mount\MoveableMount $mount
274
+     * @param string $path relative to data/
275
+     * @return boolean
276
+     */
277
+    protected function removeMount($mount, $path) {
278
+        if ($mount instanceof MoveableMount) {
279
+            // cut of /user/files to get the relative path to data/user/files
280
+            $pathParts = explode('/', $path, 4);
281
+            $relPath = '/' . $pathParts[3];
282
+            $this->lockFile($relPath, ILockingProvider::LOCK_SHARED, true);
283
+            \OC_Hook::emit(
284
+                Filesystem::CLASSNAME, "umount",
285
+                array(Filesystem::signal_param_path => $relPath)
286
+            );
287
+            $this->changeLock($relPath, ILockingProvider::LOCK_EXCLUSIVE, true);
288
+            $result = $mount->removeMount();
289
+            $this->changeLock($relPath, ILockingProvider::LOCK_SHARED, true);
290
+            if ($result) {
291
+                \OC_Hook::emit(
292
+                    Filesystem::CLASSNAME, "post_umount",
293
+                    array(Filesystem::signal_param_path => $relPath)
294
+                );
295
+            }
296
+            $this->unlockFile($relPath, ILockingProvider::LOCK_SHARED, true);
297
+            return $result;
298
+        } else {
299
+            // do not allow deleting the storage's root / the mount point
300
+            // because for some storages it might delete the whole contents
301
+            // but isn't supposed to work that way
302
+            return false;
303
+        }
304
+    }
305
+
306
+    public function disableCacheUpdate() {
307
+        $this->updaterEnabled = false;
308
+    }
309
+
310
+    public function enableCacheUpdate() {
311
+        $this->updaterEnabled = true;
312
+    }
313
+
314
+    protected function writeUpdate(Storage $storage, $internalPath, $time = null) {
315
+        if ($this->updaterEnabled) {
316
+            if (is_null($time)) {
317
+                $time = time();
318
+            }
319
+            $storage->getUpdater()->update($internalPath, $time);
320
+        }
321
+    }
322
+
323
+    protected function removeUpdate(Storage $storage, $internalPath) {
324
+        if ($this->updaterEnabled) {
325
+            $storage->getUpdater()->remove($internalPath);
326
+        }
327
+    }
328
+
329
+    protected function renameUpdate(Storage $sourceStorage, Storage $targetStorage, $sourceInternalPath, $targetInternalPath) {
330
+        if ($this->updaterEnabled) {
331
+            $targetStorage->getUpdater()->renameFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
332
+        }
333
+    }
334
+
335
+    /**
336
+     * @param string $path
337
+     * @return bool|mixed
338
+     */
339
+    public function rmdir($path) {
340
+        $absolutePath = $this->getAbsolutePath($path);
341
+        $mount = Filesystem::getMountManager()->find($absolutePath);
342
+        if ($mount->getInternalPath($absolutePath) === '') {
343
+            return $this->removeMount($mount, $absolutePath);
344
+        }
345
+        if ($this->is_dir($path)) {
346
+            $result = $this->basicOperation('rmdir', $path, array('delete'));
347
+        } else {
348
+            $result = false;
349
+        }
350
+
351
+        if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
352
+            $storage = $mount->getStorage();
353
+            $internalPath = $mount->getInternalPath($absolutePath);
354
+            $storage->getUpdater()->remove($internalPath);
355
+        }
356
+        return $result;
357
+    }
358
+
359
+    /**
360
+     * @param string $path
361
+     * @return resource
362
+     */
363
+    public function opendir($path) {
364
+        return $this->basicOperation('opendir', $path, array('read'));
365
+    }
366
+
367
+    /**
368
+     * @param string $path
369
+     * @return bool|mixed
370
+     */
371
+    public function is_dir($path) {
372
+        if ($path == '/') {
373
+            return true;
374
+        }
375
+        return $this->basicOperation('is_dir', $path);
376
+    }
377
+
378
+    /**
379
+     * @param string $path
380
+     * @return bool|mixed
381
+     */
382
+    public function is_file($path) {
383
+        if ($path == '/') {
384
+            return false;
385
+        }
386
+        return $this->basicOperation('is_file', $path);
387
+    }
388
+
389
+    /**
390
+     * @param string $path
391
+     * @return mixed
392
+     */
393
+    public function stat($path) {
394
+        return $this->basicOperation('stat', $path);
395
+    }
396
+
397
+    /**
398
+     * @param string $path
399
+     * @return mixed
400
+     */
401
+    public function filetype($path) {
402
+        return $this->basicOperation('filetype', $path);
403
+    }
404
+
405
+    /**
406
+     * @param string $path
407
+     * @return mixed
408
+     */
409
+    public function filesize($path) {
410
+        return $this->basicOperation('filesize', $path);
411
+    }
412
+
413
+    /**
414
+     * @param string $path
415
+     * @return bool|mixed
416
+     * @throws \OCP\Files\InvalidPathException
417
+     */
418
+    public function readfile($path) {
419
+        $this->assertPathLength($path);
420
+        @ob_end_clean();
421
+        $handle = $this->fopen($path, 'rb');
422
+        if ($handle) {
423
+            $chunkSize = 8192; // 8 kB chunks
424
+            while (!feof($handle)) {
425
+                echo fread($handle, $chunkSize);
426
+                flush();
427
+            }
428
+            fclose($handle);
429
+            return $this->filesize($path);
430
+        }
431
+        return false;
432
+    }
433
+
434
+    /**
435
+     * @param string $path
436
+     * @param int $from
437
+     * @param int $to
438
+     * @return bool|mixed
439
+     * @throws \OCP\Files\InvalidPathException
440
+     * @throws \OCP\Files\UnseekableException
441
+     */
442
+    public function readfilePart($path, $from, $to) {
443
+        $this->assertPathLength($path);
444
+        @ob_end_clean();
445
+        $handle = $this->fopen($path, 'rb');
446
+        if ($handle) {
447
+            $chunkSize = 8192; // 8 kB chunks
448
+            $startReading = true;
449
+
450
+            if ($from !== 0 && $from !== '0' && fseek($handle, $from) !== 0) {
451
+                // forward file handle via chunked fread because fseek seem to have failed
452
+
453
+                $end = $from + 1;
454
+                while (!feof($handle) && ftell($handle) < $end) {
455
+                    $len = $from - ftell($handle);
456
+                    if ($len > $chunkSize) {
457
+                        $len = $chunkSize;
458
+                    }
459
+                    $result = fread($handle, $len);
460
+
461
+                    if ($result === false) {
462
+                        $startReading = false;
463
+                        break;
464
+                    }
465
+                }
466
+            }
467
+
468
+            if ($startReading) {
469
+                $end = $to + 1;
470
+                while (!feof($handle) && ftell($handle) < $end) {
471
+                    $len = $end - ftell($handle);
472
+                    if ($len > $chunkSize) {
473
+                        $len = $chunkSize;
474
+                    }
475
+                    echo fread($handle, $len);
476
+                    flush();
477
+                }
478
+                return ftell($handle) - $from;
479
+            }
480
+
481
+            throw new \OCP\Files\UnseekableException('fseek error');
482
+        }
483
+        return false;
484
+    }
485
+
486
+    /**
487
+     * @param string $path
488
+     * @return mixed
489
+     */
490
+    public function isCreatable($path) {
491
+        return $this->basicOperation('isCreatable', $path);
492
+    }
493
+
494
+    /**
495
+     * @param string $path
496
+     * @return mixed
497
+     */
498
+    public function isReadable($path) {
499
+        return $this->basicOperation('isReadable', $path);
500
+    }
501
+
502
+    /**
503
+     * @param string $path
504
+     * @return mixed
505
+     */
506
+    public function isUpdatable($path) {
507
+        return $this->basicOperation('isUpdatable', $path);
508
+    }
509
+
510
+    /**
511
+     * @param string $path
512
+     * @return bool|mixed
513
+     */
514
+    public function isDeletable($path) {
515
+        $absolutePath = $this->getAbsolutePath($path);
516
+        $mount = Filesystem::getMountManager()->find($absolutePath);
517
+        if ($mount->getInternalPath($absolutePath) === '') {
518
+            return $mount instanceof MoveableMount;
519
+        }
520
+        return $this->basicOperation('isDeletable', $path);
521
+    }
522
+
523
+    /**
524
+     * @param string $path
525
+     * @return mixed
526
+     */
527
+    public function isSharable($path) {
528
+        return $this->basicOperation('isSharable', $path);
529
+    }
530
+
531
+    /**
532
+     * @param string $path
533
+     * @return bool|mixed
534
+     */
535
+    public function file_exists($path) {
536
+        if ($path == '/') {
537
+            return true;
538
+        }
539
+        return $this->basicOperation('file_exists', $path);
540
+    }
541
+
542
+    /**
543
+     * @param string $path
544
+     * @return mixed
545
+     */
546
+    public function filemtime($path) {
547
+        return $this->basicOperation('filemtime', $path);
548
+    }
549
+
550
+    /**
551
+     * @param string $path
552
+     * @param int|string $mtime
553
+     * @return bool
554
+     */
555
+    public function touch($path, $mtime = null) {
556
+        if (!is_null($mtime) and !is_numeric($mtime)) {
557
+            $mtime = strtotime($mtime);
558
+        }
559
+
560
+        $hooks = array('touch');
561
+
562
+        if (!$this->file_exists($path)) {
563
+            $hooks[] = 'create';
564
+            $hooks[] = 'write';
565
+        }
566
+        $result = $this->basicOperation('touch', $path, $hooks, $mtime);
567
+        if (!$result) {
568
+            // If create file fails because of permissions on external storage like SMB folders,
569
+            // check file exists and return false if not.
570
+            if (!$this->file_exists($path)) {
571
+                return false;
572
+            }
573
+            if (is_null($mtime)) {
574
+                $mtime = time();
575
+            }
576
+            //if native touch fails, we emulate it by changing the mtime in the cache
577
+            $this->putFileInfo($path, array('mtime' => floor($mtime)));
578
+        }
579
+        return true;
580
+    }
581
+
582
+    /**
583
+     * @param string $path
584
+     * @return mixed
585
+     */
586
+    public function file_get_contents($path) {
587
+        return $this->basicOperation('file_get_contents', $path, array('read'));
588
+    }
589
+
590
+    /**
591
+     * @param bool $exists
592
+     * @param string $path
593
+     * @param bool $run
594
+     */
595
+    protected function emit_file_hooks_pre($exists, $path, &$run) {
596
+        if (!$exists) {
597
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_create, array(
598
+                Filesystem::signal_param_path => $this->getHookPath($path),
599
+                Filesystem::signal_param_run => &$run,
600
+            ));
601
+        } else {
602
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_update, array(
603
+                Filesystem::signal_param_path => $this->getHookPath($path),
604
+                Filesystem::signal_param_run => &$run,
605
+            ));
606
+        }
607
+        \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_write, array(
608
+            Filesystem::signal_param_path => $this->getHookPath($path),
609
+            Filesystem::signal_param_run => &$run,
610
+        ));
611
+    }
612
+
613
+    /**
614
+     * @param bool $exists
615
+     * @param string $path
616
+     */
617
+    protected function emit_file_hooks_post($exists, $path) {
618
+        if (!$exists) {
619
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_create, array(
620
+                Filesystem::signal_param_path => $this->getHookPath($path),
621
+            ));
622
+        } else {
623
+            \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_update, array(
624
+                Filesystem::signal_param_path => $this->getHookPath($path),
625
+            ));
626
+        }
627
+        \OC_Hook::emit(Filesystem::CLASSNAME, Filesystem::signal_post_write, array(
628
+            Filesystem::signal_param_path => $this->getHookPath($path),
629
+        ));
630
+    }
631
+
632
+    /**
633
+     * @param string $path
634
+     * @param mixed $data
635
+     * @return bool|mixed
636
+     * @throws \Exception
637
+     */
638
+    public function file_put_contents($path, $data) {
639
+        if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
640
+            $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
641
+            if (Filesystem::isValidPath($path)
642
+                and !Filesystem::isFileBlacklisted($path)
643
+            ) {
644
+                $path = $this->getRelativePath($absolutePath);
645
+
646
+                $this->lockFile($path, ILockingProvider::LOCK_SHARED);
647
+
648
+                $exists = $this->file_exists($path);
649
+                $run = true;
650
+                if ($this->shouldEmitHooks($path)) {
651
+                    $this->emit_file_hooks_pre($exists, $path, $run);
652
+                }
653
+                if (!$run) {
654
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
655
+                    return false;
656
+                }
657
+
658
+                $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
659
+
660
+                /** @var \OC\Files\Storage\Storage $storage */
661
+                list($storage, $internalPath) = $this->resolvePath($path);
662
+                $target = $storage->fopen($internalPath, 'w');
663
+                if ($target) {
664
+                    list (, $result) = \OC_Helper::streamCopy($data, $target);
665
+                    fclose($target);
666
+                    fclose($data);
667
+
668
+                    $this->writeUpdate($storage, $internalPath);
669
+
670
+                    $this->changeLock($path, ILockingProvider::LOCK_SHARED);
671
+
672
+                    if ($this->shouldEmitHooks($path) && $result !== false) {
673
+                        $this->emit_file_hooks_post($exists, $path);
674
+                    }
675
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
676
+                    return $result;
677
+                } else {
678
+                    $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
679
+                    return false;
680
+                }
681
+            } else {
682
+                return false;
683
+            }
684
+        } else {
685
+            $hooks = $this->file_exists($path) ? array('update', 'write') : array('create', 'write');
686
+            return $this->basicOperation('file_put_contents', $path, $hooks, $data);
687
+        }
688
+    }
689
+
690
+    /**
691
+     * @param string $path
692
+     * @return bool|mixed
693
+     */
694
+    public function unlink($path) {
695
+        if ($path === '' || $path === '/') {
696
+            // do not allow deleting the root
697
+            return false;
698
+        }
699
+        $postFix = (substr($path, -1) === '/') ? '/' : '';
700
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
701
+        $mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
702
+        if ($mount and $mount->getInternalPath($absolutePath) === '') {
703
+            return $this->removeMount($mount, $absolutePath);
704
+        }
705
+        if ($this->is_dir($path)) {
706
+            $result = $this->basicOperation('rmdir', $path, ['delete']);
707
+        } else {
708
+            $result = $this->basicOperation('unlink', $path, ['delete']);
709
+        }
710
+        if (!$result && !$this->file_exists($path)) { //clear ghost files from the cache on delete
711
+            $storage = $mount->getStorage();
712
+            $internalPath = $mount->getInternalPath($absolutePath);
713
+            $storage->getUpdater()->remove($internalPath);
714
+            return true;
715
+        } else {
716
+            return $result;
717
+        }
718
+    }
719
+
720
+    /**
721
+     * @param string $directory
722
+     * @return bool|mixed
723
+     */
724
+    public function deleteAll($directory) {
725
+        return $this->rmdir($directory);
726
+    }
727
+
728
+    /**
729
+     * Rename/move a file or folder from the source path to target path.
730
+     *
731
+     * @param string $path1 source path
732
+     * @param string $path2 target path
733
+     *
734
+     * @return bool|mixed
735
+     */
736
+    public function rename($path1, $path2) {
737
+        $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
738
+        $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
739
+        $result = false;
740
+        if (
741
+            Filesystem::isValidPath($path2)
742
+            and Filesystem::isValidPath($path1)
743
+            and !Filesystem::isFileBlacklisted($path2)
744
+        ) {
745
+            $path1 = $this->getRelativePath($absolutePath1);
746
+            $path2 = $this->getRelativePath($absolutePath2);
747
+            $exists = $this->file_exists($path2);
748
+
749
+            if ($path1 == null or $path2 == null) {
750
+                return false;
751
+            }
752
+
753
+            $this->lockFile($path1, ILockingProvider::LOCK_SHARED, true);
754
+            try {
755
+                $this->lockFile($path2, ILockingProvider::LOCK_SHARED, true);
756
+
757
+                $run = true;
758
+                if ($this->shouldEmitHooks($path1) && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
759
+                    // if it was a rename from a part file to a regular file it was a write and not a rename operation
760
+                    $this->emit_file_hooks_pre($exists, $path2, $run);
761
+                } elseif ($this->shouldEmitHooks($path1)) {
762
+                    \OC_Hook::emit(
763
+                        Filesystem::CLASSNAME, Filesystem::signal_rename,
764
+                        array(
765
+                            Filesystem::signal_param_oldpath => $this->getHookPath($path1),
766
+                            Filesystem::signal_param_newpath => $this->getHookPath($path2),
767
+                            Filesystem::signal_param_run => &$run
768
+                        )
769
+                    );
770
+                }
771
+                if ($run) {
772
+                    $this->verifyPath(dirname($path2), basename($path2));
773
+
774
+                    $manager = Filesystem::getMountManager();
775
+                    $mount1 = $this->getMount($path1);
776
+                    $mount2 = $this->getMount($path2);
777
+                    $storage1 = $mount1->getStorage();
778
+                    $storage2 = $mount2->getStorage();
779
+                    $internalPath1 = $mount1->getInternalPath($absolutePath1);
780
+                    $internalPath2 = $mount2->getInternalPath($absolutePath2);
781
+
782
+                    $this->changeLock($path1, ILockingProvider::LOCK_EXCLUSIVE, true);
783
+                    try {
784
+                        $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE, true);
785
+
786
+                        if ($internalPath1 === '') {
787
+                            if ($mount1 instanceof MoveableMount) {
788
+                                if ($this->isTargetAllowed($absolutePath2)) {
789
+                                    /**
790
+                                     * @var \OC\Files\Mount\MountPoint | \OC\Files\Mount\MoveableMount $mount1
791
+                                     */
792
+                                    $sourceMountPoint = $mount1->getMountPoint();
793
+                                    $result = $mount1->moveMount($absolutePath2);
794
+                                    $manager->moveMount($sourceMountPoint, $mount1->getMountPoint());
795
+                                } else {
796
+                                    $result = false;
797
+                                }
798
+                            } else {
799
+                                $result = false;
800
+                            }
801
+                            // moving a file/folder within the same mount point
802
+                        } elseif ($storage1 === $storage2) {
803
+                            if ($storage1) {
804
+                                $result = $storage1->rename($internalPath1, $internalPath2);
805
+                            } else {
806
+                                $result = false;
807
+                            }
808
+                            // moving a file/folder between storages (from $storage1 to $storage2)
809
+                        } else {
810
+                            $result = $storage2->moveFromStorage($storage1, $internalPath1, $internalPath2);
811
+                        }
812
+
813
+                        if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
814
+                            // if it was a rename from a part file to a regular file it was a write and not a rename operation
815
+                            $this->writeUpdate($storage2, $internalPath2);
816
+                        } else if ($result) {
817
+                            if ($internalPath1 !== '') { // don't do a cache update for moved mounts
818
+                                $this->renameUpdate($storage1, $storage2, $internalPath1, $internalPath2);
819
+                            }
820
+                        }
821
+                    } catch(\Exception $e) {
822
+                        throw $e;
823
+                    } finally {
824
+                        $this->changeLock($path1, ILockingProvider::LOCK_SHARED, true);
825
+                        $this->changeLock($path2, ILockingProvider::LOCK_SHARED, true);
826
+                    }
827
+
828
+                    if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
829
+                        if ($this->shouldEmitHooks()) {
830
+                            $this->emit_file_hooks_post($exists, $path2);
831
+                        }
832
+                    } elseif ($result) {
833
+                        if ($this->shouldEmitHooks($path1) and $this->shouldEmitHooks($path2)) {
834
+                            \OC_Hook::emit(
835
+                                Filesystem::CLASSNAME,
836
+                                Filesystem::signal_post_rename,
837
+                                array(
838
+                                    Filesystem::signal_param_oldpath => $this->getHookPath($path1),
839
+                                    Filesystem::signal_param_newpath => $this->getHookPath($path2)
840
+                                )
841
+                            );
842
+                        }
843
+                    }
844
+                }
845
+            } catch(\Exception $e) {
846
+                throw $e;
847
+            } finally {
848
+                $this->unlockFile($path1, ILockingProvider::LOCK_SHARED, true);
849
+                $this->unlockFile($path2, ILockingProvider::LOCK_SHARED, true);
850
+            }
851
+        }
852
+        return $result;
853
+    }
854
+
855
+    /**
856
+     * Copy a file/folder from the source path to target path
857
+     *
858
+     * @param string $path1 source path
859
+     * @param string $path2 target path
860
+     * @param bool $preserveMtime whether to preserve mtime on the copy
861
+     *
862
+     * @return bool|mixed
863
+     */
864
+    public function copy($path1, $path2, $preserveMtime = false) {
865
+        $absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
866
+        $absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
867
+        $result = false;
868
+        if (
869
+            Filesystem::isValidPath($path2)
870
+            and Filesystem::isValidPath($path1)
871
+            and !Filesystem::isFileBlacklisted($path2)
872
+        ) {
873
+            $path1 = $this->getRelativePath($absolutePath1);
874
+            $path2 = $this->getRelativePath($absolutePath2);
875
+
876
+            if ($path1 == null or $path2 == null) {
877
+                return false;
878
+            }
879
+            $run = true;
880
+
881
+            $this->lockFile($path2, ILockingProvider::LOCK_SHARED);
882
+            $this->lockFile($path1, ILockingProvider::LOCK_SHARED);
883
+            $lockTypePath1 = ILockingProvider::LOCK_SHARED;
884
+            $lockTypePath2 = ILockingProvider::LOCK_SHARED;
885
+
886
+            try {
887
+
888
+                $exists = $this->file_exists($path2);
889
+                if ($this->shouldEmitHooks()) {
890
+                    \OC_Hook::emit(
891
+                        Filesystem::CLASSNAME,
892
+                        Filesystem::signal_copy,
893
+                        array(
894
+                            Filesystem::signal_param_oldpath => $this->getHookPath($path1),
895
+                            Filesystem::signal_param_newpath => $this->getHookPath($path2),
896
+                            Filesystem::signal_param_run => &$run
897
+                        )
898
+                    );
899
+                    $this->emit_file_hooks_pre($exists, $path2, $run);
900
+                }
901
+                if ($run) {
902
+                    $mount1 = $this->getMount($path1);
903
+                    $mount2 = $this->getMount($path2);
904
+                    $storage1 = $mount1->getStorage();
905
+                    $internalPath1 = $mount1->getInternalPath($absolutePath1);
906
+                    $storage2 = $mount2->getStorage();
907
+                    $internalPath2 = $mount2->getInternalPath($absolutePath2);
908
+
909
+                    $this->changeLock($path2, ILockingProvider::LOCK_EXCLUSIVE);
910
+                    $lockTypePath2 = ILockingProvider::LOCK_EXCLUSIVE;
911
+
912
+                    if ($mount1->getMountPoint() == $mount2->getMountPoint()) {
913
+                        if ($storage1) {
914
+                            $result = $storage1->copy($internalPath1, $internalPath2);
915
+                        } else {
916
+                            $result = false;
917
+                        }
918
+                    } else {
919
+                        $result = $storage2->copyFromStorage($storage1, $internalPath1, $internalPath2);
920
+                    }
921
+
922
+                    $this->writeUpdate($storage2, $internalPath2);
923
+
924
+                    $this->changeLock($path2, ILockingProvider::LOCK_SHARED);
925
+                    $lockTypePath2 = ILockingProvider::LOCK_SHARED;
926
+
927
+                    if ($this->shouldEmitHooks() && $result !== false) {
928
+                        \OC_Hook::emit(
929
+                            Filesystem::CLASSNAME,
930
+                            Filesystem::signal_post_copy,
931
+                            array(
932
+                                Filesystem::signal_param_oldpath => $this->getHookPath($path1),
933
+                                Filesystem::signal_param_newpath => $this->getHookPath($path2)
934
+                            )
935
+                        );
936
+                        $this->emit_file_hooks_post($exists, $path2);
937
+                    }
938
+
939
+                }
940
+            } catch (\Exception $e) {
941
+                $this->unlockFile($path2, $lockTypePath2);
942
+                $this->unlockFile($path1, $lockTypePath1);
943
+                throw $e;
944
+            }
945
+
946
+            $this->unlockFile($path2, $lockTypePath2);
947
+            $this->unlockFile($path1, $lockTypePath1);
948
+
949
+        }
950
+        return $result;
951
+    }
952
+
953
+    /**
954
+     * @param string $path
955
+     * @param string $mode 'r' or 'w'
956
+     * @return resource
957
+     */
958
+    public function fopen($path, $mode) {
959
+        $mode = str_replace('b', '', $mode); // the binary flag is a windows only feature which we do not support
960
+        $hooks = array();
961
+        switch ($mode) {
962
+            case 'r':
963
+                $hooks[] = 'read';
964
+                break;
965
+            case 'r+':
966
+            case 'w+':
967
+            case 'x+':
968
+            case 'a+':
969
+                $hooks[] = 'read';
970
+                $hooks[] = 'write';
971
+                break;
972
+            case 'w':
973
+            case 'x':
974
+            case 'a':
975
+                $hooks[] = 'write';
976
+                break;
977
+            default:
978
+                \OCP\Util::writeLog('core', 'invalid mode (' . $mode . ') for ' . $path, \OCP\Util::ERROR);
979
+        }
980
+
981
+        if ($mode !== 'r' && $mode !== 'w') {
982
+            \OC::$server->getLogger()->info('Trying to open a file with a mode other than "r" or "w" can cause severe performance issues with some backends');
983
+        }
984
+
985
+        return $this->basicOperation('fopen', $path, $hooks, $mode);
986
+    }
987
+
988
+    /**
989
+     * @param string $path
990
+     * @return bool|string
991
+     * @throws \OCP\Files\InvalidPathException
992
+     */
993
+    public function toTmpFile($path) {
994
+        $this->assertPathLength($path);
995
+        if (Filesystem::isValidPath($path)) {
996
+            $source = $this->fopen($path, 'r');
997
+            if ($source) {
998
+                $extension = pathinfo($path, PATHINFO_EXTENSION);
999
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
1000
+                file_put_contents($tmpFile, $source);
1001
+                return $tmpFile;
1002
+            } else {
1003
+                return false;
1004
+            }
1005
+        } else {
1006
+            return false;
1007
+        }
1008
+    }
1009
+
1010
+    /**
1011
+     * @param string $tmpFile
1012
+     * @param string $path
1013
+     * @return bool|mixed
1014
+     * @throws \OCP\Files\InvalidPathException
1015
+     */
1016
+    public function fromTmpFile($tmpFile, $path) {
1017
+        $this->assertPathLength($path);
1018
+        if (Filesystem::isValidPath($path)) {
1019
+
1020
+            // Get directory that the file is going into
1021
+            $filePath = dirname($path);
1022
+
1023
+            // Create the directories if any
1024
+            if (!$this->file_exists($filePath)) {
1025
+                $result = $this->createParentDirectories($filePath);
1026
+                if ($result === false) {
1027
+                    return false;
1028
+                }
1029
+            }
1030
+
1031
+            $source = fopen($tmpFile, 'r');
1032
+            if ($source) {
1033
+                $result = $this->file_put_contents($path, $source);
1034
+                // $this->file_put_contents() might have already closed
1035
+                // the resource, so we check it, before trying to close it
1036
+                // to avoid messages in the error log.
1037
+                if (is_resource($source)) {
1038
+                    fclose($source);
1039
+                }
1040
+                unlink($tmpFile);
1041
+                return $result;
1042
+            } else {
1043
+                return false;
1044
+            }
1045
+        } else {
1046
+            return false;
1047
+        }
1048
+    }
1049
+
1050
+
1051
+    /**
1052
+     * @param string $path
1053
+     * @return mixed
1054
+     * @throws \OCP\Files\InvalidPathException
1055
+     */
1056
+    public function getMimeType($path) {
1057
+        $this->assertPathLength($path);
1058
+        return $this->basicOperation('getMimeType', $path);
1059
+    }
1060
+
1061
+    /**
1062
+     * @param string $type
1063
+     * @param string $path
1064
+     * @param bool $raw
1065
+     * @return bool|null|string
1066
+     */
1067
+    public function hash($type, $path, $raw = false) {
1068
+        $postFix = (substr($path, -1) === '/') ? '/' : '';
1069
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1070
+        if (Filesystem::isValidPath($path)) {
1071
+            $path = $this->getRelativePath($absolutePath);
1072
+            if ($path == null) {
1073
+                return false;
1074
+            }
1075
+            if ($this->shouldEmitHooks($path)) {
1076
+                \OC_Hook::emit(
1077
+                    Filesystem::CLASSNAME,
1078
+                    Filesystem::signal_read,
1079
+                    array(Filesystem::signal_param_path => $this->getHookPath($path))
1080
+                );
1081
+            }
1082
+            list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1083
+            if ($storage) {
1084
+                return $storage->hash($type, $internalPath, $raw);
1085
+            }
1086
+        }
1087
+        return null;
1088
+    }
1089
+
1090
+    /**
1091
+     * @param string $path
1092
+     * @return mixed
1093
+     * @throws \OCP\Files\InvalidPathException
1094
+     */
1095
+    public function free_space($path = '/') {
1096
+        $this->assertPathLength($path);
1097
+        $result = $this->basicOperation('free_space', $path);
1098
+        if ($result === null) {
1099
+            throw new InvalidPathException();
1100
+        }
1101
+        return $result;
1102
+    }
1103
+
1104
+    /**
1105
+     * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage
1106
+     *
1107
+     * @param string $operation
1108
+     * @param string $path
1109
+     * @param array $hooks (optional)
1110
+     * @param mixed $extraParam (optional)
1111
+     * @return mixed
1112
+     * @throws \Exception
1113
+     *
1114
+     * This method takes requests for basic filesystem functions (e.g. reading & writing
1115
+     * files), processes hooks and proxies, sanitises paths, and finally passes them on to
1116
+     * \OC\Files\Storage\Storage for delegation to a storage backend for execution
1117
+     */
1118
+    private function basicOperation($operation, $path, $hooks = [], $extraParam = null) {
1119
+        $postFix = (substr($path, -1) === '/') ? '/' : '';
1120
+        $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
1121
+        if (Filesystem::isValidPath($path)
1122
+            and !Filesystem::isFileBlacklisted($path)
1123
+        ) {
1124
+            $path = $this->getRelativePath($absolutePath);
1125
+            if ($path == null) {
1126
+                return false;
1127
+            }
1128
+
1129
+            if (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks)) {
1130
+                // always a shared lock during pre-hooks so the hook can read the file
1131
+                $this->lockFile($path, ILockingProvider::LOCK_SHARED);
1132
+            }
1133
+
1134
+            $run = $this->runHooks($hooks, $path);
1135
+            /** @var \OC\Files\Storage\Storage $storage */
1136
+            list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
1137
+            if ($run and $storage) {
1138
+                if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1139
+                    $this->changeLock($path, ILockingProvider::LOCK_EXCLUSIVE);
1140
+                }
1141
+                try {
1142
+                    if (!is_null($extraParam)) {
1143
+                        $result = $storage->$operation($internalPath, $extraParam);
1144
+                    } else {
1145
+                        $result = $storage->$operation($internalPath);
1146
+                    }
1147
+                } catch (\Exception $e) {
1148
+                    if (in_array('write', $hooks) || in_array('delete', $hooks)) {
1149
+                        $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1150
+                    } else if (in_array('read', $hooks)) {
1151
+                        $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1152
+                    }
1153
+                    throw $e;
1154
+                }
1155
+
1156
+                if ($result && in_array('delete', $hooks) and $result) {
1157
+                    $this->removeUpdate($storage, $internalPath);
1158
+                }
1159
+                if ($result && in_array('write', $hooks) and $operation !== 'fopen') {
1160
+                    $this->writeUpdate($storage, $internalPath);
1161
+                }
1162
+                if ($result && in_array('touch', $hooks)) {
1163
+                    $this->writeUpdate($storage, $internalPath, $extraParam);
1164
+                }
1165
+
1166
+                if ((in_array('write', $hooks) || in_array('delete', $hooks)) && ($operation !== 'fopen' || $result === false)) {
1167
+                    $this->changeLock($path, ILockingProvider::LOCK_SHARED);
1168
+                }
1169
+
1170
+                $unlockLater = false;
1171
+                if ($this->lockingEnabled && $operation === 'fopen' && is_resource($result)) {
1172
+                    $unlockLater = true;
1173
+                    // make sure our unlocking callback will still be called if connection is aborted
1174
+                    ignore_user_abort(true);
1175
+                    $result = CallbackWrapper::wrap($result, null, null, function () use ($hooks, $path) {
1176
+                        if (in_array('write', $hooks)) {
1177
+                            $this->unlockFile($path, ILockingProvider::LOCK_EXCLUSIVE);
1178
+                        } else if (in_array('read', $hooks)) {
1179
+                            $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1180
+                        }
1181
+                    });
1182
+                }
1183
+
1184
+                if ($this->shouldEmitHooks($path) && $result !== false) {
1185
+                    if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
1186
+                        $this->runHooks($hooks, $path, true);
1187
+                    }
1188
+                }
1189
+
1190
+                if (!$unlockLater
1191
+                    && (in_array('write', $hooks) || in_array('delete', $hooks) || in_array('read', $hooks))
1192
+                ) {
1193
+                    $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1194
+                }
1195
+                return $result;
1196
+            } else {
1197
+                $this->unlockFile($path, ILockingProvider::LOCK_SHARED);
1198
+            }
1199
+        }
1200
+        return null;
1201
+    }
1202
+
1203
+    /**
1204
+     * get the path relative to the default root for hook usage
1205
+     *
1206
+     * @param string $path
1207
+     * @return string
1208
+     */
1209
+    private function getHookPath($path) {
1210
+        if (!Filesystem::getView()) {
1211
+            return $path;
1212
+        }
1213
+        return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path));
1214
+    }
1215
+
1216
+    private function shouldEmitHooks($path = '') {
1217
+        if ($path && Cache\Scanner::isPartialFile($path)) {
1218
+            return false;
1219
+        }
1220
+        if (!Filesystem::$loaded) {
1221
+            return false;
1222
+        }
1223
+        $defaultRoot = Filesystem::getRoot();
1224
+        if ($defaultRoot === null) {
1225
+            return false;
1226
+        }
1227
+        if ($this->fakeRoot === $defaultRoot) {
1228
+            return true;
1229
+        }
1230
+        $fullPath = $this->getAbsolutePath($path);
1231
+
1232
+        if ($fullPath === $defaultRoot) {
1233
+            return true;
1234
+        }
1235
+
1236
+        return (strlen($fullPath) > strlen($defaultRoot)) && (substr($fullPath, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
1237
+    }
1238
+
1239
+    /**
1240
+     * @param string[] $hooks
1241
+     * @param string $path
1242
+     * @param bool $post
1243
+     * @return bool
1244
+     */
1245
+    private function runHooks($hooks, $path, $post = false) {
1246
+        $relativePath = $path;
1247
+        $path = $this->getHookPath($path);
1248
+        $prefix = $post ? 'post_' : '';
1249
+        $run = true;
1250
+        if ($this->shouldEmitHooks($relativePath)) {
1251
+            foreach ($hooks as $hook) {
1252
+                if ($hook != 'read') {
1253
+                    \OC_Hook::emit(
1254
+                        Filesystem::CLASSNAME,
1255
+                        $prefix . $hook,
1256
+                        array(
1257
+                            Filesystem::signal_param_run => &$run,
1258
+                            Filesystem::signal_param_path => $path
1259
+                        )
1260
+                    );
1261
+                } elseif (!$post) {
1262
+                    \OC_Hook::emit(
1263
+                        Filesystem::CLASSNAME,
1264
+                        $prefix . $hook,
1265
+                        array(
1266
+                            Filesystem::signal_param_path => $path
1267
+                        )
1268
+                    );
1269
+                }
1270
+            }
1271
+        }
1272
+        return $run;
1273
+    }
1274
+
1275
+    /**
1276
+     * check if a file or folder has been updated since $time
1277
+     *
1278
+     * @param string $path
1279
+     * @param int $time
1280
+     * @return bool
1281
+     */
1282
+    public function hasUpdated($path, $time) {
1283
+        return $this->basicOperation('hasUpdated', $path, array(), $time);
1284
+    }
1285
+
1286
+    /**
1287
+     * @param string $ownerId
1288
+     * @return \OC\User\User
1289
+     */
1290
+    private function getUserObjectForOwner($ownerId) {
1291
+        $owner = $this->userManager->get($ownerId);
1292
+        if ($owner instanceof IUser) {
1293
+            return $owner;
1294
+        } else {
1295
+            return new User($ownerId, null);
1296
+        }
1297
+    }
1298
+
1299
+    /**
1300
+     * Get file info from cache
1301
+     *
1302
+     * If the file is not in cached it will be scanned
1303
+     * If the file has changed on storage the cache will be updated
1304
+     *
1305
+     * @param \OC\Files\Storage\Storage $storage
1306
+     * @param string $internalPath
1307
+     * @param string $relativePath
1308
+     * @return ICacheEntry|bool
1309
+     */
1310
+    private function getCacheEntry($storage, $internalPath, $relativePath) {
1311
+        $cache = $storage->getCache($internalPath);
1312
+        $data = $cache->get($internalPath);
1313
+        $watcher = $storage->getWatcher($internalPath);
1314
+
1315
+        try {
1316
+            // if the file is not in the cache or needs to be updated, trigger the scanner and reload the data
1317
+            if (!$data || $data['size'] === -1) {
1318
+                $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1319
+                if (!$storage->file_exists($internalPath)) {
1320
+                    $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1321
+                    return false;
1322
+                }
1323
+                $scanner = $storage->getScanner($internalPath);
1324
+                $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1325
+                $data = $cache->get($internalPath);
1326
+                $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1327
+            } else if (!Cache\Scanner::isPartialFile($internalPath) && $watcher->needsUpdate($internalPath, $data)) {
1328
+                $this->lockFile($relativePath, ILockingProvider::LOCK_SHARED);
1329
+                $watcher->update($internalPath, $data);
1330
+                $storage->getPropagator()->propagateChange($internalPath, time());
1331
+                $data = $cache->get($internalPath);
1332
+                $this->unlockFile($relativePath, ILockingProvider::LOCK_SHARED);
1333
+            }
1334
+        } catch (LockedException $e) {
1335
+            // if the file is locked we just use the old cache info
1336
+        }
1337
+
1338
+        return $data;
1339
+    }
1340
+
1341
+    /**
1342
+     * get the filesystem info
1343
+     *
1344
+     * @param string $path
1345
+     * @param boolean|string $includeMountPoints true to add mountpoint sizes,
1346
+     * 'ext' to add only ext storage mount point sizes. Defaults to true.
1347
+     * defaults to true
1348
+     * @return \OC\Files\FileInfo|false False if file does not exist
1349
+     */
1350
+    public function getFileInfo($path, $includeMountPoints = true) {
1351
+        $this->assertPathLength($path);
1352
+        if (!Filesystem::isValidPath($path)) {
1353
+            return false;
1354
+        }
1355
+        if (Cache\Scanner::isPartialFile($path)) {
1356
+            return $this->getPartFileInfo($path);
1357
+        }
1358
+        $relativePath = $path;
1359
+        $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1360
+
1361
+        $mount = Filesystem::getMountManager()->find($path);
1362
+        if (!$mount) {
1363
+            return false;
1364
+        }
1365
+        $storage = $mount->getStorage();
1366
+        $internalPath = $mount->getInternalPath($path);
1367
+        if ($storage) {
1368
+            $data = $this->getCacheEntry($storage, $internalPath, $relativePath);
1369
+
1370
+            if (!$data instanceof ICacheEntry) {
1371
+                return false;
1372
+            }
1373
+
1374
+            if ($mount instanceof MoveableMount && $internalPath === '') {
1375
+                $data['permissions'] |= \OCP\Constants::PERMISSION_DELETE;
1376
+            }
1377
+
1378
+            $owner = $this->getUserObjectForOwner($storage->getOwner($internalPath));
1379
+            $info = new FileInfo($path, $storage, $internalPath, $data, $mount, $owner);
1380
+
1381
+            if ($data and isset($data['fileid'])) {
1382
+                if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
1383
+                    //add the sizes of other mount points to the folder
1384
+                    $extOnly = ($includeMountPoints === 'ext');
1385
+                    $mounts = Filesystem::getMountManager()->findIn($path);
1386
+                    $info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
1387
+                        $subStorage = $mount->getStorage();
1388
+                        return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
1389
+                    }));
1390
+                }
1391
+            }
1392
+
1393
+            return $info;
1394
+        }
1395
+
1396
+        return false;
1397
+    }
1398
+
1399
+    /**
1400
+     * get the content of a directory
1401
+     *
1402
+     * @param string $directory path under datadirectory
1403
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
1404
+     * @return FileInfo[]
1405
+     */
1406
+    public function getDirectoryContent($directory, $mimetype_filter = '') {
1407
+        $this->assertPathLength($directory);
1408
+        if (!Filesystem::isValidPath($directory)) {
1409
+            return [];
1410
+        }
1411
+        $path = $this->getAbsolutePath($directory);
1412
+        $path = Filesystem::normalizePath($path);
1413
+        $mount = $this->getMount($directory);
1414
+        if (!$mount) {
1415
+            return [];
1416
+        }
1417
+        $storage = $mount->getStorage();
1418
+        $internalPath = $mount->getInternalPath($path);
1419
+        if ($storage) {
1420
+            $cache = $storage->getCache($internalPath);
1421
+            $user = \OC_User::getUser();
1422
+
1423
+            $data = $this->getCacheEntry($storage, $internalPath, $directory);
1424
+
1425
+            if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
1426
+                return [];
1427
+            }
1428
+
1429
+            $folderId = $data['fileid'];
1430
+            $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
1431
+
1432
+            $sharingDisabled = \OCP\Util::isSharingDisabledForUser();
1433
+            /**
1434
+             * @var \OC\Files\FileInfo[] $files
1435
+             */
1436
+            $files = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
1437
+                if ($sharingDisabled) {
1438
+                    $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1439
+                }
1440
+                $owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
1441
+                return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
1442
+            }, $contents);
1443
+
1444
+            //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
1445
+            $mounts = Filesystem::getMountManager()->findIn($path);
1446
+            $dirLength = strlen($path);
1447
+            foreach ($mounts as $mount) {
1448
+                $mountPoint = $mount->getMountPoint();
1449
+                $subStorage = $mount->getStorage();
1450
+                if ($subStorage) {
1451
+                    $subCache = $subStorage->getCache('');
1452
+
1453
+                    $rootEntry = $subCache->get('');
1454
+                    if (!$rootEntry) {
1455
+                        $subScanner = $subStorage->getScanner('');
1456
+                        try {
1457
+                            $subScanner->scanFile('');
1458
+                        } catch (\OCP\Files\StorageNotAvailableException $e) {
1459
+                            continue;
1460
+                        } catch (\OCP\Files\StorageInvalidException $e) {
1461
+                            continue;
1462
+                        } catch (\Exception $e) {
1463
+                            // sometimes when the storage is not available it can be any exception
1464
+                            \OC::$server->getLogger()->logException($e, [
1465
+                                'message' => 'Exception while scanning storage "' . $subStorage->getId() . '"',
1466
+                                'level' => \OCP\Util::ERROR,
1467
+                                'app' => 'lib',
1468
+                            ]);
1469
+                            continue;
1470
+                        }
1471
+                        $rootEntry = $subCache->get('');
1472
+                    }
1473
+
1474
+                    if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
1475
+                        $relativePath = trim(substr($mountPoint, $dirLength), '/');
1476
+                        if ($pos = strpos($relativePath, '/')) {
1477
+                            //mountpoint inside subfolder add size to the correct folder
1478
+                            $entryName = substr($relativePath, 0, $pos);
1479
+                            foreach ($files as &$entry) {
1480
+                                if ($entry->getName() === $entryName) {
1481
+                                    $entry->addSubEntry($rootEntry, $mountPoint);
1482
+                                }
1483
+                            }
1484
+                        } else { //mountpoint in this folder, add an entry for it
1485
+                            $rootEntry['name'] = $relativePath;
1486
+                            $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
1487
+                            $permissions = $rootEntry['permissions'];
1488
+                            // do not allow renaming/deleting the mount point if they are not shared files/folders
1489
+                            // for shared files/folders we use the permissions given by the owner
1490
+                            if ($mount instanceof MoveableMount) {
1491
+                                $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
1492
+                            } else {
1493
+                                $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
1494
+                            }
1495
+
1496
+                            //remove any existing entry with the same name
1497
+                            foreach ($files as $i => $file) {
1498
+                                if ($file['name'] === $rootEntry['name']) {
1499
+                                    unset($files[$i]);
1500
+                                    break;
1501
+                                }
1502
+                            }
1503
+                            $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
1504
+
1505
+                            // if sharing was disabled for the user we remove the share permissions
1506
+                            if (\OCP\Util::isSharingDisabledForUser()) {
1507
+                                $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
1508
+                            }
1509
+
1510
+                            $owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
1511
+                            $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
1512
+                        }
1513
+                    }
1514
+                }
1515
+            }
1516
+
1517
+            if ($mimetype_filter) {
1518
+                $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
1519
+                    if (strpos($mimetype_filter, '/')) {
1520
+                        return $file->getMimetype() === $mimetype_filter;
1521
+                    } else {
1522
+                        return $file->getMimePart() === $mimetype_filter;
1523
+                    }
1524
+                });
1525
+            }
1526
+
1527
+            return $files;
1528
+        } else {
1529
+            return [];
1530
+        }
1531
+    }
1532
+
1533
+    /**
1534
+     * change file metadata
1535
+     *
1536
+     * @param string $path
1537
+     * @param array|\OCP\Files\FileInfo $data
1538
+     * @return int
1539
+     *
1540
+     * returns the fileid of the updated file
1541
+     */
1542
+    public function putFileInfo($path, $data) {
1543
+        $this->assertPathLength($path);
1544
+        if ($data instanceof FileInfo) {
1545
+            $data = $data->getData();
1546
+        }
1547
+        $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
1548
+        /**
1549
+         * @var \OC\Files\Storage\Storage $storage
1550
+         * @var string $internalPath
1551
+         */
1552
+        list($storage, $internalPath) = Filesystem::resolvePath($path);
1553
+        if ($storage) {
1554
+            $cache = $storage->getCache($path);
1555
+
1556
+            if (!$cache->inCache($internalPath)) {
1557
+                $scanner = $storage->getScanner($internalPath);
1558
+                $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
1559
+            }
1560
+
1561
+            return $cache->put($internalPath, $data);
1562
+        } else {
1563
+            return -1;
1564
+        }
1565
+    }
1566
+
1567
+    /**
1568
+     * search for files with the name matching $query
1569
+     *
1570
+     * @param string $query
1571
+     * @return FileInfo[]
1572
+     */
1573
+    public function search($query) {
1574
+        return $this->searchCommon('search', array('%' . $query . '%'));
1575
+    }
1576
+
1577
+    /**
1578
+     * search for files with the name matching $query
1579
+     *
1580
+     * @param string $query
1581
+     * @return FileInfo[]
1582
+     */
1583
+    public function searchRaw($query) {
1584
+        return $this->searchCommon('search', array($query));
1585
+    }
1586
+
1587
+    /**
1588
+     * search for files by mimetype
1589
+     *
1590
+     * @param string $mimetype
1591
+     * @return FileInfo[]
1592
+     */
1593
+    public function searchByMime($mimetype) {
1594
+        return $this->searchCommon('searchByMime', array($mimetype));
1595
+    }
1596
+
1597
+    /**
1598
+     * search for files by tag
1599
+     *
1600
+     * @param string|int $tag name or tag id
1601
+     * @param string $userId owner of the tags
1602
+     * @return FileInfo[]
1603
+     */
1604
+    public function searchByTag($tag, $userId) {
1605
+        return $this->searchCommon('searchByTag', array($tag, $userId));
1606
+    }
1607
+
1608
+    /**
1609
+     * @param string $method cache method
1610
+     * @param array $args
1611
+     * @return FileInfo[]
1612
+     */
1613
+    private function searchCommon($method, $args) {
1614
+        $files = array();
1615
+        $rootLength = strlen($this->fakeRoot);
1616
+
1617
+        $mount = $this->getMount('');
1618
+        $mountPoint = $mount->getMountPoint();
1619
+        $storage = $mount->getStorage();
1620
+        if ($storage) {
1621
+            $cache = $storage->getCache('');
1622
+
1623
+            $results = call_user_func_array(array($cache, $method), $args);
1624
+            foreach ($results as $result) {
1625
+                if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1626
+                    $internalPath = $result['path'];
1627
+                    $path = $mountPoint . $result['path'];
1628
+                    $result['path'] = substr($mountPoint . $result['path'], $rootLength);
1629
+                    $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1630
+                    $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1631
+                }
1632
+            }
1633
+
1634
+            $mounts = Filesystem::getMountManager()->findIn($this->fakeRoot);
1635
+            foreach ($mounts as $mount) {
1636
+                $mountPoint = $mount->getMountPoint();
1637
+                $storage = $mount->getStorage();
1638
+                if ($storage) {
1639
+                    $cache = $storage->getCache('');
1640
+
1641
+                    $relativeMountPoint = substr($mountPoint, $rootLength);
1642
+                    $results = call_user_func_array(array($cache, $method), $args);
1643
+                    if ($results) {
1644
+                        foreach ($results as $result) {
1645
+                            $internalPath = $result['path'];
1646
+                            $result['path'] = rtrim($relativeMountPoint . $result['path'], '/');
1647
+                            $path = rtrim($mountPoint . $internalPath, '/');
1648
+                            $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1649
+                            $files[] = new FileInfo($path, $storage, $internalPath, $result, $mount, $owner);
1650
+                        }
1651
+                    }
1652
+                }
1653
+            }
1654
+        }
1655
+        return $files;
1656
+    }
1657
+
1658
+    /**
1659
+     * Get the owner for a file or folder
1660
+     *
1661
+     * @param string $path
1662
+     * @return string the user id of the owner
1663
+     * @throws NotFoundException
1664
+     */
1665
+    public function getOwner($path) {
1666
+        $info = $this->getFileInfo($path);
1667
+        if (!$info) {
1668
+            throw new NotFoundException($path . ' not found while trying to get owner');
1669
+        }
1670
+        return $info->getOwner()->getUID();
1671
+    }
1672
+
1673
+    /**
1674
+     * get the ETag for a file or folder
1675
+     *
1676
+     * @param string $path
1677
+     * @return string
1678
+     */
1679
+    public function getETag($path) {
1680
+        /**
1681
+         * @var Storage\Storage $storage
1682
+         * @var string $internalPath
1683
+         */
1684
+        list($storage, $internalPath) = $this->resolvePath($path);
1685
+        if ($storage) {
1686
+            return $storage->getETag($internalPath);
1687
+        } else {
1688
+            return null;
1689
+        }
1690
+    }
1691
+
1692
+    /**
1693
+     * Get the path of a file by id, relative to the view
1694
+     *
1695
+     * Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
1696
+     *
1697
+     * @param int $id
1698
+     * @throws NotFoundException
1699
+     * @return string
1700
+     */
1701
+    public function getPath($id) {
1702
+        $id = (int)$id;
1703
+        $manager = Filesystem::getMountManager();
1704
+        $mounts = $manager->findIn($this->fakeRoot);
1705
+        $mounts[] = $manager->find($this->fakeRoot);
1706
+        // reverse the array so we start with the storage this view is in
1707
+        // which is the most likely to contain the file we're looking for
1708
+        $mounts = array_reverse($mounts);
1709
+        foreach ($mounts as $mount) {
1710
+            /**
1711
+             * @var \OC\Files\Mount\MountPoint $mount
1712
+             */
1713
+            if ($mount->getStorage()) {
1714
+                $cache = $mount->getStorage()->getCache();
1715
+                $internalPath = $cache->getPathById($id);
1716
+                if (is_string($internalPath)) {
1717
+                    $fullPath = $mount->getMountPoint() . $internalPath;
1718
+                    if (!is_null($path = $this->getRelativePath($fullPath))) {
1719
+                        return $path;
1720
+                    }
1721
+                }
1722
+            }
1723
+        }
1724
+        throw new NotFoundException(sprintf('File with id "%s" has not been found.', $id));
1725
+    }
1726
+
1727
+    /**
1728
+     * @param string $path
1729
+     * @throws InvalidPathException
1730
+     */
1731
+    private function assertPathLength($path) {
1732
+        $maxLen = min(PHP_MAXPATHLEN, 4000);
1733
+        // Check for the string length - performed using isset() instead of strlen()
1734
+        // because isset() is about 5x-40x faster.
1735
+        if (isset($path[$maxLen])) {
1736
+            $pathLen = strlen($path);
1737
+            throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path");
1738
+        }
1739
+    }
1740
+
1741
+    /**
1742
+     * check if it is allowed to move a mount point to a given target.
1743
+     * It is not allowed to move a mount point into a different mount point or
1744
+     * into an already shared folder
1745
+     *
1746
+     * @param string $target path
1747
+     * @return boolean
1748
+     */
1749
+    private function isTargetAllowed($target) {
1750
+
1751
+        list($targetStorage, $targetInternalPath) = \OC\Files\Filesystem::resolvePath($target);
1752
+        if (!$targetStorage->instanceOfStorage('\OCP\Files\IHomeStorage')) {
1753
+            \OCP\Util::writeLog('files',
1754
+                'It is not allowed to move one mount point into another one',
1755
+                \OCP\Util::DEBUG);
1756
+            return false;
1757
+        }
1758
+
1759
+        // note: cannot use the view because the target is already locked
1760
+        $fileId = (int)$targetStorage->getCache()->getId($targetInternalPath);
1761
+        if ($fileId === -1) {
1762
+            // target might not exist, need to check parent instead
1763
+            $fileId = (int)$targetStorage->getCache()->getId(dirname($targetInternalPath));
1764
+        }
1765
+
1766
+        // check if any of the parents were shared by the current owner (include collections)
1767
+        $shares = \OCP\Share::getItemShared(
1768
+            'folder',
1769
+            $fileId,
1770
+            \OCP\Share::FORMAT_NONE,
1771
+            null,
1772
+            true
1773
+        );
1774
+
1775
+        if (count($shares) > 0) {
1776
+            \OCP\Util::writeLog('files',
1777
+                'It is not allowed to move one mount point into a shared folder',
1778
+                \OCP\Util::DEBUG);
1779
+            return false;
1780
+        }
1781
+
1782
+        return true;
1783
+    }
1784
+
1785
+    /**
1786
+     * Get a fileinfo object for files that are ignored in the cache (part files)
1787
+     *
1788
+     * @param string $path
1789
+     * @return \OCP\Files\FileInfo
1790
+     */
1791
+    private function getPartFileInfo($path) {
1792
+        $mount = $this->getMount($path);
1793
+        $storage = $mount->getStorage();
1794
+        $internalPath = $mount->getInternalPath($this->getAbsolutePath($path));
1795
+        $owner = \OC::$server->getUserManager()->get($storage->getOwner($internalPath));
1796
+        return new FileInfo(
1797
+            $this->getAbsolutePath($path),
1798
+            $storage,
1799
+            $internalPath,
1800
+            [
1801
+                'fileid' => null,
1802
+                'mimetype' => $storage->getMimeType($internalPath),
1803
+                'name' => basename($path),
1804
+                'etag' => null,
1805
+                'size' => $storage->filesize($internalPath),
1806
+                'mtime' => $storage->filemtime($internalPath),
1807
+                'encrypted' => false,
1808
+                'permissions' => \OCP\Constants::PERMISSION_ALL
1809
+            ],
1810
+            $mount,
1811
+            $owner
1812
+        );
1813
+    }
1814
+
1815
+    /**
1816
+     * @param string $path
1817
+     * @param string $fileName
1818
+     * @throws InvalidPathException
1819
+     */
1820
+    public function verifyPath($path, $fileName) {
1821
+        try {
1822
+            /** @type \OCP\Files\Storage $storage */
1823
+            list($storage, $internalPath) = $this->resolvePath($path);
1824
+            $storage->verifyPath($internalPath, $fileName);
1825
+        } catch (ReservedWordException $ex) {
1826
+            $l = \OC::$server->getL10N('lib');
1827
+            throw new InvalidPathException($l->t('File name is a reserved word'));
1828
+        } catch (InvalidCharacterInPathException $ex) {
1829
+            $l = \OC::$server->getL10N('lib');
1830
+            throw new InvalidPathException($l->t('File name contains at least one invalid character'));
1831
+        } catch (FileNameTooLongException $ex) {
1832
+            $l = \OC::$server->getL10N('lib');
1833
+            throw new InvalidPathException($l->t('File name is too long'));
1834
+        } catch (InvalidDirectoryException $ex) {
1835
+            $l = \OC::$server->getL10N('lib');
1836
+            throw new InvalidPathException($l->t('Dot files are not allowed'));
1837
+        } catch (EmptyFileNameException $ex) {
1838
+            $l = \OC::$server->getL10N('lib');
1839
+            throw new InvalidPathException($l->t('Empty filename is not allowed'));
1840
+        }
1841
+    }
1842
+
1843
+    /**
1844
+     * get all parent folders of $path
1845
+     *
1846
+     * @param string $path
1847
+     * @return string[]
1848
+     */
1849
+    private function getParents($path) {
1850
+        $path = trim($path, '/');
1851
+        if (!$path) {
1852
+            return [];
1853
+        }
1854
+
1855
+        $parts = explode('/', $path);
1856
+
1857
+        // remove the single file
1858
+        array_pop($parts);
1859
+        $result = array('/');
1860
+        $resultPath = '';
1861
+        foreach ($parts as $part) {
1862
+            if ($part) {
1863
+                $resultPath .= '/' . $part;
1864
+                $result[] = $resultPath;
1865
+            }
1866
+        }
1867
+        return $result;
1868
+    }
1869
+
1870
+    /**
1871
+     * Returns the mount point for which to lock
1872
+     *
1873
+     * @param string $absolutePath absolute path
1874
+     * @param bool $useParentMount true to return parent mount instead of whatever
1875
+     * is mounted directly on the given path, false otherwise
1876
+     * @return \OC\Files\Mount\MountPoint mount point for which to apply locks
1877
+     */
1878
+    private function getMountForLock($absolutePath, $useParentMount = false) {
1879
+        $results = [];
1880
+        $mount = Filesystem::getMountManager()->find($absolutePath);
1881
+        if (!$mount) {
1882
+            return $results;
1883
+        }
1884
+
1885
+        if ($useParentMount) {
1886
+            // find out if something is mounted directly on the path
1887
+            $internalPath = $mount->getInternalPath($absolutePath);
1888
+            if ($internalPath === '') {
1889
+                // resolve the parent mount instead
1890
+                $mount = Filesystem::getMountManager()->find(dirname($absolutePath));
1891
+            }
1892
+        }
1893
+
1894
+        return $mount;
1895
+    }
1896
+
1897
+    /**
1898
+     * Lock the given path
1899
+     *
1900
+     * @param string $path the path of the file to lock, relative to the view
1901
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1902
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1903
+     *
1904
+     * @return bool False if the path is excluded from locking, true otherwise
1905
+     * @throws \OCP\Lock\LockedException if the path is already locked
1906
+     */
1907
+    private function lockPath($path, $type, $lockMountPoint = false) {
1908
+        $absolutePath = $this->getAbsolutePath($path);
1909
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1910
+        if (!$this->shouldLockFile($absolutePath)) {
1911
+            return false;
1912
+        }
1913
+
1914
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1915
+        if ($mount) {
1916
+            try {
1917
+                $storage = $mount->getStorage();
1918
+                if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1919
+                    $storage->acquireLock(
1920
+                        $mount->getInternalPath($absolutePath),
1921
+                        $type,
1922
+                        $this->lockingProvider
1923
+                    );
1924
+                }
1925
+            } catch (\OCP\Lock\LockedException $e) {
1926
+                // rethrow with the a human-readable path
1927
+                throw new \OCP\Lock\LockedException(
1928
+                    $this->getPathRelativeToFiles($absolutePath),
1929
+                    $e
1930
+                );
1931
+            }
1932
+        }
1933
+
1934
+        return true;
1935
+    }
1936
+
1937
+    /**
1938
+     * Change the lock type
1939
+     *
1940
+     * @param string $path the path of the file to lock, relative to the view
1941
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1942
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1943
+     *
1944
+     * @return bool False if the path is excluded from locking, true otherwise
1945
+     * @throws \OCP\Lock\LockedException if the path is already locked
1946
+     */
1947
+    public function changeLock($path, $type, $lockMountPoint = false) {
1948
+        $path = Filesystem::normalizePath($path);
1949
+        $absolutePath = $this->getAbsolutePath($path);
1950
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1951
+        if (!$this->shouldLockFile($absolutePath)) {
1952
+            return false;
1953
+        }
1954
+
1955
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
1956
+        if ($mount) {
1957
+            try {
1958
+                $storage = $mount->getStorage();
1959
+                if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
1960
+                    $storage->changeLock(
1961
+                        $mount->getInternalPath($absolutePath),
1962
+                        $type,
1963
+                        $this->lockingProvider
1964
+                    );
1965
+                }
1966
+            } catch (\OCP\Lock\LockedException $e) {
1967
+                try {
1968
+                    // rethrow with the a human-readable path
1969
+                    throw new \OCP\Lock\LockedException(
1970
+                        $this->getPathRelativeToFiles($absolutePath),
1971
+                        $e
1972
+                    );
1973
+                } catch (\InvalidArgumentException $e) {
1974
+                    throw new \OCP\Lock\LockedException(
1975
+                        $absolutePath,
1976
+                        $e
1977
+                    );
1978
+                }
1979
+            }
1980
+        }
1981
+
1982
+        return true;
1983
+    }
1984
+
1985
+    /**
1986
+     * Unlock the given path
1987
+     *
1988
+     * @param string $path the path of the file to unlock, relative to the view
1989
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
1990
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
1991
+     *
1992
+     * @return bool False if the path is excluded from locking, true otherwise
1993
+     */
1994
+    private function unlockPath($path, $type, $lockMountPoint = false) {
1995
+        $absolutePath = $this->getAbsolutePath($path);
1996
+        $absolutePath = Filesystem::normalizePath($absolutePath);
1997
+        if (!$this->shouldLockFile($absolutePath)) {
1998
+            return false;
1999
+        }
2000
+
2001
+        $mount = $this->getMountForLock($absolutePath, $lockMountPoint);
2002
+        if ($mount) {
2003
+            $storage = $mount->getStorage();
2004
+            if ($storage && $storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) {
2005
+                $storage->releaseLock(
2006
+                    $mount->getInternalPath($absolutePath),
2007
+                    $type,
2008
+                    $this->lockingProvider
2009
+                );
2010
+            }
2011
+        }
2012
+
2013
+        return true;
2014
+    }
2015
+
2016
+    /**
2017
+     * Lock a path and all its parents up to the root of the view
2018
+     *
2019
+     * @param string $path the path of the file to lock relative to the view
2020
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2021
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2022
+     *
2023
+     * @return bool False if the path is excluded from locking, true otherwise
2024
+     */
2025
+    public function lockFile($path, $type, $lockMountPoint = false) {
2026
+        $absolutePath = $this->getAbsolutePath($path);
2027
+        $absolutePath = Filesystem::normalizePath($absolutePath);
2028
+        if (!$this->shouldLockFile($absolutePath)) {
2029
+            return false;
2030
+        }
2031
+
2032
+        $this->lockPath($path, $type, $lockMountPoint);
2033
+
2034
+        $parents = $this->getParents($path);
2035
+        foreach ($parents as $parent) {
2036
+            $this->lockPath($parent, ILockingProvider::LOCK_SHARED);
2037
+        }
2038
+
2039
+        return true;
2040
+    }
2041
+
2042
+    /**
2043
+     * Unlock a path and all its parents up to the root of the view
2044
+     *
2045
+     * @param string $path the path of the file to lock relative to the view
2046
+     * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE
2047
+     * @param bool $lockMountPoint true to lock the mount point, false to lock the attached mount/storage
2048
+     *
2049
+     * @return bool False if the path is excluded from locking, true otherwise
2050
+     */
2051
+    public function unlockFile($path, $type, $lockMountPoint = false) {
2052
+        $absolutePath = $this->getAbsolutePath($path);
2053
+        $absolutePath = Filesystem::normalizePath($absolutePath);
2054
+        if (!$this->shouldLockFile($absolutePath)) {
2055
+            return false;
2056
+        }
2057
+
2058
+        $this->unlockPath($path, $type, $lockMountPoint);
2059
+
2060
+        $parents = $this->getParents($path);
2061
+        foreach ($parents as $parent) {
2062
+            $this->unlockPath($parent, ILockingProvider::LOCK_SHARED);
2063
+        }
2064
+
2065
+        return true;
2066
+    }
2067
+
2068
+    /**
2069
+     * Only lock files in data/user/files/
2070
+     *
2071
+     * @param string $path Absolute path to the file/folder we try to (un)lock
2072
+     * @return bool
2073
+     */
2074
+    protected function shouldLockFile($path) {
2075
+        $path = Filesystem::normalizePath($path);
2076
+
2077
+        $pathSegments = explode('/', $path);
2078
+        if (isset($pathSegments[2])) {
2079
+            // E.g.: /username/files/path-to-file
2080
+            return ($pathSegments[2] === 'files') && (count($pathSegments) > 3);
2081
+        }
2082
+
2083
+        return strpos($path, '/appdata_') !== 0;
2084
+    }
2085
+
2086
+    /**
2087
+     * Shortens the given absolute path to be relative to
2088
+     * "$user/files".
2089
+     *
2090
+     * @param string $absolutePath absolute path which is under "files"
2091
+     *
2092
+     * @return string path relative to "files" with trimmed slashes or null
2093
+     * if the path was NOT relative to files
2094
+     *
2095
+     * @throws \InvalidArgumentException if the given path was not under "files"
2096
+     * @since 8.1.0
2097
+     */
2098
+    public function getPathRelativeToFiles($absolutePath) {
2099
+        $path = Filesystem::normalizePath($absolutePath);
2100
+        $parts = explode('/', trim($path, '/'), 3);
2101
+        // "$user", "files", "path/to/dir"
2102
+        if (!isset($parts[1]) || $parts[1] !== 'files') {
2103
+            $this->logger->error(
2104
+                '$absolutePath must be relative to "files", value is "%s"',
2105
+                [
2106
+                    $absolutePath
2107
+                ]
2108
+            );
2109
+            throw new \InvalidArgumentException('$absolutePath must be relative to "files"');
2110
+        }
2111
+        if (isset($parts[2])) {
2112
+            return $parts[2];
2113
+        }
2114
+        return '';
2115
+    }
2116
+
2117
+    /**
2118
+     * @param string $filename
2119
+     * @return array
2120
+     * @throws \OC\User\NoUserException
2121
+     * @throws NotFoundException
2122
+     */
2123
+    public function getUidAndFilename($filename) {
2124
+        $info = $this->getFileInfo($filename);
2125
+        if (!$info instanceof \OCP\Files\FileInfo) {
2126
+            throw new NotFoundException($this->getAbsolutePath($filename) . ' not found');
2127
+        }
2128
+        $uid = $info->getOwner()->getUID();
2129
+        if ($uid != \OCP\User::getUser()) {
2130
+            Filesystem::initMountPoints($uid);
2131
+            $ownerView = new View('/' . $uid . '/files');
2132
+            try {
2133
+                $filename = $ownerView->getPath($info['fileid']);
2134
+            } catch (NotFoundException $e) {
2135
+                throw new NotFoundException('File with id ' . $info['fileid'] . ' not found for user ' . $uid);
2136
+            }
2137
+        }
2138
+        return [$uid, $filename];
2139
+    }
2140
+
2141
+    /**
2142
+     * Creates parent non-existing folders
2143
+     *
2144
+     * @param string $filePath
2145
+     * @return bool
2146
+     */
2147
+    private function createParentDirectories($filePath) {
2148
+        $directoryParts = explode('/', $filePath);
2149
+        $directoryParts = array_filter($directoryParts);
2150
+        foreach ($directoryParts as $key => $part) {
2151
+            $currentPathElements = array_slice($directoryParts, 0, $key);
2152
+            $currentPath = '/' . implode('/', $currentPathElements);
2153
+            if ($this->is_file($currentPath)) {
2154
+                return false;
2155
+            }
2156
+            if (!$this->file_exists($currentPath)) {
2157
+                $this->mkdir($currentPath);
2158
+            }
2159
+        }
2160
+
2161
+        return true;
2162
+    }
2163 2163
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Helper.php 3 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -303,6 +303,7 @@
 block discarded – undo
303 303
 	 * get default share folder
304 304
 	 *
305 305
 	 * @param \OC\Files\View
306
+	 * @param View $view
306 307
 	 * @return string
307 308
 	 */
308 309
 	public static function getShareFolder($view = null) {
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
 
88 88
 		$basePath = $path;
89 89
 
90
-		if ($relativePath !== null && Filesystem::isReadable($basePath . $relativePath)) {
90
+		if ($relativePath !== null && Filesystem::isReadable($basePath.$relativePath)) {
91 91
 			$path .= Filesystem::normalizePath($relativePath);
92 92
 		}
93 93
 
@@ -112,14 +112,14 @@  discard block
 block discarded – undo
112 112
 		if ($password !== null) {
113 113
 			if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
114 114
 				if ($shareManager->checkPassword($share, $password)) {
115
-					\OC::$server->getSession()->set('public_link_authenticated', (string)$share->getId());
115
+					\OC::$server->getSession()->set('public_link_authenticated', (string) $share->getId());
116 116
 					return true;
117 117
 				}
118 118
 			}
119 119
 		} else {
120 120
 			// not authenticated ?
121 121
 			if (\OC::$server->getSession()->exists('public_link_authenticated')
122
-				&& \OC::$server->getSession()->get('public_link_authenticated') !== (string)$share->getId()) {
122
+				&& \OC::$server->getSession()->get('public_link_authenticated') !== (string) $share->getId()) {
123 123
 				return true;
124 124
 			}
125 125
 		}
@@ -132,7 +132,7 @@  discard block
 block discarded – undo
132 132
 		Filesystem::initMountPoints($owner);
133 133
 		$info = Filesystem::getFileInfo($target);
134 134
 		$ownerView = new View('/'.$owner.'/files');
135
-		if ( $owner !== User::getUser() ) {
135
+		if ($owner !== User::getUser()) {
136 136
 			$path = $ownerView->getPath($info['fileid']);
137 137
 		} else {
138 138
 			$path = $target;
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
 			if ($info instanceof \OC\Files\FileInfo) {
146 146
 				$ids[] = $info['fileid'];
147 147
 			} else {
148
-				\OCP\Util::writeLog('sharing', 'No fileinfo available for: ' . $path, \OCP\Util::WARN);
148
+				\OCP\Util::writeLog('sharing', 'No fileinfo available for: '.$path, \OCP\Util::WARN);
149 149
 			}
150 150
 			$path = dirname($path);
151 151
 		}
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 			$idList = array_chunk($ids, 99, true);
156 156
 
157 157
 			foreach ($idList as $subList) {
158
-				$statement = "SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN (" . implode(',', $subList) . ") AND `share_type` IN (0, 1, 2)";
158
+				$statement = "SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN (".implode(',', $subList).") AND `share_type` IN (0, 1, 2)";
159 159
 				$query = \OCP\DB::prepare($statement);
160 160
 				$r = $query->execute();
161 161
 				$result = array_merge($result, $r->fetchAll());
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
 			$uid = User::getUser();
184 184
 		}
185 185
 		Filesystem::initMountPoints($uid);
186
-		if ( $uid !== User::getUser() ) {
186
+		if ($uid !== User::getUser()) {
187 187
 			$info = Filesystem::getFileInfo($filename);
188 188
 			$ownerView = new View('/'.$uid.'/files');
189 189
 			try {
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
 		$dir = $pathinfo['dirname'];
231 231
 		$i = 2;
232 232
 		while ($view->file_exists($path) || in_array($path, $excludeList)) {
233
-			$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
233
+			$path = Filesystem::normalizePath($dir.'/'.$name.' ('.$i.')'.$ext);
234 234
 			$i++;
235 235
 		}
236 236
 
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
 			$dir = '';
255 255
 			$subdirs = explode('/', $shareFolder);
256 256
 			foreach ($subdirs as $subdir) {
257
-				$dir = $dir . '/' . $subdir;
257
+				$dir = $dir.'/'.$subdir;
258 258
 				if (!$view->is_dir($dir)) {
259 259
 					$view->mkdir($dir);
260 260
 				}
Please login to merge, or discard this patch.
Indentation   +237 added lines, -237 removed lines patch added patch discarded remove patch
@@ -36,242 +36,242 @@
 block discarded – undo
36 36
 
37 37
 class Helper {
38 38
 
39
-	public static function registerHooks() {
40
-		\OCP\Util::connectHook('OC_Filesystem', 'post_rename', '\OCA\Files_Sharing\Updater', 'renameHook');
41
-		\OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren');
42
-
43
-		\OCP\Util::connectHook('OC_User', 'post_deleteUser', '\OCA\Files_Sharing\Hooks', 'deleteUser');
44
-	}
45
-
46
-	/**
47
-	 * Sets up the filesystem and user for public sharing
48
-	 * @param string $token string share token
49
-	 * @param string $relativePath optional path relative to the share
50
-	 * @param string $password optional password
51
-	 * @return array
52
-	 */
53
-	public static function setupFromToken($token, $relativePath = null, $password = null) {
54
-		\OC_User::setIncognitoMode(true);
55
-
56
-		$shareManager = \OC::$server->getShareManager();
57
-
58
-		try {
59
-			$share = $shareManager->getShareByToken($token);
60
-		} catch (ShareNotFound $e) {
61
-			\OC_Response::setStatus(404);
62
-			\OCP\Util::writeLog('core-preview', 'Passed token parameter is not valid', \OCP\Util::DEBUG);
63
-			exit;
64
-		}
65
-
66
-		\OCP\JSON::checkUserExists($share->getShareOwner());
67
-		\OC_Util::tearDownFS();
68
-		\OC_Util::setupFS($share->getShareOwner());
69
-
70
-
71
-		try {
72
-			$path = Filesystem::getPath($share->getNodeId());
73
-		} catch (NotFoundException $e) {
74
-			\OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
75
-			\OC_Response::setStatus(404);
76
-			\OCP\JSON::error(array('success' => false));
77
-			exit();
78
-		}
79
-
80
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK && $share->getPassword() !== null) {
81
-			if (!self::authenticate($share, $password)) {
82
-				\OC_Response::setStatus(403);
83
-				\OCP\JSON::error(array('success' => false));
84
-				exit();
85
-			}
86
-		}
87
-
88
-		$basePath = $path;
89
-
90
-		if ($relativePath !== null && Filesystem::isReadable($basePath . $relativePath)) {
91
-			$path .= Filesystem::normalizePath($relativePath);
92
-		}
93
-
94
-		return array(
95
-			'share' => $share,
96
-			'basePath' => $basePath,
97
-			'realPath' => $path
98
-		);
99
-	}
100
-
101
-	/**
102
-	 * Authenticate link item with the given password
103
-	 * or with the session if no password was given.
104
-	 * @param \OCP\Share\IShare $share
105
-	 * @param string $password optional password
106
-	 *
107
-	 * @return boolean true if authorized, false otherwise
108
-	 */
109
-	public static function authenticate($share, $password = null) {
110
-		$shareManager = \OC::$server->getShareManager();
111
-
112
-		if ($password !== null) {
113
-			if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
114
-				if ($shareManager->checkPassword($share, $password)) {
115
-					\OC::$server->getSession()->set('public_link_authenticated', (string)$share->getId());
116
-					return true;
117
-				}
118
-			}
119
-		} else {
120
-			// not authenticated ?
121
-			if (\OC::$server->getSession()->exists('public_link_authenticated')
122
-				&& \OC::$server->getSession()->get('public_link_authenticated') !== (string)$share->getId()) {
123
-				return true;
124
-			}
125
-		}
126
-		return false;
127
-	}
128
-
129
-	public static function getSharesFromItem($target) {
130
-		$result = array();
131
-		$owner = Filesystem::getOwner($target);
132
-		Filesystem::initMountPoints($owner);
133
-		$info = Filesystem::getFileInfo($target);
134
-		$ownerView = new View('/'.$owner.'/files');
135
-		if ( $owner !== User::getUser() ) {
136
-			$path = $ownerView->getPath($info['fileid']);
137
-		} else {
138
-			$path = $target;
139
-		}
140
-
141
-
142
-		$ids = array();
143
-		while ($path !== dirname($path)) {
144
-			$info = $ownerView->getFileInfo($path);
145
-			if ($info instanceof \OC\Files\FileInfo) {
146
-				$ids[] = $info['fileid'];
147
-			} else {
148
-				\OCP\Util::writeLog('sharing', 'No fileinfo available for: ' . $path, \OCP\Util::WARN);
149
-			}
150
-			$path = dirname($path);
151
-		}
152
-
153
-		if (!empty($ids)) {
154
-
155
-			$idList = array_chunk($ids, 99, true);
156
-
157
-			foreach ($idList as $subList) {
158
-				$statement = "SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN (" . implode(',', $subList) . ") AND `share_type` IN (0, 1, 2)";
159
-				$query = \OCP\DB::prepare($statement);
160
-				$r = $query->execute();
161
-				$result = array_merge($result, $r->fetchAll());
162
-			}
163
-		}
164
-
165
-		return $result;
166
-	}
167
-
168
-	/**
169
-	 * get the UID of the owner of the file and the path to the file relative to
170
-	 * owners files folder
171
-	 *
172
-	 * @param $filename
173
-	 * @return array
174
-	 * @throws \OC\User\NoUserException
175
-	 */
176
-	public static function getUidAndFilename($filename) {
177
-		$uid = Filesystem::getOwner($filename);
178
-		$userManager = \OC::$server->getUserManager();
179
-		// if the user with the UID doesn't exists, e.g. because the UID points
180
-		// to a remote user with a federated cloud ID we use the current logged-in
181
-		// user. We need a valid local user to create the share
182
-		if (!$userManager->userExists($uid)) {
183
-			$uid = User::getUser();
184
-		}
185
-		Filesystem::initMountPoints($uid);
186
-		if ( $uid !== User::getUser() ) {
187
-			$info = Filesystem::getFileInfo($filename);
188
-			$ownerView = new View('/'.$uid.'/files');
189
-			try {
190
-				$filename = $ownerView->getPath($info['fileid']);
191
-			} catch (NotFoundException $e) {
192
-				$filename = null;
193
-			}
194
-		}
195
-		return [$uid, $filename];
196
-	}
197
-
198
-	/**
199
-	 * Format a path to be relative to the /user/files/ directory
200
-	 * @param string $path the absolute path
201
-	 * @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
202
-	 */
203
-	public static function stripUserFilesPath($path) {
204
-		$trimmed = ltrim($path, '/');
205
-		$split = explode('/', $trimmed);
206
-
207
-		// it is not a file relative to data/user/files
208
-		if (count($split) < 3 || $split[1] !== 'files') {
209
-			return false;
210
-		}
211
-
212
-		$sliced = array_slice($split, 2);
213
-		$relPath = implode('/', $sliced);
214
-
215
-		return $relPath;
216
-	}
217
-
218
-	/**
219
-	 * check if file name already exists and generate unique target
220
-	 *
221
-	 * @param string $path
222
-	 * @param array $excludeList
223
-	 * @param View $view
224
-	 * @return string $path
225
-	 */
226
-	public static function generateUniqueTarget($path, $excludeList, $view) {
227
-		$pathinfo = pathinfo($path);
228
-		$ext = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
229
-		$name = $pathinfo['filename'];
230
-		$dir = $pathinfo['dirname'];
231
-		$i = 2;
232
-		while ($view->file_exists($path) || in_array($path, $excludeList)) {
233
-			$path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
234
-			$i++;
235
-		}
236
-
237
-		return $path;
238
-	}
239
-
240
-	/**
241
-	 * get default share folder
242
-	 *
243
-	 * @param \OC\Files\View
244
-	 * @return string
245
-	 */
246
-	public static function getShareFolder($view = null) {
247
-		if ($view === null) {
248
-			$view = Filesystem::getView();
249
-		}
250
-		$shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
251
-		$shareFolder = Filesystem::normalizePath($shareFolder);
252
-
253
-		if (!$view->file_exists($shareFolder)) {
254
-			$dir = '';
255
-			$subdirs = explode('/', $shareFolder);
256
-			foreach ($subdirs as $subdir) {
257
-				$dir = $dir . '/' . $subdir;
258
-				if (!$view->is_dir($dir)) {
259
-					$view->mkdir($dir);
260
-				}
261
-			}
262
-		}
263
-
264
-		return $shareFolder;
265
-
266
-	}
267
-
268
-	/**
269
-	 * set default share folder
270
-	 *
271
-	 * @param string $shareFolder
272
-	 */
273
-	public static function setShareFolder($shareFolder) {
274
-		\OC::$server->getConfig()->setSystemValue('share_folder', $shareFolder);
275
-	}
39
+    public static function registerHooks() {
40
+        \OCP\Util::connectHook('OC_Filesystem', 'post_rename', '\OCA\Files_Sharing\Updater', 'renameHook');
41
+        \OCP\Util::connectHook('OC_Filesystem', 'post_delete', '\OCA\Files_Sharing\Hooks', 'unshareChildren');
42
+
43
+        \OCP\Util::connectHook('OC_User', 'post_deleteUser', '\OCA\Files_Sharing\Hooks', 'deleteUser');
44
+    }
45
+
46
+    /**
47
+     * Sets up the filesystem and user for public sharing
48
+     * @param string $token string share token
49
+     * @param string $relativePath optional path relative to the share
50
+     * @param string $password optional password
51
+     * @return array
52
+     */
53
+    public static function setupFromToken($token, $relativePath = null, $password = null) {
54
+        \OC_User::setIncognitoMode(true);
55
+
56
+        $shareManager = \OC::$server->getShareManager();
57
+
58
+        try {
59
+            $share = $shareManager->getShareByToken($token);
60
+        } catch (ShareNotFound $e) {
61
+            \OC_Response::setStatus(404);
62
+            \OCP\Util::writeLog('core-preview', 'Passed token parameter is not valid', \OCP\Util::DEBUG);
63
+            exit;
64
+        }
65
+
66
+        \OCP\JSON::checkUserExists($share->getShareOwner());
67
+        \OC_Util::tearDownFS();
68
+        \OC_Util::setupFS($share->getShareOwner());
69
+
70
+
71
+        try {
72
+            $path = Filesystem::getPath($share->getNodeId());
73
+        } catch (NotFoundException $e) {
74
+            \OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
75
+            \OC_Response::setStatus(404);
76
+            \OCP\JSON::error(array('success' => false));
77
+            exit();
78
+        }
79
+
80
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK && $share->getPassword() !== null) {
81
+            if (!self::authenticate($share, $password)) {
82
+                \OC_Response::setStatus(403);
83
+                \OCP\JSON::error(array('success' => false));
84
+                exit();
85
+            }
86
+        }
87
+
88
+        $basePath = $path;
89
+
90
+        if ($relativePath !== null && Filesystem::isReadable($basePath . $relativePath)) {
91
+            $path .= Filesystem::normalizePath($relativePath);
92
+        }
93
+
94
+        return array(
95
+            'share' => $share,
96
+            'basePath' => $basePath,
97
+            'realPath' => $path
98
+        );
99
+    }
100
+
101
+    /**
102
+     * Authenticate link item with the given password
103
+     * or with the session if no password was given.
104
+     * @param \OCP\Share\IShare $share
105
+     * @param string $password optional password
106
+     *
107
+     * @return boolean true if authorized, false otherwise
108
+     */
109
+    public static function authenticate($share, $password = null) {
110
+        $shareManager = \OC::$server->getShareManager();
111
+
112
+        if ($password !== null) {
113
+            if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
114
+                if ($shareManager->checkPassword($share, $password)) {
115
+                    \OC::$server->getSession()->set('public_link_authenticated', (string)$share->getId());
116
+                    return true;
117
+                }
118
+            }
119
+        } else {
120
+            // not authenticated ?
121
+            if (\OC::$server->getSession()->exists('public_link_authenticated')
122
+                && \OC::$server->getSession()->get('public_link_authenticated') !== (string)$share->getId()) {
123
+                return true;
124
+            }
125
+        }
126
+        return false;
127
+    }
128
+
129
+    public static function getSharesFromItem($target) {
130
+        $result = array();
131
+        $owner = Filesystem::getOwner($target);
132
+        Filesystem::initMountPoints($owner);
133
+        $info = Filesystem::getFileInfo($target);
134
+        $ownerView = new View('/'.$owner.'/files');
135
+        if ( $owner !== User::getUser() ) {
136
+            $path = $ownerView->getPath($info['fileid']);
137
+        } else {
138
+            $path = $target;
139
+        }
140
+
141
+
142
+        $ids = array();
143
+        while ($path !== dirname($path)) {
144
+            $info = $ownerView->getFileInfo($path);
145
+            if ($info instanceof \OC\Files\FileInfo) {
146
+                $ids[] = $info['fileid'];
147
+            } else {
148
+                \OCP\Util::writeLog('sharing', 'No fileinfo available for: ' . $path, \OCP\Util::WARN);
149
+            }
150
+            $path = dirname($path);
151
+        }
152
+
153
+        if (!empty($ids)) {
154
+
155
+            $idList = array_chunk($ids, 99, true);
156
+
157
+            foreach ($idList as $subList) {
158
+                $statement = "SELECT `share_with`, `share_type`, `file_target` FROM `*PREFIX*share` WHERE `file_source` IN (" . implode(',', $subList) . ") AND `share_type` IN (0, 1, 2)";
159
+                $query = \OCP\DB::prepare($statement);
160
+                $r = $query->execute();
161
+                $result = array_merge($result, $r->fetchAll());
162
+            }
163
+        }
164
+
165
+        return $result;
166
+    }
167
+
168
+    /**
169
+     * get the UID of the owner of the file and the path to the file relative to
170
+     * owners files folder
171
+     *
172
+     * @param $filename
173
+     * @return array
174
+     * @throws \OC\User\NoUserException
175
+     */
176
+    public static function getUidAndFilename($filename) {
177
+        $uid = Filesystem::getOwner($filename);
178
+        $userManager = \OC::$server->getUserManager();
179
+        // if the user with the UID doesn't exists, e.g. because the UID points
180
+        // to a remote user with a federated cloud ID we use the current logged-in
181
+        // user. We need a valid local user to create the share
182
+        if (!$userManager->userExists($uid)) {
183
+            $uid = User::getUser();
184
+        }
185
+        Filesystem::initMountPoints($uid);
186
+        if ( $uid !== User::getUser() ) {
187
+            $info = Filesystem::getFileInfo($filename);
188
+            $ownerView = new View('/'.$uid.'/files');
189
+            try {
190
+                $filename = $ownerView->getPath($info['fileid']);
191
+            } catch (NotFoundException $e) {
192
+                $filename = null;
193
+            }
194
+        }
195
+        return [$uid, $filename];
196
+    }
197
+
198
+    /**
199
+     * Format a path to be relative to the /user/files/ directory
200
+     * @param string $path the absolute path
201
+     * @return string e.g. turns '/admin/files/test.txt' into 'test.txt'
202
+     */
203
+    public static function stripUserFilesPath($path) {
204
+        $trimmed = ltrim($path, '/');
205
+        $split = explode('/', $trimmed);
206
+
207
+        // it is not a file relative to data/user/files
208
+        if (count($split) < 3 || $split[1] !== 'files') {
209
+            return false;
210
+        }
211
+
212
+        $sliced = array_slice($split, 2);
213
+        $relPath = implode('/', $sliced);
214
+
215
+        return $relPath;
216
+    }
217
+
218
+    /**
219
+     * check if file name already exists and generate unique target
220
+     *
221
+     * @param string $path
222
+     * @param array $excludeList
223
+     * @param View $view
224
+     * @return string $path
225
+     */
226
+    public static function generateUniqueTarget($path, $excludeList, $view) {
227
+        $pathinfo = pathinfo($path);
228
+        $ext = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
229
+        $name = $pathinfo['filename'];
230
+        $dir = $pathinfo['dirname'];
231
+        $i = 2;
232
+        while ($view->file_exists($path) || in_array($path, $excludeList)) {
233
+            $path = Filesystem::normalizePath($dir . '/' . $name . ' ('.$i.')' . $ext);
234
+            $i++;
235
+        }
236
+
237
+        return $path;
238
+    }
239
+
240
+    /**
241
+     * get default share folder
242
+     *
243
+     * @param \OC\Files\View
244
+     * @return string
245
+     */
246
+    public static function getShareFolder($view = null) {
247
+        if ($view === null) {
248
+            $view = Filesystem::getView();
249
+        }
250
+        $shareFolder = \OC::$server->getConfig()->getSystemValue('share_folder', '/');
251
+        $shareFolder = Filesystem::normalizePath($shareFolder);
252
+
253
+        if (!$view->file_exists($shareFolder)) {
254
+            $dir = '';
255
+            $subdirs = explode('/', $shareFolder);
256
+            foreach ($subdirs as $subdir) {
257
+                $dir = $dir . '/' . $subdir;
258
+                if (!$view->is_dir($dir)) {
259
+                    $view->mkdir($dir);
260
+                }
261
+            }
262
+        }
263
+
264
+        return $shareFolder;
265
+
266
+    }
267
+
268
+    /**
269
+     * set default share folder
270
+     *
271
+     * @param string $shareFolder
272
+     */
273
+    public static function setShareFolder($shareFolder) {
274
+        \OC::$server->getConfig()->setSystemValue('share_folder', $shareFolder);
275
+    }
276 276
 
277 277
 }
Please login to merge, or discard this patch.
apps/dav/lib/SystemTag/SystemTagsObjectMappingCollection.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -89,6 +89,9 @@
 block discarded – undo
89 89
 		$this->user = $user;
90 90
 	}
91 91
 
92
+	/**
93
+	 * @param string $tagId
94
+	 */
92 95
 	function createFile($tagId, $data = null) {
93 96
 		try {
94 97
 			$tags = $this->tagManager->getTagsByIds([$tagId]);
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -95,15 +95,15 @@  discard block
 block discarded – undo
95 95
 			$tags = $this->tagManager->getTagsByIds([$tagId]);
96 96
 			$tag = current($tags);
97 97
 			if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
98
-				throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
98
+				throw new PreconditionFailed('Tag with id '.$tagId.' does not exist, cannot assign');
99 99
 			}
100 100
 			if (!$this->tagManager->canUserAssignTag($tag, $this->user)) {
101
-				throw new Forbidden('No permission to assign tag ' . $tagId);
101
+				throw new Forbidden('No permission to assign tag '.$tagId);
102 102
 			}
103 103
 
104 104
 			$this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
105 105
 		} catch (TagNotFoundException $e) {
106
-			throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
106
+			throw new PreconditionFailed('Tag with id '.$tagId.' does not exist, cannot assign');
107 107
 		}
108 108
 	}
109 109
 
@@ -120,11 +120,11 @@  discard block
 block discarded – undo
120 120
 					return $this->makeNode($tag);
121 121
 				}
122 122
 			}
123
-			throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId);
123
+			throw new NotFound('Tag with id '.$tagId.' not present for object '.$this->objectId);
124 124
 		} catch (\InvalidArgumentException $e) {
125 125
 			throw new BadRequest('Invalid tag id', 0, $e);
126 126
 		} catch (TagNotFoundException $e) {
127
-			throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e);
127
+			throw new NotFound('Tag with id '.$tagId.' not found', 0, $e);
128 128
 		}
129 129
 	}
130 130
 
Please login to merge, or discard this patch.
Indentation   +165 added lines, -165 removed lines patch added patch discarded remove patch
@@ -39,169 +39,169 @@
 block discarded – undo
39 39
  */
40 40
 class SystemTagsObjectMappingCollection implements ICollection {
41 41
 
42
-	/**
43
-	 * @var string
44
-	 */
45
-	private $objectId;
46
-
47
-	/**
48
-	 * @var string
49
-	 */
50
-	private $objectType;
51
-
52
-	/**
53
-	 * @var ISystemTagManager
54
-	 */
55
-	private $tagManager;
56
-
57
-	/**
58
-	 * @var ISystemTagObjectMapper
59
-	 */
60
-	private $tagMapper;
61
-
62
-	/**
63
-	 * User
64
-	 *
65
-	 * @var IUser
66
-	 */
67
-	private $user;
68
-
69
-
70
-	/**
71
-	 * Constructor
72
-	 *
73
-	 * @param string $objectId object id
74
-	 * @param string $objectType object type
75
-	 * @param IUser $user user
76
-	 * @param ISystemTagManager $tagManager tag manager
77
-	 * @param ISystemTagObjectMapper $tagMapper tag mapper
78
-	 */
79
-	public function __construct(
80
-		$objectId,
81
-		$objectType,
82
-		IUser $user,
83
-		ISystemTagManager $tagManager,
84
-		ISystemTagObjectMapper $tagMapper
85
-	) {
86
-		$this->tagManager = $tagManager;
87
-		$this->tagMapper = $tagMapper;
88
-		$this->objectId = $objectId;
89
-		$this->objectType = $objectType;
90
-		$this->user = $user;
91
-	}
92
-
93
-	function createFile($tagId, $data = null) {
94
-		try {
95
-			$tags = $this->tagManager->getTagsByIds([$tagId]);
96
-			$tag = current($tags);
97
-			if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
98
-				throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
99
-			}
100
-			if (!$this->tagManager->canUserAssignTag($tag, $this->user)) {
101
-				throw new Forbidden('No permission to assign tag ' . $tagId);
102
-			}
103
-
104
-			$this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
105
-		} catch (TagNotFoundException $e) {
106
-			throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
107
-		}
108
-	}
109
-
110
-	function createDirectory($name) {
111
-		throw new Forbidden('Permission denied to create collections');
112
-	}
113
-
114
-	function getChild($tagId) {
115
-		try {
116
-			if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) {
117
-				$tag = $this->tagManager->getTagsByIds([$tagId]);
118
-				$tag = current($tag);
119
-				if ($this->tagManager->canUserSeeTag($tag, $this->user)) {
120
-					return $this->makeNode($tag);
121
-				}
122
-			}
123
-			throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId);
124
-		} catch (\InvalidArgumentException $e) {
125
-			throw new BadRequest('Invalid tag id', 0, $e);
126
-		} catch (TagNotFoundException $e) {
127
-			throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e);
128
-		}
129
-	}
130
-
131
-	function getChildren() {
132
-		$tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType));
133
-		if (empty($tagIds)) {
134
-			return [];
135
-		}
136
-		$tags = $this->tagManager->getTagsByIds($tagIds);
137
-
138
-		// filter out non-visible tags
139
-		$tags = array_filter($tags, function($tag) {
140
-			return $this->tagManager->canUserSeeTag($tag, $this->user);
141
-		});
142
-
143
-		return array_values(array_map(function($tag) {
144
-			return $this->makeNode($tag);
145
-		}, $tags));
146
-	}
147
-
148
-	function childExists($tagId) {
149
-		try {
150
-			$result = $this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true);
151
-
152
-			if ($result) {
153
-				$tags = $this->tagManager->getTagsByIds([$tagId]);
154
-				$tag = current($tags);
155
-				if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
156
-					return false;
157
-				}
158
-			}
159
-
160
-			return $result;
161
-		} catch (\InvalidArgumentException $e) {
162
-			throw new BadRequest('Invalid tag id', 0, $e);
163
-		} catch (TagNotFoundException $e) {
164
-			return false;
165
-		}
166
-	}
167
-
168
-	function delete() {
169
-		throw new Forbidden('Permission denied to delete this collection');
170
-	}
171
-
172
-	function getName() {
173
-		return $this->objectId;
174
-	}
175
-
176
-	function setName($name) {
177
-		throw new Forbidden('Permission denied to rename this collection');
178
-	}
179
-
180
-	/**
181
-	 * Returns the last modification time, as a unix timestamp
182
-	 *
183
-	 * @return int
184
-	 */
185
-	function getLastModified() {
186
-		return null;
187
-	}
188
-
189
-	/**
190
-	 * Create a sabre node for the mapping of the 
191
-	 * given system tag to the collection's object
192
-	 *
193
-	 * @param ISystemTag $tag
194
-	 *
195
-	 * @return SystemTagMappingNode
196
-	 */
197
-	private function makeNode(ISystemTag $tag) {
198
-		return new SystemTagMappingNode(
199
-			$tag,
200
-			$this->objectId,
201
-			$this->objectType,
202
-			$this->user,
203
-			$this->tagManager,
204
-			$this->tagMapper
205
-		);
206
-	}
42
+    /**
43
+     * @var string
44
+     */
45
+    private $objectId;
46
+
47
+    /**
48
+     * @var string
49
+     */
50
+    private $objectType;
51
+
52
+    /**
53
+     * @var ISystemTagManager
54
+     */
55
+    private $tagManager;
56
+
57
+    /**
58
+     * @var ISystemTagObjectMapper
59
+     */
60
+    private $tagMapper;
61
+
62
+    /**
63
+     * User
64
+     *
65
+     * @var IUser
66
+     */
67
+    private $user;
68
+
69
+
70
+    /**
71
+     * Constructor
72
+     *
73
+     * @param string $objectId object id
74
+     * @param string $objectType object type
75
+     * @param IUser $user user
76
+     * @param ISystemTagManager $tagManager tag manager
77
+     * @param ISystemTagObjectMapper $tagMapper tag mapper
78
+     */
79
+    public function __construct(
80
+        $objectId,
81
+        $objectType,
82
+        IUser $user,
83
+        ISystemTagManager $tagManager,
84
+        ISystemTagObjectMapper $tagMapper
85
+    ) {
86
+        $this->tagManager = $tagManager;
87
+        $this->tagMapper = $tagMapper;
88
+        $this->objectId = $objectId;
89
+        $this->objectType = $objectType;
90
+        $this->user = $user;
91
+    }
92
+
93
+    function createFile($tagId, $data = null) {
94
+        try {
95
+            $tags = $this->tagManager->getTagsByIds([$tagId]);
96
+            $tag = current($tags);
97
+            if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
98
+                throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
99
+            }
100
+            if (!$this->tagManager->canUserAssignTag($tag, $this->user)) {
101
+                throw new Forbidden('No permission to assign tag ' . $tagId);
102
+            }
103
+
104
+            $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId);
105
+        } catch (TagNotFoundException $e) {
106
+            throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign');
107
+        }
108
+    }
109
+
110
+    function createDirectory($name) {
111
+        throw new Forbidden('Permission denied to create collections');
112
+    }
113
+
114
+    function getChild($tagId) {
115
+        try {
116
+            if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) {
117
+                $tag = $this->tagManager->getTagsByIds([$tagId]);
118
+                $tag = current($tag);
119
+                if ($this->tagManager->canUserSeeTag($tag, $this->user)) {
120
+                    return $this->makeNode($tag);
121
+                }
122
+            }
123
+            throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId);
124
+        } catch (\InvalidArgumentException $e) {
125
+            throw new BadRequest('Invalid tag id', 0, $e);
126
+        } catch (TagNotFoundException $e) {
127
+            throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e);
128
+        }
129
+    }
130
+
131
+    function getChildren() {
132
+        $tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType));
133
+        if (empty($tagIds)) {
134
+            return [];
135
+        }
136
+        $tags = $this->tagManager->getTagsByIds($tagIds);
137
+
138
+        // filter out non-visible tags
139
+        $tags = array_filter($tags, function($tag) {
140
+            return $this->tagManager->canUserSeeTag($tag, $this->user);
141
+        });
142
+
143
+        return array_values(array_map(function($tag) {
144
+            return $this->makeNode($tag);
145
+        }, $tags));
146
+    }
147
+
148
+    function childExists($tagId) {
149
+        try {
150
+            $result = $this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true);
151
+
152
+            if ($result) {
153
+                $tags = $this->tagManager->getTagsByIds([$tagId]);
154
+                $tag = current($tags);
155
+                if (!$this->tagManager->canUserSeeTag($tag, $this->user)) {
156
+                    return false;
157
+                }
158
+            }
159
+
160
+            return $result;
161
+        } catch (\InvalidArgumentException $e) {
162
+            throw new BadRequest('Invalid tag id', 0, $e);
163
+        } catch (TagNotFoundException $e) {
164
+            return false;
165
+        }
166
+    }
167
+
168
+    function delete() {
169
+        throw new Forbidden('Permission denied to delete this collection');
170
+    }
171
+
172
+    function getName() {
173
+        return $this->objectId;
174
+    }
175
+
176
+    function setName($name) {
177
+        throw new Forbidden('Permission denied to rename this collection');
178
+    }
179
+
180
+    /**
181
+     * Returns the last modification time, as a unix timestamp
182
+     *
183
+     * @return int
184
+     */
185
+    function getLastModified() {
186
+        return null;
187
+    }
188
+
189
+    /**
190
+     * Create a sabre node for the mapping of the 
191
+     * given system tag to the collection's object
192
+     *
193
+     * @param ISystemTag $tag
194
+     *
195
+     * @return SystemTagMappingNode
196
+     */
197
+    private function makeNode(ISystemTag $tag) {
198
+        return new SystemTagMappingNode(
199
+            $tag,
200
+            $this->objectId,
201
+            $this->objectType,
202
+            $this->user,
203
+            $this->tagManager,
204
+            $this->tagMapper
205
+        );
206
+    }
207 207
 }
Please login to merge, or discard this patch.
lib/private/DB/Migrator.php 3 patches
Doc Comments   +8 added lines patch added patch discarded remove patch
@@ -273,6 +273,10 @@  discard block
 block discarded – undo
273 273
 		return '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
274 274
 	}
275 275
 
276
+	/**
277
+	 * @param integer $step
278
+	 * @param integer $max
279
+	 */
276 280
 	protected function emit($sql, $step, $max) {
277 281
 		if ($this->noEmit) {
278 282
 			return;
@@ -283,6 +287,10 @@  discard block
 block discarded – undo
283 287
 		$this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max]));
284 288
 	}
285 289
 
290
+	/**
291
+	 * @param integer $step
292
+	 * @param integer $max
293
+	 */
286 294
 	private function emitCheckStep($tableName, $step, $max) {
287 295
 		if(is_null($this->dispatcher)) {
288 296
 			return;
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -137,7 +137,7 @@  discard block
 block discarded – undo
137 137
 	 * @return string
138 138
 	 */
139 139
 	protected function generateTemporaryTableName($name) {
140
-		return $this->config->getSystemValue('dbtableprefix', 'oc_') . $name . '_' . $this->random->generate(13, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
140
+		return $this->config->getSystemValue('dbtableprefix', 'oc_').$name.'_'.$this->random->generate(13, ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS);
141 141
 	}
142 142
 
143 143
 	/**
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
 				$indexName = $index->getName();
189 189
 			} else {
190 190
 				// avoid conflicts in index names
191
-				$indexName = $this->config->getSystemValue('dbtableprefix', 'oc_') . $this->random->generate(13, ISecureRandom::CHAR_LOWER);
191
+				$indexName = $this->config->getSystemValue('dbtableprefix', 'oc_').$this->random->generate(13, ISecureRandom::CHAR_LOWER);
192 192
 			}
193 193
 			$newIndexes[] = new Index($indexName, $index->getColumns(), $index->isUnique(), $index->isPrimary());
194 194
 		}
@@ -268,15 +268,15 @@  discard block
 block discarded – undo
268 268
 		$quotedSource = $this->connection->quoteIdentifier($sourceName);
269 269
 		$quotedTarget = $this->connection->quoteIdentifier($targetName);
270 270
 
271
-		$this->connection->exec('CREATE TABLE ' . $quotedTarget . ' (LIKE ' . $quotedSource . ')');
272
-		$this->connection->exec('INSERT INTO ' . $quotedTarget . ' SELECT * FROM ' . $quotedSource);
271
+		$this->connection->exec('CREATE TABLE '.$quotedTarget.' (LIKE '.$quotedSource.')');
272
+		$this->connection->exec('INSERT INTO '.$quotedTarget.' SELECT * FROM '.$quotedSource);
273 273
 	}
274 274
 
275 275
 	/**
276 276
 	 * @param string $name
277 277
 	 */
278 278
 	protected function dropTable($name) {
279
-		$this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($name));
279
+		$this->connection->exec('DROP TABLE '.$this->connection->quoteIdentifier($name));
280 280
 	}
281 281
 
282 282
 	/**
@@ -284,30 +284,30 @@  discard block
 block discarded – undo
284 284
 	 * @return string
285 285
 	 */
286 286
 	protected function convertStatementToScript($statement) {
287
-		$script = $statement . ';';
287
+		$script = $statement.';';
288 288
 		$script .= PHP_EOL;
289 289
 		$script .= PHP_EOL;
290 290
 		return $script;
291 291
 	}
292 292
 
293 293
 	protected function getFilterExpression() {
294
-		return '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
294
+		return '/^'.preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')).'/';
295 295
 	}
296 296
 
297 297
 	protected function emit($sql, $step, $max) {
298 298
 		if ($this->noEmit) {
299 299
 			return;
300 300
 		}
301
-		if(is_null($this->dispatcher)) {
301
+		if (is_null($this->dispatcher)) {
302 302
 			return;
303 303
 		}
304
-		$this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max]));
304
+		$this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step + 1, $max]));
305 305
 	}
306 306
 
307 307
 	private function emitCheckStep($tableName, $step, $max) {
308
-		if(is_null($this->dispatcher)) {
308
+		if (is_null($this->dispatcher)) {
309 309
 			return;
310 310
 		}
311
-		$this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step+1, $max]));
311
+		$this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step + 1, $max]));
312 312
 	}
313 313
 }
Please login to merge, or discard this patch.
Indentation   +268 added lines, -268 removed lines patch added patch discarded remove patch
@@ -43,272 +43,272 @@
 block discarded – undo
43 43
 
44 44
 class Migrator {
45 45
 
46
-	/** @var \Doctrine\DBAL\Connection */
47
-	protected $connection;
48
-
49
-	/** @var ISecureRandom */
50
-	private $random;
51
-
52
-	/** @var IConfig */
53
-	protected $config;
54
-
55
-	/** @var EventDispatcher  */
56
-	private $dispatcher;
57
-
58
-	/** @var bool */
59
-	private $noEmit = false;
60
-
61
-	/**
62
-	 * @param \Doctrine\DBAL\Connection|Connection $connection
63
-	 * @param ISecureRandom $random
64
-	 * @param IConfig $config
65
-	 * @param EventDispatcher $dispatcher
66
-	 */
67
-	public function __construct(\Doctrine\DBAL\Connection $connection,
68
-								ISecureRandom $random,
69
-								IConfig $config,
70
-								EventDispatcher $dispatcher = null) {
71
-		$this->connection = $connection;
72
-		$this->random = $random;
73
-		$this->config = $config;
74
-		$this->dispatcher = $dispatcher;
75
-	}
76
-
77
-	/**
78
-	 * @param \Doctrine\DBAL\Schema\Schema $targetSchema
79
-	 */
80
-	public function migrate(Schema $targetSchema) {
81
-		$this->noEmit = true;
82
-		$this->applySchema($targetSchema);
83
-	}
84
-
85
-	/**
86
-	 * @param \Doctrine\DBAL\Schema\Schema $targetSchema
87
-	 * @return string
88
-	 */
89
-	public function generateChangeScript(Schema $targetSchema) {
90
-		$schemaDiff = $this->getDiff($targetSchema, $this->connection);
91
-
92
-		$script = '';
93
-		$sqls = $schemaDiff->toSql($this->connection->getDatabasePlatform());
94
-		foreach ($sqls as $sql) {
95
-			$script .= $this->convertStatementToScript($sql);
96
-		}
97
-
98
-		return $script;
99
-	}
100
-
101
-	/**
102
-	 * @param Schema $targetSchema
103
-	 * @throws \OC\DB\MigrationException
104
-	 */
105
-	public function checkMigrate(Schema $targetSchema) {
106
-		$this->noEmit = true;
107
-		/**@var \Doctrine\DBAL\Schema\Table[] $tables */
108
-		$tables = $targetSchema->getTables();
109
-		$filterExpression = $this->getFilterExpression();
110
-		$this->connection->getConfiguration()->
111
-			setFilterSchemaAssetsExpression($filterExpression);
112
-		$existingTables = $this->connection->getSchemaManager()->listTableNames();
113
-
114
-		$step = 0;
115
-		foreach ($tables as $table) {
116
-			if (strpos($table->getName(), '.')) {
117
-				list(, $tableName) = explode('.', $table->getName());
118
-			} else {
119
-				$tableName = $table->getName();
120
-			}
121
-			$this->emitCheckStep($tableName, $step++, count($tables));
122
-			// don't need to check for new tables
123
-			if (array_search($tableName, $existingTables) !== false) {
124
-				$this->checkTableMigrate($table);
125
-			}
126
-		}
127
-	}
128
-
129
-	/**
130
-	 * Create a unique name for the temporary table
131
-	 *
132
-	 * @param string $name
133
-	 * @return string
134
-	 */
135
-	protected function generateTemporaryTableName($name) {
136
-		return $this->config->getSystemValue('dbtableprefix', 'oc_') . $name . '_' . $this->random->generate(13, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
137
-	}
138
-
139
-	/**
140
-	 * Check the migration of a table on a copy so we can detect errors before messing with the real table
141
-	 *
142
-	 * @param \Doctrine\DBAL\Schema\Table $table
143
-	 * @throws \OC\DB\MigrationException
144
-	 */
145
-	protected function checkTableMigrate(Table $table) {
146
-		$name = $table->getName();
147
-		$tmpName = $this->generateTemporaryTableName($name);
148
-
149
-		$this->copyTable($name, $tmpName);
150
-
151
-		//create the migration schema for the temporary table
152
-		$tmpTable = $this->renameTableSchema($table, $tmpName);
153
-		$schemaConfig = new SchemaConfig();
154
-		$schemaConfig->setName($this->connection->getDatabase());
155
-		$schema = new Schema(array($tmpTable), array(), $schemaConfig);
156
-
157
-		try {
158
-			$this->applySchema($schema);
159
-			$this->dropTable($tmpName);
160
-		} catch (DBALException $e) {
161
-			// pgsql needs to commit it's failed transaction before doing anything else
162
-			if ($this->connection->isTransactionActive()) {
163
-				$this->connection->commit();
164
-			}
165
-			$this->dropTable($tmpName);
166
-			throw new MigrationException($table->getName(), $e->getMessage());
167
-		}
168
-	}
169
-
170
-	/**
171
-	 * @param \Doctrine\DBAL\Schema\Table $table
172
-	 * @param string $newName
173
-	 * @return \Doctrine\DBAL\Schema\Table
174
-	 */
175
-	protected function renameTableSchema(Table $table, $newName) {
176
-		/**
177
-		 * @var \Doctrine\DBAL\Schema\Index[] $indexes
178
-		 */
179
-		$indexes = $table->getIndexes();
180
-		$newIndexes = array();
181
-		foreach ($indexes as $index) {
182
-			if ($index->isPrimary()) {
183
-				// do not rename primary key
184
-				$indexName = $index->getName();
185
-			} else {
186
-				// avoid conflicts in index names
187
-				$indexName = $this->config->getSystemValue('dbtableprefix', 'oc_') . $this->random->generate(13, ISecureRandom::CHAR_LOWER);
188
-			}
189
-			$newIndexes[] = new Index($indexName, $index->getColumns(), $index->isUnique(), $index->isPrimary());
190
-		}
191
-
192
-		// foreign keys are not supported so we just set it to an empty array
193
-		return new Table($newName, $table->getColumns(), $newIndexes, array(), 0, $table->getOptions());
194
-	}
195
-
196
-	public function createSchema() {
197
-		$filterExpression = $this->getFilterExpression();
198
-		$this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression);
199
-		return $this->connection->getSchemaManager()->createSchema();
200
-	}
201
-
202
-	/**
203
-	 * @param Schema $targetSchema
204
-	 * @param \Doctrine\DBAL\Connection $connection
205
-	 * @return \Doctrine\DBAL\Schema\SchemaDiff
206
-	 * @throws DBALException
207
-	 */
208
-	protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) {
209
-		// adjust varchar columns with a length higher then getVarcharMaxLength to clob
210
-		foreach ($targetSchema->getTables() as $table) {
211
-			foreach ($table->getColumns() as $column) {
212
-				if ($column->getType() instanceof StringType) {
213
-					if ($column->getLength() > $connection->getDatabasePlatform()->getVarcharMaxLength()) {
214
-						$column->setType(Type::getType('text'));
215
-						$column->setLength(null);
216
-					}
217
-				}
218
-			}
219
-		}
220
-
221
-		$filterExpression = $this->getFilterExpression();
222
-		$this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression);
223
-		$sourceSchema = $connection->getSchemaManager()->createSchema();
224
-
225
-		// remove tables we don't know about
226
-		/** @var $table \Doctrine\DBAL\Schema\Table */
227
-		foreach ($sourceSchema->getTables() as $table) {
228
-			if (!$targetSchema->hasTable($table->getName())) {
229
-				$sourceSchema->dropTable($table->getName());
230
-			}
231
-		}
232
-		// remove sequences we don't know about
233
-		foreach ($sourceSchema->getSequences() as $table) {
234
-			if (!$targetSchema->hasSequence($table->getName())) {
235
-				$sourceSchema->dropSequence($table->getName());
236
-			}
237
-		}
238
-
239
-		$comparator = new Comparator();
240
-		return $comparator->compare($sourceSchema, $targetSchema);
241
-	}
242
-
243
-	/**
244
-	 * @param \Doctrine\DBAL\Schema\Schema $targetSchema
245
-	 * @param \Doctrine\DBAL\Connection $connection
246
-	 */
247
-	protected function applySchema(Schema $targetSchema, \Doctrine\DBAL\Connection $connection = null) {
248
-		if (is_null($connection)) {
249
-			$connection = $this->connection;
250
-		}
251
-
252
-		$schemaDiff = $this->getDiff($targetSchema, $connection);
253
-
254
-		$connection->beginTransaction();
255
-		$sqls = $schemaDiff->toSql($connection->getDatabasePlatform());
256
-		$step = 0;
257
-		foreach ($sqls as $sql) {
258
-			$this->emit($sql, $step++, count($sqls));
259
-			$connection->query($sql);
260
-		}
261
-		$connection->commit();
262
-	}
263
-
264
-	/**
265
-	 * @param string $sourceName
266
-	 * @param string $targetName
267
-	 */
268
-	protected function copyTable($sourceName, $targetName) {
269
-		$quotedSource = $this->connection->quoteIdentifier($sourceName);
270
-		$quotedTarget = $this->connection->quoteIdentifier($targetName);
271
-
272
-		$this->connection->exec('CREATE TABLE ' . $quotedTarget . ' (LIKE ' . $quotedSource . ')');
273
-		$this->connection->exec('INSERT INTO ' . $quotedTarget . ' SELECT * FROM ' . $quotedSource);
274
-	}
275
-
276
-	/**
277
-	 * @param string $name
278
-	 */
279
-	protected function dropTable($name) {
280
-		$this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($name));
281
-	}
282
-
283
-	/**
284
-	 * @param $statement
285
-	 * @return string
286
-	 */
287
-	protected function convertStatementToScript($statement) {
288
-		$script = $statement . ';';
289
-		$script .= PHP_EOL;
290
-		$script .= PHP_EOL;
291
-		return $script;
292
-	}
293
-
294
-	protected function getFilterExpression() {
295
-		return '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
296
-	}
297
-
298
-	protected function emit($sql, $step, $max) {
299
-		if ($this->noEmit) {
300
-			return;
301
-		}
302
-		if(is_null($this->dispatcher)) {
303
-			return;
304
-		}
305
-		$this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max]));
306
-	}
307
-
308
-	private function emitCheckStep($tableName, $step, $max) {
309
-		if(is_null($this->dispatcher)) {
310
-			return;
311
-		}
312
-		$this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step+1, $max]));
313
-	}
46
+    /** @var \Doctrine\DBAL\Connection */
47
+    protected $connection;
48
+
49
+    /** @var ISecureRandom */
50
+    private $random;
51
+
52
+    /** @var IConfig */
53
+    protected $config;
54
+
55
+    /** @var EventDispatcher  */
56
+    private $dispatcher;
57
+
58
+    /** @var bool */
59
+    private $noEmit = false;
60
+
61
+    /**
62
+     * @param \Doctrine\DBAL\Connection|Connection $connection
63
+     * @param ISecureRandom $random
64
+     * @param IConfig $config
65
+     * @param EventDispatcher $dispatcher
66
+     */
67
+    public function __construct(\Doctrine\DBAL\Connection $connection,
68
+                                ISecureRandom $random,
69
+                                IConfig $config,
70
+                                EventDispatcher $dispatcher = null) {
71
+        $this->connection = $connection;
72
+        $this->random = $random;
73
+        $this->config = $config;
74
+        $this->dispatcher = $dispatcher;
75
+    }
76
+
77
+    /**
78
+     * @param \Doctrine\DBAL\Schema\Schema $targetSchema
79
+     */
80
+    public function migrate(Schema $targetSchema) {
81
+        $this->noEmit = true;
82
+        $this->applySchema($targetSchema);
83
+    }
84
+
85
+    /**
86
+     * @param \Doctrine\DBAL\Schema\Schema $targetSchema
87
+     * @return string
88
+     */
89
+    public function generateChangeScript(Schema $targetSchema) {
90
+        $schemaDiff = $this->getDiff($targetSchema, $this->connection);
91
+
92
+        $script = '';
93
+        $sqls = $schemaDiff->toSql($this->connection->getDatabasePlatform());
94
+        foreach ($sqls as $sql) {
95
+            $script .= $this->convertStatementToScript($sql);
96
+        }
97
+
98
+        return $script;
99
+    }
100
+
101
+    /**
102
+     * @param Schema $targetSchema
103
+     * @throws \OC\DB\MigrationException
104
+     */
105
+    public function checkMigrate(Schema $targetSchema) {
106
+        $this->noEmit = true;
107
+        /**@var \Doctrine\DBAL\Schema\Table[] $tables */
108
+        $tables = $targetSchema->getTables();
109
+        $filterExpression = $this->getFilterExpression();
110
+        $this->connection->getConfiguration()->
111
+            setFilterSchemaAssetsExpression($filterExpression);
112
+        $existingTables = $this->connection->getSchemaManager()->listTableNames();
113
+
114
+        $step = 0;
115
+        foreach ($tables as $table) {
116
+            if (strpos($table->getName(), '.')) {
117
+                list(, $tableName) = explode('.', $table->getName());
118
+            } else {
119
+                $tableName = $table->getName();
120
+            }
121
+            $this->emitCheckStep($tableName, $step++, count($tables));
122
+            // don't need to check for new tables
123
+            if (array_search($tableName, $existingTables) !== false) {
124
+                $this->checkTableMigrate($table);
125
+            }
126
+        }
127
+    }
128
+
129
+    /**
130
+     * Create a unique name for the temporary table
131
+     *
132
+     * @param string $name
133
+     * @return string
134
+     */
135
+    protected function generateTemporaryTableName($name) {
136
+        return $this->config->getSystemValue('dbtableprefix', 'oc_') . $name . '_' . $this->random->generate(13, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS);
137
+    }
138
+
139
+    /**
140
+     * Check the migration of a table on a copy so we can detect errors before messing with the real table
141
+     *
142
+     * @param \Doctrine\DBAL\Schema\Table $table
143
+     * @throws \OC\DB\MigrationException
144
+     */
145
+    protected function checkTableMigrate(Table $table) {
146
+        $name = $table->getName();
147
+        $tmpName = $this->generateTemporaryTableName($name);
148
+
149
+        $this->copyTable($name, $tmpName);
150
+
151
+        //create the migration schema for the temporary table
152
+        $tmpTable = $this->renameTableSchema($table, $tmpName);
153
+        $schemaConfig = new SchemaConfig();
154
+        $schemaConfig->setName($this->connection->getDatabase());
155
+        $schema = new Schema(array($tmpTable), array(), $schemaConfig);
156
+
157
+        try {
158
+            $this->applySchema($schema);
159
+            $this->dropTable($tmpName);
160
+        } catch (DBALException $e) {
161
+            // pgsql needs to commit it's failed transaction before doing anything else
162
+            if ($this->connection->isTransactionActive()) {
163
+                $this->connection->commit();
164
+            }
165
+            $this->dropTable($tmpName);
166
+            throw new MigrationException($table->getName(), $e->getMessage());
167
+        }
168
+    }
169
+
170
+    /**
171
+     * @param \Doctrine\DBAL\Schema\Table $table
172
+     * @param string $newName
173
+     * @return \Doctrine\DBAL\Schema\Table
174
+     */
175
+    protected function renameTableSchema(Table $table, $newName) {
176
+        /**
177
+         * @var \Doctrine\DBAL\Schema\Index[] $indexes
178
+         */
179
+        $indexes = $table->getIndexes();
180
+        $newIndexes = array();
181
+        foreach ($indexes as $index) {
182
+            if ($index->isPrimary()) {
183
+                // do not rename primary key
184
+                $indexName = $index->getName();
185
+            } else {
186
+                // avoid conflicts in index names
187
+                $indexName = $this->config->getSystemValue('dbtableprefix', 'oc_') . $this->random->generate(13, ISecureRandom::CHAR_LOWER);
188
+            }
189
+            $newIndexes[] = new Index($indexName, $index->getColumns(), $index->isUnique(), $index->isPrimary());
190
+        }
191
+
192
+        // foreign keys are not supported so we just set it to an empty array
193
+        return new Table($newName, $table->getColumns(), $newIndexes, array(), 0, $table->getOptions());
194
+    }
195
+
196
+    public function createSchema() {
197
+        $filterExpression = $this->getFilterExpression();
198
+        $this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression);
199
+        return $this->connection->getSchemaManager()->createSchema();
200
+    }
201
+
202
+    /**
203
+     * @param Schema $targetSchema
204
+     * @param \Doctrine\DBAL\Connection $connection
205
+     * @return \Doctrine\DBAL\Schema\SchemaDiff
206
+     * @throws DBALException
207
+     */
208
+    protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) {
209
+        // adjust varchar columns with a length higher then getVarcharMaxLength to clob
210
+        foreach ($targetSchema->getTables() as $table) {
211
+            foreach ($table->getColumns() as $column) {
212
+                if ($column->getType() instanceof StringType) {
213
+                    if ($column->getLength() > $connection->getDatabasePlatform()->getVarcharMaxLength()) {
214
+                        $column->setType(Type::getType('text'));
215
+                        $column->setLength(null);
216
+                    }
217
+                }
218
+            }
219
+        }
220
+
221
+        $filterExpression = $this->getFilterExpression();
222
+        $this->connection->getConfiguration()->setFilterSchemaAssetsExpression($filterExpression);
223
+        $sourceSchema = $connection->getSchemaManager()->createSchema();
224
+
225
+        // remove tables we don't know about
226
+        /** @var $table \Doctrine\DBAL\Schema\Table */
227
+        foreach ($sourceSchema->getTables() as $table) {
228
+            if (!$targetSchema->hasTable($table->getName())) {
229
+                $sourceSchema->dropTable($table->getName());
230
+            }
231
+        }
232
+        // remove sequences we don't know about
233
+        foreach ($sourceSchema->getSequences() as $table) {
234
+            if (!$targetSchema->hasSequence($table->getName())) {
235
+                $sourceSchema->dropSequence($table->getName());
236
+            }
237
+        }
238
+
239
+        $comparator = new Comparator();
240
+        return $comparator->compare($sourceSchema, $targetSchema);
241
+    }
242
+
243
+    /**
244
+     * @param \Doctrine\DBAL\Schema\Schema $targetSchema
245
+     * @param \Doctrine\DBAL\Connection $connection
246
+     */
247
+    protected function applySchema(Schema $targetSchema, \Doctrine\DBAL\Connection $connection = null) {
248
+        if (is_null($connection)) {
249
+            $connection = $this->connection;
250
+        }
251
+
252
+        $schemaDiff = $this->getDiff($targetSchema, $connection);
253
+
254
+        $connection->beginTransaction();
255
+        $sqls = $schemaDiff->toSql($connection->getDatabasePlatform());
256
+        $step = 0;
257
+        foreach ($sqls as $sql) {
258
+            $this->emit($sql, $step++, count($sqls));
259
+            $connection->query($sql);
260
+        }
261
+        $connection->commit();
262
+    }
263
+
264
+    /**
265
+     * @param string $sourceName
266
+     * @param string $targetName
267
+     */
268
+    protected function copyTable($sourceName, $targetName) {
269
+        $quotedSource = $this->connection->quoteIdentifier($sourceName);
270
+        $quotedTarget = $this->connection->quoteIdentifier($targetName);
271
+
272
+        $this->connection->exec('CREATE TABLE ' . $quotedTarget . ' (LIKE ' . $quotedSource . ')');
273
+        $this->connection->exec('INSERT INTO ' . $quotedTarget . ' SELECT * FROM ' . $quotedSource);
274
+    }
275
+
276
+    /**
277
+     * @param string $name
278
+     */
279
+    protected function dropTable($name) {
280
+        $this->connection->exec('DROP TABLE ' . $this->connection->quoteIdentifier($name));
281
+    }
282
+
283
+    /**
284
+     * @param $statement
285
+     * @return string
286
+     */
287
+    protected function convertStatementToScript($statement) {
288
+        $script = $statement . ';';
289
+        $script .= PHP_EOL;
290
+        $script .= PHP_EOL;
291
+        return $script;
292
+    }
293
+
294
+    protected function getFilterExpression() {
295
+        return '/^' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
296
+    }
297
+
298
+    protected function emit($sql, $step, $max) {
299
+        if ($this->noEmit) {
300
+            return;
301
+        }
302
+        if(is_null($this->dispatcher)) {
303
+            return;
304
+        }
305
+        $this->dispatcher->dispatch('\OC\DB\Migrator::executeSql', new GenericEvent($sql, [$step+1, $max]));
306
+    }
307
+
308
+    private function emitCheckStep($tableName, $step, $max) {
309
+        if(is_null($this->dispatcher)) {
310
+            return;
311
+        }
312
+        $this->dispatcher->dispatch('\OC\DB\Migrator::checkTable', new GenericEvent($tableName, [$step+1, $max]));
313
+    }
314 314
 }
Please login to merge, or discard this patch.
settings/Controller/CheckSetupController.php 3 patches
Doc Comments   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -103,6 +103,7 @@  discard block
 block discarded – undo
103 103
 
104 104
 	/**
105 105
 	* Chceks if the ownCloud server can connect to a specific URL using both HTTPS and HTTP
106
+	* @param string $sitename
106 107
 	* @return bool
107 108
 	*/
108 109
 	private function isSiteReachable($sitename) {
@@ -285,7 +286,7 @@  discard block
 block discarded – undo
285 286
 
286 287
 	/**
287 288
 	 * @NoCSRFRequired
288
-	 * @return DataResponse
289
+	 * @return DataDisplayResponse
289 290
 	 */
290 291
 	public function getFailedIntegrityCheckFiles() {
291 292
 		if(!$this->checker->isCodeCheckEnforced()) {
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -104,7 +104,7 @@  discard block
 block discarded – undo
104 104
 						'www.google.com',
105 105
 						'www.github.com'];
106 106
 
107
-		foreach($siteArray as $site) {
107
+		foreach ($siteArray as $site) {
108 108
 			if ($this->isSiteReachable($site)) {
109 109
 				return true;
110 110
 			}
@@ -117,8 +117,8 @@  discard block
 block discarded – undo
117 117
 	* @return bool
118 118
 	*/
119 119
 	private function isSiteReachable($sitename) {
120
-		$httpSiteName = 'http://' . $sitename . '/';
121
-		$httpsSiteName = 'https://' . $sitename . '/';
120
+		$httpSiteName = 'http://'.$sitename.'/';
121
+		$httpsSiteName = 'https://'.$sitename.'/';
122 122
 
123 123
 		try {
124 124
 			$client = $this->clientService->newClient();
@@ -145,9 +145,9 @@  discard block
 block discarded – undo
145 145
 	 * @return bool
146 146
 	 */
147 147
 	private function isUrandomAvailable() {
148
-		if(@file_exists('/dev/urandom')) {
148
+		if (@file_exists('/dev/urandom')) {
149 149
 			$file = fopen('/dev/urandom', 'rb');
150
-			if($file) {
150
+			if ($file) {
151 151
 				fclose($file);
152 152
 				return true;
153 153
 			}
@@ -178,40 +178,40 @@  discard block
 block discarded – undo
178 178
 		// Don't run check when:
179 179
 		// 1. Server has `has_internet_connection` set to false
180 180
 		// 2. AppStore AND S2S is disabled
181
-		if(!$this->config->getSystemValue('has_internet_connection', true)) {
181
+		if (!$this->config->getSystemValue('has_internet_connection', true)) {
182 182
 			return '';
183 183
 		}
184
-		if(!$this->config->getSystemValue('appstoreenabled', true)
184
+		if (!$this->config->getSystemValue('appstoreenabled', true)
185 185
 			&& $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
186 186
 			&& $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
187 187
 			return '';
188 188
 		}
189 189
 
190 190
 		$versionString = $this->getCurlVersion();
191
-		if(isset($versionString['ssl_version'])) {
191
+		if (isset($versionString['ssl_version'])) {
192 192
 			$versionString = $versionString['ssl_version'];
193 193
 		} else {
194 194
 			return '';
195 195
 		}
196 196
 
197
-		$features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
198
-		if(!$this->config->getSystemValue('appstoreenabled', true)) {
199
-			$features = (string)$this->l10n->t('Federated Cloud Sharing');
197
+		$features = (string) $this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
198
+		if (!$this->config->getSystemValue('appstoreenabled', true)) {
199
+			$features = (string) $this->l10n->t('Federated Cloud Sharing');
200 200
 		}
201 201
 
202 202
 		// Check if at least OpenSSL after 1.01d or 1.0.2b
203
-		if(strpos($versionString, 'OpenSSL/') === 0) {
203
+		if (strpos($versionString, 'OpenSSL/') === 0) {
204 204
 			$majorVersion = substr($versionString, 8, 5);
205 205
 			$patchRelease = substr($versionString, 13, 6);
206 206
 
207
-			if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
207
+			if (($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
208 208
 				($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
209 209
 				return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['OpenSSL', $versionString, $features]);
210 210
 			}
211 211
 		}
212 212
 
213 213
 		// Check if NSS and perform heuristic check
214
-		if(strpos($versionString, 'NSS/') === 0) {
214
+		if (strpos($versionString, 'NSS/') === 0) {
215 215
 			try {
216 216
 				$firstClient = $this->clientService->newClient();
217 217
 				$firstClient->get('https://nextcloud.com/');
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
 				$secondClient = $this->clientService->newClient();
220 220
 				$secondClient->get('https://nextcloud.com/');
221 221
 			} catch (ClientException $e) {
222
-				if($e->getResponse()->getStatusCode() === 400) {
222
+				if ($e->getResponse()->getStatusCode() === 400) {
223 223
 					return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['NSS', $versionString, $features]);
224 224
 				}
225 225
 			}
@@ -314,13 +314,13 @@  discard block
 block discarded – undo
314 314
 	 * @return DataResponse
315 315
 	 */
316 316
 	public function getFailedIntegrityCheckFiles() {
317
-		if(!$this->checker->isCodeCheckEnforced()) {
317
+		if (!$this->checker->isCodeCheckEnforced()) {
318 318
 			return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
319 319
 		}
320 320
 
321 321
 		$completeResults = $this->checker->getResults();
322 322
 
323
-		if(!empty($completeResults)) {
323
+		if (!empty($completeResults)) {
324 324
 			$formattedTextResponse = 'Technical information
325 325
 =====================
326 326
 The following list covers which files have failed the integrity check. Please read
@@ -330,12 +330,12 @@  discard block
 block discarded – undo
330 330
 Results
331 331
 =======
332 332
 ';
333
-			foreach($completeResults as $context => $contextResult) {
333
+			foreach ($completeResults as $context => $contextResult) {
334 334
 				$formattedTextResponse .= "- $context\n";
335 335
 
336
-				foreach($contextResult as $category => $result) {
336
+				foreach ($contextResult as $category => $result) {
337 337
 					$formattedTextResponse .= "\t- $category\n";
338
-					if($category !== 'EXCEPTION') {
338
+					if ($category !== 'EXCEPTION') {
339 339
 						foreach ($result as $key => $results) {
340 340
 							$formattedTextResponse .= "\t\t- $key\n";
341 341
 						}
@@ -378,27 +378,27 @@  discard block
 block discarded – undo
378 378
 
379 379
 		$isOpcacheProperlySetUp = true;
380 380
 
381
-		if(!$iniWrapper->getBool('opcache.enable')) {
381
+		if (!$iniWrapper->getBool('opcache.enable')) {
382 382
 			$isOpcacheProperlySetUp = false;
383 383
 		}
384 384
 
385
-		if(!$iniWrapper->getBool('opcache.save_comments')) {
385
+		if (!$iniWrapper->getBool('opcache.save_comments')) {
386 386
 			$isOpcacheProperlySetUp = false;
387 387
 		}
388 388
 
389
-		if(!$iniWrapper->getBool('opcache.enable_cli')) {
389
+		if (!$iniWrapper->getBool('opcache.enable_cli')) {
390 390
 			$isOpcacheProperlySetUp = false;
391 391
 		}
392 392
 
393
-		if($iniWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
393
+		if ($iniWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
394 394
 			$isOpcacheProperlySetUp = false;
395 395
 		}
396 396
 
397
-		if($iniWrapper->getNumeric('opcache.memory_consumption') < 128) {
397
+		if ($iniWrapper->getNumeric('opcache.memory_consumption') < 128) {
398 398
 			$isOpcacheProperlySetUp = false;
399 399
 		}
400 400
 
401
-		if($iniWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
401
+		if ($iniWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
402 402
 			$isOpcacheProperlySetUp = false;
403 403
 		}
404 404
 
Please login to merge, or discard this patch.
Indentation   +381 added lines, -381 removed lines patch added patch discarded remove patch
@@ -50,282 +50,282 @@  discard block
 block discarded – undo
50 50
  * @package OC\Settings\Controller
51 51
  */
52 52
 class CheckSetupController extends Controller {
53
-	/** @var IConfig */
54
-	private $config;
55
-	/** @var IClientService */
56
-	private $clientService;
57
-	/** @var \OC_Util */
58
-	private $util;
59
-	/** @var IURLGenerator */
60
-	private $urlGenerator;
61
-	/** @var IL10N */
62
-	private $l10n;
63
-	/** @var Checker */
64
-	private $checker;
65
-	/** @var ILogger */
66
-	private $logger;
67
-
68
-	/**
69
-	 * @param string $AppName
70
-	 * @param IRequest $request
71
-	 * @param IConfig $config
72
-	 * @param IClientService $clientService
73
-	 * @param IURLGenerator $urlGenerator
74
-	 * @param \OC_Util $util
75
-	 * @param IL10N $l10n
76
-	 * @param Checker $checker
77
-	 * @param ILogger $logger
78
-	 */
79
-	public function __construct($AppName,
80
-								IRequest $request,
81
-								IConfig $config,
82
-								IClientService $clientService,
83
-								IURLGenerator $urlGenerator,
84
-								\OC_Util $util,
85
-								IL10N $l10n,
86
-								Checker $checker,
87
-								ILogger $logger) {
88
-		parent::__construct($AppName, $request);
89
-		$this->config = $config;
90
-		$this->clientService = $clientService;
91
-		$this->util = $util;
92
-		$this->urlGenerator = $urlGenerator;
93
-		$this->l10n = $l10n;
94
-		$this->checker = $checker;
95
-		$this->logger = $logger;
96
-	}
97
-
98
-	/**
99
-	 * Checks if the ownCloud server can connect to the internet using HTTPS and HTTP
100
-	 * @return bool
101
-	 */
102
-	private function isInternetConnectionWorking() {
103
-		if ($this->config->getSystemValue('has_internet_connection', true) === false) {
104
-			return false;
105
-		}
106
-
107
-		$siteArray = ['www.nextcloud.com',
108
-						'www.google.com',
109
-						'www.github.com'];
110
-
111
-		foreach($siteArray as $site) {
112
-			if ($this->isSiteReachable($site)) {
113
-				return true;
114
-			}
115
-		}
116
-		return false;
117
-	}
118
-
119
-	/**
120
-	* Chceks if the ownCloud server can connect to a specific URL using both HTTPS and HTTP
121
-	* @return bool
122
-	*/
123
-	private function isSiteReachable($sitename) {
124
-		$httpSiteName = 'http://' . $sitename . '/';
125
-		$httpsSiteName = 'https://' . $sitename . '/';
126
-
127
-		try {
128
-			$client = $this->clientService->newClient();
129
-			$client->get($httpSiteName);
130
-			$client->get($httpsSiteName);
131
-		} catch (\Exception $e) {
132
-			$this->logger->logException($e, ['app' => 'internet_connection_check']);
133
-			return false;
134
-		}
135
-		return true;
136
-	}
137
-
138
-	/**
139
-	 * Checks whether a local memcache is installed or not
140
-	 * @return bool
141
-	 */
142
-	private function isMemcacheConfigured() {
143
-		return $this->config->getSystemValue('memcache.local', null) !== null;
144
-	}
145
-
146
-	/**
147
-	 * Whether /dev/urandom is available to the PHP controller
148
-	 *
149
-	 * @return bool
150
-	 */
151
-	private function isUrandomAvailable() {
152
-		if(@file_exists('/dev/urandom')) {
153
-			$file = fopen('/dev/urandom', 'rb');
154
-			if($file) {
155
-				fclose($file);
156
-				return true;
157
-			}
158
-		}
159
-
160
-		return false;
161
-	}
162
-
163
-	/**
164
-	 * Public for the sake of unit-testing
165
-	 *
166
-	 * @return array
167
-	 */
168
-	protected function getCurlVersion() {
169
-		return curl_version();
170
-	}
171
-
172
-	/**
173
-	 * Check if the used  SSL lib is outdated. Older OpenSSL and NSS versions do
174
-	 * have multiple bugs which likely lead to problems in combination with
175
-	 * functionality required by ownCloud such as SNI.
176
-	 *
177
-	 * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
178
-	 * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
179
-	 * @return string
180
-	 */
181
-	private function isUsedTlsLibOutdated() {
182
-		// Don't run check when:
183
-		// 1. Server has `has_internet_connection` set to false
184
-		// 2. AppStore AND S2S is disabled
185
-		if(!$this->config->getSystemValue('has_internet_connection', true)) {
186
-			return '';
187
-		}
188
-		if(!$this->config->getSystemValue('appstoreenabled', true)
189
-			&& $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
190
-			&& $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
191
-			return '';
192
-		}
193
-
194
-		$versionString = $this->getCurlVersion();
195
-		if(isset($versionString['ssl_version'])) {
196
-			$versionString = $versionString['ssl_version'];
197
-		} else {
198
-			return '';
199
-		}
200
-
201
-		$features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
202
-		if(!$this->config->getSystemValue('appstoreenabled', true)) {
203
-			$features = (string)$this->l10n->t('Federated Cloud Sharing');
204
-		}
205
-
206
-		// Check if at least OpenSSL after 1.01d or 1.0.2b
207
-		if(strpos($versionString, 'OpenSSL/') === 0) {
208
-			$majorVersion = substr($versionString, 8, 5);
209
-			$patchRelease = substr($versionString, 13, 6);
210
-
211
-			if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
212
-				($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
213
-				return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['OpenSSL', $versionString, $features]);
214
-			}
215
-		}
216
-
217
-		// Check if NSS and perform heuristic check
218
-		if(strpos($versionString, 'NSS/') === 0) {
219
-			try {
220
-				$firstClient = $this->clientService->newClient();
221
-				$firstClient->get('https://nextcloud.com/');
222
-
223
-				$secondClient = $this->clientService->newClient();
224
-				$secondClient->get('https://nextcloud.com/');
225
-			} catch (ClientException $e) {
226
-				if($e->getResponse()->getStatusCode() === 400) {
227
-					return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['NSS', $versionString, $features]);
228
-				}
229
-			}
230
-		}
231
-
232
-		return '';
233
-	}
234
-
235
-	/**
236
-	 * Whether the version is outdated
237
-	 *
238
-	 * @return bool
239
-	 */
240
-	protected function isPhpOutdated() {
241
-		if (version_compare(PHP_VERSION, '7.0.0', '<')) {
242
-			return true;
243
-		}
244
-
245
-		return false;
246
-	}
247
-
248
-	/**
249
-	 * Whether the php version is still supported (at time of release)
250
-	 * according to: https://secure.php.net/supported-versions.php
251
-	 *
252
-	 * @return array
253
-	 */
254
-	private function isPhpSupported() {
255
-		return ['eol' => $this->isPhpOutdated(), 'version' => PHP_VERSION];
256
-	}
257
-
258
-	/**
259
-	 * Check if the reverse proxy configuration is working as expected
260
-	 *
261
-	 * @return bool
262
-	 */
263
-	private function forwardedForHeadersWorking() {
264
-		$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
265
-		$remoteAddress = $this->request->getRemoteAddress();
266
-
267
-		if (is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
268
-			return false;
269
-		}
270
-
271
-		// either not enabled or working correctly
272
-		return true;
273
-	}
274
-
275
-	/**
276
-	 * Checks if the correct memcache module for PHP is installed. Only
277
-	 * fails if memcached is configured and the working module is not installed.
278
-	 *
279
-	 * @return bool
280
-	 */
281
-	private function isCorrectMemcachedPHPModuleInstalled() {
282
-		if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') {
283
-			return true;
284
-		}
285
-
286
-		// there are two different memcached modules for PHP
287
-		// we only support memcached and not memcache
288
-		// https://code.google.com/p/memcached/wiki/PHPClientComparison
289
-		return !(!extension_loaded('memcached') && extension_loaded('memcache'));
290
-	}
291
-
292
-	/**
293
-	 * Checks if set_time_limit is not disabled.
294
-	 *
295
-	 * @return bool
296
-	 */
297
-	private function isSettimelimitAvailable() {
298
-		if (function_exists('set_time_limit')
299
-			&& strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
300
-			return true;
301
-		}
302
-
303
-		return false;
304
-	}
305
-
306
-	/**
307
-	 * @return RedirectResponse
308
-	 */
309
-	public function rescanFailedIntegrityCheck() {
310
-		$this->checker->runInstanceVerification();
311
-		return new RedirectResponse(
312
-			$this->urlGenerator->linkToRoute('settings.AdminSettings.index')
313
-		);
314
-	}
315
-
316
-	/**
317
-	 * @NoCSRFRequired
318
-	 * @return DataResponse
319
-	 */
320
-	public function getFailedIntegrityCheckFiles() {
321
-		if(!$this->checker->isCodeCheckEnforced()) {
322
-			return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
323
-		}
324
-
325
-		$completeResults = $this->checker->getResults();
326
-
327
-		if(!empty($completeResults)) {
328
-			$formattedTextResponse = 'Technical information
53
+    /** @var IConfig */
54
+    private $config;
55
+    /** @var IClientService */
56
+    private $clientService;
57
+    /** @var \OC_Util */
58
+    private $util;
59
+    /** @var IURLGenerator */
60
+    private $urlGenerator;
61
+    /** @var IL10N */
62
+    private $l10n;
63
+    /** @var Checker */
64
+    private $checker;
65
+    /** @var ILogger */
66
+    private $logger;
67
+
68
+    /**
69
+     * @param string $AppName
70
+     * @param IRequest $request
71
+     * @param IConfig $config
72
+     * @param IClientService $clientService
73
+     * @param IURLGenerator $urlGenerator
74
+     * @param \OC_Util $util
75
+     * @param IL10N $l10n
76
+     * @param Checker $checker
77
+     * @param ILogger $logger
78
+     */
79
+    public function __construct($AppName,
80
+                                IRequest $request,
81
+                                IConfig $config,
82
+                                IClientService $clientService,
83
+                                IURLGenerator $urlGenerator,
84
+                                \OC_Util $util,
85
+                                IL10N $l10n,
86
+                                Checker $checker,
87
+                                ILogger $logger) {
88
+        parent::__construct($AppName, $request);
89
+        $this->config = $config;
90
+        $this->clientService = $clientService;
91
+        $this->util = $util;
92
+        $this->urlGenerator = $urlGenerator;
93
+        $this->l10n = $l10n;
94
+        $this->checker = $checker;
95
+        $this->logger = $logger;
96
+    }
97
+
98
+    /**
99
+     * Checks if the ownCloud server can connect to the internet using HTTPS and HTTP
100
+     * @return bool
101
+     */
102
+    private function isInternetConnectionWorking() {
103
+        if ($this->config->getSystemValue('has_internet_connection', true) === false) {
104
+            return false;
105
+        }
106
+
107
+        $siteArray = ['www.nextcloud.com',
108
+                        'www.google.com',
109
+                        'www.github.com'];
110
+
111
+        foreach($siteArray as $site) {
112
+            if ($this->isSiteReachable($site)) {
113
+                return true;
114
+            }
115
+        }
116
+        return false;
117
+    }
118
+
119
+    /**
120
+     * Chceks if the ownCloud server can connect to a specific URL using both HTTPS and HTTP
121
+     * @return bool
122
+     */
123
+    private function isSiteReachable($sitename) {
124
+        $httpSiteName = 'http://' . $sitename . '/';
125
+        $httpsSiteName = 'https://' . $sitename . '/';
126
+
127
+        try {
128
+            $client = $this->clientService->newClient();
129
+            $client->get($httpSiteName);
130
+            $client->get($httpsSiteName);
131
+        } catch (\Exception $e) {
132
+            $this->logger->logException($e, ['app' => 'internet_connection_check']);
133
+            return false;
134
+        }
135
+        return true;
136
+    }
137
+
138
+    /**
139
+     * Checks whether a local memcache is installed or not
140
+     * @return bool
141
+     */
142
+    private function isMemcacheConfigured() {
143
+        return $this->config->getSystemValue('memcache.local', null) !== null;
144
+    }
145
+
146
+    /**
147
+     * Whether /dev/urandom is available to the PHP controller
148
+     *
149
+     * @return bool
150
+     */
151
+    private function isUrandomAvailable() {
152
+        if(@file_exists('/dev/urandom')) {
153
+            $file = fopen('/dev/urandom', 'rb');
154
+            if($file) {
155
+                fclose($file);
156
+                return true;
157
+            }
158
+        }
159
+
160
+        return false;
161
+    }
162
+
163
+    /**
164
+     * Public for the sake of unit-testing
165
+     *
166
+     * @return array
167
+     */
168
+    protected function getCurlVersion() {
169
+        return curl_version();
170
+    }
171
+
172
+    /**
173
+     * Check if the used  SSL lib is outdated. Older OpenSSL and NSS versions do
174
+     * have multiple bugs which likely lead to problems in combination with
175
+     * functionality required by ownCloud such as SNI.
176
+     *
177
+     * @link https://github.com/owncloud/core/issues/17446#issuecomment-122877546
178
+     * @link https://bugzilla.redhat.com/show_bug.cgi?id=1241172
179
+     * @return string
180
+     */
181
+    private function isUsedTlsLibOutdated() {
182
+        // Don't run check when:
183
+        // 1. Server has `has_internet_connection` set to false
184
+        // 2. AppStore AND S2S is disabled
185
+        if(!$this->config->getSystemValue('has_internet_connection', true)) {
186
+            return '';
187
+        }
188
+        if(!$this->config->getSystemValue('appstoreenabled', true)
189
+            && $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'no'
190
+            && $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes') === 'no') {
191
+            return '';
192
+        }
193
+
194
+        $versionString = $this->getCurlVersion();
195
+        if(isset($versionString['ssl_version'])) {
196
+            $versionString = $versionString['ssl_version'];
197
+        } else {
198
+            return '';
199
+        }
200
+
201
+        $features = (string)$this->l10n->t('installing and updating apps via the app store or Federated Cloud Sharing');
202
+        if(!$this->config->getSystemValue('appstoreenabled', true)) {
203
+            $features = (string)$this->l10n->t('Federated Cloud Sharing');
204
+        }
205
+
206
+        // Check if at least OpenSSL after 1.01d or 1.0.2b
207
+        if(strpos($versionString, 'OpenSSL/') === 0) {
208
+            $majorVersion = substr($versionString, 8, 5);
209
+            $patchRelease = substr($versionString, 13, 6);
210
+
211
+            if(($majorVersion === '1.0.1' && ord($patchRelease) < ord('d')) ||
212
+                ($majorVersion === '1.0.2' && ord($patchRelease) < ord('b'))) {
213
+                return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['OpenSSL', $versionString, $features]);
214
+            }
215
+        }
216
+
217
+        // Check if NSS and perform heuristic check
218
+        if(strpos($versionString, 'NSS/') === 0) {
219
+            try {
220
+                $firstClient = $this->clientService->newClient();
221
+                $firstClient->get('https://nextcloud.com/');
222
+
223
+                $secondClient = $this->clientService->newClient();
224
+                $secondClient->get('https://nextcloud.com/');
225
+            } catch (ClientException $e) {
226
+                if($e->getResponse()->getStatusCode() === 400) {
227
+                    return (string) $this->l10n->t('cURL is using an outdated %s version (%s). Please update your operating system or features such as %s will not work reliably.', ['NSS', $versionString, $features]);
228
+                }
229
+            }
230
+        }
231
+
232
+        return '';
233
+    }
234
+
235
+    /**
236
+     * Whether the version is outdated
237
+     *
238
+     * @return bool
239
+     */
240
+    protected function isPhpOutdated() {
241
+        if (version_compare(PHP_VERSION, '7.0.0', '<')) {
242
+            return true;
243
+        }
244
+
245
+        return false;
246
+    }
247
+
248
+    /**
249
+     * Whether the php version is still supported (at time of release)
250
+     * according to: https://secure.php.net/supported-versions.php
251
+     *
252
+     * @return array
253
+     */
254
+    private function isPhpSupported() {
255
+        return ['eol' => $this->isPhpOutdated(), 'version' => PHP_VERSION];
256
+    }
257
+
258
+    /**
259
+     * Check if the reverse proxy configuration is working as expected
260
+     *
261
+     * @return bool
262
+     */
263
+    private function forwardedForHeadersWorking() {
264
+        $trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
265
+        $remoteAddress = $this->request->getRemoteAddress();
266
+
267
+        if (is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
268
+            return false;
269
+        }
270
+
271
+        // either not enabled or working correctly
272
+        return true;
273
+    }
274
+
275
+    /**
276
+     * Checks if the correct memcache module for PHP is installed. Only
277
+     * fails if memcached is configured and the working module is not installed.
278
+     *
279
+     * @return bool
280
+     */
281
+    private function isCorrectMemcachedPHPModuleInstalled() {
282
+        if ($this->config->getSystemValue('memcache.distributed', null) !== '\OC\Memcache\Memcached') {
283
+            return true;
284
+        }
285
+
286
+        // there are two different memcached modules for PHP
287
+        // we only support memcached and not memcache
288
+        // https://code.google.com/p/memcached/wiki/PHPClientComparison
289
+        return !(!extension_loaded('memcached') && extension_loaded('memcache'));
290
+    }
291
+
292
+    /**
293
+     * Checks if set_time_limit is not disabled.
294
+     *
295
+     * @return bool
296
+     */
297
+    private function isSettimelimitAvailable() {
298
+        if (function_exists('set_time_limit')
299
+            && strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
300
+            return true;
301
+        }
302
+
303
+        return false;
304
+    }
305
+
306
+    /**
307
+     * @return RedirectResponse
308
+     */
309
+    public function rescanFailedIntegrityCheck() {
310
+        $this->checker->runInstanceVerification();
311
+        return new RedirectResponse(
312
+            $this->urlGenerator->linkToRoute('settings.AdminSettings.index')
313
+        );
314
+    }
315
+
316
+    /**
317
+     * @NoCSRFRequired
318
+     * @return DataResponse
319
+     */
320
+    public function getFailedIntegrityCheckFiles() {
321
+        if(!$this->checker->isCodeCheckEnforced()) {
322
+            return new DataDisplayResponse('Integrity checker has been disabled. Integrity cannot be verified.');
323
+        }
324
+
325
+        $completeResults = $this->checker->getResults();
326
+
327
+        if(!empty($completeResults)) {
328
+            $formattedTextResponse = 'Technical information
329 329
 =====================
330 330
 The following list covers which files have failed the integrity check. Please read
331 331
 the previous linked documentation to learn more about the errors and how to fix
@@ -334,112 +334,112 @@  discard block
 block discarded – undo
334 334
 Results
335 335
 =======
336 336
 ';
337
-			foreach($completeResults as $context => $contextResult) {
338
-				$formattedTextResponse .= "- $context\n";
339
-
340
-				foreach($contextResult as $category => $result) {
341
-					$formattedTextResponse .= "\t- $category\n";
342
-					if($category !== 'EXCEPTION') {
343
-						foreach ($result as $key => $results) {
344
-							$formattedTextResponse .= "\t\t- $key\n";
345
-						}
346
-					} else {
347
-						foreach ($result as $key => $results) {
348
-							$formattedTextResponse .= "\t\t- $results\n";
349
-						}
350
-					}
351
-
352
-				}
353
-			}
354
-
355
-			$formattedTextResponse .= '
337
+            foreach($completeResults as $context => $contextResult) {
338
+                $formattedTextResponse .= "- $context\n";
339
+
340
+                foreach($contextResult as $category => $result) {
341
+                    $formattedTextResponse .= "\t- $category\n";
342
+                    if($category !== 'EXCEPTION') {
343
+                        foreach ($result as $key => $results) {
344
+                            $formattedTextResponse .= "\t\t- $key\n";
345
+                        }
346
+                    } else {
347
+                        foreach ($result as $key => $results) {
348
+                            $formattedTextResponse .= "\t\t- $results\n";
349
+                        }
350
+                    }
351
+
352
+                }
353
+            }
354
+
355
+            $formattedTextResponse .= '
356 356
 Raw output
357 357
 ==========
358 358
 ';
359
-			$formattedTextResponse .= print_r($completeResults, true);
360
-		} else {
361
-			$formattedTextResponse = 'No errors have been found.';
362
-		}
363
-
364
-
365
-		$response = new DataDisplayResponse(
366
-			$formattedTextResponse,
367
-			Http::STATUS_OK,
368
-			[
369
-				'Content-Type' => 'text/plain',
370
-			]
371
-		);
372
-
373
-		return $response;
374
-	}
375
-
376
-	/**
377
-	 * Checks whether a PHP opcache is properly set up
378
-	 * @return bool
379
-	 */
380
-	protected function isOpcacheProperlySetup() {
381
-		$iniWrapper = new IniGetWrapper();
382
-
383
-		$isOpcacheProperlySetUp = true;
384
-
385
-		if(!$iniWrapper->getBool('opcache.enable')) {
386
-			$isOpcacheProperlySetUp = false;
387
-		}
388
-
389
-		if(!$iniWrapper->getBool('opcache.save_comments')) {
390
-			$isOpcacheProperlySetUp = false;
391
-		}
392
-
393
-		if(!$iniWrapper->getBool('opcache.enable_cli')) {
394
-			$isOpcacheProperlySetUp = false;
395
-		}
396
-
397
-		if($iniWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
398
-			$isOpcacheProperlySetUp = false;
399
-		}
400
-
401
-		if($iniWrapper->getNumeric('opcache.memory_consumption') < 128) {
402
-			$isOpcacheProperlySetUp = false;
403
-		}
404
-
405
-		if($iniWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
406
-			$isOpcacheProperlySetUp = false;
407
-		}
408
-
409
-		return $isOpcacheProperlySetUp;
410
-	}
411
-
412
-	/**
413
-	 * Check if the required FreeType functions are present
414
-	 * @return bool
415
-	 */
416
-	protected function hasFreeTypeSupport() {
417
-		return function_exists('imagettfbbox') && function_exists('imagettftext');
418
-	}
419
-
420
-	/**
421
-	 * @return DataResponse
422
-	 */
423
-	public function check() {
424
-		return new DataResponse(
425
-			[
426
-				'serverHasInternetConnection' => $this->isInternetConnectionWorking(),
427
-				'isMemcacheConfigured' => $this->isMemcacheConfigured(),
428
-				'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
429
-				'isUrandomAvailable' => $this->isUrandomAvailable(),
430
-				'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
431
-				'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
432
-				'phpSupported' => $this->isPhpSupported(),
433
-				'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
434
-				'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
435
-				'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
436
-				'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
437
-				'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
438
-				'isOpcacheProperlySetup' => $this->isOpcacheProperlySetup(),
439
-				'phpOpcacheDocumentation' => $this->urlGenerator->linkToDocs('admin-php-opcache'),
440
-				'isSettimelimitAvailable' => $this->isSettimelimitAvailable(),
441
-				'hasFreeTypeSupport' => $this->hasFreeTypeSupport(),
442
-			]
443
-		);
444
-	}
359
+            $formattedTextResponse .= print_r($completeResults, true);
360
+        } else {
361
+            $formattedTextResponse = 'No errors have been found.';
362
+        }
363
+
364
+
365
+        $response = new DataDisplayResponse(
366
+            $formattedTextResponse,
367
+            Http::STATUS_OK,
368
+            [
369
+                'Content-Type' => 'text/plain',
370
+            ]
371
+        );
372
+
373
+        return $response;
374
+    }
375
+
376
+    /**
377
+     * Checks whether a PHP opcache is properly set up
378
+     * @return bool
379
+     */
380
+    protected function isOpcacheProperlySetup() {
381
+        $iniWrapper = new IniGetWrapper();
382
+
383
+        $isOpcacheProperlySetUp = true;
384
+
385
+        if(!$iniWrapper->getBool('opcache.enable')) {
386
+            $isOpcacheProperlySetUp = false;
387
+        }
388
+
389
+        if(!$iniWrapper->getBool('opcache.save_comments')) {
390
+            $isOpcacheProperlySetUp = false;
391
+        }
392
+
393
+        if(!$iniWrapper->getBool('opcache.enable_cli')) {
394
+            $isOpcacheProperlySetUp = false;
395
+        }
396
+
397
+        if($iniWrapper->getNumeric('opcache.max_accelerated_files') < 10000) {
398
+            $isOpcacheProperlySetUp = false;
399
+        }
400
+
401
+        if($iniWrapper->getNumeric('opcache.memory_consumption') < 128) {
402
+            $isOpcacheProperlySetUp = false;
403
+        }
404
+
405
+        if($iniWrapper->getNumeric('opcache.interned_strings_buffer') < 8) {
406
+            $isOpcacheProperlySetUp = false;
407
+        }
408
+
409
+        return $isOpcacheProperlySetUp;
410
+    }
411
+
412
+    /**
413
+     * Check if the required FreeType functions are present
414
+     * @return bool
415
+     */
416
+    protected function hasFreeTypeSupport() {
417
+        return function_exists('imagettfbbox') && function_exists('imagettftext');
418
+    }
419
+
420
+    /**
421
+     * @return DataResponse
422
+     */
423
+    public function check() {
424
+        return new DataResponse(
425
+            [
426
+                'serverHasInternetConnection' => $this->isInternetConnectionWorking(),
427
+                'isMemcacheConfigured' => $this->isMemcacheConfigured(),
428
+                'memcacheDocs' => $this->urlGenerator->linkToDocs('admin-performance'),
429
+                'isUrandomAvailable' => $this->isUrandomAvailable(),
430
+                'securityDocs' => $this->urlGenerator->linkToDocs('admin-security'),
431
+                'isUsedTlsLibOutdated' => $this->isUsedTlsLibOutdated(),
432
+                'phpSupported' => $this->isPhpSupported(),
433
+                'forwardedForHeadersWorking' => $this->forwardedForHeadersWorking(),
434
+                'reverseProxyDocs' => $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
435
+                'isCorrectMemcachedPHPModuleInstalled' => $this->isCorrectMemcachedPHPModuleInstalled(),
436
+                'hasPassedCodeIntegrityCheck' => $this->checker->hasPassedCheck(),
437
+                'codeIntegrityCheckerDocumentation' => $this->urlGenerator->linkToDocs('admin-code-integrity'),
438
+                'isOpcacheProperlySetup' => $this->isOpcacheProperlySetup(),
439
+                'phpOpcacheDocumentation' => $this->urlGenerator->linkToDocs('admin-php-opcache'),
440
+                'isSettimelimitAvailable' => $this->isSettimelimitAvailable(),
441
+                'hasFreeTypeSupport' => $this->hasFreeTypeSupport(),
442
+            ]
443
+        );
444
+    }
445 445
 }
Please login to merge, or discard this patch.
apps/user_ldap/lib/Wizard.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1104,7 +1104,7 @@
 block discarded – undo
1104 1104
 	}
1105 1105
 
1106 1106
 	/**
1107
-	 * @param array $reqs
1107
+	 * @param string[] $reqs
1108 1108
 	 * @return bool
1109 1109
 	 */
1110 1110
 	private function checkRequirements($reqs) {
Please login to merge, or discard this patch.
Spacing   +154 added lines, -154 removed lines patch added patch discarded remove patch
@@ -71,7 +71,7 @@  discard block
 block discarded – undo
71 71
 	public function __construct(Configuration $configuration, ILDAPWrapper $ldap, Access $access) {
72 72
 		parent::__construct($ldap);
73 73
 		$this->configuration = $configuration;
74
-		if(is_null(Wizard::$l)) {
74
+		if (is_null(Wizard::$l)) {
75 75
 			Wizard::$l = \OC::$server->getL10N('user_ldap');
76 76
 		}
77 77
 		$this->access = $access;
@@ -79,7 +79,7 @@  discard block
 block discarded – undo
79 79
 	}
80 80
 
81 81
 	public function  __destruct() {
82
-		if($this->result->hasChanges()) {
82
+		if ($this->result->hasChanges()) {
83 83
 			$this->configuration->saveConfiguration();
84 84
 		}
85 85
 	}
@@ -94,18 +94,18 @@  discard block
 block discarded – undo
94 94
 	 */
95 95
 	public function countEntries($filter, $type) {
96 96
 		$reqs = array('ldapHost', 'ldapPort', 'ldapBase');
97
-		if($type === 'users') {
97
+		if ($type === 'users') {
98 98
 			$reqs[] = 'ldapUserFilter';
99 99
 		}
100
-		if(!$this->checkRequirements($reqs)) {
100
+		if (!$this->checkRequirements($reqs)) {
101 101
 			throw new \Exception('Requirements not met', 400);
102 102
 		}
103 103
 
104 104
 		$attr = array('dn'); // default
105 105
 		$limit = 1001;
106
-		if($type === 'groups') {
107
-			$result =  $this->access->countGroups($filter, $attr, $limit);
108
-		} else if($type === 'users') {
106
+		if ($type === 'groups') {
107
+			$result = $this->access->countGroups($filter, $attr, $limit);
108
+		} else if ($type === 'users') {
109 109
 			$result = $this->access->countUsers($filter, $attr, $limit);
110 110
 		} else if ($type === 'objects') {
111 111
 			$result = $this->access->countObjects($limit);
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
 	 */
126 126
 	private function formatCountResult($count) {
127 127
 		$formatted = ($count !== false) ? $count : 0;
128
-		if($formatted > 1000) {
128
+		if ($formatted > 1000) {
129 129
 			$formatted = '> 1000';
130 130
 		}
131 131
 		return $formatted;
@@ -134,7 +134,7 @@  discard block
 block discarded – undo
134 134
 	public function countGroups() {
135 135
 		$filter = $this->configuration->ldapGroupFilter;
136 136
 
137
-		if(empty($filter)) {
137
+		if (empty($filter)) {
138 138
 			$output = self::$l->n('%s group found', '%s groups found', 0, array(0));
139 139
 			$this->result->addChange('ldap_group_count', $output);
140 140
 			return $this->result;
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 			$groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups'));
145 145
 		} catch (\Exception $e) {
146 146
 			//400 can be ignored, 500 is forwarded
147
-			if($e->getCode() === 500) {
147
+			if ($e->getCode() === 500) {
148 148
 				throw $e;
149 149
 			}
150 150
 			return false;
@@ -176,7 +176,7 @@  discard block
 block discarded – undo
176 176
 	public function countInBaseDN() {
177 177
 		// we don't need to provide a filter in this case
178 178
 		$total = $this->countEntries(null, 'objects');
179
-		if($total === false) {
179
+		if ($total === false) {
180 180
 			throw new \Exception('invalid results received');
181 181
 		}
182 182
 		$this->result->addChange('ldap_test_base', $total);
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
 	 * @return int|bool
191 191
 	 */
192 192
 	public function countUsersWithAttribute($attr, $existsCheck = false) {
193
-		if(!$this->checkRequirements(array('ldapHost',
193
+		if (!$this->checkRequirements(array('ldapHost',
194 194
 										   'ldapPort',
195 195
 										   'ldapBase',
196 196
 										   'ldapUserFilter',
@@ -200,7 +200,7 @@  discard block
 block discarded – undo
200 200
 
201 201
 		$filter = $this->access->combineFilterWithAnd(array(
202 202
 			$this->configuration->ldapUserFilter,
203
-			$attr . '=*'
203
+			$attr.'=*'
204 204
 		));
205 205
 
206 206
 		$limit = ($existsCheck === false) ? null : 1;
@@ -215,7 +215,7 @@  discard block
 block discarded – undo
215 215
 	 * @throws \Exception
216 216
 	 */
217 217
 	public function detectUserDisplayNameAttribute() {
218
-		if(!$this->checkRequirements(array('ldapHost',
218
+		if (!$this->checkRequirements(array('ldapHost',
219 219
 										'ldapPort',
220 220
 										'ldapBase',
221 221
 										'ldapUserFilter',
@@ -227,8 +227,8 @@  discard block
 block discarded – undo
227 227
 		if ($attr !== '' && $attr !== 'displayName') {
228 228
 			// most likely not the default value with upper case N,
229 229
 			// verify it still produces a result
230
-			$count = (int)$this->countUsersWithAttribute($attr, true);
231
-			if($count > 0) {
230
+			$count = (int) $this->countUsersWithAttribute($attr, true);
231
+			if ($count > 0) {
232 232
 				//no change, but we sent it back to make sure the user interface
233 233
 				//is still correct, even if the ajax call was cancelled meanwhile
234 234
 				$this->result->addChange('ldap_display_name', $attr);
@@ -239,9 +239,9 @@  discard block
 block discarded – undo
239 239
 		// first attribute that has at least one result wins
240 240
 		$displayNameAttrs = array('displayname', 'cn');
241 241
 		foreach ($displayNameAttrs as $attr) {
242
-			$count = (int)$this->countUsersWithAttribute($attr, true);
242
+			$count = (int) $this->countUsersWithAttribute($attr, true);
243 243
 
244
-			if($count > 0) {
244
+			if ($count > 0) {
245 245
 				$this->applyFind('ldap_display_name', $attr);
246 246
 				return $this->result;
247 247
 			}
@@ -257,7 +257,7 @@  discard block
 block discarded – undo
257 257
 	 * @return WizardResult|bool
258 258
 	 */
259 259
 	public function detectEmailAttribute() {
260
-		if(!$this->checkRequirements(array('ldapHost',
260
+		if (!$this->checkRequirements(array('ldapHost',
261 261
 										   'ldapPort',
262 262
 										   'ldapBase',
263 263
 										   'ldapUserFilter',
@@ -267,8 +267,8 @@  discard block
 block discarded – undo
267 267
 
268 268
 		$attr = $this->configuration->ldapEmailAttribute;
269 269
 		if ($attr !== '') {
270
-			$count = (int)$this->countUsersWithAttribute($attr, true);
271
-			if($count > 0) {
270
+			$count = (int) $this->countUsersWithAttribute($attr, true);
271
+			if ($count > 0) {
272 272
 				return false;
273 273
 			}
274 274
 			$writeLog = true;
@@ -279,19 +279,19 @@  discard block
 block discarded – undo
279 279
 		$emailAttributes = array('mail', 'mailPrimaryAddress');
280 280
 		$winner = '';
281 281
 		$maxUsers = 0;
282
-		foreach($emailAttributes as $attr) {
282
+		foreach ($emailAttributes as $attr) {
283 283
 			$count = $this->countUsersWithAttribute($attr);
284
-			if($count > $maxUsers) {
284
+			if ($count > $maxUsers) {
285 285
 				$maxUsers = $count;
286 286
 				$winner = $attr;
287 287
 			}
288 288
 		}
289 289
 
290
-		if($winner !== '') {
290
+		if ($winner !== '') {
291 291
 			$this->applyFind('ldap_email_attr', $winner);
292
-			if($writeLog) {
293
-				\OCP\Util::writeLog('user_ldap', 'The mail attribute has ' .
294
-					'automatically been reset, because the original value ' .
292
+			if ($writeLog) {
293
+				\OCP\Util::writeLog('user_ldap', 'The mail attribute has '.
294
+					'automatically been reset, because the original value '.
295 295
 					'did not return any results.', \OCP\Util::INFO);
296 296
 			}
297 297
 		}
@@ -304,7 +304,7 @@  discard block
 block discarded – undo
304 304
 	 * @throws \Exception
305 305
 	 */
306 306
 	public function determineAttributes() {
307
-		if(!$this->checkRequirements(array('ldapHost',
307
+		if (!$this->checkRequirements(array('ldapHost',
308 308
 										   'ldapPort',
309 309
 										   'ldapBase',
310 310
 										   'ldapUserFilter',
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
 		$this->result->addOptions('ldap_loginfilter_attributes', $attributes);
321 321
 
322 322
 		$selected = $this->configuration->ldapLoginFilterAttributes;
323
-		if(is_array($selected) && !empty($selected)) {
323
+		if (is_array($selected) && !empty($selected)) {
324 324
 			$this->result->addChange('ldap_loginfilter_attributes', $selected);
325 325
 		}
326 326
 
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
 	 * @throws \Exception
334 334
 	 */
335 335
 	private function getUserAttributes() {
336
-		if(!$this->checkRequirements(array('ldapHost',
336
+		if (!$this->checkRequirements(array('ldapHost',
337 337
 										   'ldapPort',
338 338
 										   'ldapBase',
339 339
 										   'ldapUserFilter',
@@ -341,20 +341,20 @@  discard block
 block discarded – undo
341 341
 			return  false;
342 342
 		}
343 343
 		$cr = $this->getConnection();
344
-		if(!$cr) {
344
+		if (!$cr) {
345 345
 			throw new \Exception('Could not connect to LDAP');
346 346
 		}
347 347
 
348 348
 		$base = $this->configuration->ldapBase[0];
349 349
 		$filter = $this->configuration->ldapUserFilter;
350 350
 		$rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1);
351
-		if(!$this->ldap->isResource($rr)) {
351
+		if (!$this->ldap->isResource($rr)) {
352 352
 			return false;
353 353
 		}
354 354
 		$er = $this->ldap->firstEntry($cr, $rr);
355 355
 		$attributes = $this->ldap->getAttributes($cr, $er);
356 356
 		$pureAttributes = array();
357
-		for($i = 0; $i < $attributes['count']; $i++) {
357
+		for ($i = 0; $i < $attributes['count']; $i++) {
358 358
 			$pureAttributes[] = $attributes[$i];
359 359
 		}
360 360
 
@@ -389,23 +389,23 @@  discard block
 block discarded – undo
389 389
 	 * @throws \Exception
390 390
 	 */
391 391
 	private function determineGroups($dbKey, $confKey, $testMemberOf = true) {
392
-		if(!$this->checkRequirements(array('ldapHost',
392
+		if (!$this->checkRequirements(array('ldapHost',
393 393
 										   'ldapPort',
394 394
 										   'ldapBase',
395 395
 										   ))) {
396 396
 			return  false;
397 397
 		}
398 398
 		$cr = $this->getConnection();
399
-		if(!$cr) {
399
+		if (!$cr) {
400 400
 			throw new \Exception('Could not connect to LDAP');
401 401
 		}
402 402
 
403 403
 		$this->fetchGroups($dbKey, $confKey);
404 404
 
405
-		if($testMemberOf) {
405
+		if ($testMemberOf) {
406 406
 			$this->configuration->hasMemberOfFilterSupport = $this->testMemberOf();
407 407
 			$this->result->markChange();
408
-			if(!$this->configuration->hasMemberOfFilterSupport) {
408
+			if (!$this->configuration->hasMemberOfFilterSupport) {
409 409
 				throw new \Exception('memberOf is not supported by the server');
410 410
 			}
411 411
 		}
@@ -425,7 +425,7 @@  discard block
 block discarded – undo
425 425
 		$obclasses = array('posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames', 'groupOfUniqueNames');
426 426
 
427 427
 		$filterParts = array();
428
-		foreach($obclasses as $obclass) {
428
+		foreach ($obclasses as $obclass) {
429 429
 			$filterParts[] = 'objectclass='.$obclass;
430 430
 		}
431 431
 		//we filter for everything
@@ -442,8 +442,8 @@  discard block
 block discarded – undo
442 442
 			// we need to request dn additionally here, otherwise memberOf
443 443
 			// detection will fail later
444 444
 			$result = $this->access->searchGroups($filter, array('cn', 'dn'), $limit, $offset);
445
-			foreach($result as $item) {
446
-				if(!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) {
445
+			foreach ($result as $item) {
446
+				if (!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) {
447 447
 					// just in case - no issue known
448 448
 					continue;
449 449
 				}
@@ -453,7 +453,7 @@  discard block
 block discarded – undo
453 453
 			$offset += $limit;
454 454
 		} while ($this->access->hasMoreResults());
455 455
 
456
-		if(count($groupNames) > 0) {
456
+		if (count($groupNames) > 0) {
457 457
 			natsort($groupNames);
458 458
 			$this->result->addOptions($dbKey, array_values($groupNames));
459 459
 		} else {
@@ -461,7 +461,7 @@  discard block
 block discarded – undo
461 461
 		}
462 462
 
463 463
 		$setFeatures = $this->configuration->$confKey;
464
-		if(is_array($setFeatures) && !empty($setFeatures)) {
464
+		if (is_array($setFeatures) && !empty($setFeatures)) {
465 465
 			//something is already configured? pre-select it.
466 466
 			$this->result->addChange($dbKey, $setFeatures);
467 467
 		}
@@ -469,14 +469,14 @@  discard block
 block discarded – undo
469 469
 	}
470 470
 
471 471
 	public function determineGroupMemberAssoc() {
472
-		if(!$this->checkRequirements(array('ldapHost',
472
+		if (!$this->checkRequirements(array('ldapHost',
473 473
 										   'ldapPort',
474 474
 										   'ldapGroupFilter',
475 475
 										   ))) {
476 476
 			return  false;
477 477
 		}
478 478
 		$attribute = $this->detectGroupMemberAssoc();
479
-		if($attribute === false) {
479
+		if ($attribute === false) {
480 480
 			return false;
481 481
 		}
482 482
 		$this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute));
@@ -491,14 +491,14 @@  discard block
 block discarded – undo
491 491
 	 * @throws \Exception
492 492
 	 */
493 493
 	public function determineGroupObjectClasses() {
494
-		if(!$this->checkRequirements(array('ldapHost',
494
+		if (!$this->checkRequirements(array('ldapHost',
495 495
 										   'ldapPort',
496 496
 										   'ldapBase',
497 497
 										   ))) {
498 498
 			return  false;
499 499
 		}
500 500
 		$cr = $this->getConnection();
501
-		if(!$cr) {
501
+		if (!$cr) {
502 502
 			throw new \Exception('Could not connect to LDAP');
503 503
 		}
504 504
 
@@ -518,14 +518,14 @@  discard block
 block discarded – undo
518 518
 	 * @throws \Exception
519 519
 	 */
520 520
 	public function determineUserObjectClasses() {
521
-		if(!$this->checkRequirements(array('ldapHost',
521
+		if (!$this->checkRequirements(array('ldapHost',
522 522
 										   'ldapPort',
523 523
 										   'ldapBase',
524 524
 										   ))) {
525 525
 			return  false;
526 526
 		}
527 527
 		$cr = $this->getConnection();
528
-		if(!$cr) {
528
+		if (!$cr) {
529 529
 			throw new \Exception('Could not connect to LDAP');
530 530
 		}
531 531
 
@@ -548,7 +548,7 @@  discard block
 block discarded – undo
548 548
 	 * @throws \Exception
549 549
 	 */
550 550
 	public function getGroupFilter() {
551
-		if(!$this->checkRequirements(array('ldapHost',
551
+		if (!$this->checkRequirements(array('ldapHost',
552 552
 										   'ldapPort',
553 553
 										   'ldapBase',
554 554
 										   ))) {
@@ -572,7 +572,7 @@  discard block
 block discarded – undo
572 572
 	 * @throws \Exception
573 573
 	 */
574 574
 	public function getUserListFilter() {
575
-		if(!$this->checkRequirements(array('ldapHost',
575
+		if (!$this->checkRequirements(array('ldapHost',
576 576
 										   'ldapPort',
577 577
 										   'ldapBase',
578 578
 										   ))) {
@@ -585,7 +585,7 @@  discard block
 block discarded – undo
585 585
 			$this->applyFind('ldap_display_name', $d['ldap_display_name']);
586 586
 		}
587 587
 		$filter = $this->composeLdapFilter(self::LFILTER_USER_LIST);
588
-		if(!$filter) {
588
+		if (!$filter) {
589 589
 			throw new \Exception('Cannot create filter');
590 590
 		}
591 591
 
@@ -598,7 +598,7 @@  discard block
 block discarded – undo
598 598
 	 * @throws \Exception
599 599
 	 */
600 600
 	public function getUserLoginFilter() {
601
-		if(!$this->checkRequirements(array('ldapHost',
601
+		if (!$this->checkRequirements(array('ldapHost',
602 602
 										   'ldapPort',
603 603
 										   'ldapBase',
604 604
 										   'ldapUserFilter',
@@ -607,7 +607,7 @@  discard block
 block discarded – undo
607 607
 		}
608 608
 
609 609
 		$filter = $this->composeLdapFilter(self::LFILTER_LOGIN);
610
-		if(!$filter) {
610
+		if (!$filter) {
611 611
 			throw new \Exception('Cannot create filter');
612 612
 		}
613 613
 
@@ -621,7 +621,7 @@  discard block
 block discarded – undo
621 621
 	 * @throws \Exception
622 622
 	 */
623 623
 	public function testLoginName($loginName) {
624
-		if(!$this->checkRequirements(array('ldapHost',
624
+		if (!$this->checkRequirements(array('ldapHost',
625 625
 			'ldapPort',
626 626
 			'ldapBase',
627 627
 			'ldapLoginFilter',
@@ -630,17 +630,17 @@  discard block
 block discarded – undo
630 630
 		}
631 631
 
632 632
 		$cr = $this->access->connection->getConnectionResource();
633
-		if(!$this->ldap->isResource($cr)) {
633
+		if (!$this->ldap->isResource($cr)) {
634 634
 			throw new \Exception('connection error');
635 635
 		}
636 636
 
637
-		if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8')
637
+		if (mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8')
638 638
 			=== false) {
639 639
 			throw new \Exception('missing placeholder');
640 640
 		}
641 641
 
642 642
 		$users = $this->access->countUsersByLoginName($loginName);
643
-		if($this->ldap->errno($cr) !== 0) {
643
+		if ($this->ldap->errno($cr) !== 0) {
644 644
 			throw new \Exception($this->ldap->error($cr));
645 645
 		}
646 646
 		$filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
@@ -655,22 +655,22 @@  discard block
 block discarded – undo
655 655
 	 * @throws \Exception
656 656
 	 */
657 657
 	public function guessPortAndTLS() {
658
-		if(!$this->checkRequirements(array('ldapHost',
658
+		if (!$this->checkRequirements(array('ldapHost',
659 659
 										   ))) {
660 660
 			return false;
661 661
 		}
662 662
 		$this->checkHost();
663 663
 		$portSettings = $this->getPortSettingsToTry();
664 664
 
665
-		if(!is_array($portSettings)) {
665
+		if (!is_array($portSettings)) {
666 666
 			throw new \Exception(print_r($portSettings, true));
667 667
 		}
668 668
 
669 669
 		//proceed from the best configuration and return on first success
670
-		foreach($portSettings as $setting) {
670
+		foreach ($portSettings as $setting) {
671 671
 			$p = $setting['port'];
672 672
 			$t = $setting['tls'];
673
-			\OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG);
673
+			\OCP\Util::writeLog('user_ldap', 'Wiz: trying port '.$p.', TLS '.$t, \OCP\Util::DEBUG);
674 674
 			//connectAndBind may throw Exception, it needs to be catched by the
675 675
 			//callee of this method
676 676
 
@@ -680,7 +680,7 @@  discard block
 block discarded – undo
680 680
 				// any reply other than -1 (= cannot connect) is already okay,
681 681
 				// because then we found the server
682 682
 				// unavailable startTLS returns -11
683
-				if($e->getCode() > 0) {
683
+				if ($e->getCode() > 0) {
684 684
 					$settingsFound = true;
685 685
 				} else {
686 686
 					throw $e;
@@ -690,10 +690,10 @@  discard block
 block discarded – undo
690 690
 			if ($settingsFound === true) {
691 691
 				$config = array(
692 692
 					'ldapPort' => $p,
693
-					'ldapTLS' => (int)$t
693
+					'ldapTLS' => (int) $t
694 694
 				);
695 695
 				$this->configuration->setConfiguration($config);
696
-				\OCP\Util::writeLog('user_ldap', 'Wiz: detected Port ' . $p, \OCP\Util::DEBUG);
696
+				\OCP\Util::writeLog('user_ldap', 'Wiz: detected Port '.$p, \OCP\Util::DEBUG);
697 697
 				$this->result->addChange('ldap_port', $p);
698 698
 				return $this->result;
699 699
 			}
@@ -708,7 +708,7 @@  discard block
 block discarded – undo
708 708
 	 * @return WizardResult|false WizardResult on success, false otherwise
709 709
 	 */
710 710
 	public function guessBaseDN() {
711
-		if(!$this->checkRequirements(array('ldapHost',
711
+		if (!$this->checkRequirements(array('ldapHost',
712 712
 										   'ldapPort',
713 713
 										   ))) {
714 714
 			return false;
@@ -717,9 +717,9 @@  discard block
 block discarded – undo
717 717
 		//check whether a DN is given in the agent name (99.9% of all cases)
718 718
 		$base = null;
719 719
 		$i = stripos($this->configuration->ldapAgentName, 'dc=');
720
-		if($i !== false) {
720
+		if ($i !== false) {
721 721
 			$base = substr($this->configuration->ldapAgentName, $i);
722
-			if($this->testBaseDN($base)) {
722
+			if ($this->testBaseDN($base)) {
723 723
 				$this->applyFind('ldap_base', $base);
724 724
 				return $this->result;
725 725
 			}
@@ -730,13 +730,13 @@  discard block
 block discarded – undo
730 730
 		//a base DN
731 731
 		$helper = new Helper(\OC::$server->getConfig());
732 732
 		$domain = $helper->getDomainFromURL($this->configuration->ldapHost);
733
-		if(!$domain) {
733
+		if (!$domain) {
734 734
 			return false;
735 735
 		}
736 736
 
737 737
 		$dparts = explode('.', $domain);
738
-		while(count($dparts) > 0) {
739
-			$base2 = 'dc=' . implode(',dc=', $dparts);
738
+		while (count($dparts) > 0) {
739
+			$base2 = 'dc='.implode(',dc=', $dparts);
740 740
 			if ($base !== $base2 && $this->testBaseDN($base2)) {
741 741
 				$this->applyFind('ldap_base', $base2);
742 742
 				return $this->result;
@@ -769,7 +769,7 @@  discard block
 block discarded – undo
769 769
 		$hostInfo = parse_url($host);
770 770
 
771 771
 		//removes Port from Host
772
-		if(is_array($hostInfo) && isset($hostInfo['port'])) {
772
+		if (is_array($hostInfo) && isset($hostInfo['port'])) {
773 773
 			$port = $hostInfo['port'];
774 774
 			$host = str_replace(':'.$port, '', $host);
775 775
 			$this->applyFind('ldap_host', $host);
@@ -786,30 +786,30 @@  discard block
 block discarded – undo
786 786
 	private function detectGroupMemberAssoc() {
787 787
 		$possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'gidNumber');
788 788
 		$filter = $this->configuration->ldapGroupFilter;
789
-		if(empty($filter)) {
789
+		if (empty($filter)) {
790 790
 			return false;
791 791
 		}
792 792
 		$cr = $this->getConnection();
793
-		if(!$cr) {
793
+		if (!$cr) {
794 794
 			throw new \Exception('Could not connect to LDAP');
795 795
 		}
796 796
 		$base = $this->configuration->ldapBase[0];
797 797
 		$rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000);
798
-		if(!$this->ldap->isResource($rr)) {
798
+		if (!$this->ldap->isResource($rr)) {
799 799
 			return false;
800 800
 		}
801 801
 		$er = $this->ldap->firstEntry($cr, $rr);
802
-		while(is_resource($er)) {
802
+		while (is_resource($er)) {
803 803
 			$this->ldap->getDN($cr, $er);
804 804
 			$attrs = $this->ldap->getAttributes($cr, $er);
805 805
 			$result = array();
806 806
 			$possibleAttrsCount = count($possibleAttrs);
807
-			for($i = 0; $i < $possibleAttrsCount; $i++) {
808
-				if(isset($attrs[$possibleAttrs[$i]])) {
807
+			for ($i = 0; $i < $possibleAttrsCount; $i++) {
808
+				if (isset($attrs[$possibleAttrs[$i]])) {
809 809
 					$result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count'];
810 810
 				}
811 811
 			}
812
-			if(!empty($result)) {
812
+			if (!empty($result)) {
813 813
 				natsort($result);
814 814
 				return key($result);
815 815
 			}
@@ -828,14 +828,14 @@  discard block
 block discarded – undo
828 828
 	 */
829 829
 	private function testBaseDN($base) {
830 830
 		$cr = $this->getConnection();
831
-		if(!$cr) {
831
+		if (!$cr) {
832 832
 			throw new \Exception('Could not connect to LDAP');
833 833
 		}
834 834
 
835 835
 		//base is there, let's validate it. If we search for anything, we should
836 836
 		//get a result set > 0 on a proper base
837 837
 		$rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1);
838
-		if(!$this->ldap->isResource($rr)) {
838
+		if (!$this->ldap->isResource($rr)) {
839 839
 			$errorNo  = $this->ldap->errno($cr);
840 840
 			$errorMsg = $this->ldap->error($cr);
841 841
 			\OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base.
@@ -857,11 +857,11 @@  discard block
 block discarded – undo
857 857
 	 */
858 858
 	private function testMemberOf() {
859 859
 		$cr = $this->getConnection();
860
-		if(!$cr) {
860
+		if (!$cr) {
861 861
 			throw new \Exception('Could not connect to LDAP');
862 862
 		}
863 863
 		$result = $this->access->countUsers('memberOf=*', array('memberOf'), 1);
864
-		if(is_int($result) &&  $result > 0) {
864
+		if (is_int($result) && $result > 0) {
865 865
 			return true;
866 866
 		}
867 867
 		return false;
@@ -882,27 +882,27 @@  discard block
 block discarded – undo
882 882
 			case self::LFILTER_USER_LIST:
883 883
 				$objcs = $this->configuration->ldapUserFilterObjectclass;
884 884
 				//glue objectclasses
885
-				if(is_array($objcs) && count($objcs) > 0) {
885
+				if (is_array($objcs) && count($objcs) > 0) {
886 886
 					$filter .= '(|';
887
-					foreach($objcs as $objc) {
888
-						$filter .= '(objectclass=' . $objc . ')';
887
+					foreach ($objcs as $objc) {
888
+						$filter .= '(objectclass='.$objc.')';
889 889
 					}
890 890
 					$filter .= ')';
891 891
 					$parts++;
892 892
 				}
893 893
 				//glue group memberships
894
-				if($this->configuration->hasMemberOfFilterSupport) {
894
+				if ($this->configuration->hasMemberOfFilterSupport) {
895 895
 					$cns = $this->configuration->ldapUserFilterGroups;
896
-					if(is_array($cns) && count($cns) > 0) {
896
+					if (is_array($cns) && count($cns) > 0) {
897 897
 						$filter .= '(|';
898 898
 						$cr = $this->getConnection();
899
-						if(!$cr) {
899
+						if (!$cr) {
900 900
 							throw new \Exception('Could not connect to LDAP');
901 901
 						}
902 902
 						$base = $this->configuration->ldapBase[0];
903
-						foreach($cns as $cn) {
904
-							$rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken'));
905
-							if(!$this->ldap->isResource($rr)) {
903
+						foreach ($cns as $cn) {
904
+							$rr = $this->ldap->search($cr, $base, 'cn='.$cn, array('dn', 'primaryGroupToken'));
905
+							if (!$this->ldap->isResource($rr)) {
906 906
 								continue;
907 907
 							}
908 908
 							$er = $this->ldap->firstEntry($cr, $rr);
@@ -911,11 +911,11 @@  discard block
 block discarded – undo
911 911
 							if ($dn === false || $dn === '') {
912 912
 								continue;
913 913
 							}
914
-							$filterPart = '(memberof=' . $dn . ')';
915
-							if(isset($attrs['primaryGroupToken'])) {
914
+							$filterPart = '(memberof='.$dn.')';
915
+							if (isset($attrs['primaryGroupToken'])) {
916 916
 								$pgt = $attrs['primaryGroupToken'][0];
917
-								$primaryFilterPart = '(primaryGroupID=' . $pgt .')';
918
-								$filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
917
+								$primaryFilterPart = '(primaryGroupID='.$pgt.')';
918
+								$filterPart = '(|'.$filterPart.$primaryFilterPart.')';
919 919
 							}
920 920
 							$filter .= $filterPart;
921 921
 						}
@@ -924,8 +924,8 @@  discard block
 block discarded – undo
924 924
 					$parts++;
925 925
 				}
926 926
 				//wrap parts in AND condition
927
-				if($parts > 1) {
928
-					$filter = '(&' . $filter . ')';
927
+				if ($parts > 1) {
928
+					$filter = '(&'.$filter.')';
929 929
 				}
930 930
 				if ($filter === '') {
931 931
 					$filter = '(objectclass=*)';
@@ -935,27 +935,27 @@  discard block
 block discarded – undo
935 935
 			case self::LFILTER_GROUP_LIST:
936 936
 				$objcs = $this->configuration->ldapGroupFilterObjectclass;
937 937
 				//glue objectclasses
938
-				if(is_array($objcs) && count($objcs) > 0) {
938
+				if (is_array($objcs) && count($objcs) > 0) {
939 939
 					$filter .= '(|';
940
-					foreach($objcs as $objc) {
941
-						$filter .= '(objectclass=' . $objc . ')';
940
+					foreach ($objcs as $objc) {
941
+						$filter .= '(objectclass='.$objc.')';
942 942
 					}
943 943
 					$filter .= ')';
944 944
 					$parts++;
945 945
 				}
946 946
 				//glue group memberships
947 947
 				$cns = $this->configuration->ldapGroupFilterGroups;
948
-				if(is_array($cns) && count($cns) > 0) {
948
+				if (is_array($cns) && count($cns) > 0) {
949 949
 					$filter .= '(|';
950
-					foreach($cns as $cn) {
951
-						$filter .= '(cn=' . $cn . ')';
950
+					foreach ($cns as $cn) {
951
+						$filter .= '(cn='.$cn.')';
952 952
 					}
953 953
 					$filter .= ')';
954 954
 				}
955 955
 				$parts++;
956 956
 				//wrap parts in AND condition
957
-				if($parts > 1) {
958
-					$filter = '(&' . $filter . ')';
957
+				if ($parts > 1) {
958
+					$filter = '(&'.$filter.')';
959 959
 				}
960 960
 				break;
961 961
 
@@ -967,47 +967,47 @@  discard block
 block discarded – undo
967 967
 				$userAttributes = array_change_key_case(array_flip($userAttributes));
968 968
 				$parts = 0;
969 969
 
970
-				if($this->configuration->ldapLoginFilterUsername === '1') {
970
+				if ($this->configuration->ldapLoginFilterUsername === '1') {
971 971
 					$attr = '';
972
-					if(isset($userAttributes['uid'])) {
972
+					if (isset($userAttributes['uid'])) {
973 973
 						$attr = 'uid';
974
-					} else if(isset($userAttributes['samaccountname'])) {
974
+					} else if (isset($userAttributes['samaccountname'])) {
975 975
 						$attr = 'samaccountname';
976
-					} else if(isset($userAttributes['cn'])) {
976
+					} else if (isset($userAttributes['cn'])) {
977 977
 						//fallback
978 978
 						$attr = 'cn';
979 979
 					}
980 980
 					if ($attr !== '') {
981
-						$filterUsername = '(' . $attr . $loginpart . ')';
981
+						$filterUsername = '('.$attr.$loginpart.')';
982 982
 						$parts++;
983 983
 					}
984 984
 				}
985 985
 
986 986
 				$filterEmail = '';
987
-				if($this->configuration->ldapLoginFilterEmail === '1') {
987
+				if ($this->configuration->ldapLoginFilterEmail === '1') {
988 988
 					$filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))';
989 989
 					$parts++;
990 990
 				}
991 991
 
992 992
 				$filterAttributes = '';
993 993
 				$attrsToFilter = $this->configuration->ldapLoginFilterAttributes;
994
-				if(is_array($attrsToFilter) && count($attrsToFilter) > 0) {
994
+				if (is_array($attrsToFilter) && count($attrsToFilter) > 0) {
995 995
 					$filterAttributes = '(|';
996
-					foreach($attrsToFilter as $attribute) {
997
-						$filterAttributes .= '(' . $attribute . $loginpart . ')';
996
+					foreach ($attrsToFilter as $attribute) {
997
+						$filterAttributes .= '('.$attribute.$loginpart.')';
998 998
 					}
999 999
 					$filterAttributes .= ')';
1000 1000
 					$parts++;
1001 1001
 				}
1002 1002
 
1003 1003
 				$filterLogin = '';
1004
-				if($parts > 1) {
1004
+				if ($parts > 1) {
1005 1005
 					$filterLogin = '(|';
1006 1006
 				}
1007 1007
 				$filterLogin .= $filterUsername;
1008 1008
 				$filterLogin .= $filterEmail;
1009 1009
 				$filterLogin .= $filterAttributes;
1010
-				if($parts > 1) {
1010
+				if ($parts > 1) {
1011 1011
 					$filterLogin .= ')';
1012 1012
 				}
1013 1013
 
@@ -1032,12 +1032,12 @@  discard block
 block discarded – undo
1032 1032
 		//connect, does not really trigger any server communication
1033 1033
 		$host = $this->configuration->ldapHost;
1034 1034
 		$hostInfo = parse_url($host);
1035
-		if(!$hostInfo) {
1035
+		if (!$hostInfo) {
1036 1036
 			throw new \Exception(self::$l->t('Invalid Host'));
1037 1037
 		}
1038 1038
 		\OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG);
1039 1039
 		$cr = $this->ldap->connect($host, $port);
1040
-		if(!is_resource($cr)) {
1040
+		if (!is_resource($cr)) {
1041 1041
 			throw new \Exception(self::$l->t('Invalid Host'));
1042 1042
 		}
1043 1043
 
@@ -1047,9 +1047,9 @@  discard block
 block discarded – undo
1047 1047
 		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1048 1048
 
1049 1049
 		try {
1050
-			if($tls) {
1050
+			if ($tls) {
1051 1051
 				$isTlsWorking = @$this->ldap->startTls($cr);
1052
-				if(!$isTlsWorking) {
1052
+				if (!$isTlsWorking) {
1053 1053
 					return false;
1054 1054
 				}
1055 1055
 			}
@@ -1063,17 +1063,17 @@  discard block
 block discarded – undo
1063 1063
 			$errNo = $this->ldap->errno($cr);
1064 1064
 			$error = ldap_error($cr);
1065 1065
 			$this->ldap->unbind($cr);
1066
-		} catch(ServerNotAvailableException $e) {
1066
+		} catch (ServerNotAvailableException $e) {
1067 1067
 			return false;
1068 1068
 		}
1069 1069
 
1070
-		if($login === true) {
1070
+		if ($login === true) {
1071 1071
 			$this->ldap->unbind($cr);
1072
-			\OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '. $port . ' TLS ' . (int)$tls, \OCP\Util::DEBUG);
1072
+			\OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '.$port.' TLS '.(int) $tls, \OCP\Util::DEBUG);
1073 1073
 			return true;
1074 1074
 		}
1075 1075
 
1076
-		if($errNo === -1) {
1076
+		if ($errNo === -1) {
1077 1077
 			//host, port or TLS wrong
1078 1078
 			return false;
1079 1079
 		}
@@ -1101,9 +1101,9 @@  discard block
 block discarded – undo
1101 1101
 	 */
1102 1102
 	private function checkRequirements($reqs) {
1103 1103
 		$this->checkAgentRequirements();
1104
-		foreach($reqs as $option) {
1104
+		foreach ($reqs as $option) {
1105 1105
 			$value = $this->configuration->$option;
1106
-			if(empty($value)) {
1106
+			if (empty($value)) {
1107 1107
 				return false;
1108 1108
 			}
1109 1109
 		}
@@ -1125,33 +1125,33 @@  discard block
 block discarded – undo
1125 1125
 		$dnRead = array();
1126 1126
 		$foundItems = array();
1127 1127
 		$maxEntries = 0;
1128
-		if(!is_array($this->configuration->ldapBase)
1128
+		if (!is_array($this->configuration->ldapBase)
1129 1129
 		   || !isset($this->configuration->ldapBase[0])) {
1130 1130
 			return false;
1131 1131
 		}
1132 1132
 		$base = $this->configuration->ldapBase[0];
1133 1133
 		$cr = $this->getConnection();
1134
-		if(!$this->ldap->isResource($cr)) {
1134
+		if (!$this->ldap->isResource($cr)) {
1135 1135
 			return false;
1136 1136
 		}
1137 1137
 		$lastFilter = null;
1138
-		if(isset($filters[count($filters)-1])) {
1139
-			$lastFilter = $filters[count($filters)-1];
1138
+		if (isset($filters[count($filters) - 1])) {
1139
+			$lastFilter = $filters[count($filters) - 1];
1140 1140
 		}
1141
-		foreach($filters as $filter) {
1142
-			if($lastFilter === $filter && count($foundItems) > 0) {
1141
+		foreach ($filters as $filter) {
1142
+			if ($lastFilter === $filter && count($foundItems) > 0) {
1143 1143
 				//skip when the filter is a wildcard and results were found
1144 1144
 				continue;
1145 1145
 			}
1146 1146
 			// 20k limit for performance and reason
1147 1147
 			$rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000);
1148
-			if(!$this->ldap->isResource($rr)) {
1148
+			if (!$this->ldap->isResource($rr)) {
1149 1149
 				continue;
1150 1150
 			}
1151 1151
 			$entries = $this->ldap->countEntries($cr, $rr);
1152 1152
 			$getEntryFunc = 'firstEntry';
1153
-			if(($entries !== false) && ($entries > 0)) {
1154
-				if(!is_null($maxF) && $entries > $maxEntries) {
1153
+			if (($entries !== false) && ($entries > 0)) {
1154
+				if (!is_null($maxF) && $entries > $maxEntries) {
1155 1155
 					$maxEntries = $entries;
1156 1156
 					$maxF = $filter;
1157 1157
 				}
@@ -1159,13 +1159,13 @@  discard block
 block discarded – undo
1159 1159
 				do {
1160 1160
 					$entry = $this->ldap->$getEntryFunc($cr, $rr);
1161 1161
 					$getEntryFunc = 'nextEntry';
1162
-					if(!$this->ldap->isResource($entry)) {
1162
+					if (!$this->ldap->isResource($entry)) {
1163 1163
 						continue 2;
1164 1164
 					}
1165 1165
 					$rr = $entry; //will be expected by nextEntry next round
1166 1166
 					$attributes = $this->ldap->getAttributes($cr, $entry);
1167 1167
 					$dn = $this->ldap->getDN($cr, $entry);
1168
-					if($dn === false || in_array($dn, $dnRead)) {
1168
+					if ($dn === false || in_array($dn, $dnRead)) {
1169 1169
 						continue;
1170 1170
 					}
1171 1171
 					$newItems = array();
@@ -1176,7 +1176,7 @@  discard block
 block discarded – undo
1176 1176
 					$foundItems = array_merge($foundItems, $newItems);
1177 1177
 					$this->resultCache[$dn][$attr] = $newItems;
1178 1178
 					$dnRead[] = $dn;
1179
-				} while(($state === self::LRESULT_PROCESSED_SKIP
1179
+				} while (($state === self::LRESULT_PROCESSED_SKIP
1180 1180
 						|| $this->ldap->isResource($entry))
1181 1181
 						&& ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit));
1182 1182
 			}
@@ -1199,11 +1199,11 @@  discard block
 block discarded – undo
1199 1199
 	 */
1200 1200
 	private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) {
1201 1201
 		$cr = $this->getConnection();
1202
-		if(!$cr) {
1202
+		if (!$cr) {
1203 1203
 			throw new \Exception('Could not connect to LDAP');
1204 1204
 		}
1205 1205
 		$p = 'objectclass=';
1206
-		foreach($objectclasses as $key => $value) {
1206
+		foreach ($objectclasses as $key => $value) {
1207 1207
 			$objectclasses[$key] = $p.$value;
1208 1208
 		}
1209 1209
 		$maxEntryObjC = '';
@@ -1215,7 +1215,7 @@  discard block
 block discarded – undo
1215 1215
 		$availableFeatures =
1216 1216
 			$this->cumulativeSearchOnAttribute($objectclasses, $attr,
1217 1217
 											   $dig, $maxEntryObjC);
1218
-		if(is_array($availableFeatures)
1218
+		if (is_array($availableFeatures)
1219 1219
 		   && count($availableFeatures) > 0) {
1220 1220
 			natcasesort($availableFeatures);
1221 1221
 			//natcasesort keeps indices, but we must get rid of them for proper
@@ -1226,7 +1226,7 @@  discard block
 block discarded – undo
1226 1226
 		}
1227 1227
 
1228 1228
 		$setFeatures = $this->configuration->$confkey;
1229
-		if(is_array($setFeatures) && !empty($setFeatures)) {
1229
+		if (is_array($setFeatures) && !empty($setFeatures)) {
1230 1230
 			//something is already configured? pre-select it.
1231 1231
 			$this->result->addChange($dbkey, $setFeatures);
1232 1232
 		} else if ($po && $maxEntryObjC !== '') {
@@ -1248,7 +1248,7 @@  discard block
 block discarded – undo
1248 1248
 	 * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP
1249 1249
 	 */
1250 1250
 	private function getAttributeValuesFromEntry($result, $attribute, &$known) {
1251
-		if(!is_array($result)
1251
+		if (!is_array($result)
1252 1252
 		   || !isset($result['count'])
1253 1253
 		   || !$result['count'] > 0) {
1254 1254
 			return self::LRESULT_PROCESSED_INVALID;
@@ -1257,12 +1257,12 @@  discard block
 block discarded – undo
1257 1257
 		// strtolower on all keys for proper comparison
1258 1258
 		$result = \OCP\Util::mb_array_change_key_case($result);
1259 1259
 		$attribute = strtolower($attribute);
1260
-		if(isset($result[$attribute])) {
1261
-			foreach($result[$attribute] as $key => $val) {
1262
-				if($key === 'count') {
1260
+		if (isset($result[$attribute])) {
1261
+			foreach ($result[$attribute] as $key => $val) {
1262
+				if ($key === 'count') {
1263 1263
 					continue;
1264 1264
 				}
1265
-				if(!in_array($val, $known)) {
1265
+				if (!in_array($val, $known)) {
1266 1266
 					$known[] = $val;
1267 1267
 				}
1268 1268
 			}
@@ -1276,7 +1276,7 @@  discard block
 block discarded – undo
1276 1276
 	 * @return bool|mixed
1277 1277
 	 */
1278 1278
 	private function getConnection() {
1279
-		if(!is_null($this->cr)) {
1279
+		if (!is_null($this->cr)) {
1280 1280
 			return $this->cr;
1281 1281
 		}
1282 1282
 
@@ -1288,14 +1288,14 @@  discard block
 block discarded – undo
1288 1288
 		$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1289 1289
 		$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1290 1290
 		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1291
-		if($this->configuration->ldapTLS === 1) {
1291
+		if ($this->configuration->ldapTLS === 1) {
1292 1292
 			$this->ldap->startTls($cr);
1293 1293
 		}
1294 1294
 
1295 1295
 		$lo = @$this->ldap->bind($cr,
1296 1296
 								 $this->configuration->ldapAgentName,
1297 1297
 								 $this->configuration->ldapAgentPassword);
1298
-		if($lo === true) {
1298
+		if ($lo === true) {
1299 1299
 			$this->$cr = $cr;
1300 1300
 			return $cr;
1301 1301
 		}
@@ -1326,18 +1326,18 @@  discard block
 block discarded – undo
1326 1326
 		//636 ← LDAPS / SSL
1327 1327
 		//7xxx ← UCS. need to be checked first, because both ports may be open
1328 1328
 		$host = $this->configuration->ldapHost;
1329
-		$port = (int)$this->configuration->ldapPort;
1329
+		$port = (int) $this->configuration->ldapPort;
1330 1330
 		$portSettings = array();
1331 1331
 
1332 1332
 		//In case the port is already provided, we will check this first
1333
-		if($port > 0) {
1333
+		if ($port > 0) {
1334 1334
 			$hostInfo = parse_url($host);
1335
-			if(!(is_array($hostInfo)
1335
+			if (!(is_array($hostInfo)
1336 1336
 				&& isset($hostInfo['scheme'])
1337 1337
 				&& stripos($hostInfo['scheme'], 'ldaps') !== false)) {
1338 1338
 				$portSettings[] = array('port' => $port, 'tls' => true);
1339 1339
 			}
1340
-			$portSettings[] =array('port' => $port, 'tls' => false);
1340
+			$portSettings[] = array('port' => $port, 'tls' => false);
1341 1341
 		}
1342 1342
 
1343 1343
 		//default ports
Please login to merge, or discard this patch.
Indentation   +1305 added lines, -1305 removed lines patch added patch discarded remove patch
@@ -41,1311 +41,1311 @@
 block discarded – undo
41 41
 use OC\ServerNotAvailableException;
42 42
 
43 43
 class Wizard extends LDAPUtility {
44
-	/** @var \OCP\IL10N */
45
-	static protected $l;
46
-	protected $access;
47
-	protected $cr;
48
-	protected $configuration;
49
-	protected $result;
50
-	protected $resultCache = array();
51
-
52
-	const LRESULT_PROCESSED_OK = 2;
53
-	const LRESULT_PROCESSED_INVALID = 3;
54
-	const LRESULT_PROCESSED_SKIP = 4;
55
-
56
-	const LFILTER_LOGIN      = 2;
57
-	const LFILTER_USER_LIST  = 3;
58
-	const LFILTER_GROUP_LIST = 4;
59
-
60
-	const LFILTER_MODE_ASSISTED = 2;
61
-	const LFILTER_MODE_RAW = 1;
62
-
63
-	const LDAP_NW_TIMEOUT = 4;
64
-
65
-	/**
66
-	 * Constructor
67
-	 * @param Configuration $configuration an instance of Configuration
68
-	 * @param ILDAPWrapper $ldap an instance of ILDAPWrapper
69
-	 * @param Access $access
70
-	 */
71
-	public function __construct(Configuration $configuration, ILDAPWrapper $ldap, Access $access) {
72
-		parent::__construct($ldap);
73
-		$this->configuration = $configuration;
74
-		if(is_null(Wizard::$l)) {
75
-			Wizard::$l = \OC::$server->getL10N('user_ldap');
76
-		}
77
-		$this->access = $access;
78
-		$this->result = new WizardResult();
79
-	}
80
-
81
-	public function  __destruct() {
82
-		if($this->result->hasChanges()) {
83
-			$this->configuration->saveConfiguration();
84
-		}
85
-	}
86
-
87
-	/**
88
-	 * counts entries in the LDAP directory
89
-	 *
90
-	 * @param string $filter the LDAP search filter
91
-	 * @param string $type a string being either 'users' or 'groups';
92
-	 * @return bool|int
93
-	 * @throws \Exception
94
-	 */
95
-	public function countEntries($filter, $type) {
96
-		$reqs = array('ldapHost', 'ldapPort', 'ldapBase');
97
-		if($type === 'users') {
98
-			$reqs[] = 'ldapUserFilter';
99
-		}
100
-		if(!$this->checkRequirements($reqs)) {
101
-			throw new \Exception('Requirements not met', 400);
102
-		}
103
-
104
-		$attr = array('dn'); // default
105
-		$limit = 1001;
106
-		if($type === 'groups') {
107
-			$result =  $this->access->countGroups($filter, $attr, $limit);
108
-		} else if($type === 'users') {
109
-			$result = $this->access->countUsers($filter, $attr, $limit);
110
-		} else if ($type === 'objects') {
111
-			$result = $this->access->countObjects($limit);
112
-		} else {
113
-			throw new \Exception('Internal error: Invalid object type', 500);
114
-		}
115
-
116
-		return $result;
117
-	}
118
-
119
-	/**
120
-	 * formats the return value of a count operation to the string to be
121
-	 * inserted.
122
-	 *
123
-	 * @param bool|int $count
124
-	 * @return int|string
125
-	 */
126
-	private function formatCountResult($count) {
127
-		$formatted = ($count !== false) ? $count : 0;
128
-		if($formatted > 1000) {
129
-			$formatted = '> 1000';
130
-		}
131
-		return $formatted;
132
-	}
133
-
134
-	public function countGroups() {
135
-		$filter = $this->configuration->ldapGroupFilter;
136
-
137
-		if(empty($filter)) {
138
-			$output = self::$l->n('%s group found', '%s groups found', 0, array(0));
139
-			$this->result->addChange('ldap_group_count', $output);
140
-			return $this->result;
141
-		}
142
-
143
-		try {
144
-			$groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups'));
145
-		} catch (\Exception $e) {
146
-			//400 can be ignored, 500 is forwarded
147
-			if($e->getCode() === 500) {
148
-				throw $e;
149
-			}
150
-			return false;
151
-		}
152
-		$output = self::$l->n('%s group found', '%s groups found', $groupsTotal, array($groupsTotal));
153
-		$this->result->addChange('ldap_group_count', $output);
154
-		return $this->result;
155
-	}
156
-
157
-	/**
158
-	 * @return WizardResult
159
-	 * @throws \Exception
160
-	 */
161
-	public function countUsers() {
162
-		$filter = $this->access->getFilterForUserCount();
163
-
164
-		$usersTotal = $this->formatCountResult($this->countEntries($filter, 'users'));
165
-		$output = self::$l->n('%s user found', '%s users found', $usersTotal, array($usersTotal));
166
-		$this->result->addChange('ldap_user_count', $output);
167
-		return $this->result;
168
-	}
169
-
170
-	/**
171
-	 * counts any objects in the currently set base dn
172
-	 *
173
-	 * @return WizardResult
174
-	 * @throws \Exception
175
-	 */
176
-	public function countInBaseDN() {
177
-		// we don't need to provide a filter in this case
178
-		$total = $this->countEntries(null, 'objects');
179
-		if($total === false) {
180
-			throw new \Exception('invalid results received');
181
-		}
182
-		$this->result->addChange('ldap_test_base', $total);
183
-		return $this->result;
184
-	}
185
-
186
-	/**
187
-	 * counts users with a specified attribute
188
-	 * @param string $attr
189
-	 * @param bool $existsCheck
190
-	 * @return int|bool
191
-	 */
192
-	public function countUsersWithAttribute($attr, $existsCheck = false) {
193
-		if(!$this->checkRequirements(array('ldapHost',
194
-										   'ldapPort',
195
-										   'ldapBase',
196
-										   'ldapUserFilter',
197
-										   ))) {
198
-			return  false;
199
-		}
200
-
201
-		$filter = $this->access->combineFilterWithAnd(array(
202
-			$this->configuration->ldapUserFilter,
203
-			$attr . '=*'
204
-		));
205
-
206
-		$limit = ($existsCheck === false) ? null : 1;
207
-
208
-		return $this->access->countUsers($filter, array('dn'), $limit);
209
-	}
210
-
211
-	/**
212
-	 * detects the display name attribute. If a setting is already present that
213
-	 * returns at least one hit, the detection will be canceled.
214
-	 * @return WizardResult|bool
215
-	 * @throws \Exception
216
-	 */
217
-	public function detectUserDisplayNameAttribute() {
218
-		if(!$this->checkRequirements(array('ldapHost',
219
-										'ldapPort',
220
-										'ldapBase',
221
-										'ldapUserFilter',
222
-										))) {
223
-			return  false;
224
-		}
225
-
226
-		$attr = $this->configuration->ldapUserDisplayName;
227
-		if ($attr !== '' && $attr !== 'displayName') {
228
-			// most likely not the default value with upper case N,
229
-			// verify it still produces a result
230
-			$count = (int)$this->countUsersWithAttribute($attr, true);
231
-			if($count > 0) {
232
-				//no change, but we sent it back to make sure the user interface
233
-				//is still correct, even if the ajax call was cancelled meanwhile
234
-				$this->result->addChange('ldap_display_name', $attr);
235
-				return $this->result;
236
-			}
237
-		}
238
-
239
-		// first attribute that has at least one result wins
240
-		$displayNameAttrs = array('displayname', 'cn');
241
-		foreach ($displayNameAttrs as $attr) {
242
-			$count = (int)$this->countUsersWithAttribute($attr, true);
243
-
244
-			if($count > 0) {
245
-				$this->applyFind('ldap_display_name', $attr);
246
-				return $this->result;
247
-			}
248
-		}
249
-
250
-		throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced LDAP settings.'));
251
-	}
252
-
253
-	/**
254
-	 * detects the most often used email attribute for users applying to the
255
-	 * user list filter. If a setting is already present that returns at least
256
-	 * one hit, the detection will be canceled.
257
-	 * @return WizardResult|bool
258
-	 */
259
-	public function detectEmailAttribute() {
260
-		if(!$this->checkRequirements(array('ldapHost',
261
-										   'ldapPort',
262
-										   'ldapBase',
263
-										   'ldapUserFilter',
264
-										   ))) {
265
-			return  false;
266
-		}
267
-
268
-		$attr = $this->configuration->ldapEmailAttribute;
269
-		if ($attr !== '') {
270
-			$count = (int)$this->countUsersWithAttribute($attr, true);
271
-			if($count > 0) {
272
-				return false;
273
-			}
274
-			$writeLog = true;
275
-		} else {
276
-			$writeLog = false;
277
-		}
278
-
279
-		$emailAttributes = array('mail', 'mailPrimaryAddress');
280
-		$winner = '';
281
-		$maxUsers = 0;
282
-		foreach($emailAttributes as $attr) {
283
-			$count = $this->countUsersWithAttribute($attr);
284
-			if($count > $maxUsers) {
285
-				$maxUsers = $count;
286
-				$winner = $attr;
287
-			}
288
-		}
289
-
290
-		if($winner !== '') {
291
-			$this->applyFind('ldap_email_attr', $winner);
292
-			if($writeLog) {
293
-				\OCP\Util::writeLog('user_ldap', 'The mail attribute has ' .
294
-					'automatically been reset, because the original value ' .
295
-					'did not return any results.', \OCP\Util::INFO);
296
-			}
297
-		}
298
-
299
-		return $this->result;
300
-	}
301
-
302
-	/**
303
-	 * @return WizardResult
304
-	 * @throws \Exception
305
-	 */
306
-	public function determineAttributes() {
307
-		if(!$this->checkRequirements(array('ldapHost',
308
-										   'ldapPort',
309
-										   'ldapBase',
310
-										   'ldapUserFilter',
311
-										   ))) {
312
-			return  false;
313
-		}
314
-
315
-		$attributes = $this->getUserAttributes();
316
-
317
-		natcasesort($attributes);
318
-		$attributes = array_values($attributes);
319
-
320
-		$this->result->addOptions('ldap_loginfilter_attributes', $attributes);
321
-
322
-		$selected = $this->configuration->ldapLoginFilterAttributes;
323
-		if(is_array($selected) && !empty($selected)) {
324
-			$this->result->addChange('ldap_loginfilter_attributes', $selected);
325
-		}
326
-
327
-		return $this->result;
328
-	}
329
-
330
-	/**
331
-	 * detects the available LDAP attributes
332
-	 * @return array|false The instance's WizardResult instance
333
-	 * @throws \Exception
334
-	 */
335
-	private function getUserAttributes() {
336
-		if(!$this->checkRequirements(array('ldapHost',
337
-										   'ldapPort',
338
-										   'ldapBase',
339
-										   'ldapUserFilter',
340
-										   ))) {
341
-			return  false;
342
-		}
343
-		$cr = $this->getConnection();
344
-		if(!$cr) {
345
-			throw new \Exception('Could not connect to LDAP');
346
-		}
347
-
348
-		$base = $this->configuration->ldapBase[0];
349
-		$filter = $this->configuration->ldapUserFilter;
350
-		$rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1);
351
-		if(!$this->ldap->isResource($rr)) {
352
-			return false;
353
-		}
354
-		$er = $this->ldap->firstEntry($cr, $rr);
355
-		$attributes = $this->ldap->getAttributes($cr, $er);
356
-		$pureAttributes = array();
357
-		for($i = 0; $i < $attributes['count']; $i++) {
358
-			$pureAttributes[] = $attributes[$i];
359
-		}
360
-
361
-		return $pureAttributes;
362
-	}
363
-
364
-	/**
365
-	 * detects the available LDAP groups
366
-	 * @return WizardResult|false the instance's WizardResult instance
367
-	 */
368
-	public function determineGroupsForGroups() {
369
-		return $this->determineGroups('ldap_groupfilter_groups',
370
-									  'ldapGroupFilterGroups',
371
-									  false);
372
-	}
373
-
374
-	/**
375
-	 * detects the available LDAP groups
376
-	 * @return WizardResult|false the instance's WizardResult instance
377
-	 */
378
-	public function determineGroupsForUsers() {
379
-		return $this->determineGroups('ldap_userfilter_groups',
380
-									  'ldapUserFilterGroups');
381
-	}
382
-
383
-	/**
384
-	 * detects the available LDAP groups
385
-	 * @param string $dbKey
386
-	 * @param string $confKey
387
-	 * @param bool $testMemberOf
388
-	 * @return WizardResult|false the instance's WizardResult instance
389
-	 * @throws \Exception
390
-	 */
391
-	private function determineGroups($dbKey, $confKey, $testMemberOf = true) {
392
-		if(!$this->checkRequirements(array('ldapHost',
393
-										   'ldapPort',
394
-										   'ldapBase',
395
-										   ))) {
396
-			return  false;
397
-		}
398
-		$cr = $this->getConnection();
399
-		if(!$cr) {
400
-			throw new \Exception('Could not connect to LDAP');
401
-		}
402
-
403
-		$this->fetchGroups($dbKey, $confKey);
404
-
405
-		if($testMemberOf) {
406
-			$this->configuration->hasMemberOfFilterSupport = $this->testMemberOf();
407
-			$this->result->markChange();
408
-			if(!$this->configuration->hasMemberOfFilterSupport) {
409
-				throw new \Exception('memberOf is not supported by the server');
410
-			}
411
-		}
412
-
413
-		return $this->result;
414
-	}
415
-
416
-	/**
417
-	 * fetches all groups from LDAP and adds them to the result object
418
-	 *
419
-	 * @param string $dbKey
420
-	 * @param string $confKey
421
-	 * @return array $groupEntries
422
-	 * @throws \Exception
423
-	 */
424
-	public function fetchGroups($dbKey, $confKey) {
425
-		$obclasses = array('posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames', 'groupOfUniqueNames');
426
-
427
-		$filterParts = array();
428
-		foreach($obclasses as $obclass) {
429
-			$filterParts[] = 'objectclass='.$obclass;
430
-		}
431
-		//we filter for everything
432
-		//- that looks like a group and
433
-		//- has the group display name set
434
-		$filter = $this->access->combineFilterWithOr($filterParts);
435
-		$filter = $this->access->combineFilterWithAnd(array($filter, 'cn=*'));
436
-
437
-		$groupNames = array();
438
-		$groupEntries = array();
439
-		$limit = 400;
440
-		$offset = 0;
441
-		do {
442
-			// we need to request dn additionally here, otherwise memberOf
443
-			// detection will fail later
444
-			$result = $this->access->searchGroups($filter, array('cn', 'dn'), $limit, $offset);
445
-			foreach($result as $item) {
446
-				if(!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) {
447
-					// just in case - no issue known
448
-					continue;
449
-				}
450
-				$groupNames[] = $item['cn'][0];
451
-				$groupEntries[] = $item;
452
-			}
453
-			$offset += $limit;
454
-		} while ($this->access->hasMoreResults());
455
-
456
-		if(count($groupNames) > 0) {
457
-			natsort($groupNames);
458
-			$this->result->addOptions($dbKey, array_values($groupNames));
459
-		} else {
460
-			throw new \Exception(self::$l->t('Could not find the desired feature'));
461
-		}
462
-
463
-		$setFeatures = $this->configuration->$confKey;
464
-		if(is_array($setFeatures) && !empty($setFeatures)) {
465
-			//something is already configured? pre-select it.
466
-			$this->result->addChange($dbKey, $setFeatures);
467
-		}
468
-		return $groupEntries;
469
-	}
470
-
471
-	public function determineGroupMemberAssoc() {
472
-		if(!$this->checkRequirements(array('ldapHost',
473
-										   'ldapPort',
474
-										   'ldapGroupFilter',
475
-										   ))) {
476
-			return  false;
477
-		}
478
-		$attribute = $this->detectGroupMemberAssoc();
479
-		if($attribute === false) {
480
-			return false;
481
-		}
482
-		$this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute));
483
-		$this->result->addChange('ldap_group_member_assoc_attribute', $attribute);
484
-
485
-		return $this->result;
486
-	}
487
-
488
-	/**
489
-	 * Detects the available object classes
490
-	 * @return WizardResult|false the instance's WizardResult instance
491
-	 * @throws \Exception
492
-	 */
493
-	public function determineGroupObjectClasses() {
494
-		if(!$this->checkRequirements(array('ldapHost',
495
-										   'ldapPort',
496
-										   'ldapBase',
497
-										   ))) {
498
-			return  false;
499
-		}
500
-		$cr = $this->getConnection();
501
-		if(!$cr) {
502
-			throw new \Exception('Could not connect to LDAP');
503
-		}
504
-
505
-		$obclasses = array('groupOfNames', 'groupOfUniqueNames', 'group', 'posixGroup', '*');
506
-		$this->determineFeature($obclasses,
507
-								'objectclass',
508
-								'ldap_groupfilter_objectclass',
509
-								'ldapGroupFilterObjectclass',
510
-								false);
511
-
512
-		return $this->result;
513
-	}
514
-
515
-	/**
516
-	 * detects the available object classes
517
-	 * @return WizardResult
518
-	 * @throws \Exception
519
-	 */
520
-	public function determineUserObjectClasses() {
521
-		if(!$this->checkRequirements(array('ldapHost',
522
-										   'ldapPort',
523
-										   'ldapBase',
524
-										   ))) {
525
-			return  false;
526
-		}
527
-		$cr = $this->getConnection();
528
-		if(!$cr) {
529
-			throw new \Exception('Could not connect to LDAP');
530
-		}
531
-
532
-		$obclasses = array('inetOrgPerson', 'person', 'organizationalPerson',
533
-						   'user', 'posixAccount', '*');
534
-		$filter = $this->configuration->ldapUserFilter;
535
-		//if filter is empty, it is probably the first time the wizard is called
536
-		//then, apply suggestions.
537
-		$this->determineFeature($obclasses,
538
-								'objectclass',
539
-								'ldap_userfilter_objectclass',
540
-								'ldapUserFilterObjectclass',
541
-								empty($filter));
542
-
543
-		return $this->result;
544
-	}
545
-
546
-	/**
547
-	 * @return WizardResult|false
548
-	 * @throws \Exception
549
-	 */
550
-	public function getGroupFilter() {
551
-		if(!$this->checkRequirements(array('ldapHost',
552
-										   'ldapPort',
553
-										   'ldapBase',
554
-										   ))) {
555
-			return false;
556
-		}
557
-		//make sure the use display name is set
558
-		$displayName = $this->configuration->ldapGroupDisplayName;
559
-		if ($displayName === '') {
560
-			$d = $this->configuration->getDefaults();
561
-			$this->applyFind('ldap_group_display_name',
562
-							 $d['ldap_group_display_name']);
563
-		}
564
-		$filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST);
565
-
566
-		$this->applyFind('ldap_group_filter', $filter);
567
-		return $this->result;
568
-	}
569
-
570
-	/**
571
-	 * @return WizardResult|false
572
-	 * @throws \Exception
573
-	 */
574
-	public function getUserListFilter() {
575
-		if(!$this->checkRequirements(array('ldapHost',
576
-										   'ldapPort',
577
-										   'ldapBase',
578
-										   ))) {
579
-			return false;
580
-		}
581
-		//make sure the use display name is set
582
-		$displayName = $this->configuration->ldapUserDisplayName;
583
-		if ($displayName === '') {
584
-			$d = $this->configuration->getDefaults();
585
-			$this->applyFind('ldap_display_name', $d['ldap_display_name']);
586
-		}
587
-		$filter = $this->composeLdapFilter(self::LFILTER_USER_LIST);
588
-		if(!$filter) {
589
-			throw new \Exception('Cannot create filter');
590
-		}
591
-
592
-		$this->applyFind('ldap_userlist_filter', $filter);
593
-		return $this->result;
594
-	}
595
-
596
-	/**
597
-	 * @return bool|WizardResult
598
-	 * @throws \Exception
599
-	 */
600
-	public function getUserLoginFilter() {
601
-		if(!$this->checkRequirements(array('ldapHost',
602
-										   'ldapPort',
603
-										   'ldapBase',
604
-										   'ldapUserFilter',
605
-										   ))) {
606
-			return false;
607
-		}
608
-
609
-		$filter = $this->composeLdapFilter(self::LFILTER_LOGIN);
610
-		if(!$filter) {
611
-			throw new \Exception('Cannot create filter');
612
-		}
613
-
614
-		$this->applyFind('ldap_login_filter', $filter);
615
-		return $this->result;
616
-	}
617
-
618
-	/**
619
-	 * @return bool|WizardResult
620
-	 * @param string $loginName
621
-	 * @throws \Exception
622
-	 */
623
-	public function testLoginName($loginName) {
624
-		if(!$this->checkRequirements(array('ldapHost',
625
-			'ldapPort',
626
-			'ldapBase',
627
-			'ldapLoginFilter',
628
-		))) {
629
-			return false;
630
-		}
631
-
632
-		$cr = $this->access->connection->getConnectionResource();
633
-		if(!$this->ldap->isResource($cr)) {
634
-			throw new \Exception('connection error');
635
-		}
636
-
637
-		if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8')
638
-			=== false) {
639
-			throw new \Exception('missing placeholder');
640
-		}
641
-
642
-		$users = $this->access->countUsersByLoginName($loginName);
643
-		if($this->ldap->errno($cr) !== 0) {
644
-			throw new \Exception($this->ldap->error($cr));
645
-		}
646
-		$filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
647
-		$this->result->addChange('ldap_test_loginname', $users);
648
-		$this->result->addChange('ldap_test_effective_filter', $filter);
649
-		return $this->result;
650
-	}
651
-
652
-	/**
653
-	 * Tries to determine the port, requires given Host, User DN and Password
654
-	 * @return WizardResult|false WizardResult on success, false otherwise
655
-	 * @throws \Exception
656
-	 */
657
-	public function guessPortAndTLS() {
658
-		if(!$this->checkRequirements(array('ldapHost',
659
-										   ))) {
660
-			return false;
661
-		}
662
-		$this->checkHost();
663
-		$portSettings = $this->getPortSettingsToTry();
664
-
665
-		if(!is_array($portSettings)) {
666
-			throw new \Exception(print_r($portSettings, true));
667
-		}
668
-
669
-		//proceed from the best configuration and return on first success
670
-		foreach($portSettings as $setting) {
671
-			$p = $setting['port'];
672
-			$t = $setting['tls'];
673
-			\OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG);
674
-			//connectAndBind may throw Exception, it needs to be catched by the
675
-			//callee of this method
676
-
677
-			try {
678
-				$settingsFound = $this->connectAndBind($p, $t);
679
-			} catch (\Exception $e) {
680
-				// any reply other than -1 (= cannot connect) is already okay,
681
-				// because then we found the server
682
-				// unavailable startTLS returns -11
683
-				if($e->getCode() > 0) {
684
-					$settingsFound = true;
685
-				} else {
686
-					throw $e;
687
-				}
688
-			}
689
-
690
-			if ($settingsFound === true) {
691
-				$config = array(
692
-					'ldapPort' => $p,
693
-					'ldapTLS' => (int)$t
694
-				);
695
-				$this->configuration->setConfiguration($config);
696
-				\OCP\Util::writeLog('user_ldap', 'Wiz: detected Port ' . $p, \OCP\Util::DEBUG);
697
-				$this->result->addChange('ldap_port', $p);
698
-				return $this->result;
699
-			}
700
-		}
701
-
702
-		//custom port, undetected (we do not brute force)
703
-		return false;
704
-	}
705
-
706
-	/**
707
-	 * tries to determine a base dn from User DN or LDAP Host
708
-	 * @return WizardResult|false WizardResult on success, false otherwise
709
-	 */
710
-	public function guessBaseDN() {
711
-		if(!$this->checkRequirements(array('ldapHost',
712
-										   'ldapPort',
713
-										   ))) {
714
-			return false;
715
-		}
716
-
717
-		//check whether a DN is given in the agent name (99.9% of all cases)
718
-		$base = null;
719
-		$i = stripos($this->configuration->ldapAgentName, 'dc=');
720
-		if($i !== false) {
721
-			$base = substr($this->configuration->ldapAgentName, $i);
722
-			if($this->testBaseDN($base)) {
723
-				$this->applyFind('ldap_base', $base);
724
-				return $this->result;
725
-			}
726
-		}
727
-
728
-		//this did not help :(
729
-		//Let's see whether we can parse the Host URL and convert the domain to
730
-		//a base DN
731
-		$helper = new Helper(\OC::$server->getConfig());
732
-		$domain = $helper->getDomainFromURL($this->configuration->ldapHost);
733
-		if(!$domain) {
734
-			return false;
735
-		}
736
-
737
-		$dparts = explode('.', $domain);
738
-		while(count($dparts) > 0) {
739
-			$base2 = 'dc=' . implode(',dc=', $dparts);
740
-			if ($base !== $base2 && $this->testBaseDN($base2)) {
741
-				$this->applyFind('ldap_base', $base2);
742
-				return $this->result;
743
-			}
744
-			array_shift($dparts);
745
-		}
746
-
747
-		return false;
748
-	}
749
-
750
-	/**
751
-	 * sets the found value for the configuration key in the WizardResult
752
-	 * as well as in the Configuration instance
753
-	 * @param string $key the configuration key
754
-	 * @param string $value the (detected) value
755
-	 *
756
-	 */
757
-	private function applyFind($key, $value) {
758
-		$this->result->addChange($key, $value);
759
-		$this->configuration->setConfiguration(array($key => $value));
760
-	}
761
-
762
-	/**
763
-	 * Checks, whether a port was entered in the Host configuration
764
-	 * field. In this case the port will be stripped off, but also stored as
765
-	 * setting.
766
-	 */
767
-	private function checkHost() {
768
-		$host = $this->configuration->ldapHost;
769
-		$hostInfo = parse_url($host);
770
-
771
-		//removes Port from Host
772
-		if(is_array($hostInfo) && isset($hostInfo['port'])) {
773
-			$port = $hostInfo['port'];
774
-			$host = str_replace(':'.$port, '', $host);
775
-			$this->applyFind('ldap_host', $host);
776
-			$this->applyFind('ldap_port', $port);
777
-		}
778
-	}
779
-
780
-	/**
781
-	 * tries to detect the group member association attribute which is
782
-	 * one of 'uniqueMember', 'memberUid', 'member', 'gidNumber'
783
-	 * @return string|false, string with the attribute name, false on error
784
-	 * @throws \Exception
785
-	 */
786
-	private function detectGroupMemberAssoc() {
787
-		$possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'gidNumber');
788
-		$filter = $this->configuration->ldapGroupFilter;
789
-		if(empty($filter)) {
790
-			return false;
791
-		}
792
-		$cr = $this->getConnection();
793
-		if(!$cr) {
794
-			throw new \Exception('Could not connect to LDAP');
795
-		}
796
-		$base = $this->configuration->ldapBase[0];
797
-		$rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000);
798
-		if(!$this->ldap->isResource($rr)) {
799
-			return false;
800
-		}
801
-		$er = $this->ldap->firstEntry($cr, $rr);
802
-		while(is_resource($er)) {
803
-			$this->ldap->getDN($cr, $er);
804
-			$attrs = $this->ldap->getAttributes($cr, $er);
805
-			$result = array();
806
-			$possibleAttrsCount = count($possibleAttrs);
807
-			for($i = 0; $i < $possibleAttrsCount; $i++) {
808
-				if(isset($attrs[$possibleAttrs[$i]])) {
809
-					$result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count'];
810
-				}
811
-			}
812
-			if(!empty($result)) {
813
-				natsort($result);
814
-				return key($result);
815
-			}
816
-
817
-			$er = $this->ldap->nextEntry($cr, $er);
818
-		}
819
-
820
-		return false;
821
-	}
822
-
823
-	/**
824
-	 * Checks whether for a given BaseDN results will be returned
825
-	 * @param string $base the BaseDN to test
826
-	 * @return bool true on success, false otherwise
827
-	 * @throws \Exception
828
-	 */
829
-	private function testBaseDN($base) {
830
-		$cr = $this->getConnection();
831
-		if(!$cr) {
832
-			throw new \Exception('Could not connect to LDAP');
833
-		}
834
-
835
-		//base is there, let's validate it. If we search for anything, we should
836
-		//get a result set > 0 on a proper base
837
-		$rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1);
838
-		if(!$this->ldap->isResource($rr)) {
839
-			$errorNo  = $this->ldap->errno($cr);
840
-			$errorMsg = $this->ldap->error($cr);
841
-			\OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base.
842
-							' Error '.$errorNo.': '.$errorMsg, \OCP\Util::INFO);
843
-			return false;
844
-		}
845
-		$entries = $this->ldap->countEntries($cr, $rr);
846
-		return ($entries !== false) && ($entries > 0);
847
-	}
848
-
849
-	/**
850
-	 * Checks whether the server supports memberOf in LDAP Filter.
851
-	 * Note: at least in OpenLDAP, availability of memberOf is dependent on
852
-	 * a configured objectClass. I.e. not necessarily for all available groups
853
-	 * memberOf does work.
854
-	 *
855
-	 * @return bool true if it does, false otherwise
856
-	 * @throws \Exception
857
-	 */
858
-	private function testMemberOf() {
859
-		$cr = $this->getConnection();
860
-		if(!$cr) {
861
-			throw new \Exception('Could not connect to LDAP');
862
-		}
863
-		$result = $this->access->countUsers('memberOf=*', array('memberOf'), 1);
864
-		if(is_int($result) &&  $result > 0) {
865
-			return true;
866
-		}
867
-		return false;
868
-	}
869
-
870
-	/**
871
-	 * creates an LDAP Filter from given configuration
872
-	 * @param integer $filterType int, for which use case the filter shall be created
873
-	 * can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or
874
-	 * self::LFILTER_GROUP_LIST
875
-	 * @return string|false string with the filter on success, false otherwise
876
-	 * @throws \Exception
877
-	 */
878
-	private function composeLdapFilter($filterType) {
879
-		$filter = '';
880
-		$parts = 0;
881
-		switch ($filterType) {
882
-			case self::LFILTER_USER_LIST:
883
-				$objcs = $this->configuration->ldapUserFilterObjectclass;
884
-				//glue objectclasses
885
-				if(is_array($objcs) && count($objcs) > 0) {
886
-					$filter .= '(|';
887
-					foreach($objcs as $objc) {
888
-						$filter .= '(objectclass=' . $objc . ')';
889
-					}
890
-					$filter .= ')';
891
-					$parts++;
892
-				}
893
-				//glue group memberships
894
-				if($this->configuration->hasMemberOfFilterSupport) {
895
-					$cns = $this->configuration->ldapUserFilterGroups;
896
-					if(is_array($cns) && count($cns) > 0) {
897
-						$filter .= '(|';
898
-						$cr = $this->getConnection();
899
-						if(!$cr) {
900
-							throw new \Exception('Could not connect to LDAP');
901
-						}
902
-						$base = $this->configuration->ldapBase[0];
903
-						foreach($cns as $cn) {
904
-							$rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken'));
905
-							if(!$this->ldap->isResource($rr)) {
906
-								continue;
907
-							}
908
-							$er = $this->ldap->firstEntry($cr, $rr);
909
-							$attrs = $this->ldap->getAttributes($cr, $er);
910
-							$dn = $this->ldap->getDN($cr, $er);
911
-							if ($dn === false || $dn === '') {
912
-								continue;
913
-							}
914
-							$filterPart = '(memberof=' . $dn . ')';
915
-							if(isset($attrs['primaryGroupToken'])) {
916
-								$pgt = $attrs['primaryGroupToken'][0];
917
-								$primaryFilterPart = '(primaryGroupID=' . $pgt .')';
918
-								$filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
919
-							}
920
-							$filter .= $filterPart;
921
-						}
922
-						$filter .= ')';
923
-					}
924
-					$parts++;
925
-				}
926
-				//wrap parts in AND condition
927
-				if($parts > 1) {
928
-					$filter = '(&' . $filter . ')';
929
-				}
930
-				if ($filter === '') {
931
-					$filter = '(objectclass=*)';
932
-				}
933
-				break;
934
-
935
-			case self::LFILTER_GROUP_LIST:
936
-				$objcs = $this->configuration->ldapGroupFilterObjectclass;
937
-				//glue objectclasses
938
-				if(is_array($objcs) && count($objcs) > 0) {
939
-					$filter .= '(|';
940
-					foreach($objcs as $objc) {
941
-						$filter .= '(objectclass=' . $objc . ')';
942
-					}
943
-					$filter .= ')';
944
-					$parts++;
945
-				}
946
-				//glue group memberships
947
-				$cns = $this->configuration->ldapGroupFilterGroups;
948
-				if(is_array($cns) && count($cns) > 0) {
949
-					$filter .= '(|';
950
-					foreach($cns as $cn) {
951
-						$filter .= '(cn=' . $cn . ')';
952
-					}
953
-					$filter .= ')';
954
-				}
955
-				$parts++;
956
-				//wrap parts in AND condition
957
-				if($parts > 1) {
958
-					$filter = '(&' . $filter . ')';
959
-				}
960
-				break;
961
-
962
-			case self::LFILTER_LOGIN:
963
-				$ulf = $this->configuration->ldapUserFilter;
964
-				$loginpart = '=%uid';
965
-				$filterUsername = '';
966
-				$userAttributes = $this->getUserAttributes();
967
-				$userAttributes = array_change_key_case(array_flip($userAttributes));
968
-				$parts = 0;
969
-
970
-				if($this->configuration->ldapLoginFilterUsername === '1') {
971
-					$attr = '';
972
-					if(isset($userAttributes['uid'])) {
973
-						$attr = 'uid';
974
-					} else if(isset($userAttributes['samaccountname'])) {
975
-						$attr = 'samaccountname';
976
-					} else if(isset($userAttributes['cn'])) {
977
-						//fallback
978
-						$attr = 'cn';
979
-					}
980
-					if ($attr !== '') {
981
-						$filterUsername = '(' . $attr . $loginpart . ')';
982
-						$parts++;
983
-					}
984
-				}
985
-
986
-				$filterEmail = '';
987
-				if($this->configuration->ldapLoginFilterEmail === '1') {
988
-					$filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))';
989
-					$parts++;
990
-				}
991
-
992
-				$filterAttributes = '';
993
-				$attrsToFilter = $this->configuration->ldapLoginFilterAttributes;
994
-				if(is_array($attrsToFilter) && count($attrsToFilter) > 0) {
995
-					$filterAttributes = '(|';
996
-					foreach($attrsToFilter as $attribute) {
997
-						$filterAttributes .= '(' . $attribute . $loginpart . ')';
998
-					}
999
-					$filterAttributes .= ')';
1000
-					$parts++;
1001
-				}
1002
-
1003
-				$filterLogin = '';
1004
-				if($parts > 1) {
1005
-					$filterLogin = '(|';
1006
-				}
1007
-				$filterLogin .= $filterUsername;
1008
-				$filterLogin .= $filterEmail;
1009
-				$filterLogin .= $filterAttributes;
1010
-				if($parts > 1) {
1011
-					$filterLogin .= ')';
1012
-				}
1013
-
1014
-				$filter = '(&'.$ulf.$filterLogin.')';
1015
-				break;
1016
-		}
1017
-
1018
-		\OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG);
1019
-
1020
-		return $filter;
1021
-	}
1022
-
1023
-	/**
1024
-	 * Connects and Binds to an LDAP Server
1025
-	 *
1026
-	 * @param int $port the port to connect with
1027
-	 * @param bool $tls whether startTLS is to be used
1028
-	 * @return bool
1029
-	 * @throws \Exception
1030
-	 */
1031
-	private function connectAndBind($port, $tls) {
1032
-		//connect, does not really trigger any server communication
1033
-		$host = $this->configuration->ldapHost;
1034
-		$hostInfo = parse_url($host);
1035
-		if(!$hostInfo) {
1036
-			throw new \Exception(self::$l->t('Invalid Host'));
1037
-		}
1038
-		\OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG);
1039
-		$cr = $this->ldap->connect($host, $port);
1040
-		if(!is_resource($cr)) {
1041
-			throw new \Exception(self::$l->t('Invalid Host'));
1042
-		}
1043
-
1044
-		//set LDAP options
1045
-		$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1046
-		$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1047
-		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1048
-
1049
-		try {
1050
-			if($tls) {
1051
-				$isTlsWorking = @$this->ldap->startTls($cr);
1052
-				if(!$isTlsWorking) {
1053
-					return false;
1054
-				}
1055
-			}
1056
-
1057
-			\OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG);
1058
-			//interesting part: do the bind!
1059
-			$login = $this->ldap->bind($cr,
1060
-				$this->configuration->ldapAgentName,
1061
-				$this->configuration->ldapAgentPassword
1062
-			);
1063
-			$errNo = $this->ldap->errno($cr);
1064
-			$error = ldap_error($cr);
1065
-			$this->ldap->unbind($cr);
1066
-		} catch(ServerNotAvailableException $e) {
1067
-			return false;
1068
-		}
1069
-
1070
-		if($login === true) {
1071
-			$this->ldap->unbind($cr);
1072
-			\OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '. $port . ' TLS ' . (int)$tls, \OCP\Util::DEBUG);
1073
-			return true;
1074
-		}
1075
-
1076
-		if($errNo === -1) {
1077
-			//host, port or TLS wrong
1078
-			return false;
1079
-		}
1080
-		throw new \Exception($error, $errNo);
1081
-	}
1082
-
1083
-	/**
1084
-	 * checks whether a valid combination of agent and password has been
1085
-	 * provided (either two values or nothing for anonymous connect)
1086
-	 * @return bool, true if everything is fine, false otherwise
1087
-	 */
1088
-	private function checkAgentRequirements() {
1089
-		$agent = $this->configuration->ldapAgentName;
1090
-		$pwd = $this->configuration->ldapAgentPassword;
1091
-
1092
-		return
1093
-			($agent !== '' && $pwd !== '')
1094
-			||  ($agent === '' && $pwd === '')
1095
-		;
1096
-	}
1097
-
1098
-	/**
1099
-	 * @param array $reqs
1100
-	 * @return bool
1101
-	 */
1102
-	private function checkRequirements($reqs) {
1103
-		$this->checkAgentRequirements();
1104
-		foreach($reqs as $option) {
1105
-			$value = $this->configuration->$option;
1106
-			if(empty($value)) {
1107
-				return false;
1108
-			}
1109
-		}
1110
-		return true;
1111
-	}
1112
-
1113
-	/**
1114
-	 * does a cumulativeSearch on LDAP to get different values of a
1115
-	 * specified attribute
1116
-	 * @param string[] $filters array, the filters that shall be used in the search
1117
-	 * @param string $attr the attribute of which a list of values shall be returned
1118
-	 * @param int $dnReadLimit the amount of how many DNs should be analyzed.
1119
-	 * The lower, the faster
1120
-	 * @param string $maxF string. if not null, this variable will have the filter that
1121
-	 * yields most result entries
1122
-	 * @return array|false an array with the values on success, false otherwise
1123
-	 */
1124
-	public function cumulativeSearchOnAttribute($filters, $attr, $dnReadLimit = 3, &$maxF = null) {
1125
-		$dnRead = array();
1126
-		$foundItems = array();
1127
-		$maxEntries = 0;
1128
-		if(!is_array($this->configuration->ldapBase)
1129
-		   || !isset($this->configuration->ldapBase[0])) {
1130
-			return false;
1131
-		}
1132
-		$base = $this->configuration->ldapBase[0];
1133
-		$cr = $this->getConnection();
1134
-		if(!$this->ldap->isResource($cr)) {
1135
-			return false;
1136
-		}
1137
-		$lastFilter = null;
1138
-		if(isset($filters[count($filters)-1])) {
1139
-			$lastFilter = $filters[count($filters)-1];
1140
-		}
1141
-		foreach($filters as $filter) {
1142
-			if($lastFilter === $filter && count($foundItems) > 0) {
1143
-				//skip when the filter is a wildcard and results were found
1144
-				continue;
1145
-			}
1146
-			// 20k limit for performance and reason
1147
-			$rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000);
1148
-			if(!$this->ldap->isResource($rr)) {
1149
-				continue;
1150
-			}
1151
-			$entries = $this->ldap->countEntries($cr, $rr);
1152
-			$getEntryFunc = 'firstEntry';
1153
-			if(($entries !== false) && ($entries > 0)) {
1154
-				if(!is_null($maxF) && $entries > $maxEntries) {
1155
-					$maxEntries = $entries;
1156
-					$maxF = $filter;
1157
-				}
1158
-				$dnReadCount = 0;
1159
-				do {
1160
-					$entry = $this->ldap->$getEntryFunc($cr, $rr);
1161
-					$getEntryFunc = 'nextEntry';
1162
-					if(!$this->ldap->isResource($entry)) {
1163
-						continue 2;
1164
-					}
1165
-					$rr = $entry; //will be expected by nextEntry next round
1166
-					$attributes = $this->ldap->getAttributes($cr, $entry);
1167
-					$dn = $this->ldap->getDN($cr, $entry);
1168
-					if($dn === false || in_array($dn, $dnRead)) {
1169
-						continue;
1170
-					}
1171
-					$newItems = array();
1172
-					$state = $this->getAttributeValuesFromEntry($attributes,
1173
-																$attr,
1174
-																$newItems);
1175
-					$dnReadCount++;
1176
-					$foundItems = array_merge($foundItems, $newItems);
1177
-					$this->resultCache[$dn][$attr] = $newItems;
1178
-					$dnRead[] = $dn;
1179
-				} while(($state === self::LRESULT_PROCESSED_SKIP
1180
-						|| $this->ldap->isResource($entry))
1181
-						&& ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit));
1182
-			}
1183
-		}
1184
-
1185
-		return array_unique($foundItems);
1186
-	}
1187
-
1188
-	/**
1189
-	 * determines if and which $attr are available on the LDAP server
1190
-	 * @param string[] $objectclasses the objectclasses to use as search filter
1191
-	 * @param string $attr the attribute to look for
1192
-	 * @param string $dbkey the dbkey of the setting the feature is connected to
1193
-	 * @param string $confkey the confkey counterpart for the $dbkey as used in the
1194
-	 * Configuration class
1195
-	 * @param bool $po whether the objectClass with most result entries
1196
-	 * shall be pre-selected via the result
1197
-	 * @return array|false list of found items.
1198
-	 * @throws \Exception
1199
-	 */
1200
-	private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) {
1201
-		$cr = $this->getConnection();
1202
-		if(!$cr) {
1203
-			throw new \Exception('Could not connect to LDAP');
1204
-		}
1205
-		$p = 'objectclass=';
1206
-		foreach($objectclasses as $key => $value) {
1207
-			$objectclasses[$key] = $p.$value;
1208
-		}
1209
-		$maxEntryObjC = '';
1210
-
1211
-		//how deep to dig?
1212
-		//When looking for objectclasses, testing few entries is sufficient,
1213
-		$dig = 3;
1214
-
1215
-		$availableFeatures =
1216
-			$this->cumulativeSearchOnAttribute($objectclasses, $attr,
1217
-											   $dig, $maxEntryObjC);
1218
-		if(is_array($availableFeatures)
1219
-		   && count($availableFeatures) > 0) {
1220
-			natcasesort($availableFeatures);
1221
-			//natcasesort keeps indices, but we must get rid of them for proper
1222
-			//sorting in the web UI. Therefore: array_values
1223
-			$this->result->addOptions($dbkey, array_values($availableFeatures));
1224
-		} else {
1225
-			throw new \Exception(self::$l->t('Could not find the desired feature'));
1226
-		}
1227
-
1228
-		$setFeatures = $this->configuration->$confkey;
1229
-		if(is_array($setFeatures) && !empty($setFeatures)) {
1230
-			//something is already configured? pre-select it.
1231
-			$this->result->addChange($dbkey, $setFeatures);
1232
-		} else if ($po && $maxEntryObjC !== '') {
1233
-			//pre-select objectclass with most result entries
1234
-			$maxEntryObjC = str_replace($p, '', $maxEntryObjC);
1235
-			$this->applyFind($dbkey, $maxEntryObjC);
1236
-			$this->result->addChange($dbkey, $maxEntryObjC);
1237
-		}
1238
-
1239
-		return $availableFeatures;
1240
-	}
1241
-
1242
-	/**
1243
-	 * appends a list of values fr
1244
-	 * @param resource $result the return value from ldap_get_attributes
1245
-	 * @param string $attribute the attribute values to look for
1246
-	 * @param array &$known new values will be appended here
1247
-	 * @return int, state on of the class constants LRESULT_PROCESSED_OK,
1248
-	 * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP
1249
-	 */
1250
-	private function getAttributeValuesFromEntry($result, $attribute, &$known) {
1251
-		if(!is_array($result)
1252
-		   || !isset($result['count'])
1253
-		   || !$result['count'] > 0) {
1254
-			return self::LRESULT_PROCESSED_INVALID;
1255
-		}
1256
-
1257
-		// strtolower on all keys for proper comparison
1258
-		$result = \OCP\Util::mb_array_change_key_case($result);
1259
-		$attribute = strtolower($attribute);
1260
-		if(isset($result[$attribute])) {
1261
-			foreach($result[$attribute] as $key => $val) {
1262
-				if($key === 'count') {
1263
-					continue;
1264
-				}
1265
-				if(!in_array($val, $known)) {
1266
-					$known[] = $val;
1267
-				}
1268
-			}
1269
-			return self::LRESULT_PROCESSED_OK;
1270
-		} else {
1271
-			return self::LRESULT_PROCESSED_SKIP;
1272
-		}
1273
-	}
1274
-
1275
-	/**
1276
-	 * @return bool|mixed
1277
-	 */
1278
-	private function getConnection() {
1279
-		if(!is_null($this->cr)) {
1280
-			return $this->cr;
1281
-		}
1282
-
1283
-		$cr = $this->ldap->connect(
1284
-			$this->configuration->ldapHost,
1285
-			$this->configuration->ldapPort
1286
-		);
1287
-
1288
-		$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1289
-		$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1290
-		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1291
-		if($this->configuration->ldapTLS === 1) {
1292
-			$this->ldap->startTls($cr);
1293
-		}
1294
-
1295
-		$lo = @$this->ldap->bind($cr,
1296
-								 $this->configuration->ldapAgentName,
1297
-								 $this->configuration->ldapAgentPassword);
1298
-		if($lo === true) {
1299
-			$this->$cr = $cr;
1300
-			return $cr;
1301
-		}
1302
-
1303
-		return false;
1304
-	}
1305
-
1306
-	/**
1307
-	 * @return array
1308
-	 */
1309
-	private function getDefaultLdapPortSettings() {
1310
-		static $settings = array(
1311
-								array('port' => 7636, 'tls' => false),
1312
-								array('port' =>  636, 'tls' => false),
1313
-								array('port' => 7389, 'tls' => true),
1314
-								array('port' =>  389, 'tls' => true),
1315
-								array('port' => 7389, 'tls' => false),
1316
-								array('port' =>  389, 'tls' => false),
1317
-						  );
1318
-		return $settings;
1319
-	}
1320
-
1321
-	/**
1322
-	 * @return array
1323
-	 */
1324
-	private function getPortSettingsToTry() {
1325
-		//389 ← LDAP / Unencrypted or StartTLS
1326
-		//636 ← LDAPS / SSL
1327
-		//7xxx ← UCS. need to be checked first, because both ports may be open
1328
-		$host = $this->configuration->ldapHost;
1329
-		$port = (int)$this->configuration->ldapPort;
1330
-		$portSettings = array();
1331
-
1332
-		//In case the port is already provided, we will check this first
1333
-		if($port > 0) {
1334
-			$hostInfo = parse_url($host);
1335
-			if(!(is_array($hostInfo)
1336
-				&& isset($hostInfo['scheme'])
1337
-				&& stripos($hostInfo['scheme'], 'ldaps') !== false)) {
1338
-				$portSettings[] = array('port' => $port, 'tls' => true);
1339
-			}
1340
-			$portSettings[] =array('port' => $port, 'tls' => false);
1341
-		}
1342
-
1343
-		//default ports
1344
-		$portSettings = array_merge($portSettings,
1345
-		                            $this->getDefaultLdapPortSettings());
1346
-
1347
-		return $portSettings;
1348
-	}
44
+    /** @var \OCP\IL10N */
45
+    static protected $l;
46
+    protected $access;
47
+    protected $cr;
48
+    protected $configuration;
49
+    protected $result;
50
+    protected $resultCache = array();
51
+
52
+    const LRESULT_PROCESSED_OK = 2;
53
+    const LRESULT_PROCESSED_INVALID = 3;
54
+    const LRESULT_PROCESSED_SKIP = 4;
55
+
56
+    const LFILTER_LOGIN      = 2;
57
+    const LFILTER_USER_LIST  = 3;
58
+    const LFILTER_GROUP_LIST = 4;
59
+
60
+    const LFILTER_MODE_ASSISTED = 2;
61
+    const LFILTER_MODE_RAW = 1;
62
+
63
+    const LDAP_NW_TIMEOUT = 4;
64
+
65
+    /**
66
+     * Constructor
67
+     * @param Configuration $configuration an instance of Configuration
68
+     * @param ILDAPWrapper $ldap an instance of ILDAPWrapper
69
+     * @param Access $access
70
+     */
71
+    public function __construct(Configuration $configuration, ILDAPWrapper $ldap, Access $access) {
72
+        parent::__construct($ldap);
73
+        $this->configuration = $configuration;
74
+        if(is_null(Wizard::$l)) {
75
+            Wizard::$l = \OC::$server->getL10N('user_ldap');
76
+        }
77
+        $this->access = $access;
78
+        $this->result = new WizardResult();
79
+    }
80
+
81
+    public function  __destruct() {
82
+        if($this->result->hasChanges()) {
83
+            $this->configuration->saveConfiguration();
84
+        }
85
+    }
86
+
87
+    /**
88
+     * counts entries in the LDAP directory
89
+     *
90
+     * @param string $filter the LDAP search filter
91
+     * @param string $type a string being either 'users' or 'groups';
92
+     * @return bool|int
93
+     * @throws \Exception
94
+     */
95
+    public function countEntries($filter, $type) {
96
+        $reqs = array('ldapHost', 'ldapPort', 'ldapBase');
97
+        if($type === 'users') {
98
+            $reqs[] = 'ldapUserFilter';
99
+        }
100
+        if(!$this->checkRequirements($reqs)) {
101
+            throw new \Exception('Requirements not met', 400);
102
+        }
103
+
104
+        $attr = array('dn'); // default
105
+        $limit = 1001;
106
+        if($type === 'groups') {
107
+            $result =  $this->access->countGroups($filter, $attr, $limit);
108
+        } else if($type === 'users') {
109
+            $result = $this->access->countUsers($filter, $attr, $limit);
110
+        } else if ($type === 'objects') {
111
+            $result = $this->access->countObjects($limit);
112
+        } else {
113
+            throw new \Exception('Internal error: Invalid object type', 500);
114
+        }
115
+
116
+        return $result;
117
+    }
118
+
119
+    /**
120
+     * formats the return value of a count operation to the string to be
121
+     * inserted.
122
+     *
123
+     * @param bool|int $count
124
+     * @return int|string
125
+     */
126
+    private function formatCountResult($count) {
127
+        $formatted = ($count !== false) ? $count : 0;
128
+        if($formatted > 1000) {
129
+            $formatted = '> 1000';
130
+        }
131
+        return $formatted;
132
+    }
133
+
134
+    public function countGroups() {
135
+        $filter = $this->configuration->ldapGroupFilter;
136
+
137
+        if(empty($filter)) {
138
+            $output = self::$l->n('%s group found', '%s groups found', 0, array(0));
139
+            $this->result->addChange('ldap_group_count', $output);
140
+            return $this->result;
141
+        }
142
+
143
+        try {
144
+            $groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups'));
145
+        } catch (\Exception $e) {
146
+            //400 can be ignored, 500 is forwarded
147
+            if($e->getCode() === 500) {
148
+                throw $e;
149
+            }
150
+            return false;
151
+        }
152
+        $output = self::$l->n('%s group found', '%s groups found', $groupsTotal, array($groupsTotal));
153
+        $this->result->addChange('ldap_group_count', $output);
154
+        return $this->result;
155
+    }
156
+
157
+    /**
158
+     * @return WizardResult
159
+     * @throws \Exception
160
+     */
161
+    public function countUsers() {
162
+        $filter = $this->access->getFilterForUserCount();
163
+
164
+        $usersTotal = $this->formatCountResult($this->countEntries($filter, 'users'));
165
+        $output = self::$l->n('%s user found', '%s users found', $usersTotal, array($usersTotal));
166
+        $this->result->addChange('ldap_user_count', $output);
167
+        return $this->result;
168
+    }
169
+
170
+    /**
171
+     * counts any objects in the currently set base dn
172
+     *
173
+     * @return WizardResult
174
+     * @throws \Exception
175
+     */
176
+    public function countInBaseDN() {
177
+        // we don't need to provide a filter in this case
178
+        $total = $this->countEntries(null, 'objects');
179
+        if($total === false) {
180
+            throw new \Exception('invalid results received');
181
+        }
182
+        $this->result->addChange('ldap_test_base', $total);
183
+        return $this->result;
184
+    }
185
+
186
+    /**
187
+     * counts users with a specified attribute
188
+     * @param string $attr
189
+     * @param bool $existsCheck
190
+     * @return int|bool
191
+     */
192
+    public function countUsersWithAttribute($attr, $existsCheck = false) {
193
+        if(!$this->checkRequirements(array('ldapHost',
194
+                                            'ldapPort',
195
+                                            'ldapBase',
196
+                                            'ldapUserFilter',
197
+                                            ))) {
198
+            return  false;
199
+        }
200
+
201
+        $filter = $this->access->combineFilterWithAnd(array(
202
+            $this->configuration->ldapUserFilter,
203
+            $attr . '=*'
204
+        ));
205
+
206
+        $limit = ($existsCheck === false) ? null : 1;
207
+
208
+        return $this->access->countUsers($filter, array('dn'), $limit);
209
+    }
210
+
211
+    /**
212
+     * detects the display name attribute. If a setting is already present that
213
+     * returns at least one hit, the detection will be canceled.
214
+     * @return WizardResult|bool
215
+     * @throws \Exception
216
+     */
217
+    public function detectUserDisplayNameAttribute() {
218
+        if(!$this->checkRequirements(array('ldapHost',
219
+                                        'ldapPort',
220
+                                        'ldapBase',
221
+                                        'ldapUserFilter',
222
+                                        ))) {
223
+            return  false;
224
+        }
225
+
226
+        $attr = $this->configuration->ldapUserDisplayName;
227
+        if ($attr !== '' && $attr !== 'displayName') {
228
+            // most likely not the default value with upper case N,
229
+            // verify it still produces a result
230
+            $count = (int)$this->countUsersWithAttribute($attr, true);
231
+            if($count > 0) {
232
+                //no change, but we sent it back to make sure the user interface
233
+                //is still correct, even if the ajax call was cancelled meanwhile
234
+                $this->result->addChange('ldap_display_name', $attr);
235
+                return $this->result;
236
+            }
237
+        }
238
+
239
+        // first attribute that has at least one result wins
240
+        $displayNameAttrs = array('displayname', 'cn');
241
+        foreach ($displayNameAttrs as $attr) {
242
+            $count = (int)$this->countUsersWithAttribute($attr, true);
243
+
244
+            if($count > 0) {
245
+                $this->applyFind('ldap_display_name', $attr);
246
+                return $this->result;
247
+            }
248
+        }
249
+
250
+        throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced LDAP settings.'));
251
+    }
252
+
253
+    /**
254
+     * detects the most often used email attribute for users applying to the
255
+     * user list filter. If a setting is already present that returns at least
256
+     * one hit, the detection will be canceled.
257
+     * @return WizardResult|bool
258
+     */
259
+    public function detectEmailAttribute() {
260
+        if(!$this->checkRequirements(array('ldapHost',
261
+                                            'ldapPort',
262
+                                            'ldapBase',
263
+                                            'ldapUserFilter',
264
+                                            ))) {
265
+            return  false;
266
+        }
267
+
268
+        $attr = $this->configuration->ldapEmailAttribute;
269
+        if ($attr !== '') {
270
+            $count = (int)$this->countUsersWithAttribute($attr, true);
271
+            if($count > 0) {
272
+                return false;
273
+            }
274
+            $writeLog = true;
275
+        } else {
276
+            $writeLog = false;
277
+        }
278
+
279
+        $emailAttributes = array('mail', 'mailPrimaryAddress');
280
+        $winner = '';
281
+        $maxUsers = 0;
282
+        foreach($emailAttributes as $attr) {
283
+            $count = $this->countUsersWithAttribute($attr);
284
+            if($count > $maxUsers) {
285
+                $maxUsers = $count;
286
+                $winner = $attr;
287
+            }
288
+        }
289
+
290
+        if($winner !== '') {
291
+            $this->applyFind('ldap_email_attr', $winner);
292
+            if($writeLog) {
293
+                \OCP\Util::writeLog('user_ldap', 'The mail attribute has ' .
294
+                    'automatically been reset, because the original value ' .
295
+                    'did not return any results.', \OCP\Util::INFO);
296
+            }
297
+        }
298
+
299
+        return $this->result;
300
+    }
301
+
302
+    /**
303
+     * @return WizardResult
304
+     * @throws \Exception
305
+     */
306
+    public function determineAttributes() {
307
+        if(!$this->checkRequirements(array('ldapHost',
308
+                                            'ldapPort',
309
+                                            'ldapBase',
310
+                                            'ldapUserFilter',
311
+                                            ))) {
312
+            return  false;
313
+        }
314
+
315
+        $attributes = $this->getUserAttributes();
316
+
317
+        natcasesort($attributes);
318
+        $attributes = array_values($attributes);
319
+
320
+        $this->result->addOptions('ldap_loginfilter_attributes', $attributes);
321
+
322
+        $selected = $this->configuration->ldapLoginFilterAttributes;
323
+        if(is_array($selected) && !empty($selected)) {
324
+            $this->result->addChange('ldap_loginfilter_attributes', $selected);
325
+        }
326
+
327
+        return $this->result;
328
+    }
329
+
330
+    /**
331
+     * detects the available LDAP attributes
332
+     * @return array|false The instance's WizardResult instance
333
+     * @throws \Exception
334
+     */
335
+    private function getUserAttributes() {
336
+        if(!$this->checkRequirements(array('ldapHost',
337
+                                            'ldapPort',
338
+                                            'ldapBase',
339
+                                            'ldapUserFilter',
340
+                                            ))) {
341
+            return  false;
342
+        }
343
+        $cr = $this->getConnection();
344
+        if(!$cr) {
345
+            throw new \Exception('Could not connect to LDAP');
346
+        }
347
+
348
+        $base = $this->configuration->ldapBase[0];
349
+        $filter = $this->configuration->ldapUserFilter;
350
+        $rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1);
351
+        if(!$this->ldap->isResource($rr)) {
352
+            return false;
353
+        }
354
+        $er = $this->ldap->firstEntry($cr, $rr);
355
+        $attributes = $this->ldap->getAttributes($cr, $er);
356
+        $pureAttributes = array();
357
+        for($i = 0; $i < $attributes['count']; $i++) {
358
+            $pureAttributes[] = $attributes[$i];
359
+        }
360
+
361
+        return $pureAttributes;
362
+    }
363
+
364
+    /**
365
+     * detects the available LDAP groups
366
+     * @return WizardResult|false the instance's WizardResult instance
367
+     */
368
+    public function determineGroupsForGroups() {
369
+        return $this->determineGroups('ldap_groupfilter_groups',
370
+                                        'ldapGroupFilterGroups',
371
+                                        false);
372
+    }
373
+
374
+    /**
375
+     * detects the available LDAP groups
376
+     * @return WizardResult|false the instance's WizardResult instance
377
+     */
378
+    public function determineGroupsForUsers() {
379
+        return $this->determineGroups('ldap_userfilter_groups',
380
+                                        'ldapUserFilterGroups');
381
+    }
382
+
383
+    /**
384
+     * detects the available LDAP groups
385
+     * @param string $dbKey
386
+     * @param string $confKey
387
+     * @param bool $testMemberOf
388
+     * @return WizardResult|false the instance's WizardResult instance
389
+     * @throws \Exception
390
+     */
391
+    private function determineGroups($dbKey, $confKey, $testMemberOf = true) {
392
+        if(!$this->checkRequirements(array('ldapHost',
393
+                                            'ldapPort',
394
+                                            'ldapBase',
395
+                                            ))) {
396
+            return  false;
397
+        }
398
+        $cr = $this->getConnection();
399
+        if(!$cr) {
400
+            throw new \Exception('Could not connect to LDAP');
401
+        }
402
+
403
+        $this->fetchGroups($dbKey, $confKey);
404
+
405
+        if($testMemberOf) {
406
+            $this->configuration->hasMemberOfFilterSupport = $this->testMemberOf();
407
+            $this->result->markChange();
408
+            if(!$this->configuration->hasMemberOfFilterSupport) {
409
+                throw new \Exception('memberOf is not supported by the server');
410
+            }
411
+        }
412
+
413
+        return $this->result;
414
+    }
415
+
416
+    /**
417
+     * fetches all groups from LDAP and adds them to the result object
418
+     *
419
+     * @param string $dbKey
420
+     * @param string $confKey
421
+     * @return array $groupEntries
422
+     * @throws \Exception
423
+     */
424
+    public function fetchGroups($dbKey, $confKey) {
425
+        $obclasses = array('posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames', 'groupOfUniqueNames');
426
+
427
+        $filterParts = array();
428
+        foreach($obclasses as $obclass) {
429
+            $filterParts[] = 'objectclass='.$obclass;
430
+        }
431
+        //we filter for everything
432
+        //- that looks like a group and
433
+        //- has the group display name set
434
+        $filter = $this->access->combineFilterWithOr($filterParts);
435
+        $filter = $this->access->combineFilterWithAnd(array($filter, 'cn=*'));
436
+
437
+        $groupNames = array();
438
+        $groupEntries = array();
439
+        $limit = 400;
440
+        $offset = 0;
441
+        do {
442
+            // we need to request dn additionally here, otherwise memberOf
443
+            // detection will fail later
444
+            $result = $this->access->searchGroups($filter, array('cn', 'dn'), $limit, $offset);
445
+            foreach($result as $item) {
446
+                if(!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) {
447
+                    // just in case - no issue known
448
+                    continue;
449
+                }
450
+                $groupNames[] = $item['cn'][0];
451
+                $groupEntries[] = $item;
452
+            }
453
+            $offset += $limit;
454
+        } while ($this->access->hasMoreResults());
455
+
456
+        if(count($groupNames) > 0) {
457
+            natsort($groupNames);
458
+            $this->result->addOptions($dbKey, array_values($groupNames));
459
+        } else {
460
+            throw new \Exception(self::$l->t('Could not find the desired feature'));
461
+        }
462
+
463
+        $setFeatures = $this->configuration->$confKey;
464
+        if(is_array($setFeatures) && !empty($setFeatures)) {
465
+            //something is already configured? pre-select it.
466
+            $this->result->addChange($dbKey, $setFeatures);
467
+        }
468
+        return $groupEntries;
469
+    }
470
+
471
+    public function determineGroupMemberAssoc() {
472
+        if(!$this->checkRequirements(array('ldapHost',
473
+                                            'ldapPort',
474
+                                            'ldapGroupFilter',
475
+                                            ))) {
476
+            return  false;
477
+        }
478
+        $attribute = $this->detectGroupMemberAssoc();
479
+        if($attribute === false) {
480
+            return false;
481
+        }
482
+        $this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute));
483
+        $this->result->addChange('ldap_group_member_assoc_attribute', $attribute);
484
+
485
+        return $this->result;
486
+    }
487
+
488
+    /**
489
+     * Detects the available object classes
490
+     * @return WizardResult|false the instance's WizardResult instance
491
+     * @throws \Exception
492
+     */
493
+    public function determineGroupObjectClasses() {
494
+        if(!$this->checkRequirements(array('ldapHost',
495
+                                            'ldapPort',
496
+                                            'ldapBase',
497
+                                            ))) {
498
+            return  false;
499
+        }
500
+        $cr = $this->getConnection();
501
+        if(!$cr) {
502
+            throw new \Exception('Could not connect to LDAP');
503
+        }
504
+
505
+        $obclasses = array('groupOfNames', 'groupOfUniqueNames', 'group', 'posixGroup', '*');
506
+        $this->determineFeature($obclasses,
507
+                                'objectclass',
508
+                                'ldap_groupfilter_objectclass',
509
+                                'ldapGroupFilterObjectclass',
510
+                                false);
511
+
512
+        return $this->result;
513
+    }
514
+
515
+    /**
516
+     * detects the available object classes
517
+     * @return WizardResult
518
+     * @throws \Exception
519
+     */
520
+    public function determineUserObjectClasses() {
521
+        if(!$this->checkRequirements(array('ldapHost',
522
+                                            'ldapPort',
523
+                                            'ldapBase',
524
+                                            ))) {
525
+            return  false;
526
+        }
527
+        $cr = $this->getConnection();
528
+        if(!$cr) {
529
+            throw new \Exception('Could not connect to LDAP');
530
+        }
531
+
532
+        $obclasses = array('inetOrgPerson', 'person', 'organizationalPerson',
533
+                            'user', 'posixAccount', '*');
534
+        $filter = $this->configuration->ldapUserFilter;
535
+        //if filter is empty, it is probably the first time the wizard is called
536
+        //then, apply suggestions.
537
+        $this->determineFeature($obclasses,
538
+                                'objectclass',
539
+                                'ldap_userfilter_objectclass',
540
+                                'ldapUserFilterObjectclass',
541
+                                empty($filter));
542
+
543
+        return $this->result;
544
+    }
545
+
546
+    /**
547
+     * @return WizardResult|false
548
+     * @throws \Exception
549
+     */
550
+    public function getGroupFilter() {
551
+        if(!$this->checkRequirements(array('ldapHost',
552
+                                            'ldapPort',
553
+                                            'ldapBase',
554
+                                            ))) {
555
+            return false;
556
+        }
557
+        //make sure the use display name is set
558
+        $displayName = $this->configuration->ldapGroupDisplayName;
559
+        if ($displayName === '') {
560
+            $d = $this->configuration->getDefaults();
561
+            $this->applyFind('ldap_group_display_name',
562
+                                $d['ldap_group_display_name']);
563
+        }
564
+        $filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST);
565
+
566
+        $this->applyFind('ldap_group_filter', $filter);
567
+        return $this->result;
568
+    }
569
+
570
+    /**
571
+     * @return WizardResult|false
572
+     * @throws \Exception
573
+     */
574
+    public function getUserListFilter() {
575
+        if(!$this->checkRequirements(array('ldapHost',
576
+                                            'ldapPort',
577
+                                            'ldapBase',
578
+                                            ))) {
579
+            return false;
580
+        }
581
+        //make sure the use display name is set
582
+        $displayName = $this->configuration->ldapUserDisplayName;
583
+        if ($displayName === '') {
584
+            $d = $this->configuration->getDefaults();
585
+            $this->applyFind('ldap_display_name', $d['ldap_display_name']);
586
+        }
587
+        $filter = $this->composeLdapFilter(self::LFILTER_USER_LIST);
588
+        if(!$filter) {
589
+            throw new \Exception('Cannot create filter');
590
+        }
591
+
592
+        $this->applyFind('ldap_userlist_filter', $filter);
593
+        return $this->result;
594
+    }
595
+
596
+    /**
597
+     * @return bool|WizardResult
598
+     * @throws \Exception
599
+     */
600
+    public function getUserLoginFilter() {
601
+        if(!$this->checkRequirements(array('ldapHost',
602
+                                            'ldapPort',
603
+                                            'ldapBase',
604
+                                            'ldapUserFilter',
605
+                                            ))) {
606
+            return false;
607
+        }
608
+
609
+        $filter = $this->composeLdapFilter(self::LFILTER_LOGIN);
610
+        if(!$filter) {
611
+            throw new \Exception('Cannot create filter');
612
+        }
613
+
614
+        $this->applyFind('ldap_login_filter', $filter);
615
+        return $this->result;
616
+    }
617
+
618
+    /**
619
+     * @return bool|WizardResult
620
+     * @param string $loginName
621
+     * @throws \Exception
622
+     */
623
+    public function testLoginName($loginName) {
624
+        if(!$this->checkRequirements(array('ldapHost',
625
+            'ldapPort',
626
+            'ldapBase',
627
+            'ldapLoginFilter',
628
+        ))) {
629
+            return false;
630
+        }
631
+
632
+        $cr = $this->access->connection->getConnectionResource();
633
+        if(!$this->ldap->isResource($cr)) {
634
+            throw new \Exception('connection error');
635
+        }
636
+
637
+        if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8')
638
+            === false) {
639
+            throw new \Exception('missing placeholder');
640
+        }
641
+
642
+        $users = $this->access->countUsersByLoginName($loginName);
643
+        if($this->ldap->errno($cr) !== 0) {
644
+            throw new \Exception($this->ldap->error($cr));
645
+        }
646
+        $filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
647
+        $this->result->addChange('ldap_test_loginname', $users);
648
+        $this->result->addChange('ldap_test_effective_filter', $filter);
649
+        return $this->result;
650
+    }
651
+
652
+    /**
653
+     * Tries to determine the port, requires given Host, User DN and Password
654
+     * @return WizardResult|false WizardResult on success, false otherwise
655
+     * @throws \Exception
656
+     */
657
+    public function guessPortAndTLS() {
658
+        if(!$this->checkRequirements(array('ldapHost',
659
+                                            ))) {
660
+            return false;
661
+        }
662
+        $this->checkHost();
663
+        $portSettings = $this->getPortSettingsToTry();
664
+
665
+        if(!is_array($portSettings)) {
666
+            throw new \Exception(print_r($portSettings, true));
667
+        }
668
+
669
+        //proceed from the best configuration and return on first success
670
+        foreach($portSettings as $setting) {
671
+            $p = $setting['port'];
672
+            $t = $setting['tls'];
673
+            \OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG);
674
+            //connectAndBind may throw Exception, it needs to be catched by the
675
+            //callee of this method
676
+
677
+            try {
678
+                $settingsFound = $this->connectAndBind($p, $t);
679
+            } catch (\Exception $e) {
680
+                // any reply other than -1 (= cannot connect) is already okay,
681
+                // because then we found the server
682
+                // unavailable startTLS returns -11
683
+                if($e->getCode() > 0) {
684
+                    $settingsFound = true;
685
+                } else {
686
+                    throw $e;
687
+                }
688
+            }
689
+
690
+            if ($settingsFound === true) {
691
+                $config = array(
692
+                    'ldapPort' => $p,
693
+                    'ldapTLS' => (int)$t
694
+                );
695
+                $this->configuration->setConfiguration($config);
696
+                \OCP\Util::writeLog('user_ldap', 'Wiz: detected Port ' . $p, \OCP\Util::DEBUG);
697
+                $this->result->addChange('ldap_port', $p);
698
+                return $this->result;
699
+            }
700
+        }
701
+
702
+        //custom port, undetected (we do not brute force)
703
+        return false;
704
+    }
705
+
706
+    /**
707
+     * tries to determine a base dn from User DN or LDAP Host
708
+     * @return WizardResult|false WizardResult on success, false otherwise
709
+     */
710
+    public function guessBaseDN() {
711
+        if(!$this->checkRequirements(array('ldapHost',
712
+                                            'ldapPort',
713
+                                            ))) {
714
+            return false;
715
+        }
716
+
717
+        //check whether a DN is given in the agent name (99.9% of all cases)
718
+        $base = null;
719
+        $i = stripos($this->configuration->ldapAgentName, 'dc=');
720
+        if($i !== false) {
721
+            $base = substr($this->configuration->ldapAgentName, $i);
722
+            if($this->testBaseDN($base)) {
723
+                $this->applyFind('ldap_base', $base);
724
+                return $this->result;
725
+            }
726
+        }
727
+
728
+        //this did not help :(
729
+        //Let's see whether we can parse the Host URL and convert the domain to
730
+        //a base DN
731
+        $helper = new Helper(\OC::$server->getConfig());
732
+        $domain = $helper->getDomainFromURL($this->configuration->ldapHost);
733
+        if(!$domain) {
734
+            return false;
735
+        }
736
+
737
+        $dparts = explode('.', $domain);
738
+        while(count($dparts) > 0) {
739
+            $base2 = 'dc=' . implode(',dc=', $dparts);
740
+            if ($base !== $base2 && $this->testBaseDN($base2)) {
741
+                $this->applyFind('ldap_base', $base2);
742
+                return $this->result;
743
+            }
744
+            array_shift($dparts);
745
+        }
746
+
747
+        return false;
748
+    }
749
+
750
+    /**
751
+     * sets the found value for the configuration key in the WizardResult
752
+     * as well as in the Configuration instance
753
+     * @param string $key the configuration key
754
+     * @param string $value the (detected) value
755
+     *
756
+     */
757
+    private function applyFind($key, $value) {
758
+        $this->result->addChange($key, $value);
759
+        $this->configuration->setConfiguration(array($key => $value));
760
+    }
761
+
762
+    /**
763
+     * Checks, whether a port was entered in the Host configuration
764
+     * field. In this case the port will be stripped off, but also stored as
765
+     * setting.
766
+     */
767
+    private function checkHost() {
768
+        $host = $this->configuration->ldapHost;
769
+        $hostInfo = parse_url($host);
770
+
771
+        //removes Port from Host
772
+        if(is_array($hostInfo) && isset($hostInfo['port'])) {
773
+            $port = $hostInfo['port'];
774
+            $host = str_replace(':'.$port, '', $host);
775
+            $this->applyFind('ldap_host', $host);
776
+            $this->applyFind('ldap_port', $port);
777
+        }
778
+    }
779
+
780
+    /**
781
+     * tries to detect the group member association attribute which is
782
+     * one of 'uniqueMember', 'memberUid', 'member', 'gidNumber'
783
+     * @return string|false, string with the attribute name, false on error
784
+     * @throws \Exception
785
+     */
786
+    private function detectGroupMemberAssoc() {
787
+        $possibleAttrs = array('uniqueMember', 'memberUid', 'member', 'gidNumber');
788
+        $filter = $this->configuration->ldapGroupFilter;
789
+        if(empty($filter)) {
790
+            return false;
791
+        }
792
+        $cr = $this->getConnection();
793
+        if(!$cr) {
794
+            throw new \Exception('Could not connect to LDAP');
795
+        }
796
+        $base = $this->configuration->ldapBase[0];
797
+        $rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000);
798
+        if(!$this->ldap->isResource($rr)) {
799
+            return false;
800
+        }
801
+        $er = $this->ldap->firstEntry($cr, $rr);
802
+        while(is_resource($er)) {
803
+            $this->ldap->getDN($cr, $er);
804
+            $attrs = $this->ldap->getAttributes($cr, $er);
805
+            $result = array();
806
+            $possibleAttrsCount = count($possibleAttrs);
807
+            for($i = 0; $i < $possibleAttrsCount; $i++) {
808
+                if(isset($attrs[$possibleAttrs[$i]])) {
809
+                    $result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count'];
810
+                }
811
+            }
812
+            if(!empty($result)) {
813
+                natsort($result);
814
+                return key($result);
815
+            }
816
+
817
+            $er = $this->ldap->nextEntry($cr, $er);
818
+        }
819
+
820
+        return false;
821
+    }
822
+
823
+    /**
824
+     * Checks whether for a given BaseDN results will be returned
825
+     * @param string $base the BaseDN to test
826
+     * @return bool true on success, false otherwise
827
+     * @throws \Exception
828
+     */
829
+    private function testBaseDN($base) {
830
+        $cr = $this->getConnection();
831
+        if(!$cr) {
832
+            throw new \Exception('Could not connect to LDAP');
833
+        }
834
+
835
+        //base is there, let's validate it. If we search for anything, we should
836
+        //get a result set > 0 on a proper base
837
+        $rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1);
838
+        if(!$this->ldap->isResource($rr)) {
839
+            $errorNo  = $this->ldap->errno($cr);
840
+            $errorMsg = $this->ldap->error($cr);
841
+            \OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base.
842
+                            ' Error '.$errorNo.': '.$errorMsg, \OCP\Util::INFO);
843
+            return false;
844
+        }
845
+        $entries = $this->ldap->countEntries($cr, $rr);
846
+        return ($entries !== false) && ($entries > 0);
847
+    }
848
+
849
+    /**
850
+     * Checks whether the server supports memberOf in LDAP Filter.
851
+     * Note: at least in OpenLDAP, availability of memberOf is dependent on
852
+     * a configured objectClass. I.e. not necessarily for all available groups
853
+     * memberOf does work.
854
+     *
855
+     * @return bool true if it does, false otherwise
856
+     * @throws \Exception
857
+     */
858
+    private function testMemberOf() {
859
+        $cr = $this->getConnection();
860
+        if(!$cr) {
861
+            throw new \Exception('Could not connect to LDAP');
862
+        }
863
+        $result = $this->access->countUsers('memberOf=*', array('memberOf'), 1);
864
+        if(is_int($result) &&  $result > 0) {
865
+            return true;
866
+        }
867
+        return false;
868
+    }
869
+
870
+    /**
871
+     * creates an LDAP Filter from given configuration
872
+     * @param integer $filterType int, for which use case the filter shall be created
873
+     * can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or
874
+     * self::LFILTER_GROUP_LIST
875
+     * @return string|false string with the filter on success, false otherwise
876
+     * @throws \Exception
877
+     */
878
+    private function composeLdapFilter($filterType) {
879
+        $filter = '';
880
+        $parts = 0;
881
+        switch ($filterType) {
882
+            case self::LFILTER_USER_LIST:
883
+                $objcs = $this->configuration->ldapUserFilterObjectclass;
884
+                //glue objectclasses
885
+                if(is_array($objcs) && count($objcs) > 0) {
886
+                    $filter .= '(|';
887
+                    foreach($objcs as $objc) {
888
+                        $filter .= '(objectclass=' . $objc . ')';
889
+                    }
890
+                    $filter .= ')';
891
+                    $parts++;
892
+                }
893
+                //glue group memberships
894
+                if($this->configuration->hasMemberOfFilterSupport) {
895
+                    $cns = $this->configuration->ldapUserFilterGroups;
896
+                    if(is_array($cns) && count($cns) > 0) {
897
+                        $filter .= '(|';
898
+                        $cr = $this->getConnection();
899
+                        if(!$cr) {
900
+                            throw new \Exception('Could not connect to LDAP');
901
+                        }
902
+                        $base = $this->configuration->ldapBase[0];
903
+                        foreach($cns as $cn) {
904
+                            $rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken'));
905
+                            if(!$this->ldap->isResource($rr)) {
906
+                                continue;
907
+                            }
908
+                            $er = $this->ldap->firstEntry($cr, $rr);
909
+                            $attrs = $this->ldap->getAttributes($cr, $er);
910
+                            $dn = $this->ldap->getDN($cr, $er);
911
+                            if ($dn === false || $dn === '') {
912
+                                continue;
913
+                            }
914
+                            $filterPart = '(memberof=' . $dn . ')';
915
+                            if(isset($attrs['primaryGroupToken'])) {
916
+                                $pgt = $attrs['primaryGroupToken'][0];
917
+                                $primaryFilterPart = '(primaryGroupID=' . $pgt .')';
918
+                                $filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
919
+                            }
920
+                            $filter .= $filterPart;
921
+                        }
922
+                        $filter .= ')';
923
+                    }
924
+                    $parts++;
925
+                }
926
+                //wrap parts in AND condition
927
+                if($parts > 1) {
928
+                    $filter = '(&' . $filter . ')';
929
+                }
930
+                if ($filter === '') {
931
+                    $filter = '(objectclass=*)';
932
+                }
933
+                break;
934
+
935
+            case self::LFILTER_GROUP_LIST:
936
+                $objcs = $this->configuration->ldapGroupFilterObjectclass;
937
+                //glue objectclasses
938
+                if(is_array($objcs) && count($objcs) > 0) {
939
+                    $filter .= '(|';
940
+                    foreach($objcs as $objc) {
941
+                        $filter .= '(objectclass=' . $objc . ')';
942
+                    }
943
+                    $filter .= ')';
944
+                    $parts++;
945
+                }
946
+                //glue group memberships
947
+                $cns = $this->configuration->ldapGroupFilterGroups;
948
+                if(is_array($cns) && count($cns) > 0) {
949
+                    $filter .= '(|';
950
+                    foreach($cns as $cn) {
951
+                        $filter .= '(cn=' . $cn . ')';
952
+                    }
953
+                    $filter .= ')';
954
+                }
955
+                $parts++;
956
+                //wrap parts in AND condition
957
+                if($parts > 1) {
958
+                    $filter = '(&' . $filter . ')';
959
+                }
960
+                break;
961
+
962
+            case self::LFILTER_LOGIN:
963
+                $ulf = $this->configuration->ldapUserFilter;
964
+                $loginpart = '=%uid';
965
+                $filterUsername = '';
966
+                $userAttributes = $this->getUserAttributes();
967
+                $userAttributes = array_change_key_case(array_flip($userAttributes));
968
+                $parts = 0;
969
+
970
+                if($this->configuration->ldapLoginFilterUsername === '1') {
971
+                    $attr = '';
972
+                    if(isset($userAttributes['uid'])) {
973
+                        $attr = 'uid';
974
+                    } else if(isset($userAttributes['samaccountname'])) {
975
+                        $attr = 'samaccountname';
976
+                    } else if(isset($userAttributes['cn'])) {
977
+                        //fallback
978
+                        $attr = 'cn';
979
+                    }
980
+                    if ($attr !== '') {
981
+                        $filterUsername = '(' . $attr . $loginpart . ')';
982
+                        $parts++;
983
+                    }
984
+                }
985
+
986
+                $filterEmail = '';
987
+                if($this->configuration->ldapLoginFilterEmail === '1') {
988
+                    $filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))';
989
+                    $parts++;
990
+                }
991
+
992
+                $filterAttributes = '';
993
+                $attrsToFilter = $this->configuration->ldapLoginFilterAttributes;
994
+                if(is_array($attrsToFilter) && count($attrsToFilter) > 0) {
995
+                    $filterAttributes = '(|';
996
+                    foreach($attrsToFilter as $attribute) {
997
+                        $filterAttributes .= '(' . $attribute . $loginpart . ')';
998
+                    }
999
+                    $filterAttributes .= ')';
1000
+                    $parts++;
1001
+                }
1002
+
1003
+                $filterLogin = '';
1004
+                if($parts > 1) {
1005
+                    $filterLogin = '(|';
1006
+                }
1007
+                $filterLogin .= $filterUsername;
1008
+                $filterLogin .= $filterEmail;
1009
+                $filterLogin .= $filterAttributes;
1010
+                if($parts > 1) {
1011
+                    $filterLogin .= ')';
1012
+                }
1013
+
1014
+                $filter = '(&'.$ulf.$filterLogin.')';
1015
+                break;
1016
+        }
1017
+
1018
+        \OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG);
1019
+
1020
+        return $filter;
1021
+    }
1022
+
1023
+    /**
1024
+     * Connects and Binds to an LDAP Server
1025
+     *
1026
+     * @param int $port the port to connect with
1027
+     * @param bool $tls whether startTLS is to be used
1028
+     * @return bool
1029
+     * @throws \Exception
1030
+     */
1031
+    private function connectAndBind($port, $tls) {
1032
+        //connect, does not really trigger any server communication
1033
+        $host = $this->configuration->ldapHost;
1034
+        $hostInfo = parse_url($host);
1035
+        if(!$hostInfo) {
1036
+            throw new \Exception(self::$l->t('Invalid Host'));
1037
+        }
1038
+        \OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG);
1039
+        $cr = $this->ldap->connect($host, $port);
1040
+        if(!is_resource($cr)) {
1041
+            throw new \Exception(self::$l->t('Invalid Host'));
1042
+        }
1043
+
1044
+        //set LDAP options
1045
+        $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1046
+        $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1047
+        $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1048
+
1049
+        try {
1050
+            if($tls) {
1051
+                $isTlsWorking = @$this->ldap->startTls($cr);
1052
+                if(!$isTlsWorking) {
1053
+                    return false;
1054
+                }
1055
+            }
1056
+
1057
+            \OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG);
1058
+            //interesting part: do the bind!
1059
+            $login = $this->ldap->bind($cr,
1060
+                $this->configuration->ldapAgentName,
1061
+                $this->configuration->ldapAgentPassword
1062
+            );
1063
+            $errNo = $this->ldap->errno($cr);
1064
+            $error = ldap_error($cr);
1065
+            $this->ldap->unbind($cr);
1066
+        } catch(ServerNotAvailableException $e) {
1067
+            return false;
1068
+        }
1069
+
1070
+        if($login === true) {
1071
+            $this->ldap->unbind($cr);
1072
+            \OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '. $port . ' TLS ' . (int)$tls, \OCP\Util::DEBUG);
1073
+            return true;
1074
+        }
1075
+
1076
+        if($errNo === -1) {
1077
+            //host, port or TLS wrong
1078
+            return false;
1079
+        }
1080
+        throw new \Exception($error, $errNo);
1081
+    }
1082
+
1083
+    /**
1084
+     * checks whether a valid combination of agent and password has been
1085
+     * provided (either two values or nothing for anonymous connect)
1086
+     * @return bool, true if everything is fine, false otherwise
1087
+     */
1088
+    private function checkAgentRequirements() {
1089
+        $agent = $this->configuration->ldapAgentName;
1090
+        $pwd = $this->configuration->ldapAgentPassword;
1091
+
1092
+        return
1093
+            ($agent !== '' && $pwd !== '')
1094
+            ||  ($agent === '' && $pwd === '')
1095
+        ;
1096
+    }
1097
+
1098
+    /**
1099
+     * @param array $reqs
1100
+     * @return bool
1101
+     */
1102
+    private function checkRequirements($reqs) {
1103
+        $this->checkAgentRequirements();
1104
+        foreach($reqs as $option) {
1105
+            $value = $this->configuration->$option;
1106
+            if(empty($value)) {
1107
+                return false;
1108
+            }
1109
+        }
1110
+        return true;
1111
+    }
1112
+
1113
+    /**
1114
+     * does a cumulativeSearch on LDAP to get different values of a
1115
+     * specified attribute
1116
+     * @param string[] $filters array, the filters that shall be used in the search
1117
+     * @param string $attr the attribute of which a list of values shall be returned
1118
+     * @param int $dnReadLimit the amount of how many DNs should be analyzed.
1119
+     * The lower, the faster
1120
+     * @param string $maxF string. if not null, this variable will have the filter that
1121
+     * yields most result entries
1122
+     * @return array|false an array with the values on success, false otherwise
1123
+     */
1124
+    public function cumulativeSearchOnAttribute($filters, $attr, $dnReadLimit = 3, &$maxF = null) {
1125
+        $dnRead = array();
1126
+        $foundItems = array();
1127
+        $maxEntries = 0;
1128
+        if(!is_array($this->configuration->ldapBase)
1129
+           || !isset($this->configuration->ldapBase[0])) {
1130
+            return false;
1131
+        }
1132
+        $base = $this->configuration->ldapBase[0];
1133
+        $cr = $this->getConnection();
1134
+        if(!$this->ldap->isResource($cr)) {
1135
+            return false;
1136
+        }
1137
+        $lastFilter = null;
1138
+        if(isset($filters[count($filters)-1])) {
1139
+            $lastFilter = $filters[count($filters)-1];
1140
+        }
1141
+        foreach($filters as $filter) {
1142
+            if($lastFilter === $filter && count($foundItems) > 0) {
1143
+                //skip when the filter is a wildcard and results were found
1144
+                continue;
1145
+            }
1146
+            // 20k limit for performance and reason
1147
+            $rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000);
1148
+            if(!$this->ldap->isResource($rr)) {
1149
+                continue;
1150
+            }
1151
+            $entries = $this->ldap->countEntries($cr, $rr);
1152
+            $getEntryFunc = 'firstEntry';
1153
+            if(($entries !== false) && ($entries > 0)) {
1154
+                if(!is_null($maxF) && $entries > $maxEntries) {
1155
+                    $maxEntries = $entries;
1156
+                    $maxF = $filter;
1157
+                }
1158
+                $dnReadCount = 0;
1159
+                do {
1160
+                    $entry = $this->ldap->$getEntryFunc($cr, $rr);
1161
+                    $getEntryFunc = 'nextEntry';
1162
+                    if(!$this->ldap->isResource($entry)) {
1163
+                        continue 2;
1164
+                    }
1165
+                    $rr = $entry; //will be expected by nextEntry next round
1166
+                    $attributes = $this->ldap->getAttributes($cr, $entry);
1167
+                    $dn = $this->ldap->getDN($cr, $entry);
1168
+                    if($dn === false || in_array($dn, $dnRead)) {
1169
+                        continue;
1170
+                    }
1171
+                    $newItems = array();
1172
+                    $state = $this->getAttributeValuesFromEntry($attributes,
1173
+                                                                $attr,
1174
+                                                                $newItems);
1175
+                    $dnReadCount++;
1176
+                    $foundItems = array_merge($foundItems, $newItems);
1177
+                    $this->resultCache[$dn][$attr] = $newItems;
1178
+                    $dnRead[] = $dn;
1179
+                } while(($state === self::LRESULT_PROCESSED_SKIP
1180
+                        || $this->ldap->isResource($entry))
1181
+                        && ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit));
1182
+            }
1183
+        }
1184
+
1185
+        return array_unique($foundItems);
1186
+    }
1187
+
1188
+    /**
1189
+     * determines if and which $attr are available on the LDAP server
1190
+     * @param string[] $objectclasses the objectclasses to use as search filter
1191
+     * @param string $attr the attribute to look for
1192
+     * @param string $dbkey the dbkey of the setting the feature is connected to
1193
+     * @param string $confkey the confkey counterpart for the $dbkey as used in the
1194
+     * Configuration class
1195
+     * @param bool $po whether the objectClass with most result entries
1196
+     * shall be pre-selected via the result
1197
+     * @return array|false list of found items.
1198
+     * @throws \Exception
1199
+     */
1200
+    private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) {
1201
+        $cr = $this->getConnection();
1202
+        if(!$cr) {
1203
+            throw new \Exception('Could not connect to LDAP');
1204
+        }
1205
+        $p = 'objectclass=';
1206
+        foreach($objectclasses as $key => $value) {
1207
+            $objectclasses[$key] = $p.$value;
1208
+        }
1209
+        $maxEntryObjC = '';
1210
+
1211
+        //how deep to dig?
1212
+        //When looking for objectclasses, testing few entries is sufficient,
1213
+        $dig = 3;
1214
+
1215
+        $availableFeatures =
1216
+            $this->cumulativeSearchOnAttribute($objectclasses, $attr,
1217
+                                                $dig, $maxEntryObjC);
1218
+        if(is_array($availableFeatures)
1219
+           && count($availableFeatures) > 0) {
1220
+            natcasesort($availableFeatures);
1221
+            //natcasesort keeps indices, but we must get rid of them for proper
1222
+            //sorting in the web UI. Therefore: array_values
1223
+            $this->result->addOptions($dbkey, array_values($availableFeatures));
1224
+        } else {
1225
+            throw new \Exception(self::$l->t('Could not find the desired feature'));
1226
+        }
1227
+
1228
+        $setFeatures = $this->configuration->$confkey;
1229
+        if(is_array($setFeatures) && !empty($setFeatures)) {
1230
+            //something is already configured? pre-select it.
1231
+            $this->result->addChange($dbkey, $setFeatures);
1232
+        } else if ($po && $maxEntryObjC !== '') {
1233
+            //pre-select objectclass with most result entries
1234
+            $maxEntryObjC = str_replace($p, '', $maxEntryObjC);
1235
+            $this->applyFind($dbkey, $maxEntryObjC);
1236
+            $this->result->addChange($dbkey, $maxEntryObjC);
1237
+        }
1238
+
1239
+        return $availableFeatures;
1240
+    }
1241
+
1242
+    /**
1243
+     * appends a list of values fr
1244
+     * @param resource $result the return value from ldap_get_attributes
1245
+     * @param string $attribute the attribute values to look for
1246
+     * @param array &$known new values will be appended here
1247
+     * @return int, state on of the class constants LRESULT_PROCESSED_OK,
1248
+     * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP
1249
+     */
1250
+    private function getAttributeValuesFromEntry($result, $attribute, &$known) {
1251
+        if(!is_array($result)
1252
+           || !isset($result['count'])
1253
+           || !$result['count'] > 0) {
1254
+            return self::LRESULT_PROCESSED_INVALID;
1255
+        }
1256
+
1257
+        // strtolower on all keys for proper comparison
1258
+        $result = \OCP\Util::mb_array_change_key_case($result);
1259
+        $attribute = strtolower($attribute);
1260
+        if(isset($result[$attribute])) {
1261
+            foreach($result[$attribute] as $key => $val) {
1262
+                if($key === 'count') {
1263
+                    continue;
1264
+                }
1265
+                if(!in_array($val, $known)) {
1266
+                    $known[] = $val;
1267
+                }
1268
+            }
1269
+            return self::LRESULT_PROCESSED_OK;
1270
+        } else {
1271
+            return self::LRESULT_PROCESSED_SKIP;
1272
+        }
1273
+    }
1274
+
1275
+    /**
1276
+     * @return bool|mixed
1277
+     */
1278
+    private function getConnection() {
1279
+        if(!is_null($this->cr)) {
1280
+            return $this->cr;
1281
+        }
1282
+
1283
+        $cr = $this->ldap->connect(
1284
+            $this->configuration->ldapHost,
1285
+            $this->configuration->ldapPort
1286
+        );
1287
+
1288
+        $this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1289
+        $this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1290
+        $this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1291
+        if($this->configuration->ldapTLS === 1) {
1292
+            $this->ldap->startTls($cr);
1293
+        }
1294
+
1295
+        $lo = @$this->ldap->bind($cr,
1296
+                                    $this->configuration->ldapAgentName,
1297
+                                    $this->configuration->ldapAgentPassword);
1298
+        if($lo === true) {
1299
+            $this->$cr = $cr;
1300
+            return $cr;
1301
+        }
1302
+
1303
+        return false;
1304
+    }
1305
+
1306
+    /**
1307
+     * @return array
1308
+     */
1309
+    private function getDefaultLdapPortSettings() {
1310
+        static $settings = array(
1311
+                                array('port' => 7636, 'tls' => false),
1312
+                                array('port' =>  636, 'tls' => false),
1313
+                                array('port' => 7389, 'tls' => true),
1314
+                                array('port' =>  389, 'tls' => true),
1315
+                                array('port' => 7389, 'tls' => false),
1316
+                                array('port' =>  389, 'tls' => false),
1317
+                            );
1318
+        return $settings;
1319
+    }
1320
+
1321
+    /**
1322
+     * @return array
1323
+     */
1324
+    private function getPortSettingsToTry() {
1325
+        //389 ← LDAP / Unencrypted or StartTLS
1326
+        //636 ← LDAPS / SSL
1327
+        //7xxx ← UCS. need to be checked first, because both ports may be open
1328
+        $host = $this->configuration->ldapHost;
1329
+        $port = (int)$this->configuration->ldapPort;
1330
+        $portSettings = array();
1331
+
1332
+        //In case the port is already provided, we will check this first
1333
+        if($port > 0) {
1334
+            $hostInfo = parse_url($host);
1335
+            if(!(is_array($hostInfo)
1336
+                && isset($hostInfo['scheme'])
1337
+                && stripos($hostInfo['scheme'], 'ldaps') !== false)) {
1338
+                $portSettings[] = array('port' => $port, 'tls' => true);
1339
+            }
1340
+            $portSettings[] =array('port' => $port, 'tls' => false);
1341
+        }
1342
+
1343
+        //default ports
1344
+        $portSettings = array_merge($portSettings,
1345
+                                    $this->getDefaultLdapPortSettings());
1346
+
1347
+        return $portSettings;
1348
+    }
1349 1349
 
1350 1350
 
1351 1351
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/SharedMount.php 3 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
 	 *
111 111
 	 * @param string $newPath
112 112
 	 * @param \OCP\Share\IShare $share
113
-	 * @return bool
113
+	 * @return boolean|null
114 114
 	 */
115 115
 	private function updateFileTarget($newPath, &$share) {
116 116
 		$share->setTarget($newPath);
@@ -126,7 +126,7 @@  discard block
 block discarded – undo
126 126
 	 * @param string $path
127 127
 	 * @param View $view
128 128
 	 * @param SharedMount[] $mountpoints
129
-	 * @return mixed
129
+	 * @return string
130 130
 	 */
131 131
 	private function generateUniqueTarget($path, $view, array $mountpoints) {
132 132
 		$pathinfo = pathinfo($path);
Please login to merge, or discard this patch.
Indentation   +226 added lines, -226 removed lines patch added patch discarded remove patch
@@ -37,230 +37,230 @@
 block discarded – undo
37 37
  * Shared mount points can be moved by the user
38 38
  */
39 39
 class SharedMount extends MountPoint implements MoveableMount {
40
-	/**
41
-	 * @var \OCA\Files_Sharing\SharedStorage $storage
42
-	 */
43
-	protected $storage = null;
44
-
45
-	/**
46
-	 * @var \OC\Files\View
47
-	 */
48
-	private $recipientView;
49
-
50
-	/**
51
-	 * @var string
52
-	 */
53
-	private $user;
54
-
55
-	/** @var \OCP\Share\IShare */
56
-	private $superShare;
57
-
58
-	/** @var \OCP\Share\IShare[] */
59
-	private $groupedShares;
60
-
61
-	/**
62
-	 * @param string $storage
63
-	 * @param SharedMount[] $mountpoints
64
-	 * @param array|null $arguments
65
-	 * @param \OCP\Files\Storage\IStorageFactory $loader
66
-	 */
67
-	public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) {
68
-		$this->user = $arguments['user'];
69
-		$this->recipientView = new View('/' . $this->user . '/files');
70
-
71
-		$this->superShare = $arguments['superShare'];
72
-		$this->groupedShares = $arguments['groupedShares'];
73
-
74
-		$newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints);
75
-		$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
76
-		$arguments['ownerView'] = new View('/' . $this->superShare->getShareOwner() . '/files');
77
-		parent::__construct($storage, $absMountPoint, $arguments, $loader);
78
-	}
79
-
80
-	/**
81
-	 * check if the parent folder exists otherwise move the mount point up
82
-	 *
83
-	 * @param \OCP\Share\IShare $share
84
-	 * @param SharedMount[] $mountpoints
85
-	 * @return string
86
-	 */
87
-	private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints) {
88
-
89
-		$mountPoint = basename($share->getTarget());
90
-		$parent = dirname($share->getTarget());
91
-
92
-		if (!$this->recipientView->is_dir($parent)) {
93
-			$parent = Helper::getShareFolder($this->recipientView);
94
-		}
95
-
96
-		$newMountPoint = $this->generateUniqueTarget(
97
-			\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
98
-			$this->recipientView,
99
-			$mountpoints
100
-		);
101
-
102
-		if ($newMountPoint !== $share->getTarget()) {
103
-			$this->updateFileTarget($newMountPoint, $share);
104
-		}
105
-
106
-		return $newMountPoint;
107
-	}
108
-
109
-	/**
110
-	 * update fileTarget in the database if the mount point changed
111
-	 *
112
-	 * @param string $newPath
113
-	 * @param \OCP\Share\IShare $share
114
-	 * @return bool
115
-	 */
116
-	private function updateFileTarget($newPath, &$share) {
117
-		$share->setTarget($newPath);
118
-
119
-		foreach ($this->groupedShares as $tmpShare) {
120
-			$tmpShare->setTarget($newPath);
121
-			\OC::$server->getShareManager()->moveShare($tmpShare, $this->user);
122
-		}
123
-	}
124
-
125
-
126
-	/**
127
-	 * @param string $path
128
-	 * @param View $view
129
-	 * @param SharedMount[] $mountpoints
130
-	 * @return mixed
131
-	 */
132
-	private function generateUniqueTarget($path, $view, array $mountpoints) {
133
-		$pathinfo = pathinfo($path);
134
-		$ext = isset($pathinfo['extension']) ? '.' . $pathinfo['extension'] : '';
135
-		$name = $pathinfo['filename'];
136
-		$dir = $pathinfo['dirname'];
137
-
138
-		// Helper function to find existing mount points
139
-		$mountpointExists = function ($path) use ($mountpoints) {
140
-			foreach ($mountpoints as $mountpoint) {
141
-				if ($mountpoint->getShare()->getTarget() === $path) {
142
-					return true;
143
-				}
144
-			}
145
-			return false;
146
-		};
147
-
148
-		$i = 2;
149
-		while ($view->file_exists($path) || $mountpointExists($path)) {
150
-			$path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
151
-			$i++;
152
-		}
153
-
154
-		return $path;
155
-	}
156
-
157
-	/**
158
-	 * Format a path to be relative to the /user/files/ directory
159
-	 *
160
-	 * @param string $path the absolute path
161
-	 * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
162
-	 * @throws \OCA\Files_Sharing\Exceptions\BrokenPath
163
-	 */
164
-	protected function stripUserFilesPath($path) {
165
-		$trimmed = ltrim($path, '/');
166
-		$split = explode('/', $trimmed);
167
-
168
-		// it is not a file relative to data/user/files
169
-		if (count($split) < 3 || $split[1] !== 'files') {
170
-			\OCP\Util::writeLog('file sharing',
171
-				'Can not strip userid and "files/" from path: ' . $path,
172
-				\OCP\Util::ERROR);
173
-			throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
174
-		}
175
-
176
-		// skip 'user' and 'files'
177
-		$sliced = array_slice($split, 2);
178
-		$relPath = implode('/', $sliced);
179
-
180
-		return '/' . $relPath;
181
-	}
182
-
183
-	/**
184
-	 * Move the mount point to $target
185
-	 *
186
-	 * @param string $target the target mount point
187
-	 * @return bool
188
-	 */
189
-	public function moveMount($target) {
190
-
191
-		$relTargetPath = $this->stripUserFilesPath($target);
192
-		$share = $this->storage->getShare();
193
-
194
-		$result = true;
195
-
196
-		try {
197
-			$this->updateFileTarget($relTargetPath, $share);
198
-			$this->setMountPoint($target);
199
-			$this->storage->setMountPoint($relTargetPath);
200
-		} catch (\Exception $e) {
201
-			\OCP\Util::writeLog('file sharing',
202
-				'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
203
-				\OCP\Util::ERROR);
204
-		}
205
-
206
-		return $result;
207
-	}
208
-
209
-	/**
210
-	 * Remove the mount points
211
-	 *
212
-	 * @return bool
213
-	 */
214
-	public function removeMount() {
215
-		$mountManager = \OC\Files\Filesystem::getMountManager();
216
-		/** @var $storage \OCA\Files_Sharing\SharedStorage */
217
-		$storage = $this->getStorage();
218
-		$result = $storage->unshareStorage();
219
-		$mountManager->removeMount($this->mountPoint);
220
-
221
-		return $result;
222
-	}
223
-
224
-	/**
225
-	 * @return \OCP\Share\IShare
226
-	 */
227
-	public function getShare() {
228
-		return $this->superShare;
229
-	}
230
-
231
-	/**
232
-	 * Get the file id of the root of the storage
233
-	 *
234
-	 * @return int
235
-	 */
236
-	public function getStorageRootId() {
237
-		return $this->getShare()->getNodeId();
238
-	}
239
-
240
-	/**
241
-	 * @return int
242
-	 */
243
-	public function getNumericStorageId() {
244
-		if (!is_null($this->getShare()->getNodeCacheEntry())) {
245
-			return $this->getShare()->getNodeCacheEntry()->getStorageId();
246
-		} else {
247
-			$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
248
-
249
-			$query = $builder->select('storage')
250
-				->from('filecache')
251
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($this->getStorageRootId())));
252
-
253
-			$result = $query->execute();
254
-			$row = $result->fetch();
255
-			$result->closeCursor();
256
-			if ($row) {
257
-				return (int)$row['storage'];
258
-			}
259
-			return -1;
260
-		}
261
-	}
262
-
263
-	public function getMountType() {
264
-		return 'shared';
265
-	}
40
+    /**
41
+     * @var \OCA\Files_Sharing\SharedStorage $storage
42
+     */
43
+    protected $storage = null;
44
+
45
+    /**
46
+     * @var \OC\Files\View
47
+     */
48
+    private $recipientView;
49
+
50
+    /**
51
+     * @var string
52
+     */
53
+    private $user;
54
+
55
+    /** @var \OCP\Share\IShare */
56
+    private $superShare;
57
+
58
+    /** @var \OCP\Share\IShare[] */
59
+    private $groupedShares;
60
+
61
+    /**
62
+     * @param string $storage
63
+     * @param SharedMount[] $mountpoints
64
+     * @param array|null $arguments
65
+     * @param \OCP\Files\Storage\IStorageFactory $loader
66
+     */
67
+    public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) {
68
+        $this->user = $arguments['user'];
69
+        $this->recipientView = new View('/' . $this->user . '/files');
70
+
71
+        $this->superShare = $arguments['superShare'];
72
+        $this->groupedShares = $arguments['groupedShares'];
73
+
74
+        $newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints);
75
+        $absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
76
+        $arguments['ownerView'] = new View('/' . $this->superShare->getShareOwner() . '/files');
77
+        parent::__construct($storage, $absMountPoint, $arguments, $loader);
78
+    }
79
+
80
+    /**
81
+     * check if the parent folder exists otherwise move the mount point up
82
+     *
83
+     * @param \OCP\Share\IShare $share
84
+     * @param SharedMount[] $mountpoints
85
+     * @return string
86
+     */
87
+    private function verifyMountPoint(\OCP\Share\IShare $share, array $mountpoints) {
88
+
89
+        $mountPoint = basename($share->getTarget());
90
+        $parent = dirname($share->getTarget());
91
+
92
+        if (!$this->recipientView->is_dir($parent)) {
93
+            $parent = Helper::getShareFolder($this->recipientView);
94
+        }
95
+
96
+        $newMountPoint = $this->generateUniqueTarget(
97
+            \OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
98
+            $this->recipientView,
99
+            $mountpoints
100
+        );
101
+
102
+        if ($newMountPoint !== $share->getTarget()) {
103
+            $this->updateFileTarget($newMountPoint, $share);
104
+        }
105
+
106
+        return $newMountPoint;
107
+    }
108
+
109
+    /**
110
+     * update fileTarget in the database if the mount point changed
111
+     *
112
+     * @param string $newPath
113
+     * @param \OCP\Share\IShare $share
114
+     * @return bool
115
+     */
116
+    private function updateFileTarget($newPath, &$share) {
117
+        $share->setTarget($newPath);
118
+
119
+        foreach ($this->groupedShares as $tmpShare) {
120
+            $tmpShare->setTarget($newPath);
121
+            \OC::$server->getShareManager()->moveShare($tmpShare, $this->user);
122
+        }
123
+    }
124
+
125
+
126
+    /**
127
+     * @param string $path
128
+     * @param View $view
129
+     * @param SharedMount[] $mountpoints
130
+     * @return mixed
131
+     */
132
+    private function generateUniqueTarget($path, $view, array $mountpoints) {
133
+        $pathinfo = pathinfo($path);
134
+        $ext = isset($pathinfo['extension']) ? '.' . $pathinfo['extension'] : '';
135
+        $name = $pathinfo['filename'];
136
+        $dir = $pathinfo['dirname'];
137
+
138
+        // Helper function to find existing mount points
139
+        $mountpointExists = function ($path) use ($mountpoints) {
140
+            foreach ($mountpoints as $mountpoint) {
141
+                if ($mountpoint->getShare()->getTarget() === $path) {
142
+                    return true;
143
+                }
144
+            }
145
+            return false;
146
+        };
147
+
148
+        $i = 2;
149
+        while ($view->file_exists($path) || $mountpointExists($path)) {
150
+            $path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
151
+            $i++;
152
+        }
153
+
154
+        return $path;
155
+    }
156
+
157
+    /**
158
+     * Format a path to be relative to the /user/files/ directory
159
+     *
160
+     * @param string $path the absolute path
161
+     * @return string e.g. turns '/admin/files/test.txt' into '/test.txt'
162
+     * @throws \OCA\Files_Sharing\Exceptions\BrokenPath
163
+     */
164
+    protected function stripUserFilesPath($path) {
165
+        $trimmed = ltrim($path, '/');
166
+        $split = explode('/', $trimmed);
167
+
168
+        // it is not a file relative to data/user/files
169
+        if (count($split) < 3 || $split[1] !== 'files') {
170
+            \OCP\Util::writeLog('file sharing',
171
+                'Can not strip userid and "files/" from path: ' . $path,
172
+                \OCP\Util::ERROR);
173
+            throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
174
+        }
175
+
176
+        // skip 'user' and 'files'
177
+        $sliced = array_slice($split, 2);
178
+        $relPath = implode('/', $sliced);
179
+
180
+        return '/' . $relPath;
181
+    }
182
+
183
+    /**
184
+     * Move the mount point to $target
185
+     *
186
+     * @param string $target the target mount point
187
+     * @return bool
188
+     */
189
+    public function moveMount($target) {
190
+
191
+        $relTargetPath = $this->stripUserFilesPath($target);
192
+        $share = $this->storage->getShare();
193
+
194
+        $result = true;
195
+
196
+        try {
197
+            $this->updateFileTarget($relTargetPath, $share);
198
+            $this->setMountPoint($target);
199
+            $this->storage->setMountPoint($relTargetPath);
200
+        } catch (\Exception $e) {
201
+            \OCP\Util::writeLog('file sharing',
202
+                'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
203
+                \OCP\Util::ERROR);
204
+        }
205
+
206
+        return $result;
207
+    }
208
+
209
+    /**
210
+     * Remove the mount points
211
+     *
212
+     * @return bool
213
+     */
214
+    public function removeMount() {
215
+        $mountManager = \OC\Files\Filesystem::getMountManager();
216
+        /** @var $storage \OCA\Files_Sharing\SharedStorage */
217
+        $storage = $this->getStorage();
218
+        $result = $storage->unshareStorage();
219
+        $mountManager->removeMount($this->mountPoint);
220
+
221
+        return $result;
222
+    }
223
+
224
+    /**
225
+     * @return \OCP\Share\IShare
226
+     */
227
+    public function getShare() {
228
+        return $this->superShare;
229
+    }
230
+
231
+    /**
232
+     * Get the file id of the root of the storage
233
+     *
234
+     * @return int
235
+     */
236
+    public function getStorageRootId() {
237
+        return $this->getShare()->getNodeId();
238
+    }
239
+
240
+    /**
241
+     * @return int
242
+     */
243
+    public function getNumericStorageId() {
244
+        if (!is_null($this->getShare()->getNodeCacheEntry())) {
245
+            return $this->getShare()->getNodeCacheEntry()->getStorageId();
246
+        } else {
247
+            $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
248
+
249
+            $query = $builder->select('storage')
250
+                ->from('filecache')
251
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($this->getStorageRootId())));
252
+
253
+            $result = $query->execute();
254
+            $row = $result->fetch();
255
+            $result->closeCursor();
256
+            if ($row) {
257
+                return (int)$row['storage'];
258
+            }
259
+            return -1;
260
+        }
261
+    }
262
+
263
+    public function getMountType() {
264
+        return 'shared';
265
+    }
266 266
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -66,14 +66,14 @@  discard block
 block discarded – undo
66 66
 	 */
67 67
 	public function __construct($storage, array $mountpoints, $arguments = null, $loader = null) {
68 68
 		$this->user = $arguments['user'];
69
-		$this->recipientView = new View('/' . $this->user . '/files');
69
+		$this->recipientView = new View('/'.$this->user.'/files');
70 70
 
71 71
 		$this->superShare = $arguments['superShare'];
72 72
 		$this->groupedShares = $arguments['groupedShares'];
73 73
 
74 74
 		$newMountPoint = $this->verifyMountPoint($this->superShare, $mountpoints);
75
-		$absMountPoint = '/' . $this->user . '/files' . $newMountPoint;
76
-		$arguments['ownerView'] = new View('/' . $this->superShare->getShareOwner() . '/files');
75
+		$absMountPoint = '/'.$this->user.'/files'.$newMountPoint;
76
+		$arguments['ownerView'] = new View('/'.$this->superShare->getShareOwner().'/files');
77 77
 		parent::__construct($storage, $absMountPoint, $arguments, $loader);
78 78
 	}
79 79
 
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 		}
95 95
 
96 96
 		$newMountPoint = $this->generateUniqueTarget(
97
-			\OC\Files\Filesystem::normalizePath($parent . '/' . $mountPoint),
97
+			\OC\Files\Filesystem::normalizePath($parent.'/'.$mountPoint),
98 98
 			$this->recipientView,
99 99
 			$mountpoints
100 100
 		);
@@ -131,12 +131,12 @@  discard block
 block discarded – undo
131 131
 	 */
132 132
 	private function generateUniqueTarget($path, $view, array $mountpoints) {
133 133
 		$pathinfo = pathinfo($path);
134
-		$ext = isset($pathinfo['extension']) ? '.' . $pathinfo['extension'] : '';
134
+		$ext = isset($pathinfo['extension']) ? '.'.$pathinfo['extension'] : '';
135 135
 		$name = $pathinfo['filename'];
136 136
 		$dir = $pathinfo['dirname'];
137 137
 
138 138
 		// Helper function to find existing mount points
139
-		$mountpointExists = function ($path) use ($mountpoints) {
139
+		$mountpointExists = function($path) use ($mountpoints) {
140 140
 			foreach ($mountpoints as $mountpoint) {
141 141
 				if ($mountpoint->getShare()->getTarget() === $path) {
142 142
 					return true;
@@ -147,7 +147,7 @@  discard block
 block discarded – undo
147 147
 
148 148
 		$i = 2;
149 149
 		while ($view->file_exists($path) || $mountpointExists($path)) {
150
-			$path = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
150
+			$path = Filesystem::normalizePath($dir.'/'.$name.' ('.$i.')'.$ext);
151 151
 			$i++;
152 152
 		}
153 153
 
@@ -168,7 +168,7 @@  discard block
 block discarded – undo
168 168
 		// it is not a file relative to data/user/files
169 169
 		if (count($split) < 3 || $split[1] !== 'files') {
170 170
 			\OCP\Util::writeLog('file sharing',
171
-				'Can not strip userid and "files/" from path: ' . $path,
171
+				'Can not strip userid and "files/" from path: '.$path,
172 172
 				\OCP\Util::ERROR);
173 173
 			throw new \OCA\Files_Sharing\Exceptions\BrokenPath('Path does not start with /user/files', 10);
174 174
 		}
@@ -177,7 +177,7 @@  discard block
 block discarded – undo
177 177
 		$sliced = array_slice($split, 2);
178 178
 		$relPath = implode('/', $sliced);
179 179
 
180
-		return '/' . $relPath;
180
+		return '/'.$relPath;
181 181
 	}
182 182
 
183 183
 	/**
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
 			$this->storage->setMountPoint($relTargetPath);
200 200
 		} catch (\Exception $e) {
201 201
 			\OCP\Util::writeLog('file sharing',
202
-				'Could not rename mount point for shared folder "' . $this->getMountPoint() . '" to "' . $target . '"',
202
+				'Could not rename mount point for shared folder "'.$this->getMountPoint().'" to "'.$target.'"',
203 203
 				\OCP\Util::ERROR);
204 204
 		}
205 205
 
@@ -254,7 +254,7 @@  discard block
 block discarded – undo
254 254
 			$row = $result->fetch();
255 255
 			$result->closeCursor();
256 256
 			if ($row) {
257
-				return (int)$row['storage'];
257
+				return (int) $row['storage'];
258 258
 			}
259 259
 			return -1;
260 260
 		}
Please login to merge, or discard this patch.