Passed
Push — master ( 71a626...183e2e )
by Joas
21:12 queued 10:11
created
lib/private/Files/Mount/LocalHomeMountProvider.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -30,15 +30,15 @@
 block discarded – undo
30 30
  * Mount provider for regular posix home folders
31 31
  */
32 32
 class LocalHomeMountProvider implements IHomeMountProvider {
33
-	/**
34
-	 * Get the cache mount for a user
35
-	 *
36
-	 * @param IUser $user
37
-	 * @param IStorageFactory $loader
38
-	 * @return \OCP\Files\Mount\IMountPoint|null
39
-	 */
40
-	public function getHomeMountForUser(IUser $user, IStorageFactory $loader) {
41
-		$arguments = ['user' => $user];
42
-		return new MountPoint('\OC\Files\Storage\Home', '/' . $user->getUID(), $arguments, $loader);
43
-	}
33
+    /**
34
+     * Get the cache mount for a user
35
+     *
36
+     * @param IUser $user
37
+     * @param IStorageFactory $loader
38
+     * @return \OCP\Files\Mount\IMountPoint|null
39
+     */
40
+    public function getHomeMountForUser(IUser $user, IStorageFactory $loader) {
41
+        $arguments = ['user' => $user];
42
+        return new MountPoint('\OC\Files\Storage\Home', '/' . $user->getUID(), $arguments, $loader);
43
+    }
44 44
 }
Please login to merge, or discard this patch.
lib/private/Files/Mount/MountPoint.php 2 patches
Indentation   +219 added lines, -219 removed lines patch added patch discarded remove patch
@@ -38,247 +38,247 @@
 block discarded – undo
38 38
 use OCP\ILogger;
39 39
 
40 40
 class MountPoint implements IMountPoint {
41
-	/**
42
-	 * @var \OC\Files\Storage\Storage $storage
43
-	 */
44
-	protected $storage = null;
45
-	protected $class;
46
-	protected $storageId;
47
-	protected $rootId = null;
41
+    /**
42
+     * @var \OC\Files\Storage\Storage $storage
43
+     */
44
+    protected $storage = null;
45
+    protected $class;
46
+    protected $storageId;
47
+    protected $rootId = null;
48 48
 
49
-	/**
50
-	 * Configuration options for the storage backend
51
-	 *
52
-	 * @var array
53
-	 */
54
-	protected $arguments = [];
55
-	protected $mountPoint;
49
+    /**
50
+     * Configuration options for the storage backend
51
+     *
52
+     * @var array
53
+     */
54
+    protected $arguments = [];
55
+    protected $mountPoint;
56 56
 
57
-	/**
58
-	 * Mount specific options
59
-	 *
60
-	 * @var array
61
-	 */
62
-	protected $mountOptions = [];
57
+    /**
58
+     * Mount specific options
59
+     *
60
+     * @var array
61
+     */
62
+    protected $mountOptions = [];
63 63
 
64
-	/**
65
-	 * @var \OC\Files\Storage\StorageFactory $loader
66
-	 */
67
-	private $loader;
64
+    /**
65
+     * @var \OC\Files\Storage\StorageFactory $loader
66
+     */
67
+    private $loader;
68 68
 
69
-	/**
70
-	 * Specified whether the storage is invalid after failing to
71
-	 * instantiate it.
72
-	 *
73
-	 * @var bool
74
-	 */
75
-	private $invalidStorage = false;
69
+    /**
70
+     * Specified whether the storage is invalid after failing to
71
+     * instantiate it.
72
+     *
73
+     * @var bool
74
+     */
75
+    private $invalidStorage = false;
76 76
 
77
-	/** @var int|null */
78
-	protected $mountId;
77
+    /** @var int|null */
78
+    protected $mountId;
79 79
 
80
-	/**
81
-	 * @param string|\OC\Files\Storage\Storage $storage
82
-	 * @param string $mountpoint
83
-	 * @param array $arguments (optional) configuration for the storage backend
84
-	 * @param \OCP\Files\Storage\IStorageFactory $loader
85
-	 * @param array $mountOptions mount specific options
86
-	 * @param int|null $mountId
87
-	 * @throws \Exception
88
-	 */
89
-	public function __construct($storage, $mountpoint, $arguments = null, $loader = null, $mountOptions = null, $mountId = null) {
90
-		if (is_null($arguments)) {
91
-			$arguments = [];
92
-		}
93
-		if (is_null($loader)) {
94
-			$this->loader = new StorageFactory();
95
-		} else {
96
-			$this->loader = $loader;
97
-		}
80
+    /**
81
+     * @param string|\OC\Files\Storage\Storage $storage
82
+     * @param string $mountpoint
83
+     * @param array $arguments (optional) configuration for the storage backend
84
+     * @param \OCP\Files\Storage\IStorageFactory $loader
85
+     * @param array $mountOptions mount specific options
86
+     * @param int|null $mountId
87
+     * @throws \Exception
88
+     */
89
+    public function __construct($storage, $mountpoint, $arguments = null, $loader = null, $mountOptions = null, $mountId = null) {
90
+        if (is_null($arguments)) {
91
+            $arguments = [];
92
+        }
93
+        if (is_null($loader)) {
94
+            $this->loader = new StorageFactory();
95
+        } else {
96
+            $this->loader = $loader;
97
+        }
98 98
 
99
-		if (!is_null($mountOptions)) {
100
-			$this->mountOptions = $mountOptions;
101
-		}
99
+        if (!is_null($mountOptions)) {
100
+            $this->mountOptions = $mountOptions;
101
+        }
102 102
 
103
-		$mountpoint = $this->formatPath($mountpoint);
104
-		$this->mountPoint = $mountpoint;
105
-		if ($storage instanceof Storage) {
106
-			$this->class = get_class($storage);
107
-			$this->storage = $this->loader->wrap($this, $storage);
108
-		} else {
109
-			// Update old classes to new namespace
110
-			if (strpos($storage, 'OC_Filestorage_') !== false) {
111
-				$storage = '\OC\Files\Storage\\' . substr($storage, 15);
112
-			}
113
-			$this->class = $storage;
114
-			$this->arguments = $arguments;
115
-		}
116
-		$this->mountId = $mountId;
117
-	}
103
+        $mountpoint = $this->formatPath($mountpoint);
104
+        $this->mountPoint = $mountpoint;
105
+        if ($storage instanceof Storage) {
106
+            $this->class = get_class($storage);
107
+            $this->storage = $this->loader->wrap($this, $storage);
108
+        } else {
109
+            // Update old classes to new namespace
110
+            if (strpos($storage, 'OC_Filestorage_') !== false) {
111
+                $storage = '\OC\Files\Storage\\' . substr($storage, 15);
112
+            }
113
+            $this->class = $storage;
114
+            $this->arguments = $arguments;
115
+        }
116
+        $this->mountId = $mountId;
117
+    }
118 118
 
119
-	/**
120
-	 * get complete path to the mount point, relative to data/
121
-	 *
122
-	 * @return string
123
-	 */
124
-	public function getMountPoint() {
125
-		return $this->mountPoint;
126
-	}
119
+    /**
120
+     * get complete path to the mount point, relative to data/
121
+     *
122
+     * @return string
123
+     */
124
+    public function getMountPoint() {
125
+        return $this->mountPoint;
126
+    }
127 127
 
128
-	/**
129
-	 * Sets the mount point path, relative to data/
130
-	 *
131
-	 * @param string $mountPoint new mount point
132
-	 */
133
-	public function setMountPoint($mountPoint) {
134
-		$this->mountPoint = $this->formatPath($mountPoint);
135
-	}
128
+    /**
129
+     * Sets the mount point path, relative to data/
130
+     *
131
+     * @param string $mountPoint new mount point
132
+     */
133
+    public function setMountPoint($mountPoint) {
134
+        $this->mountPoint = $this->formatPath($mountPoint);
135
+    }
136 136
 
137
-	/**
138
-	 * create the storage that is mounted
139
-	 */
140
-	private function createStorage() {
141
-		if ($this->invalidStorage) {
142
-			return;
143
-		}
137
+    /**
138
+     * create the storage that is mounted
139
+     */
140
+    private function createStorage() {
141
+        if ($this->invalidStorage) {
142
+            return;
143
+        }
144 144
 
145
-		if (class_exists($this->class)) {
146
-			try {
147
-				$class = $this->class;
148
-				// prevent recursion by setting the storage before applying wrappers
149
-				$this->storage = new $class($this->arguments);
150
-				$this->storage = $this->loader->wrap($this, $this->storage);
151
-			} catch (\Exception $exception) {
152
-				$this->storage = null;
153
-				$this->invalidStorage = true;
154
-				if ($this->mountPoint === '/') {
155
-					// the root storage could not be initialized, show the user!
156
-					throw new \Exception('The root storage could not be initialized. Please contact your local administrator.', $exception->getCode(), $exception);
157
-				} else {
158
-					\OC::$server->getLogger()->logException($exception, ['level' => ILogger::ERROR]);
159
-				}
160
-				return;
161
-			}
162
-		} else {
163
-			\OCP\Util::writeLog('core', 'storage backend ' . $this->class . ' not found', ILogger::ERROR);
164
-			$this->invalidStorage = true;
165
-			return;
166
-		}
167
-	}
145
+        if (class_exists($this->class)) {
146
+            try {
147
+                $class = $this->class;
148
+                // prevent recursion by setting the storage before applying wrappers
149
+                $this->storage = new $class($this->arguments);
150
+                $this->storage = $this->loader->wrap($this, $this->storage);
151
+            } catch (\Exception $exception) {
152
+                $this->storage = null;
153
+                $this->invalidStorage = true;
154
+                if ($this->mountPoint === '/') {
155
+                    // the root storage could not be initialized, show the user!
156
+                    throw new \Exception('The root storage could not be initialized. Please contact your local administrator.', $exception->getCode(), $exception);
157
+                } else {
158
+                    \OC::$server->getLogger()->logException($exception, ['level' => ILogger::ERROR]);
159
+                }
160
+                return;
161
+            }
162
+        } else {
163
+            \OCP\Util::writeLog('core', 'storage backend ' . $this->class . ' not found', ILogger::ERROR);
164
+            $this->invalidStorage = true;
165
+            return;
166
+        }
167
+    }
168 168
 
169
-	/**
170
-	 * @return \OC\Files\Storage\Storage
171
-	 */
172
-	public function getStorage() {
173
-		if (is_null($this->storage)) {
174
-			$this->createStorage();
175
-		}
176
-		return $this->storage;
177
-	}
169
+    /**
170
+     * @return \OC\Files\Storage\Storage
171
+     */
172
+    public function getStorage() {
173
+        if (is_null($this->storage)) {
174
+            $this->createStorage();
175
+        }
176
+        return $this->storage;
177
+    }
178 178
 
179
-	/**
180
-	 * @return string
181
-	 */
182
-	public function getStorageId() {
183
-		if (!$this->storageId) {
184
-			if (is_null($this->storage)) {
185
-				$storage = $this->createStorage(); //FIXME: start using exceptions
186
-				if (is_null($storage)) {
187
-					return null;
188
-				}
179
+    /**
180
+     * @return string
181
+     */
182
+    public function getStorageId() {
183
+        if (!$this->storageId) {
184
+            if (is_null($this->storage)) {
185
+                $storage = $this->createStorage(); //FIXME: start using exceptions
186
+                if (is_null($storage)) {
187
+                    return null;
188
+                }
189 189
 
190
-				$this->storage = $storage;
191
-			}
192
-			$this->storageId = $this->storage->getId();
193
-			if (strlen($this->storageId) > 64) {
194
-				$this->storageId = md5($this->storageId);
195
-			}
196
-		}
197
-		return $this->storageId;
198
-	}
190
+                $this->storage = $storage;
191
+            }
192
+            $this->storageId = $this->storage->getId();
193
+            if (strlen($this->storageId) > 64) {
194
+                $this->storageId = md5($this->storageId);
195
+            }
196
+        }
197
+        return $this->storageId;
198
+    }
199 199
 
200
-	/**
201
-	 * @return int
202
-	 */
203
-	public function getNumericStorageId() {
204
-		return $this->getStorage()->getStorageCache()->getNumericId();
205
-	}
200
+    /**
201
+     * @return int
202
+     */
203
+    public function getNumericStorageId() {
204
+        return $this->getStorage()->getStorageCache()->getNumericId();
205
+    }
206 206
 
207
-	/**
208
-	 * @param string $path
209
-	 * @return string
210
-	 */
211
-	public function getInternalPath($path) {
212
-		$path = Filesystem::normalizePath($path, true, false, true);
213
-		if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) {
214
-			$internalPath = '';
215
-		} else {
216
-			$internalPath = substr($path, strlen($this->mountPoint));
217
-		}
218
-		// substr returns false instead of an empty string, we always want a string
219
-		return (string)$internalPath;
220
-	}
207
+    /**
208
+     * @param string $path
209
+     * @return string
210
+     */
211
+    public function getInternalPath($path) {
212
+        $path = Filesystem::normalizePath($path, true, false, true);
213
+        if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) {
214
+            $internalPath = '';
215
+        } else {
216
+            $internalPath = substr($path, strlen($this->mountPoint));
217
+        }
218
+        // substr returns false instead of an empty string, we always want a string
219
+        return (string)$internalPath;
220
+    }
221 221
 
222
-	/**
223
-	 * @param string $path
224
-	 * @return string
225
-	 */
226
-	private function formatPath($path) {
227
-		$path = Filesystem::normalizePath($path);
228
-		if (strlen($path) > 1) {
229
-			$path .= '/';
230
-		}
231
-		return $path;
232
-	}
222
+    /**
223
+     * @param string $path
224
+     * @return string
225
+     */
226
+    private function formatPath($path) {
227
+        $path = Filesystem::normalizePath($path);
228
+        if (strlen($path) > 1) {
229
+            $path .= '/';
230
+        }
231
+        return $path;
232
+    }
233 233
 
234
-	/**
235
-	 * @param callable $wrapper
236
-	 */
237
-	public function wrapStorage($wrapper) {
238
-		$storage = $this->getStorage();
239
-		// storage can be null if it couldn't be initialized
240
-		if ($storage != null) {
241
-			$this->storage = $wrapper($this->mountPoint, $storage, $this);
242
-		}
243
-	}
234
+    /**
235
+     * @param callable $wrapper
236
+     */
237
+    public function wrapStorage($wrapper) {
238
+        $storage = $this->getStorage();
239
+        // storage can be null if it couldn't be initialized
240
+        if ($storage != null) {
241
+            $this->storage = $wrapper($this->mountPoint, $storage, $this);
242
+        }
243
+    }
244 244
 
245
-	/**
246
-	 * Get a mount option
247
-	 *
248
-	 * @param string $name Name of the mount option to get
249
-	 * @param mixed $default Default value for the mount option
250
-	 * @return mixed
251
-	 */
252
-	public function getOption($name, $default) {
253
-		return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default;
254
-	}
245
+    /**
246
+     * Get a mount option
247
+     *
248
+     * @param string $name Name of the mount option to get
249
+     * @param mixed $default Default value for the mount option
250
+     * @return mixed
251
+     */
252
+    public function getOption($name, $default) {
253
+        return isset($this->mountOptions[$name]) ? $this->mountOptions[$name] : $default;
254
+    }
255 255
 
256
-	/**
257
-	 * Get all options for the mount
258
-	 *
259
-	 * @return array
260
-	 */
261
-	public function getOptions() {
262
-		return $this->mountOptions;
263
-	}
256
+    /**
257
+     * Get all options for the mount
258
+     *
259
+     * @return array
260
+     */
261
+    public function getOptions() {
262
+        return $this->mountOptions;
263
+    }
264 264
 
265
-	/**
266
-	 * Get the file id of the root of the storage
267
-	 *
268
-	 * @return int
269
-	 */
270
-	public function getStorageRootId() {
271
-		if (is_null($this->rootId) || $this->rootId === -1) {
272
-			$this->rootId = (int)$this->getStorage()->getCache()->getId('');
273
-		}
274
-		return $this->rootId;
275
-	}
265
+    /**
266
+     * Get the file id of the root of the storage
267
+     *
268
+     * @return int
269
+     */
270
+    public function getStorageRootId() {
271
+        if (is_null($this->rootId) || $this->rootId === -1) {
272
+            $this->rootId = (int)$this->getStorage()->getCache()->getId('');
273
+        }
274
+        return $this->rootId;
275
+    }
276 276
 
277
-	public function getMountId() {
278
-		return $this->mountId;
279
-	}
277
+    public function getMountId() {
278
+        return $this->mountId;
279
+    }
280 280
 
281
-	public function getMountType() {
282
-		return '';
283
-	}
281
+    public function getMountType() {
282
+        return '';
283
+    }
284 284
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 		} else {
109 109
 			// Update old classes to new namespace
110 110
 			if (strpos($storage, 'OC_Filestorage_') !== false) {
111
-				$storage = '\OC\Files\Storage\\' . substr($storage, 15);
111
+				$storage = '\OC\Files\Storage\\'.substr($storage, 15);
112 112
 			}
113 113
 			$this->class = $storage;
114 114
 			$this->arguments = $arguments;
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 				return;
161 161
 			}
162 162
 		} else {
163
-			\OCP\Util::writeLog('core', 'storage backend ' . $this->class . ' not found', ILogger::ERROR);
163
+			\OCP\Util::writeLog('core', 'storage backend '.$this->class.' not found', ILogger::ERROR);
164 164
 			$this->invalidStorage = true;
165 165
 			return;
166 166
 		}
@@ -210,13 +210,13 @@  discard block
 block discarded – undo
210 210
 	 */
211 211
 	public function getInternalPath($path) {
212 212
 		$path = Filesystem::normalizePath($path, true, false, true);
213
-		if ($this->mountPoint === $path or $this->mountPoint . '/' === $path) {
213
+		if ($this->mountPoint === $path or $this->mountPoint.'/' === $path) {
214 214
 			$internalPath = '';
215 215
 		} else {
216 216
 			$internalPath = substr($path, strlen($this->mountPoint));
217 217
 		}
218 218
 		// substr returns false instead of an empty string, we always want a string
219
-		return (string)$internalPath;
219
+		return (string) $internalPath;
220 220
 	}
221 221
 
222 222
 	/**
@@ -269,7 +269,7 @@  discard block
 block discarded – undo
269 269
 	 */
270 270
 	public function getStorageRootId() {
271 271
 		if (is_null($this->rootId) || $this->rootId === -1) {
272
-			$this->rootId = (int)$this->getStorage()->getCache()->getId('');
272
+			$this->rootId = (int) $this->getStorage()->getCache()->getId('');
273 273
 		}
274 274
 		return $this->rootId;
275 275
 	}
Please login to merge, or discard this patch.
lib/private/Files/Filesystem.php 1 patch
Indentation   +848 added lines, -848 removed lines patch added patch discarded remove patch
@@ -71,852 +71,852 @@
 block discarded – undo
71 71
 
72 72
 class Filesystem {
73 73
 
74
-	/**
75
-	 * @var Mount\Manager $mounts
76
-	 */
77
-	private static $mounts;
78
-
79
-	public static $loaded = false;
80
-	/**
81
-	 * @var \OC\Files\View $defaultInstance
82
-	 */
83
-	private static $defaultInstance;
84
-
85
-	private static $usersSetup = [];
86
-
87
-	private static $normalizedPathCache = null;
88
-
89
-	private static $listeningForProviders = false;
90
-
91
-	/**
92
-	 * classname which used for hooks handling
93
-	 * used as signalclass in OC_Hooks::emit()
94
-	 */
95
-	public const CLASSNAME = 'OC_Filesystem';
96
-
97
-	/**
98
-	 * signalname emitted before file renaming
99
-	 *
100
-	 * @param string $oldpath
101
-	 * @param string $newpath
102
-	 */
103
-	public const signal_rename = 'rename';
104
-
105
-	/**
106
-	 * signal emitted after file renaming
107
-	 *
108
-	 * @param string $oldpath
109
-	 * @param string $newpath
110
-	 */
111
-	public const signal_post_rename = 'post_rename';
112
-
113
-	/**
114
-	 * signal emitted before file/dir creation
115
-	 *
116
-	 * @param string $path
117
-	 * @param bool $run changing this flag to false in hook handler will cancel event
118
-	 */
119
-	public const signal_create = 'create';
120
-
121
-	/**
122
-	 * signal emitted after file/dir creation
123
-	 *
124
-	 * @param string $path
125
-	 * @param bool $run changing this flag to false in hook handler will cancel event
126
-	 */
127
-	public const signal_post_create = 'post_create';
128
-
129
-	/**
130
-	 * signal emits before file/dir copy
131
-	 *
132
-	 * @param string $oldpath
133
-	 * @param string $newpath
134
-	 * @param bool $run changing this flag to false in hook handler will cancel event
135
-	 */
136
-	public const signal_copy = 'copy';
137
-
138
-	/**
139
-	 * signal emits after file/dir copy
140
-	 *
141
-	 * @param string $oldpath
142
-	 * @param string $newpath
143
-	 */
144
-	public const signal_post_copy = 'post_copy';
145
-
146
-	/**
147
-	 * signal emits before file/dir save
148
-	 *
149
-	 * @param string $path
150
-	 * @param bool $run changing this flag to false in hook handler will cancel event
151
-	 */
152
-	public const signal_write = 'write';
153
-
154
-	/**
155
-	 * signal emits after file/dir save
156
-	 *
157
-	 * @param string $path
158
-	 */
159
-	public const signal_post_write = 'post_write';
160
-
161
-	/**
162
-	 * signal emitted before file/dir update
163
-	 *
164
-	 * @param string $path
165
-	 * @param bool $run changing this flag to false in hook handler will cancel event
166
-	 */
167
-	public const signal_update = 'update';
168
-
169
-	/**
170
-	 * signal emitted after file/dir update
171
-	 *
172
-	 * @param string $path
173
-	 * @param bool $run changing this flag to false in hook handler will cancel event
174
-	 */
175
-	public const signal_post_update = 'post_update';
176
-
177
-	/**
178
-	 * signal emits when reading file/dir
179
-	 *
180
-	 * @param string $path
181
-	 */
182
-	public const signal_read = 'read';
183
-
184
-	/**
185
-	 * signal emits when removing file/dir
186
-	 *
187
-	 * @param string $path
188
-	 */
189
-	public const signal_delete = 'delete';
190
-
191
-	/**
192
-	 * parameters definitions for signals
193
-	 */
194
-	public const signal_param_path = 'path';
195
-	public const signal_param_oldpath = 'oldpath';
196
-	public const signal_param_newpath = 'newpath';
197
-
198
-	/**
199
-	 * run - changing this flag to false in hook handler will cancel event
200
-	 */
201
-	public const signal_param_run = 'run';
202
-
203
-	public const signal_create_mount = 'create_mount';
204
-	public const signal_delete_mount = 'delete_mount';
205
-	public const signal_param_mount_type = 'mounttype';
206
-	public const signal_param_users = 'users';
207
-
208
-	/**
209
-	 * @var \OC\Files\Storage\StorageFactory $loader
210
-	 */
211
-	private static $loader;
212
-
213
-	/** @var bool */
214
-	private static $logWarningWhenAddingStorageWrapper = true;
215
-
216
-	/**
217
-	 * @param bool $shouldLog
218
-	 * @return bool previous value
219
-	 * @internal
220
-	 */
221
-	public static function logWarningWhenAddingStorageWrapper($shouldLog) {
222
-		$previousValue = self::$logWarningWhenAddingStorageWrapper;
223
-		self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
224
-		return $previousValue;
225
-	}
226
-
227
-	/**
228
-	 * @param string $wrapperName
229
-	 * @param callable $wrapper
230
-	 * @param int $priority
231
-	 */
232
-	public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
233
-		if (self::$logWarningWhenAddingStorageWrapper) {
234
-			\OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
235
-				'wrapper' => $wrapperName,
236
-				'app' => 'filesystem',
237
-			]);
238
-		}
239
-
240
-		$mounts = self::getMountManager()->getAll();
241
-		if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
242
-			// do not re-wrap if storage with this name already existed
243
-			return;
244
-		}
245
-	}
246
-
247
-	/**
248
-	 * Returns the storage factory
249
-	 *
250
-	 * @return IStorageFactory
251
-	 */
252
-	public static function getLoader() {
253
-		if (!self::$loader) {
254
-			self::$loader = \OC::$server->query(IStorageFactory::class);
255
-		}
256
-		return self::$loader;
257
-	}
258
-
259
-	/**
260
-	 * Returns the mount manager
261
-	 *
262
-	 * @return \OC\Files\Mount\Manager
263
-	 */
264
-	public static function getMountManager($user = '') {
265
-		if (!self::$mounts) {
266
-			\OC_Util::setupFS($user);
267
-		}
268
-		return self::$mounts;
269
-	}
270
-
271
-	/**
272
-	 * get the mountpoint of the storage object for a path
273
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
274
-	 * returned mountpoint is relative to the absolute root of the filesystem
275
-	 * and doesn't take the chroot into account )
276
-	 *
277
-	 * @param string $path
278
-	 * @return string
279
-	 */
280
-	public static function getMountPoint($path) {
281
-		if (!self::$mounts) {
282
-			\OC_Util::setupFS();
283
-		}
284
-		$mount = self::$mounts->find($path);
285
-		if ($mount) {
286
-			return $mount->getMountPoint();
287
-		} else {
288
-			return '';
289
-		}
290
-	}
291
-
292
-	/**
293
-	 * get a list of all mount points in a directory
294
-	 *
295
-	 * @param string $path
296
-	 * @return string[]
297
-	 */
298
-	public static function getMountPoints($path) {
299
-		if (!self::$mounts) {
300
-			\OC_Util::setupFS();
301
-		}
302
-		$result = [];
303
-		$mounts = self::$mounts->findIn($path);
304
-		foreach ($mounts as $mount) {
305
-			$result[] = $mount->getMountPoint();
306
-		}
307
-		return $result;
308
-	}
309
-
310
-	/**
311
-	 * get the storage mounted at $mountPoint
312
-	 *
313
-	 * @param string $mountPoint
314
-	 * @return \OC\Files\Storage\Storage
315
-	 */
316
-	public static function getStorage($mountPoint) {
317
-		if (!self::$mounts) {
318
-			\OC_Util::setupFS();
319
-		}
320
-		$mount = self::$mounts->find($mountPoint);
321
-		return $mount->getStorage();
322
-	}
323
-
324
-	/**
325
-	 * @param string $id
326
-	 * @return Mount\MountPoint[]
327
-	 */
328
-	public static function getMountByStorageId($id) {
329
-		if (!self::$mounts) {
330
-			\OC_Util::setupFS();
331
-		}
332
-		return self::$mounts->findByStorageId($id);
333
-	}
334
-
335
-	/**
336
-	 * @param int $id
337
-	 * @return Mount\MountPoint[]
338
-	 */
339
-	public static function getMountByNumericId($id) {
340
-		if (!self::$mounts) {
341
-			\OC_Util::setupFS();
342
-		}
343
-		return self::$mounts->findByNumericId($id);
344
-	}
345
-
346
-	/**
347
-	 * resolve a path to a storage and internal path
348
-	 *
349
-	 * @param string $path
350
-	 * @return array an array consisting of the storage and the internal path
351
-	 */
352
-	public static function resolvePath($path) {
353
-		if (!self::$mounts) {
354
-			\OC_Util::setupFS();
355
-		}
356
-		$mount = self::$mounts->find($path);
357
-		if ($mount) {
358
-			return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
359
-		} else {
360
-			return [null, null];
361
-		}
362
-	}
363
-
364
-	public static function init($user, $root) {
365
-		if (self::$defaultInstance) {
366
-			return false;
367
-		}
368
-		self::getLoader();
369
-		self::$defaultInstance = new View($root);
370
-
371
-		if (!self::$mounts) {
372
-			self::$mounts = \OC::$server->getMountManager();
373
-		}
374
-
375
-		//load custom mount config
376
-		self::initMountPoints($user);
377
-
378
-		self::$loaded = true;
379
-
380
-		return true;
381
-	}
382
-
383
-	public static function initMountManager() {
384
-		if (!self::$mounts) {
385
-			self::$mounts = \OC::$server->getMountManager();
386
-		}
387
-	}
388
-
389
-	/**
390
-	 * Initialize system and personal mount points for a user
391
-	 *
392
-	 * @param string $user
393
-	 * @throws \OC\User\NoUserException if the user is not available
394
-	 */
395
-	public static function initMountPoints($user = '') {
396
-		if ($user == '') {
397
-			$user = \OC_User::getUser();
398
-		}
399
-		if ($user === null || $user === false || $user === '') {
400
-			throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
401
-		}
402
-
403
-		if (isset(self::$usersSetup[$user])) {
404
-			return;
405
-		}
406
-
407
-		self::$usersSetup[$user] = true;
408
-
409
-		$userManager = \OC::$server->getUserManager();
410
-		$userObject = $userManager->get($user);
411
-
412
-		if (is_null($userObject)) {
413
-			\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR);
414
-			// reset flag, this will make it possible to rethrow the exception if called again
415
-			unset(self::$usersSetup[$user]);
416
-			throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
417
-		}
418
-
419
-		$realUid = $userObject->getUID();
420
-		// workaround in case of different casings
421
-		if ($user !== $realUid) {
422
-			$stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
423
-			\OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN);
424
-			$user = $realUid;
425
-
426
-			// again with the correct casing
427
-			if (isset(self::$usersSetup[$user])) {
428
-				return;
429
-			}
430
-
431
-			self::$usersSetup[$user] = true;
432
-		}
433
-
434
-		if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
435
-			/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
436
-			$mountConfigManager = \OC::$server->getMountProviderCollection();
437
-
438
-			// home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
439
-			$homeMount = $mountConfigManager->getHomeMountForUser($userObject);
440
-			if ($homeMount->getStorageRootId() === -1) {
441
-				$homeMount->getStorage()->mkdir('');
442
-				$homeMount->getStorage()->getScanner()->scan('');
443
-			}
444
-
445
-			self::getMountManager()->addMount($homeMount);
446
-
447
-			\OC\Files\Filesystem::getStorage($user);
448
-
449
-			// Chance to mount for other storages
450
-			if ($userObject) {
451
-				$mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
452
-				$mounts[] = $homeMount;
453
-				$mountConfigManager->registerMounts($userObject, $mounts);
454
-			}
455
-
456
-			self::listenForNewMountProviders($mountConfigManager, $userManager);
457
-		} else {
458
-			self::getMountManager()->addMount(new MountPoint(
459
-				new NullStorage([]),
460
-				'/' . $user
461
-			));
462
-			self::getMountManager()->addMount(new MountPoint(
463
-				new NullStorage([]),
464
-				'/' . $user . '/files'
465
-			));
466
-		}
467
-		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]);
468
-	}
469
-
470
-	/**
471
-	 * Get mounts from mount providers that are registered after setup
472
-	 *
473
-	 * @param MountProviderCollection $mountConfigManager
474
-	 * @param IUserManager $userManager
475
-	 */
476
-	private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
477
-		if (!self::$listeningForProviders) {
478
-			self::$listeningForProviders = true;
479
-			$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
480
-				foreach (Filesystem::$usersSetup as $user => $setup) {
481
-					$userObject = $userManager->get($user);
482
-					if ($userObject) {
483
-						$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
484
-						array_walk($mounts, [self::$mounts, 'addMount']);
485
-					}
486
-				}
487
-			});
488
-		}
489
-	}
490
-
491
-	/**
492
-	 * get the default filesystem view
493
-	 *
494
-	 * @return View
495
-	 */
496
-	public static function getView() {
497
-		return self::$defaultInstance;
498
-	}
499
-
500
-	/**
501
-	 * tear down the filesystem, removing all storage providers
502
-	 */
503
-	public static function tearDown() {
504
-		self::clearMounts();
505
-		self::$defaultInstance = null;
506
-	}
507
-
508
-	/**
509
-	 * get the relative path of the root data directory for the current user
510
-	 *
511
-	 * @return string
512
-	 *
513
-	 * Returns path like /admin/files
514
-	 */
515
-	public static function getRoot() {
516
-		if (!self::$defaultInstance) {
517
-			return null;
518
-		}
519
-		return self::$defaultInstance->getRoot();
520
-	}
521
-
522
-	/**
523
-	 * clear all mounts and storage backends
524
-	 */
525
-	public static function clearMounts() {
526
-		if (self::$mounts) {
527
-			self::$usersSetup = [];
528
-			self::$mounts->clear();
529
-		}
530
-	}
531
-
532
-	/**
533
-	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
534
-	 *
535
-	 * @param \OC\Files\Storage\Storage|string $class
536
-	 * @param array $arguments
537
-	 * @param string $mountpoint
538
-	 */
539
-	public static function mount($class, $arguments, $mountpoint) {
540
-		if (!self::$mounts) {
541
-			\OC_Util::setupFS();
542
-		}
543
-		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
544
-		self::$mounts->addMount($mount);
545
-	}
546
-
547
-	/**
548
-	 * return the path to a local version of the file
549
-	 * we need this because we can't know if a file is stored local or not from
550
-	 * outside the filestorage and for some purposes a local file is needed
551
-	 *
552
-	 * @param string $path
553
-	 * @return string
554
-	 */
555
-	public static function getLocalFile($path) {
556
-		return self::$defaultInstance->getLocalFile($path);
557
-	}
558
-
559
-	/**
560
-	 * @param string $path
561
-	 * @return string
562
-	 */
563
-	public static function getLocalFolder($path) {
564
-		return self::$defaultInstance->getLocalFolder($path);
565
-	}
566
-
567
-	/**
568
-	 * return path to file which reflects one visible in browser
569
-	 *
570
-	 * @param string $path
571
-	 * @return string
572
-	 */
573
-	public static function getLocalPath($path) {
574
-		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
575
-		$newpath = $path;
576
-		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
577
-			$newpath = substr($path, strlen($datadir));
578
-		}
579
-		return $newpath;
580
-	}
581
-
582
-	/**
583
-	 * check if the requested path is valid
584
-	 *
585
-	 * @param string $path
586
-	 * @return bool
587
-	 */
588
-	public static function isValidPath($path) {
589
-		$path = self::normalizePath($path);
590
-		if (!$path || $path[0] !== '/') {
591
-			$path = '/' . $path;
592
-		}
593
-		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
594
-			return false;
595
-		}
596
-		return true;
597
-	}
598
-
599
-	/**
600
-	 * checks if a file is blacklisted for storage in the filesystem
601
-	 * Listens to write and rename hooks
602
-	 *
603
-	 * @param array $data from hook
604
-	 */
605
-	public static function isBlacklisted($data) {
606
-		if (isset($data['path'])) {
607
-			$path = $data['path'];
608
-		} elseif (isset($data['newpath'])) {
609
-			$path = $data['newpath'];
610
-		}
611
-		if (isset($path)) {
612
-			if (self::isFileBlacklisted($path)) {
613
-				$data['run'] = false;
614
-			}
615
-		}
616
-	}
617
-
618
-	/**
619
-	 * @param string $filename
620
-	 * @return bool
621
-	 */
622
-	public static function isFileBlacklisted($filename) {
623
-		$filename = self::normalizePath($filename);
624
-
625
-		$blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
626
-		$filename = strtolower(basename($filename));
627
-		return in_array($filename, $blacklist);
628
-	}
629
-
630
-	/**
631
-	 * check if the directory should be ignored when scanning
632
-	 * NOTE: the special directories . and .. would cause never ending recursion
633
-	 *
634
-	 * @param string $dir
635
-	 * @return boolean
636
-	 */
637
-	public static function isIgnoredDir($dir) {
638
-		if ($dir === '.' || $dir === '..') {
639
-			return true;
640
-		}
641
-		return false;
642
-	}
643
-
644
-	/**
645
-	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
646
-	 */
647
-	public static function mkdir($path) {
648
-		return self::$defaultInstance->mkdir($path);
649
-	}
650
-
651
-	public static function rmdir($path) {
652
-		return self::$defaultInstance->rmdir($path);
653
-	}
654
-
655
-	public static function is_dir($path) {
656
-		return self::$defaultInstance->is_dir($path);
657
-	}
658
-
659
-	public static function is_file($path) {
660
-		return self::$defaultInstance->is_file($path);
661
-	}
662
-
663
-	public static function stat($path) {
664
-		return self::$defaultInstance->stat($path);
665
-	}
666
-
667
-	public static function filetype($path) {
668
-		return self::$defaultInstance->filetype($path);
669
-	}
670
-
671
-	public static function filesize($path) {
672
-		return self::$defaultInstance->filesize($path);
673
-	}
674
-
675
-	public static function readfile($path) {
676
-		return self::$defaultInstance->readfile($path);
677
-	}
678
-
679
-	public static function isCreatable($path) {
680
-		return self::$defaultInstance->isCreatable($path);
681
-	}
682
-
683
-	public static function isReadable($path) {
684
-		return self::$defaultInstance->isReadable($path);
685
-	}
686
-
687
-	public static function isUpdatable($path) {
688
-		return self::$defaultInstance->isUpdatable($path);
689
-	}
690
-
691
-	public static function isDeletable($path) {
692
-		return self::$defaultInstance->isDeletable($path);
693
-	}
694
-
695
-	public static function isSharable($path) {
696
-		return self::$defaultInstance->isSharable($path);
697
-	}
698
-
699
-	public static function file_exists($path) {
700
-		return self::$defaultInstance->file_exists($path);
701
-	}
702
-
703
-	public static function filemtime($path) {
704
-		return self::$defaultInstance->filemtime($path);
705
-	}
706
-
707
-	public static function touch($path, $mtime = null) {
708
-		return self::$defaultInstance->touch($path, $mtime);
709
-	}
710
-
711
-	/**
712
-	 * @return string
713
-	 */
714
-	public static function file_get_contents($path) {
715
-		return self::$defaultInstance->file_get_contents($path);
716
-	}
717
-
718
-	public static function file_put_contents($path, $data) {
719
-		return self::$defaultInstance->file_put_contents($path, $data);
720
-	}
721
-
722
-	public static function unlink($path) {
723
-		return self::$defaultInstance->unlink($path);
724
-	}
725
-
726
-	public static function rename($path1, $path2) {
727
-		return self::$defaultInstance->rename($path1, $path2);
728
-	}
729
-
730
-	public static function copy($path1, $path2) {
731
-		return self::$defaultInstance->copy($path1, $path2);
732
-	}
733
-
734
-	public static function fopen($path, $mode) {
735
-		return self::$defaultInstance->fopen($path, $mode);
736
-	}
737
-
738
-	/**
739
-	 * @return string
740
-	 */
741
-	public static function toTmpFile($path) {
742
-		return self::$defaultInstance->toTmpFile($path);
743
-	}
744
-
745
-	public static function fromTmpFile($tmpFile, $path) {
746
-		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
747
-	}
748
-
749
-	public static function getMimeType($path) {
750
-		return self::$defaultInstance->getMimeType($path);
751
-	}
752
-
753
-	public static function hash($type, $path, $raw = false) {
754
-		return self::$defaultInstance->hash($type, $path, $raw);
755
-	}
756
-
757
-	public static function free_space($path = '/') {
758
-		return self::$defaultInstance->free_space($path);
759
-	}
760
-
761
-	public static function search($query) {
762
-		return self::$defaultInstance->search($query);
763
-	}
764
-
765
-	/**
766
-	 * @param string $query
767
-	 */
768
-	public static function searchByMime($query) {
769
-		return self::$defaultInstance->searchByMime($query);
770
-	}
771
-
772
-	/**
773
-	 * @param string|int $tag name or tag id
774
-	 * @param string $userId owner of the tags
775
-	 * @return FileInfo[] array or file info
776
-	 */
777
-	public static function searchByTag($tag, $userId) {
778
-		return self::$defaultInstance->searchByTag($tag, $userId);
779
-	}
780
-
781
-	/**
782
-	 * check if a file or folder has been updated since $time
783
-	 *
784
-	 * @param string $path
785
-	 * @param int $time
786
-	 * @return bool
787
-	 */
788
-	public static function hasUpdated($path, $time) {
789
-		return self::$defaultInstance->hasUpdated($path, $time);
790
-	}
791
-
792
-	/**
793
-	 * Fix common problems with a file path
794
-	 *
795
-	 * @param string $path
796
-	 * @param bool $stripTrailingSlash whether to strip the trailing slash
797
-	 * @param bool $isAbsolutePath whether the given path is absolute
798
-	 * @param bool $keepUnicode true to disable unicode normalization
799
-	 * @return string
800
-	 */
801
-	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
802
-		if (is_null(self::$normalizedPathCache)) {
803
-			self::$normalizedPathCache = new CappedMemoryCache(2048);
804
-		}
805
-
806
-		/**
807
-		 * FIXME: This is a workaround for existing classes and files which call
808
-		 *        this function with another type than a valid string. This
809
-		 *        conversion should get removed as soon as all existing
810
-		 *        function calls have been fixed.
811
-		 */
812
-		$path = (string)$path;
813
-
814
-		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
815
-
816
-		if (isset(self::$normalizedPathCache[$cacheKey])) {
817
-			return self::$normalizedPathCache[$cacheKey];
818
-		}
819
-
820
-		if ($path === '') {
821
-			return '/';
822
-		}
823
-
824
-		//normalize unicode if possible
825
-		if (!$keepUnicode) {
826
-			$path = \OC_Util::normalizeUnicode($path);
827
-		}
828
-
829
-		//add leading slash, if it is already there we strip it anyway
830
-		$path = '/' . $path;
831
-
832
-		$patterns = [
833
-			'/\\\\/s',          // no windows style slashes
834
-			'/\/\.(\/\.)?\//s', // remove '/./'
835
-			'/\/{2,}/s',        // remove sequence of slashes
836
-			'/\/\.$/s',         // remove trailing /.
837
-		];
838
-
839
-		do {
840
-			$count = 0;
841
-			$path = preg_replace($patterns, '/', $path, -1, $count);
842
-		} while ($count > 0);
843
-
844
-		//remove trailing slash
845
-		if ($stripTrailingSlash && strlen($path) > 1) {
846
-			$path = rtrim($path, '/');
847
-		}
848
-
849
-		self::$normalizedPathCache[$cacheKey] = $path;
850
-
851
-		return $path;
852
-	}
853
-
854
-	/**
855
-	 * get the filesystem info
856
-	 *
857
-	 * @param string $path
858
-	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
859
-	 * defaults to true
860
-	 * @return \OC\Files\FileInfo|bool False if file does not exist
861
-	 */
862
-	public static function getFileInfo($path, $includeMountPoints = true) {
863
-		return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
864
-	}
865
-
866
-	/**
867
-	 * change file metadata
868
-	 *
869
-	 * @param string $path
870
-	 * @param array $data
871
-	 * @return int
872
-	 *
873
-	 * returns the fileid of the updated file
874
-	 */
875
-	public static function putFileInfo($path, $data) {
876
-		return self::$defaultInstance->putFileInfo($path, $data);
877
-	}
878
-
879
-	/**
880
-	 * get the content of a directory
881
-	 *
882
-	 * @param string $directory path under datadirectory
883
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
884
-	 * @return \OC\Files\FileInfo[]
885
-	 */
886
-	public static function getDirectoryContent($directory, $mimetype_filter = '') {
887
-		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
888
-	}
889
-
890
-	/**
891
-	 * Get the path of a file by id
892
-	 *
893
-	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
894
-	 *
895
-	 * @param int $id
896
-	 * @throws NotFoundException
897
-	 * @return string
898
-	 */
899
-	public static function getPath($id) {
900
-		return self::$defaultInstance->getPath($id);
901
-	}
902
-
903
-	/**
904
-	 * Get the owner for a file or folder
905
-	 *
906
-	 * @param string $path
907
-	 * @return string
908
-	 */
909
-	public static function getOwner($path) {
910
-		return self::$defaultInstance->getOwner($path);
911
-	}
912
-
913
-	/**
914
-	 * get the ETag for a file or folder
915
-	 *
916
-	 * @param string $path
917
-	 * @return string
918
-	 */
919
-	public static function getETag($path) {
920
-		return self::$defaultInstance->getETag($path);
921
-	}
74
+    /**
75
+     * @var Mount\Manager $mounts
76
+     */
77
+    private static $mounts;
78
+
79
+    public static $loaded = false;
80
+    /**
81
+     * @var \OC\Files\View $defaultInstance
82
+     */
83
+    private static $defaultInstance;
84
+
85
+    private static $usersSetup = [];
86
+
87
+    private static $normalizedPathCache = null;
88
+
89
+    private static $listeningForProviders = false;
90
+
91
+    /**
92
+     * classname which used for hooks handling
93
+     * used as signalclass in OC_Hooks::emit()
94
+     */
95
+    public const CLASSNAME = 'OC_Filesystem';
96
+
97
+    /**
98
+     * signalname emitted before file renaming
99
+     *
100
+     * @param string $oldpath
101
+     * @param string $newpath
102
+     */
103
+    public const signal_rename = 'rename';
104
+
105
+    /**
106
+     * signal emitted after file renaming
107
+     *
108
+     * @param string $oldpath
109
+     * @param string $newpath
110
+     */
111
+    public const signal_post_rename = 'post_rename';
112
+
113
+    /**
114
+     * signal emitted before file/dir creation
115
+     *
116
+     * @param string $path
117
+     * @param bool $run changing this flag to false in hook handler will cancel event
118
+     */
119
+    public const signal_create = 'create';
120
+
121
+    /**
122
+     * signal emitted after file/dir creation
123
+     *
124
+     * @param string $path
125
+     * @param bool $run changing this flag to false in hook handler will cancel event
126
+     */
127
+    public const signal_post_create = 'post_create';
128
+
129
+    /**
130
+     * signal emits before file/dir copy
131
+     *
132
+     * @param string $oldpath
133
+     * @param string $newpath
134
+     * @param bool $run changing this flag to false in hook handler will cancel event
135
+     */
136
+    public const signal_copy = 'copy';
137
+
138
+    /**
139
+     * signal emits after file/dir copy
140
+     *
141
+     * @param string $oldpath
142
+     * @param string $newpath
143
+     */
144
+    public const signal_post_copy = 'post_copy';
145
+
146
+    /**
147
+     * signal emits before file/dir save
148
+     *
149
+     * @param string $path
150
+     * @param bool $run changing this flag to false in hook handler will cancel event
151
+     */
152
+    public const signal_write = 'write';
153
+
154
+    /**
155
+     * signal emits after file/dir save
156
+     *
157
+     * @param string $path
158
+     */
159
+    public const signal_post_write = 'post_write';
160
+
161
+    /**
162
+     * signal emitted before file/dir update
163
+     *
164
+     * @param string $path
165
+     * @param bool $run changing this flag to false in hook handler will cancel event
166
+     */
167
+    public const signal_update = 'update';
168
+
169
+    /**
170
+     * signal emitted after file/dir update
171
+     *
172
+     * @param string $path
173
+     * @param bool $run changing this flag to false in hook handler will cancel event
174
+     */
175
+    public const signal_post_update = 'post_update';
176
+
177
+    /**
178
+     * signal emits when reading file/dir
179
+     *
180
+     * @param string $path
181
+     */
182
+    public const signal_read = 'read';
183
+
184
+    /**
185
+     * signal emits when removing file/dir
186
+     *
187
+     * @param string $path
188
+     */
189
+    public const signal_delete = 'delete';
190
+
191
+    /**
192
+     * parameters definitions for signals
193
+     */
194
+    public const signal_param_path = 'path';
195
+    public const signal_param_oldpath = 'oldpath';
196
+    public const signal_param_newpath = 'newpath';
197
+
198
+    /**
199
+     * run - changing this flag to false in hook handler will cancel event
200
+     */
201
+    public const signal_param_run = 'run';
202
+
203
+    public const signal_create_mount = 'create_mount';
204
+    public const signal_delete_mount = 'delete_mount';
205
+    public const signal_param_mount_type = 'mounttype';
206
+    public const signal_param_users = 'users';
207
+
208
+    /**
209
+     * @var \OC\Files\Storage\StorageFactory $loader
210
+     */
211
+    private static $loader;
212
+
213
+    /** @var bool */
214
+    private static $logWarningWhenAddingStorageWrapper = true;
215
+
216
+    /**
217
+     * @param bool $shouldLog
218
+     * @return bool previous value
219
+     * @internal
220
+     */
221
+    public static function logWarningWhenAddingStorageWrapper($shouldLog) {
222
+        $previousValue = self::$logWarningWhenAddingStorageWrapper;
223
+        self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
224
+        return $previousValue;
225
+    }
226
+
227
+    /**
228
+     * @param string $wrapperName
229
+     * @param callable $wrapper
230
+     * @param int $priority
231
+     */
232
+    public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
233
+        if (self::$logWarningWhenAddingStorageWrapper) {
234
+            \OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
235
+                'wrapper' => $wrapperName,
236
+                'app' => 'filesystem',
237
+            ]);
238
+        }
239
+
240
+        $mounts = self::getMountManager()->getAll();
241
+        if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
242
+            // do not re-wrap if storage with this name already existed
243
+            return;
244
+        }
245
+    }
246
+
247
+    /**
248
+     * Returns the storage factory
249
+     *
250
+     * @return IStorageFactory
251
+     */
252
+    public static function getLoader() {
253
+        if (!self::$loader) {
254
+            self::$loader = \OC::$server->query(IStorageFactory::class);
255
+        }
256
+        return self::$loader;
257
+    }
258
+
259
+    /**
260
+     * Returns the mount manager
261
+     *
262
+     * @return \OC\Files\Mount\Manager
263
+     */
264
+    public static function getMountManager($user = '') {
265
+        if (!self::$mounts) {
266
+            \OC_Util::setupFS($user);
267
+        }
268
+        return self::$mounts;
269
+    }
270
+
271
+    /**
272
+     * get the mountpoint of the storage object for a path
273
+     * ( note: because a storage is not always mounted inside the fakeroot, the
274
+     * returned mountpoint is relative to the absolute root of the filesystem
275
+     * and doesn't take the chroot into account )
276
+     *
277
+     * @param string $path
278
+     * @return string
279
+     */
280
+    public static function getMountPoint($path) {
281
+        if (!self::$mounts) {
282
+            \OC_Util::setupFS();
283
+        }
284
+        $mount = self::$mounts->find($path);
285
+        if ($mount) {
286
+            return $mount->getMountPoint();
287
+        } else {
288
+            return '';
289
+        }
290
+    }
291
+
292
+    /**
293
+     * get a list of all mount points in a directory
294
+     *
295
+     * @param string $path
296
+     * @return string[]
297
+     */
298
+    public static function getMountPoints($path) {
299
+        if (!self::$mounts) {
300
+            \OC_Util::setupFS();
301
+        }
302
+        $result = [];
303
+        $mounts = self::$mounts->findIn($path);
304
+        foreach ($mounts as $mount) {
305
+            $result[] = $mount->getMountPoint();
306
+        }
307
+        return $result;
308
+    }
309
+
310
+    /**
311
+     * get the storage mounted at $mountPoint
312
+     *
313
+     * @param string $mountPoint
314
+     * @return \OC\Files\Storage\Storage
315
+     */
316
+    public static function getStorage($mountPoint) {
317
+        if (!self::$mounts) {
318
+            \OC_Util::setupFS();
319
+        }
320
+        $mount = self::$mounts->find($mountPoint);
321
+        return $mount->getStorage();
322
+    }
323
+
324
+    /**
325
+     * @param string $id
326
+     * @return Mount\MountPoint[]
327
+     */
328
+    public static function getMountByStorageId($id) {
329
+        if (!self::$mounts) {
330
+            \OC_Util::setupFS();
331
+        }
332
+        return self::$mounts->findByStorageId($id);
333
+    }
334
+
335
+    /**
336
+     * @param int $id
337
+     * @return Mount\MountPoint[]
338
+     */
339
+    public static function getMountByNumericId($id) {
340
+        if (!self::$mounts) {
341
+            \OC_Util::setupFS();
342
+        }
343
+        return self::$mounts->findByNumericId($id);
344
+    }
345
+
346
+    /**
347
+     * resolve a path to a storage and internal path
348
+     *
349
+     * @param string $path
350
+     * @return array an array consisting of the storage and the internal path
351
+     */
352
+    public static function resolvePath($path) {
353
+        if (!self::$mounts) {
354
+            \OC_Util::setupFS();
355
+        }
356
+        $mount = self::$mounts->find($path);
357
+        if ($mount) {
358
+            return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
359
+        } else {
360
+            return [null, null];
361
+        }
362
+    }
363
+
364
+    public static function init($user, $root) {
365
+        if (self::$defaultInstance) {
366
+            return false;
367
+        }
368
+        self::getLoader();
369
+        self::$defaultInstance = new View($root);
370
+
371
+        if (!self::$mounts) {
372
+            self::$mounts = \OC::$server->getMountManager();
373
+        }
374
+
375
+        //load custom mount config
376
+        self::initMountPoints($user);
377
+
378
+        self::$loaded = true;
379
+
380
+        return true;
381
+    }
382
+
383
+    public static function initMountManager() {
384
+        if (!self::$mounts) {
385
+            self::$mounts = \OC::$server->getMountManager();
386
+        }
387
+    }
388
+
389
+    /**
390
+     * Initialize system and personal mount points for a user
391
+     *
392
+     * @param string $user
393
+     * @throws \OC\User\NoUserException if the user is not available
394
+     */
395
+    public static function initMountPoints($user = '') {
396
+        if ($user == '') {
397
+            $user = \OC_User::getUser();
398
+        }
399
+        if ($user === null || $user === false || $user === '') {
400
+            throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
401
+        }
402
+
403
+        if (isset(self::$usersSetup[$user])) {
404
+            return;
405
+        }
406
+
407
+        self::$usersSetup[$user] = true;
408
+
409
+        $userManager = \OC::$server->getUserManager();
410
+        $userObject = $userManager->get($user);
411
+
412
+        if (is_null($userObject)) {
413
+            \OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR);
414
+            // reset flag, this will make it possible to rethrow the exception if called again
415
+            unset(self::$usersSetup[$user]);
416
+            throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
417
+        }
418
+
419
+        $realUid = $userObject->getUID();
420
+        // workaround in case of different casings
421
+        if ($user !== $realUid) {
422
+            $stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
423
+            \OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN);
424
+            $user = $realUid;
425
+
426
+            // again with the correct casing
427
+            if (isset(self::$usersSetup[$user])) {
428
+                return;
429
+            }
430
+
431
+            self::$usersSetup[$user] = true;
432
+        }
433
+
434
+        if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
435
+            /** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
436
+            $mountConfigManager = \OC::$server->getMountProviderCollection();
437
+
438
+            // home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
439
+            $homeMount = $mountConfigManager->getHomeMountForUser($userObject);
440
+            if ($homeMount->getStorageRootId() === -1) {
441
+                $homeMount->getStorage()->mkdir('');
442
+                $homeMount->getStorage()->getScanner()->scan('');
443
+            }
444
+
445
+            self::getMountManager()->addMount($homeMount);
446
+
447
+            \OC\Files\Filesystem::getStorage($user);
448
+
449
+            // Chance to mount for other storages
450
+            if ($userObject) {
451
+                $mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
452
+                $mounts[] = $homeMount;
453
+                $mountConfigManager->registerMounts($userObject, $mounts);
454
+            }
455
+
456
+            self::listenForNewMountProviders($mountConfigManager, $userManager);
457
+        } else {
458
+            self::getMountManager()->addMount(new MountPoint(
459
+                new NullStorage([]),
460
+                '/' . $user
461
+            ));
462
+            self::getMountManager()->addMount(new MountPoint(
463
+                new NullStorage([]),
464
+                '/' . $user . '/files'
465
+            ));
466
+        }
467
+        \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]);
468
+    }
469
+
470
+    /**
471
+     * Get mounts from mount providers that are registered after setup
472
+     *
473
+     * @param MountProviderCollection $mountConfigManager
474
+     * @param IUserManager $userManager
475
+     */
476
+    private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
477
+        if (!self::$listeningForProviders) {
478
+            self::$listeningForProviders = true;
479
+            $mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
480
+                foreach (Filesystem::$usersSetup as $user => $setup) {
481
+                    $userObject = $userManager->get($user);
482
+                    if ($userObject) {
483
+                        $mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
484
+                        array_walk($mounts, [self::$mounts, 'addMount']);
485
+                    }
486
+                }
487
+            });
488
+        }
489
+    }
490
+
491
+    /**
492
+     * get the default filesystem view
493
+     *
494
+     * @return View
495
+     */
496
+    public static function getView() {
497
+        return self::$defaultInstance;
498
+    }
499
+
500
+    /**
501
+     * tear down the filesystem, removing all storage providers
502
+     */
503
+    public static function tearDown() {
504
+        self::clearMounts();
505
+        self::$defaultInstance = null;
506
+    }
507
+
508
+    /**
509
+     * get the relative path of the root data directory for the current user
510
+     *
511
+     * @return string
512
+     *
513
+     * Returns path like /admin/files
514
+     */
515
+    public static function getRoot() {
516
+        if (!self::$defaultInstance) {
517
+            return null;
518
+        }
519
+        return self::$defaultInstance->getRoot();
520
+    }
521
+
522
+    /**
523
+     * clear all mounts and storage backends
524
+     */
525
+    public static function clearMounts() {
526
+        if (self::$mounts) {
527
+            self::$usersSetup = [];
528
+            self::$mounts->clear();
529
+        }
530
+    }
531
+
532
+    /**
533
+     * mount an \OC\Files\Storage\Storage in our virtual filesystem
534
+     *
535
+     * @param \OC\Files\Storage\Storage|string $class
536
+     * @param array $arguments
537
+     * @param string $mountpoint
538
+     */
539
+    public static function mount($class, $arguments, $mountpoint) {
540
+        if (!self::$mounts) {
541
+            \OC_Util::setupFS();
542
+        }
543
+        $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
544
+        self::$mounts->addMount($mount);
545
+    }
546
+
547
+    /**
548
+     * return the path to a local version of the file
549
+     * we need this because we can't know if a file is stored local or not from
550
+     * outside the filestorage and for some purposes a local file is needed
551
+     *
552
+     * @param string $path
553
+     * @return string
554
+     */
555
+    public static function getLocalFile($path) {
556
+        return self::$defaultInstance->getLocalFile($path);
557
+    }
558
+
559
+    /**
560
+     * @param string $path
561
+     * @return string
562
+     */
563
+    public static function getLocalFolder($path) {
564
+        return self::$defaultInstance->getLocalFolder($path);
565
+    }
566
+
567
+    /**
568
+     * return path to file which reflects one visible in browser
569
+     *
570
+     * @param string $path
571
+     * @return string
572
+     */
573
+    public static function getLocalPath($path) {
574
+        $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
575
+        $newpath = $path;
576
+        if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
577
+            $newpath = substr($path, strlen($datadir));
578
+        }
579
+        return $newpath;
580
+    }
581
+
582
+    /**
583
+     * check if the requested path is valid
584
+     *
585
+     * @param string $path
586
+     * @return bool
587
+     */
588
+    public static function isValidPath($path) {
589
+        $path = self::normalizePath($path);
590
+        if (!$path || $path[0] !== '/') {
591
+            $path = '/' . $path;
592
+        }
593
+        if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
594
+            return false;
595
+        }
596
+        return true;
597
+    }
598
+
599
+    /**
600
+     * checks if a file is blacklisted for storage in the filesystem
601
+     * Listens to write and rename hooks
602
+     *
603
+     * @param array $data from hook
604
+     */
605
+    public static function isBlacklisted($data) {
606
+        if (isset($data['path'])) {
607
+            $path = $data['path'];
608
+        } elseif (isset($data['newpath'])) {
609
+            $path = $data['newpath'];
610
+        }
611
+        if (isset($path)) {
612
+            if (self::isFileBlacklisted($path)) {
613
+                $data['run'] = false;
614
+            }
615
+        }
616
+    }
617
+
618
+    /**
619
+     * @param string $filename
620
+     * @return bool
621
+     */
622
+    public static function isFileBlacklisted($filename) {
623
+        $filename = self::normalizePath($filename);
624
+
625
+        $blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
626
+        $filename = strtolower(basename($filename));
627
+        return in_array($filename, $blacklist);
628
+    }
629
+
630
+    /**
631
+     * check if the directory should be ignored when scanning
632
+     * NOTE: the special directories . and .. would cause never ending recursion
633
+     *
634
+     * @param string $dir
635
+     * @return boolean
636
+     */
637
+    public static function isIgnoredDir($dir) {
638
+        if ($dir === '.' || $dir === '..') {
639
+            return true;
640
+        }
641
+        return false;
642
+    }
643
+
644
+    /**
645
+     * following functions are equivalent to their php builtin equivalents for arguments/return values.
646
+     */
647
+    public static function mkdir($path) {
648
+        return self::$defaultInstance->mkdir($path);
649
+    }
650
+
651
+    public static function rmdir($path) {
652
+        return self::$defaultInstance->rmdir($path);
653
+    }
654
+
655
+    public static function is_dir($path) {
656
+        return self::$defaultInstance->is_dir($path);
657
+    }
658
+
659
+    public static function is_file($path) {
660
+        return self::$defaultInstance->is_file($path);
661
+    }
662
+
663
+    public static function stat($path) {
664
+        return self::$defaultInstance->stat($path);
665
+    }
666
+
667
+    public static function filetype($path) {
668
+        return self::$defaultInstance->filetype($path);
669
+    }
670
+
671
+    public static function filesize($path) {
672
+        return self::$defaultInstance->filesize($path);
673
+    }
674
+
675
+    public static function readfile($path) {
676
+        return self::$defaultInstance->readfile($path);
677
+    }
678
+
679
+    public static function isCreatable($path) {
680
+        return self::$defaultInstance->isCreatable($path);
681
+    }
682
+
683
+    public static function isReadable($path) {
684
+        return self::$defaultInstance->isReadable($path);
685
+    }
686
+
687
+    public static function isUpdatable($path) {
688
+        return self::$defaultInstance->isUpdatable($path);
689
+    }
690
+
691
+    public static function isDeletable($path) {
692
+        return self::$defaultInstance->isDeletable($path);
693
+    }
694
+
695
+    public static function isSharable($path) {
696
+        return self::$defaultInstance->isSharable($path);
697
+    }
698
+
699
+    public static function file_exists($path) {
700
+        return self::$defaultInstance->file_exists($path);
701
+    }
702
+
703
+    public static function filemtime($path) {
704
+        return self::$defaultInstance->filemtime($path);
705
+    }
706
+
707
+    public static function touch($path, $mtime = null) {
708
+        return self::$defaultInstance->touch($path, $mtime);
709
+    }
710
+
711
+    /**
712
+     * @return string
713
+     */
714
+    public static function file_get_contents($path) {
715
+        return self::$defaultInstance->file_get_contents($path);
716
+    }
717
+
718
+    public static function file_put_contents($path, $data) {
719
+        return self::$defaultInstance->file_put_contents($path, $data);
720
+    }
721
+
722
+    public static function unlink($path) {
723
+        return self::$defaultInstance->unlink($path);
724
+    }
725
+
726
+    public static function rename($path1, $path2) {
727
+        return self::$defaultInstance->rename($path1, $path2);
728
+    }
729
+
730
+    public static function copy($path1, $path2) {
731
+        return self::$defaultInstance->copy($path1, $path2);
732
+    }
733
+
734
+    public static function fopen($path, $mode) {
735
+        return self::$defaultInstance->fopen($path, $mode);
736
+    }
737
+
738
+    /**
739
+     * @return string
740
+     */
741
+    public static function toTmpFile($path) {
742
+        return self::$defaultInstance->toTmpFile($path);
743
+    }
744
+
745
+    public static function fromTmpFile($tmpFile, $path) {
746
+        return self::$defaultInstance->fromTmpFile($tmpFile, $path);
747
+    }
748
+
749
+    public static function getMimeType($path) {
750
+        return self::$defaultInstance->getMimeType($path);
751
+    }
752
+
753
+    public static function hash($type, $path, $raw = false) {
754
+        return self::$defaultInstance->hash($type, $path, $raw);
755
+    }
756
+
757
+    public static function free_space($path = '/') {
758
+        return self::$defaultInstance->free_space($path);
759
+    }
760
+
761
+    public static function search($query) {
762
+        return self::$defaultInstance->search($query);
763
+    }
764
+
765
+    /**
766
+     * @param string $query
767
+     */
768
+    public static function searchByMime($query) {
769
+        return self::$defaultInstance->searchByMime($query);
770
+    }
771
+
772
+    /**
773
+     * @param string|int $tag name or tag id
774
+     * @param string $userId owner of the tags
775
+     * @return FileInfo[] array or file info
776
+     */
777
+    public static function searchByTag($tag, $userId) {
778
+        return self::$defaultInstance->searchByTag($tag, $userId);
779
+    }
780
+
781
+    /**
782
+     * check if a file or folder has been updated since $time
783
+     *
784
+     * @param string $path
785
+     * @param int $time
786
+     * @return bool
787
+     */
788
+    public static function hasUpdated($path, $time) {
789
+        return self::$defaultInstance->hasUpdated($path, $time);
790
+    }
791
+
792
+    /**
793
+     * Fix common problems with a file path
794
+     *
795
+     * @param string $path
796
+     * @param bool $stripTrailingSlash whether to strip the trailing slash
797
+     * @param bool $isAbsolutePath whether the given path is absolute
798
+     * @param bool $keepUnicode true to disable unicode normalization
799
+     * @return string
800
+     */
801
+    public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
802
+        if (is_null(self::$normalizedPathCache)) {
803
+            self::$normalizedPathCache = new CappedMemoryCache(2048);
804
+        }
805
+
806
+        /**
807
+         * FIXME: This is a workaround for existing classes and files which call
808
+         *        this function with another type than a valid string. This
809
+         *        conversion should get removed as soon as all existing
810
+         *        function calls have been fixed.
811
+         */
812
+        $path = (string)$path;
813
+
814
+        $cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
815
+
816
+        if (isset(self::$normalizedPathCache[$cacheKey])) {
817
+            return self::$normalizedPathCache[$cacheKey];
818
+        }
819
+
820
+        if ($path === '') {
821
+            return '/';
822
+        }
823
+
824
+        //normalize unicode if possible
825
+        if (!$keepUnicode) {
826
+            $path = \OC_Util::normalizeUnicode($path);
827
+        }
828
+
829
+        //add leading slash, if it is already there we strip it anyway
830
+        $path = '/' . $path;
831
+
832
+        $patterns = [
833
+            '/\\\\/s',          // no windows style slashes
834
+            '/\/\.(\/\.)?\//s', // remove '/./'
835
+            '/\/{2,}/s',        // remove sequence of slashes
836
+            '/\/\.$/s',         // remove trailing /.
837
+        ];
838
+
839
+        do {
840
+            $count = 0;
841
+            $path = preg_replace($patterns, '/', $path, -1, $count);
842
+        } while ($count > 0);
843
+
844
+        //remove trailing slash
845
+        if ($stripTrailingSlash && strlen($path) > 1) {
846
+            $path = rtrim($path, '/');
847
+        }
848
+
849
+        self::$normalizedPathCache[$cacheKey] = $path;
850
+
851
+        return $path;
852
+    }
853
+
854
+    /**
855
+     * get the filesystem info
856
+     *
857
+     * @param string $path
858
+     * @param boolean $includeMountPoints whether to add mountpoint sizes,
859
+     * defaults to true
860
+     * @return \OC\Files\FileInfo|bool False if file does not exist
861
+     */
862
+    public static function getFileInfo($path, $includeMountPoints = true) {
863
+        return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
864
+    }
865
+
866
+    /**
867
+     * change file metadata
868
+     *
869
+     * @param string $path
870
+     * @param array $data
871
+     * @return int
872
+     *
873
+     * returns the fileid of the updated file
874
+     */
875
+    public static function putFileInfo($path, $data) {
876
+        return self::$defaultInstance->putFileInfo($path, $data);
877
+    }
878
+
879
+    /**
880
+     * get the content of a directory
881
+     *
882
+     * @param string $directory path under datadirectory
883
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
884
+     * @return \OC\Files\FileInfo[]
885
+     */
886
+    public static function getDirectoryContent($directory, $mimetype_filter = '') {
887
+        return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
888
+    }
889
+
890
+    /**
891
+     * Get the path of a file by id
892
+     *
893
+     * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
894
+     *
895
+     * @param int $id
896
+     * @throws NotFoundException
897
+     * @return string
898
+     */
899
+    public static function getPath($id) {
900
+        return self::$defaultInstance->getPath($id);
901
+    }
902
+
903
+    /**
904
+     * Get the owner for a file or folder
905
+     *
906
+     * @param string $path
907
+     * @return string
908
+     */
909
+    public static function getOwner($path) {
910
+        return self::$defaultInstance->getOwner($path);
911
+    }
912
+
913
+    /**
914
+     * get the ETag for a file or folder
915
+     *
916
+     * @param string $path
917
+     * @return string
918
+     */
919
+    public static function getETag($path) {
920
+        return self::$defaultInstance->getETag($path);
921
+    }
922 922
 }
Please login to merge, or discard this patch.
lib/private/Share20/Manager.php 2 patches
Indentation   +1787 added lines, -1787 removed lines patch added patch discarded remove patch
@@ -76,1814 +76,1814 @@
 block discarded – undo
76 76
  */
77 77
 class Manager implements IManager {
78 78
 
79
-	/** @var IProviderFactory */
80
-	private $factory;
81
-	/** @var ILogger */
82
-	private $logger;
83
-	/** @var IConfig */
84
-	private $config;
85
-	/** @var ISecureRandom */
86
-	private $secureRandom;
87
-	/** @var IHasher */
88
-	private $hasher;
89
-	/** @var IMountManager */
90
-	private $mountManager;
91
-	/** @var IGroupManager */
92
-	private $groupManager;
93
-	/** @var IL10N */
94
-	private $l;
95
-	/** @var IFactory */
96
-	private $l10nFactory;
97
-	/** @var IUserManager */
98
-	private $userManager;
99
-	/** @var IRootFolder */
100
-	private $rootFolder;
101
-	/** @var CappedMemoryCache */
102
-	private $sharingDisabledForUsersCache;
103
-	/** @var EventDispatcherInterface */
104
-	private $legacyDispatcher;
105
-	/** @var LegacyHooks */
106
-	private $legacyHooks;
107
-	/** @var IMailer */
108
-	private $mailer;
109
-	/** @var IURLGenerator */
110
-	private $urlGenerator;
111
-	/** @var \OC_Defaults */
112
-	private $defaults;
113
-	/** @var IEventDispatcher */
114
-	private $dispatcher;
115
-
116
-
117
-	/**
118
-	 * Manager constructor.
119
-	 *
120
-	 * @param ILogger $logger
121
-	 * @param IConfig $config
122
-	 * @param ISecureRandom $secureRandom
123
-	 * @param IHasher $hasher
124
-	 * @param IMountManager $mountManager
125
-	 * @param IGroupManager $groupManager
126
-	 * @param IL10N $l
127
-	 * @param IFactory $l10nFactory
128
-	 * @param IProviderFactory $factory
129
-	 * @param IUserManager $userManager
130
-	 * @param IRootFolder $rootFolder
131
-	 * @param EventDispatcherInterface $eventDispatcher
132
-	 * @param IMailer $mailer
133
-	 * @param IURLGenerator $urlGenerator
134
-	 * @param \OC_Defaults $defaults
135
-	 */
136
-	public function __construct(
137
-			ILogger $logger,
138
-			IConfig $config,
139
-			ISecureRandom $secureRandom,
140
-			IHasher $hasher,
141
-			IMountManager $mountManager,
142
-			IGroupManager $groupManager,
143
-			IL10N $l,
144
-			IFactory $l10nFactory,
145
-			IProviderFactory $factory,
146
-			IUserManager $userManager,
147
-			IRootFolder $rootFolder,
148
-			EventDispatcherInterface $legacyDispatcher,
149
-			IMailer $mailer,
150
-			IURLGenerator $urlGenerator,
151
-			\OC_Defaults $defaults,
152
-			IEventDispatcher $dispatcher
153
-	) {
154
-		$this->logger = $logger;
155
-		$this->config = $config;
156
-		$this->secureRandom = $secureRandom;
157
-		$this->hasher = $hasher;
158
-		$this->mountManager = $mountManager;
159
-		$this->groupManager = $groupManager;
160
-		$this->l = $l;
161
-		$this->l10nFactory = $l10nFactory;
162
-		$this->factory = $factory;
163
-		$this->userManager = $userManager;
164
-		$this->rootFolder = $rootFolder;
165
-		$this->legacyDispatcher = $legacyDispatcher;
166
-		$this->sharingDisabledForUsersCache = new CappedMemoryCache();
167
-		$this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
168
-		$this->mailer = $mailer;
169
-		$this->urlGenerator = $urlGenerator;
170
-		$this->defaults = $defaults;
171
-		$this->dispatcher = $dispatcher;
172
-	}
173
-
174
-	/**
175
-	 * Convert from a full share id to a tuple (providerId, shareId)
176
-	 *
177
-	 * @param string $id
178
-	 * @return string[]
179
-	 */
180
-	private function splitFullId($id) {
181
-		return explode(':', $id, 2);
182
-	}
183
-
184
-	/**
185
-	 * Verify if a password meets all requirements
186
-	 *
187
-	 * @param string $password
188
-	 * @throws \Exception
189
-	 */
190
-	protected function verifyPassword($password) {
191
-		if ($password === null) {
192
-			// No password is set, check if this is allowed.
193
-			if ($this->shareApiLinkEnforcePassword()) {
194
-				throw new \InvalidArgumentException('Passwords are enforced for link shares');
195
-			}
196
-
197
-			return;
198
-		}
199
-
200
-		// Let others verify the password
201
-		try {
202
-			$this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
203
-		} catch (HintException $e) {
204
-			throw new \Exception($e->getHint());
205
-		}
206
-	}
207
-
208
-	/**
209
-	 * Check for generic requirements before creating a share
210
-	 *
211
-	 * @param IShare $share
212
-	 * @throws \InvalidArgumentException
213
-	 * @throws GenericShareException
214
-	 *
215
-	 * @suppress PhanUndeclaredClassMethod
216
-	 */
217
-	protected function generalCreateChecks(IShare $share) {
218
-		if ($share->getShareType() === IShare::TYPE_USER) {
219
-			// We expect a valid user as sharedWith for user shares
220
-			if (!$this->userManager->userExists($share->getSharedWith())) {
221
-				throw new \InvalidArgumentException('SharedWith is not a valid user');
222
-			}
223
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
224
-			// We expect a valid group as sharedWith for group shares
225
-			if (!$this->groupManager->groupExists($share->getSharedWith())) {
226
-				throw new \InvalidArgumentException('SharedWith is not a valid group');
227
-			}
228
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
229
-			if ($share->getSharedWith() !== null) {
230
-				throw new \InvalidArgumentException('SharedWith should be empty');
231
-			}
232
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
233
-			if ($share->getSharedWith() === null) {
234
-				throw new \InvalidArgumentException('SharedWith should not be empty');
235
-			}
236
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
237
-			if ($share->getSharedWith() === null) {
238
-				throw new \InvalidArgumentException('SharedWith should not be empty');
239
-			}
240
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
241
-			if ($share->getSharedWith() === null) {
242
-				throw new \InvalidArgumentException('SharedWith should not be empty');
243
-			}
244
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
245
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
246
-			if ($circle === null) {
247
-				throw new \InvalidArgumentException('SharedWith is not a valid circle');
248
-			}
249
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
250
-		} else {
251
-			// We can't handle other types yet
252
-			throw new \InvalidArgumentException('unknown share type');
253
-		}
254
-
255
-		// Verify the initiator of the share is set
256
-		if ($share->getSharedBy() === null) {
257
-			throw new \InvalidArgumentException('SharedBy should be set');
258
-		}
259
-
260
-		// Cannot share with yourself
261
-		if ($share->getShareType() === IShare::TYPE_USER &&
262
-			$share->getSharedWith() === $share->getSharedBy()) {
263
-			throw new \InvalidArgumentException('Can’t share with yourself');
264
-		}
265
-
266
-		// The path should be set
267
-		if ($share->getNode() === null) {
268
-			throw new \InvalidArgumentException('Path should be set');
269
-		}
270
-
271
-		// And it should be a file or a folder
272
-		if (!($share->getNode() instanceof \OCP\Files\File) &&
273
-				!($share->getNode() instanceof \OCP\Files\Folder)) {
274
-			throw new \InvalidArgumentException('Path should be either a file or a folder');
275
-		}
276
-
277
-		// And you can't share your rootfolder
278
-		if ($this->userManager->userExists($share->getSharedBy())) {
279
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
280
-		} else {
281
-			$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
282
-		}
283
-		if ($userFolder->getId() === $share->getNode()->getId()) {
284
-			throw new \InvalidArgumentException('You can’t share your root folder');
285
-		}
286
-
287
-		// Check if we actually have share permissions
288
-		if (!$share->getNode()->isShareable()) {
289
-			$path = $userFolder->getRelativePath($share->getNode()->getPath());
290
-			$message_t = $this->l->t('You are not allowed to share %s', [$path]);
291
-			throw new GenericShareException($message_t, $message_t, 404);
292
-		}
293
-
294
-		// Permissions should be set
295
-		if ($share->getPermissions() === null) {
296
-			throw new \InvalidArgumentException('A share requires permissions');
297
-		}
298
-
299
-		$isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
300
-		$permissions = 0;
301
-
302
-		$userMounts = $userFolder->getById($share->getNode()->getId());
303
-		$userMount = array_shift($userMounts);
304
-		$mount = $userMount->getMountPoint();
305
-		if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
-			// When it's a reshare use the parent share permissions as maximum
307
-			$userMountPointId = $mount->getStorageRootId();
308
-			$userMountPoints = $userFolder->getById($userMountPointId);
309
-			$userMountPoint = array_shift($userMountPoints);
310
-
311
-			if ($userMountPoint === null) {
312
-				throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
313
-			}
314
-
315
-			/* Check if this is an incoming share */
316
-			$incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
317
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
318
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
319
-			$incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
320
-
321
-			/** @var IShare[] $incomingShares */
322
-			if (!empty($incomingShares)) {
323
-				foreach ($incomingShares as $incomingShare) {
324
-					$permissions |= $incomingShare->getPermissions();
325
-				}
326
-			}
327
-		} else {
328
-			/*
79
+    /** @var IProviderFactory */
80
+    private $factory;
81
+    /** @var ILogger */
82
+    private $logger;
83
+    /** @var IConfig */
84
+    private $config;
85
+    /** @var ISecureRandom */
86
+    private $secureRandom;
87
+    /** @var IHasher */
88
+    private $hasher;
89
+    /** @var IMountManager */
90
+    private $mountManager;
91
+    /** @var IGroupManager */
92
+    private $groupManager;
93
+    /** @var IL10N */
94
+    private $l;
95
+    /** @var IFactory */
96
+    private $l10nFactory;
97
+    /** @var IUserManager */
98
+    private $userManager;
99
+    /** @var IRootFolder */
100
+    private $rootFolder;
101
+    /** @var CappedMemoryCache */
102
+    private $sharingDisabledForUsersCache;
103
+    /** @var EventDispatcherInterface */
104
+    private $legacyDispatcher;
105
+    /** @var LegacyHooks */
106
+    private $legacyHooks;
107
+    /** @var IMailer */
108
+    private $mailer;
109
+    /** @var IURLGenerator */
110
+    private $urlGenerator;
111
+    /** @var \OC_Defaults */
112
+    private $defaults;
113
+    /** @var IEventDispatcher */
114
+    private $dispatcher;
115
+
116
+
117
+    /**
118
+     * Manager constructor.
119
+     *
120
+     * @param ILogger $logger
121
+     * @param IConfig $config
122
+     * @param ISecureRandom $secureRandom
123
+     * @param IHasher $hasher
124
+     * @param IMountManager $mountManager
125
+     * @param IGroupManager $groupManager
126
+     * @param IL10N $l
127
+     * @param IFactory $l10nFactory
128
+     * @param IProviderFactory $factory
129
+     * @param IUserManager $userManager
130
+     * @param IRootFolder $rootFolder
131
+     * @param EventDispatcherInterface $eventDispatcher
132
+     * @param IMailer $mailer
133
+     * @param IURLGenerator $urlGenerator
134
+     * @param \OC_Defaults $defaults
135
+     */
136
+    public function __construct(
137
+            ILogger $logger,
138
+            IConfig $config,
139
+            ISecureRandom $secureRandom,
140
+            IHasher $hasher,
141
+            IMountManager $mountManager,
142
+            IGroupManager $groupManager,
143
+            IL10N $l,
144
+            IFactory $l10nFactory,
145
+            IProviderFactory $factory,
146
+            IUserManager $userManager,
147
+            IRootFolder $rootFolder,
148
+            EventDispatcherInterface $legacyDispatcher,
149
+            IMailer $mailer,
150
+            IURLGenerator $urlGenerator,
151
+            \OC_Defaults $defaults,
152
+            IEventDispatcher $dispatcher
153
+    ) {
154
+        $this->logger = $logger;
155
+        $this->config = $config;
156
+        $this->secureRandom = $secureRandom;
157
+        $this->hasher = $hasher;
158
+        $this->mountManager = $mountManager;
159
+        $this->groupManager = $groupManager;
160
+        $this->l = $l;
161
+        $this->l10nFactory = $l10nFactory;
162
+        $this->factory = $factory;
163
+        $this->userManager = $userManager;
164
+        $this->rootFolder = $rootFolder;
165
+        $this->legacyDispatcher = $legacyDispatcher;
166
+        $this->sharingDisabledForUsersCache = new CappedMemoryCache();
167
+        $this->legacyHooks = new LegacyHooks($this->legacyDispatcher);
168
+        $this->mailer = $mailer;
169
+        $this->urlGenerator = $urlGenerator;
170
+        $this->defaults = $defaults;
171
+        $this->dispatcher = $dispatcher;
172
+    }
173
+
174
+    /**
175
+     * Convert from a full share id to a tuple (providerId, shareId)
176
+     *
177
+     * @param string $id
178
+     * @return string[]
179
+     */
180
+    private function splitFullId($id) {
181
+        return explode(':', $id, 2);
182
+    }
183
+
184
+    /**
185
+     * Verify if a password meets all requirements
186
+     *
187
+     * @param string $password
188
+     * @throws \Exception
189
+     */
190
+    protected function verifyPassword($password) {
191
+        if ($password === null) {
192
+            // No password is set, check if this is allowed.
193
+            if ($this->shareApiLinkEnforcePassword()) {
194
+                throw new \InvalidArgumentException('Passwords are enforced for link shares');
195
+            }
196
+
197
+            return;
198
+        }
199
+
200
+        // Let others verify the password
201
+        try {
202
+            $this->legacyDispatcher->dispatch(new ValidatePasswordPolicyEvent($password));
203
+        } catch (HintException $e) {
204
+            throw new \Exception($e->getHint());
205
+        }
206
+    }
207
+
208
+    /**
209
+     * Check for generic requirements before creating a share
210
+     *
211
+     * @param IShare $share
212
+     * @throws \InvalidArgumentException
213
+     * @throws GenericShareException
214
+     *
215
+     * @suppress PhanUndeclaredClassMethod
216
+     */
217
+    protected function generalCreateChecks(IShare $share) {
218
+        if ($share->getShareType() === IShare::TYPE_USER) {
219
+            // We expect a valid user as sharedWith for user shares
220
+            if (!$this->userManager->userExists($share->getSharedWith())) {
221
+                throw new \InvalidArgumentException('SharedWith is not a valid user');
222
+            }
223
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
224
+            // We expect a valid group as sharedWith for group shares
225
+            if (!$this->groupManager->groupExists($share->getSharedWith())) {
226
+                throw new \InvalidArgumentException('SharedWith is not a valid group');
227
+            }
228
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
229
+            if ($share->getSharedWith() !== null) {
230
+                throw new \InvalidArgumentException('SharedWith should be empty');
231
+            }
232
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE) {
233
+            if ($share->getSharedWith() === null) {
234
+                throw new \InvalidArgumentException('SharedWith should not be empty');
235
+            }
236
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
237
+            if ($share->getSharedWith() === null) {
238
+                throw new \InvalidArgumentException('SharedWith should not be empty');
239
+            }
240
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
241
+            if ($share->getSharedWith() === null) {
242
+                throw new \InvalidArgumentException('SharedWith should not be empty');
243
+            }
244
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
245
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($share->getSharedWith());
246
+            if ($circle === null) {
247
+                throw new \InvalidArgumentException('SharedWith is not a valid circle');
248
+            }
249
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
250
+        } else {
251
+            // We can't handle other types yet
252
+            throw new \InvalidArgumentException('unknown share type');
253
+        }
254
+
255
+        // Verify the initiator of the share is set
256
+        if ($share->getSharedBy() === null) {
257
+            throw new \InvalidArgumentException('SharedBy should be set');
258
+        }
259
+
260
+        // Cannot share with yourself
261
+        if ($share->getShareType() === IShare::TYPE_USER &&
262
+            $share->getSharedWith() === $share->getSharedBy()) {
263
+            throw new \InvalidArgumentException('Can’t share with yourself');
264
+        }
265
+
266
+        // The path should be set
267
+        if ($share->getNode() === null) {
268
+            throw new \InvalidArgumentException('Path should be set');
269
+        }
270
+
271
+        // And it should be a file or a folder
272
+        if (!($share->getNode() instanceof \OCP\Files\File) &&
273
+                !($share->getNode() instanceof \OCP\Files\Folder)) {
274
+            throw new \InvalidArgumentException('Path should be either a file or a folder');
275
+        }
276
+
277
+        // And you can't share your rootfolder
278
+        if ($this->userManager->userExists($share->getSharedBy())) {
279
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
280
+        } else {
281
+            $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
282
+        }
283
+        if ($userFolder->getId() === $share->getNode()->getId()) {
284
+            throw new \InvalidArgumentException('You can’t share your root folder');
285
+        }
286
+
287
+        // Check if we actually have share permissions
288
+        if (!$share->getNode()->isShareable()) {
289
+            $path = $userFolder->getRelativePath($share->getNode()->getPath());
290
+            $message_t = $this->l->t('You are not allowed to share %s', [$path]);
291
+            throw new GenericShareException($message_t, $message_t, 404);
292
+        }
293
+
294
+        // Permissions should be set
295
+        if ($share->getPermissions() === null) {
296
+            throw new \InvalidArgumentException('A share requires permissions');
297
+        }
298
+
299
+        $isFederatedShare = $share->getNode()->getStorage()->instanceOfStorage('\OCA\Files_Sharing\External\Storage');
300
+        $permissions = 0;
301
+
302
+        $userMounts = $userFolder->getById($share->getNode()->getId());
303
+        $userMount = array_shift($userMounts);
304
+        $mount = $userMount->getMountPoint();
305
+        if (!$isFederatedShare && $share->getNode()->getOwner() && $share->getNode()->getOwner()->getUID() !== $share->getSharedBy()) {
306
+            // When it's a reshare use the parent share permissions as maximum
307
+            $userMountPointId = $mount->getStorageRootId();
308
+            $userMountPoints = $userFolder->getById($userMountPointId);
309
+            $userMountPoint = array_shift($userMountPoints);
310
+
311
+            if ($userMountPoint === null) {
312
+                throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
313
+            }
314
+
315
+            /* Check if this is an incoming share */
316
+            $incomingShares = $this->getSharedWith($share->getSharedBy(), IShare::TYPE_USER, $userMountPoint, -1, 0);
317
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_GROUP, $userMountPoint, -1, 0));
318
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_CIRCLE, $userMountPoint, -1, 0));
319
+            $incomingShares = array_merge($incomingShares, $this->getSharedWith($share->getSharedBy(), IShare::TYPE_ROOM, $userMountPoint, -1, 0));
320
+
321
+            /** @var IShare[] $incomingShares */
322
+            if (!empty($incomingShares)) {
323
+                foreach ($incomingShares as $incomingShare) {
324
+                    $permissions |= $incomingShare->getPermissions();
325
+                }
326
+            }
327
+        } else {
328
+            /*
329 329
 			 * Quick fix for #23536
330 330
 			 * Non moveable mount points do not have update and delete permissions
331 331
 			 * while we 'most likely' do have that on the storage.
332 332
 			 */
333
-			$permissions = $share->getNode()->getPermissions();
334
-			if (!($mount instanceof MoveableMount)) {
335
-				$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
336
-			}
337
-		}
338
-
339
-		// Check that we do not share with more permissions than we have
340
-		if ($share->getPermissions() & ~$permissions) {
341
-			$path = $userFolder->getRelativePath($share->getNode()->getPath());
342
-			$message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
343
-			throw new GenericShareException($message_t, $message_t, 404);
344
-		}
345
-
346
-
347
-		// Check that read permissions are always set
348
-		// Link shares are allowed to have no read permissions to allow upload to hidden folders
349
-		$noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
350
-			|| $share->getShareType() === IShare::TYPE_EMAIL;
351
-		if (!$noReadPermissionRequired &&
352
-			($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
353
-			throw new \InvalidArgumentException('Shares need at least read permissions');
354
-		}
355
-
356
-		if ($share->getNode() instanceof \OCP\Files\File) {
357
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
358
-				$message_t = $this->l->t('Files can’t be shared with delete permissions');
359
-				throw new GenericShareException($message_t);
360
-			}
361
-			if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
362
-				$message_t = $this->l->t('Files can’t be shared with create permissions');
363
-				throw new GenericShareException($message_t);
364
-			}
365
-		}
366
-	}
367
-
368
-	/**
369
-	 * Validate if the expiration date fits the system settings
370
-	 *
371
-	 * @param IShare $share The share to validate the expiration date of
372
-	 * @return IShare The modified share object
373
-	 * @throws GenericShareException
374
-	 * @throws \InvalidArgumentException
375
-	 * @throws \Exception
376
-	 */
377
-	protected function validateExpirationDateInternal(IShare $share) {
378
-		$expirationDate = $share->getExpirationDate();
379
-
380
-		if ($expirationDate !== null) {
381
-			//Make sure the expiration date is a date
382
-			$expirationDate->setTime(0, 0, 0);
383
-
384
-			$date = new \DateTime();
385
-			$date->setTime(0, 0, 0);
386
-			if ($date >= $expirationDate) {
387
-				$message = $this->l->t('Expiration date is in the past');
388
-				throw new GenericShareException($message, $message, 404);
389
-			}
390
-		}
391
-
392
-		// If expiredate is empty set a default one if there is a default
393
-		$fullId = null;
394
-		try {
395
-			$fullId = $share->getFullId();
396
-		} catch (\UnexpectedValueException $e) {
397
-			// This is a new share
398
-		}
399
-
400
-		if ($fullId === null && $expirationDate === null && $this->shareApiInternalDefaultExpireDate()) {
401
-			$expirationDate = new \DateTime();
402
-			$expirationDate->setTime(0,0,0);
403
-
404
-			$days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
405
-			if ($days > $this->shareApiLinkDefaultExpireDays()) {
406
-				$days = $this->shareApiLinkDefaultExpireDays();
407
-			}
408
-			$expirationDate->add(new \DateInterval('P'.$days.'D'));
409
-		}
410
-
411
-		// If we enforce the expiration date check that is does not exceed
412
-		if ($this->shareApiInternalDefaultExpireDateEnforced()) {
413
-			if ($expirationDate === null) {
414
-				throw new \InvalidArgumentException('Expiration date is enforced');
415
-			}
416
-
417
-			$date = new \DateTime();
418
-			$date->setTime(0, 0, 0);
419
-			$date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
420
-			if ($date < $expirationDate) {
421
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
422
-				throw new GenericShareException($message, $message, 404);
423
-			}
424
-		}
425
-
426
-		$accepted = true;
427
-		$message = '';
428
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
429
-			'expirationDate' => &$expirationDate,
430
-			'accepted' => &$accepted,
431
-			'message' => &$message,
432
-			'passwordSet' => $share->getPassword() !== null,
433
-		]);
434
-
435
-		if (!$accepted) {
436
-			throw new \Exception($message);
437
-		}
438
-
439
-		$share->setExpirationDate($expirationDate);
440
-
441
-		return $share;
442
-	}
443
-
444
-	/**
445
-	 * Validate if the expiration date fits the system settings
446
-	 *
447
-	 * @param IShare $share The share to validate the expiration date of
448
-	 * @return IShare The modified share object
449
-	 * @throws GenericShareException
450
-	 * @throws \InvalidArgumentException
451
-	 * @throws \Exception
452
-	 */
453
-	protected function validateExpirationDate(IShare $share) {
454
-		$expirationDate = $share->getExpirationDate();
455
-
456
-		if ($expirationDate !== null) {
457
-			//Make sure the expiration date is a date
458
-			$expirationDate->setTime(0, 0, 0);
459
-
460
-			$date = new \DateTime();
461
-			$date->setTime(0, 0, 0);
462
-			if ($date >= $expirationDate) {
463
-				$message = $this->l->t('Expiration date is in the past');
464
-				throw new GenericShareException($message, $message, 404);
465
-			}
466
-		}
467
-
468
-		// If expiredate is empty set a default one if there is a default
469
-		$fullId = null;
470
-		try {
471
-			$fullId = $share->getFullId();
472
-		} catch (\UnexpectedValueException $e) {
473
-			// This is a new share
474
-		}
475
-
476
-		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
477
-			$expirationDate = new \DateTime();
478
-			$expirationDate->setTime(0,0,0);
479
-
480
-			$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
481
-			if ($days > $this->shareApiLinkDefaultExpireDays()) {
482
-				$days = $this->shareApiLinkDefaultExpireDays();
483
-			}
484
-			$expirationDate->add(new \DateInterval('P'.$days.'D'));
485
-		}
486
-
487
-		// If we enforce the expiration date check that is does not exceed
488
-		if ($this->shareApiLinkDefaultExpireDateEnforced()) {
489
-			if ($expirationDate === null) {
490
-				throw new \InvalidArgumentException('Expiration date is enforced');
491
-			}
492
-
493
-			$date = new \DateTime();
494
-			$date->setTime(0, 0, 0);
495
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
496
-			if ($date < $expirationDate) {
497
-				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
498
-				throw new GenericShareException($message, $message, 404);
499
-			}
500
-		}
501
-
502
-		$accepted = true;
503
-		$message = '';
504
-		\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
505
-			'expirationDate' => &$expirationDate,
506
-			'accepted' => &$accepted,
507
-			'message' => &$message,
508
-			'passwordSet' => $share->getPassword() !== null,
509
-		]);
510
-
511
-		if (!$accepted) {
512
-			throw new \Exception($message);
513
-		}
514
-
515
-		$share->setExpirationDate($expirationDate);
516
-
517
-		return $share;
518
-	}
519
-
520
-	/**
521
-	 * Check for pre share requirements for user shares
522
-	 *
523
-	 * @param IShare $share
524
-	 * @throws \Exception
525
-	 */
526
-	protected function userCreateChecks(IShare $share) {
527
-		// Check if we can share with group members only
528
-		if ($this->shareWithGroupMembersOnly()) {
529
-			$sharedBy = $this->userManager->get($share->getSharedBy());
530
-			$sharedWith = $this->userManager->get($share->getSharedWith());
531
-			// Verify we can share with this user
532
-			$groups = array_intersect(
533
-					$this->groupManager->getUserGroupIds($sharedBy),
534
-					$this->groupManager->getUserGroupIds($sharedWith)
535
-			);
536
-			if (empty($groups)) {
537
-				throw new \Exception('Sharing is only allowed with group members');
538
-			}
539
-		}
540
-
541
-		/*
333
+            $permissions = $share->getNode()->getPermissions();
334
+            if (!($mount instanceof MoveableMount)) {
335
+                $permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
336
+            }
337
+        }
338
+
339
+        // Check that we do not share with more permissions than we have
340
+        if ($share->getPermissions() & ~$permissions) {
341
+            $path = $userFolder->getRelativePath($share->getNode()->getPath());
342
+            $message_t = $this->l->t('Can’t increase permissions of %s', [$path]);
343
+            throw new GenericShareException($message_t, $message_t, 404);
344
+        }
345
+
346
+
347
+        // Check that read permissions are always set
348
+        // Link shares are allowed to have no read permissions to allow upload to hidden folders
349
+        $noReadPermissionRequired = $share->getShareType() === IShare::TYPE_LINK
350
+            || $share->getShareType() === IShare::TYPE_EMAIL;
351
+        if (!$noReadPermissionRequired &&
352
+            ($share->getPermissions() & \OCP\Constants::PERMISSION_READ) === 0) {
353
+            throw new \InvalidArgumentException('Shares need at least read permissions');
354
+        }
355
+
356
+        if ($share->getNode() instanceof \OCP\Files\File) {
357
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
358
+                $message_t = $this->l->t('Files can’t be shared with delete permissions');
359
+                throw new GenericShareException($message_t);
360
+            }
361
+            if ($share->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
362
+                $message_t = $this->l->t('Files can’t be shared with create permissions');
363
+                throw new GenericShareException($message_t);
364
+            }
365
+        }
366
+    }
367
+
368
+    /**
369
+     * Validate if the expiration date fits the system settings
370
+     *
371
+     * @param IShare $share The share to validate the expiration date of
372
+     * @return IShare The modified share object
373
+     * @throws GenericShareException
374
+     * @throws \InvalidArgumentException
375
+     * @throws \Exception
376
+     */
377
+    protected function validateExpirationDateInternal(IShare $share) {
378
+        $expirationDate = $share->getExpirationDate();
379
+
380
+        if ($expirationDate !== null) {
381
+            //Make sure the expiration date is a date
382
+            $expirationDate->setTime(0, 0, 0);
383
+
384
+            $date = new \DateTime();
385
+            $date->setTime(0, 0, 0);
386
+            if ($date >= $expirationDate) {
387
+                $message = $this->l->t('Expiration date is in the past');
388
+                throw new GenericShareException($message, $message, 404);
389
+            }
390
+        }
391
+
392
+        // If expiredate is empty set a default one if there is a default
393
+        $fullId = null;
394
+        try {
395
+            $fullId = $share->getFullId();
396
+        } catch (\UnexpectedValueException $e) {
397
+            // This is a new share
398
+        }
399
+
400
+        if ($fullId === null && $expirationDate === null && $this->shareApiInternalDefaultExpireDate()) {
401
+            $expirationDate = new \DateTime();
402
+            $expirationDate->setTime(0,0,0);
403
+
404
+            $days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
405
+            if ($days > $this->shareApiLinkDefaultExpireDays()) {
406
+                $days = $this->shareApiLinkDefaultExpireDays();
407
+            }
408
+            $expirationDate->add(new \DateInterval('P'.$days.'D'));
409
+        }
410
+
411
+        // If we enforce the expiration date check that is does not exceed
412
+        if ($this->shareApiInternalDefaultExpireDateEnforced()) {
413
+            if ($expirationDate === null) {
414
+                throw new \InvalidArgumentException('Expiration date is enforced');
415
+            }
416
+
417
+            $date = new \DateTime();
418
+            $date->setTime(0, 0, 0);
419
+            $date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
420
+            if ($date < $expirationDate) {
421
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
422
+                throw new GenericShareException($message, $message, 404);
423
+            }
424
+        }
425
+
426
+        $accepted = true;
427
+        $message = '';
428
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
429
+            'expirationDate' => &$expirationDate,
430
+            'accepted' => &$accepted,
431
+            'message' => &$message,
432
+            'passwordSet' => $share->getPassword() !== null,
433
+        ]);
434
+
435
+        if (!$accepted) {
436
+            throw new \Exception($message);
437
+        }
438
+
439
+        $share->setExpirationDate($expirationDate);
440
+
441
+        return $share;
442
+    }
443
+
444
+    /**
445
+     * Validate if the expiration date fits the system settings
446
+     *
447
+     * @param IShare $share The share to validate the expiration date of
448
+     * @return IShare The modified share object
449
+     * @throws GenericShareException
450
+     * @throws \InvalidArgumentException
451
+     * @throws \Exception
452
+     */
453
+    protected function validateExpirationDate(IShare $share) {
454
+        $expirationDate = $share->getExpirationDate();
455
+
456
+        if ($expirationDate !== null) {
457
+            //Make sure the expiration date is a date
458
+            $expirationDate->setTime(0, 0, 0);
459
+
460
+            $date = new \DateTime();
461
+            $date->setTime(0, 0, 0);
462
+            if ($date >= $expirationDate) {
463
+                $message = $this->l->t('Expiration date is in the past');
464
+                throw new GenericShareException($message, $message, 404);
465
+            }
466
+        }
467
+
468
+        // If expiredate is empty set a default one if there is a default
469
+        $fullId = null;
470
+        try {
471
+            $fullId = $share->getFullId();
472
+        } catch (\UnexpectedValueException $e) {
473
+            // This is a new share
474
+        }
475
+
476
+        if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
477
+            $expirationDate = new \DateTime();
478
+            $expirationDate->setTime(0,0,0);
479
+
480
+            $days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
481
+            if ($days > $this->shareApiLinkDefaultExpireDays()) {
482
+                $days = $this->shareApiLinkDefaultExpireDays();
483
+            }
484
+            $expirationDate->add(new \DateInterval('P'.$days.'D'));
485
+        }
486
+
487
+        // If we enforce the expiration date check that is does not exceed
488
+        if ($this->shareApiLinkDefaultExpireDateEnforced()) {
489
+            if ($expirationDate === null) {
490
+                throw new \InvalidArgumentException('Expiration date is enforced');
491
+            }
492
+
493
+            $date = new \DateTime();
494
+            $date->setTime(0, 0, 0);
495
+            $date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
496
+            if ($date < $expirationDate) {
497
+                $message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
498
+                throw new GenericShareException($message, $message, 404);
499
+            }
500
+        }
501
+
502
+        $accepted = true;
503
+        $message = '';
504
+        \OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
505
+            'expirationDate' => &$expirationDate,
506
+            'accepted' => &$accepted,
507
+            'message' => &$message,
508
+            'passwordSet' => $share->getPassword() !== null,
509
+        ]);
510
+
511
+        if (!$accepted) {
512
+            throw new \Exception($message);
513
+        }
514
+
515
+        $share->setExpirationDate($expirationDate);
516
+
517
+        return $share;
518
+    }
519
+
520
+    /**
521
+     * Check for pre share requirements for user shares
522
+     *
523
+     * @param IShare $share
524
+     * @throws \Exception
525
+     */
526
+    protected function userCreateChecks(IShare $share) {
527
+        // Check if we can share with group members only
528
+        if ($this->shareWithGroupMembersOnly()) {
529
+            $sharedBy = $this->userManager->get($share->getSharedBy());
530
+            $sharedWith = $this->userManager->get($share->getSharedWith());
531
+            // Verify we can share with this user
532
+            $groups = array_intersect(
533
+                    $this->groupManager->getUserGroupIds($sharedBy),
534
+                    $this->groupManager->getUserGroupIds($sharedWith)
535
+            );
536
+            if (empty($groups)) {
537
+                throw new \Exception('Sharing is only allowed with group members');
538
+            }
539
+        }
540
+
541
+        /*
542 542
 		 * TODO: Could be costly, fix
543 543
 		 *
544 544
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
545 545
 		 */
546
-		$provider = $this->factory->getProviderForType(IShare::TYPE_USER);
547
-		$existingShares = $provider->getSharesByPath($share->getNode());
548
-		foreach ($existingShares as $existingShare) {
549
-			// Ignore if it is the same share
550
-			try {
551
-				if ($existingShare->getFullId() === $share->getFullId()) {
552
-					continue;
553
-				}
554
-			} catch (\UnexpectedValueException $e) {
555
-				//Shares are not identical
556
-			}
557
-
558
-			// Identical share already existst
559
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
560
-				throw new \Exception('Path is already shared with this user');
561
-			}
562
-
563
-			// The share is already shared with this user via a group share
564
-			if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
565
-				$group = $this->groupManager->get($existingShare->getSharedWith());
566
-				if (!is_null($group)) {
567
-					$user = $this->userManager->get($share->getSharedWith());
568
-
569
-					if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
570
-						throw new \Exception('Path is already shared with this user');
571
-					}
572
-				}
573
-			}
574
-		}
575
-	}
576
-
577
-	/**
578
-	 * Check for pre share requirements for group shares
579
-	 *
580
-	 * @param IShare $share
581
-	 * @throws \Exception
582
-	 */
583
-	protected function groupCreateChecks(IShare $share) {
584
-		// Verify group shares are allowed
585
-		if (!$this->allowGroupSharing()) {
586
-			throw new \Exception('Group sharing is now allowed');
587
-		}
588
-
589
-		// Verify if the user can share with this group
590
-		if ($this->shareWithGroupMembersOnly()) {
591
-			$sharedBy = $this->userManager->get($share->getSharedBy());
592
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
593
-			if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
594
-				throw new \Exception('Sharing is only allowed within your own groups');
595
-			}
596
-		}
597
-
598
-		/*
546
+        $provider = $this->factory->getProviderForType(IShare::TYPE_USER);
547
+        $existingShares = $provider->getSharesByPath($share->getNode());
548
+        foreach ($existingShares as $existingShare) {
549
+            // Ignore if it is the same share
550
+            try {
551
+                if ($existingShare->getFullId() === $share->getFullId()) {
552
+                    continue;
553
+                }
554
+            } catch (\UnexpectedValueException $e) {
555
+                //Shares are not identical
556
+            }
557
+
558
+            // Identical share already existst
559
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
560
+                throw new \Exception('Path is already shared with this user');
561
+            }
562
+
563
+            // The share is already shared with this user via a group share
564
+            if ($existingShare->getShareType() === IShare::TYPE_GROUP) {
565
+                $group = $this->groupManager->get($existingShare->getSharedWith());
566
+                if (!is_null($group)) {
567
+                    $user = $this->userManager->get($share->getSharedWith());
568
+
569
+                    if ($group->inGroup($user) && $existingShare->getShareOwner() !== $share->getShareOwner()) {
570
+                        throw new \Exception('Path is already shared with this user');
571
+                    }
572
+                }
573
+            }
574
+        }
575
+    }
576
+
577
+    /**
578
+     * Check for pre share requirements for group shares
579
+     *
580
+     * @param IShare $share
581
+     * @throws \Exception
582
+     */
583
+    protected function groupCreateChecks(IShare $share) {
584
+        // Verify group shares are allowed
585
+        if (!$this->allowGroupSharing()) {
586
+            throw new \Exception('Group sharing is now allowed');
587
+        }
588
+
589
+        // Verify if the user can share with this group
590
+        if ($this->shareWithGroupMembersOnly()) {
591
+            $sharedBy = $this->userManager->get($share->getSharedBy());
592
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
593
+            if (is_null($sharedWith) || !$sharedWith->inGroup($sharedBy)) {
594
+                throw new \Exception('Sharing is only allowed within your own groups');
595
+            }
596
+        }
597
+
598
+        /*
599 599
 		 * TODO: Could be costly, fix
600 600
 		 *
601 601
 		 * Also this is not what we want in the future.. then we want to squash identical shares.
602 602
 		 */
603
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
604
-		$existingShares = $provider->getSharesByPath($share->getNode());
605
-		foreach ($existingShares as $existingShare) {
606
-			try {
607
-				if ($existingShare->getFullId() === $share->getFullId()) {
608
-					continue;
609
-				}
610
-			} catch (\UnexpectedValueException $e) {
611
-				//It is a new share so just continue
612
-			}
613
-
614
-			if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
615
-				throw new \Exception('Path is already shared with this group');
616
-			}
617
-		}
618
-	}
619
-
620
-	/**
621
-	 * Check for pre share requirements for link shares
622
-	 *
623
-	 * @param IShare $share
624
-	 * @throws \Exception
625
-	 */
626
-	protected function linkCreateChecks(IShare $share) {
627
-		// Are link shares allowed?
628
-		if (!$this->shareApiAllowLinks()) {
629
-			throw new \Exception('Link sharing is not allowed');
630
-		}
631
-
632
-		// Check if public upload is allowed
633
-		if (!$this->shareApiLinkAllowPublicUpload() &&
634
-			($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
635
-			throw new \InvalidArgumentException('Public upload is not allowed');
636
-		}
637
-	}
638
-
639
-	/**
640
-	 * To make sure we don't get invisible link shares we set the parent
641
-	 * of a link if it is a reshare. This is a quick word around
642
-	 * until we can properly display multiple link shares in the UI
643
-	 *
644
-	 * See: https://github.com/owncloud/core/issues/22295
645
-	 *
646
-	 * FIXME: Remove once multiple link shares can be properly displayed
647
-	 *
648
-	 * @param IShare $share
649
-	 */
650
-	protected function setLinkParent(IShare $share) {
651
-
652
-		// No sense in checking if the method is not there.
653
-		if (method_exists($share, 'setParent')) {
654
-			$storage = $share->getNode()->getStorage();
655
-			if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
656
-				/** @var \OCA\Files_Sharing\SharedStorage $storage */
657
-				$share->setParent($storage->getShareId());
658
-			}
659
-		}
660
-	}
661
-
662
-	/**
663
-	 * @param File|Folder $path
664
-	 */
665
-	protected function pathCreateChecks($path) {
666
-		// Make sure that we do not share a path that contains a shared mountpoint
667
-		if ($path instanceof \OCP\Files\Folder) {
668
-			$mounts = $this->mountManager->findIn($path->getPath());
669
-			foreach ($mounts as $mount) {
670
-				if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
671
-					throw new \InvalidArgumentException('Path contains files shared with you');
672
-				}
673
-			}
674
-		}
675
-	}
676
-
677
-	/**
678
-	 * Check if the user that is sharing can actually share
679
-	 *
680
-	 * @param IShare $share
681
-	 * @throws \Exception
682
-	 */
683
-	protected function canShare(IShare $share) {
684
-		if (!$this->shareApiEnabled()) {
685
-			throw new \Exception('Sharing is disabled');
686
-		}
687
-
688
-		if ($this->sharingDisabledForUser($share->getSharedBy())) {
689
-			throw new \Exception('Sharing is disabled for you');
690
-		}
691
-	}
692
-
693
-	/**
694
-	 * Share a path
695
-	 *
696
-	 * @param IShare $share
697
-	 * @return IShare The share object
698
-	 * @throws \Exception
699
-	 *
700
-	 * TODO: handle link share permissions or check them
701
-	 */
702
-	public function createShare(IShare $share) {
703
-		$this->canShare($share);
704
-
705
-		$this->generalCreateChecks($share);
706
-
707
-		// Verify if there are any issues with the path
708
-		$this->pathCreateChecks($share->getNode());
709
-
710
-		/*
603
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
604
+        $existingShares = $provider->getSharesByPath($share->getNode());
605
+        foreach ($existingShares as $existingShare) {
606
+            try {
607
+                if ($existingShare->getFullId() === $share->getFullId()) {
608
+                    continue;
609
+                }
610
+            } catch (\UnexpectedValueException $e) {
611
+                //It is a new share so just continue
612
+            }
613
+
614
+            if ($existingShare->getSharedWith() === $share->getSharedWith() && $existingShare->getShareType() === $share->getShareType()) {
615
+                throw new \Exception('Path is already shared with this group');
616
+            }
617
+        }
618
+    }
619
+
620
+    /**
621
+     * Check for pre share requirements for link shares
622
+     *
623
+     * @param IShare $share
624
+     * @throws \Exception
625
+     */
626
+    protected function linkCreateChecks(IShare $share) {
627
+        // Are link shares allowed?
628
+        if (!$this->shareApiAllowLinks()) {
629
+            throw new \Exception('Link sharing is not allowed');
630
+        }
631
+
632
+        // Check if public upload is allowed
633
+        if (!$this->shareApiLinkAllowPublicUpload() &&
634
+            ($share->getPermissions() & (\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE))) {
635
+            throw new \InvalidArgumentException('Public upload is not allowed');
636
+        }
637
+    }
638
+
639
+    /**
640
+     * To make sure we don't get invisible link shares we set the parent
641
+     * of a link if it is a reshare. This is a quick word around
642
+     * until we can properly display multiple link shares in the UI
643
+     *
644
+     * See: https://github.com/owncloud/core/issues/22295
645
+     *
646
+     * FIXME: Remove once multiple link shares can be properly displayed
647
+     *
648
+     * @param IShare $share
649
+     */
650
+    protected function setLinkParent(IShare $share) {
651
+
652
+        // No sense in checking if the method is not there.
653
+        if (method_exists($share, 'setParent')) {
654
+            $storage = $share->getNode()->getStorage();
655
+            if ($storage->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
656
+                /** @var \OCA\Files_Sharing\SharedStorage $storage */
657
+                $share->setParent($storage->getShareId());
658
+            }
659
+        }
660
+    }
661
+
662
+    /**
663
+     * @param File|Folder $path
664
+     */
665
+    protected function pathCreateChecks($path) {
666
+        // Make sure that we do not share a path that contains a shared mountpoint
667
+        if ($path instanceof \OCP\Files\Folder) {
668
+            $mounts = $this->mountManager->findIn($path->getPath());
669
+            foreach ($mounts as $mount) {
670
+                if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
671
+                    throw new \InvalidArgumentException('Path contains files shared with you');
672
+                }
673
+            }
674
+        }
675
+    }
676
+
677
+    /**
678
+     * Check if the user that is sharing can actually share
679
+     *
680
+     * @param IShare $share
681
+     * @throws \Exception
682
+     */
683
+    protected function canShare(IShare $share) {
684
+        if (!$this->shareApiEnabled()) {
685
+            throw new \Exception('Sharing is disabled');
686
+        }
687
+
688
+        if ($this->sharingDisabledForUser($share->getSharedBy())) {
689
+            throw new \Exception('Sharing is disabled for you');
690
+        }
691
+    }
692
+
693
+    /**
694
+     * Share a path
695
+     *
696
+     * @param IShare $share
697
+     * @return IShare The share object
698
+     * @throws \Exception
699
+     *
700
+     * TODO: handle link share permissions or check them
701
+     */
702
+    public function createShare(IShare $share) {
703
+        $this->canShare($share);
704
+
705
+        $this->generalCreateChecks($share);
706
+
707
+        // Verify if there are any issues with the path
708
+        $this->pathCreateChecks($share->getNode());
709
+
710
+        /*
711 711
 		 * On creation of a share the owner is always the owner of the path
712 712
 		 * Except for mounted federated shares.
713 713
 		 */
714
-		$storage = $share->getNode()->getStorage();
715
-		if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
716
-			$parent = $share->getNode()->getParent();
717
-			while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
718
-				$parent = $parent->getParent();
719
-			}
720
-			$share->setShareOwner($parent->getOwner()->getUID());
721
-		} else {
722
-			if ($share->getNode()->getOwner()) {
723
-				$share->setShareOwner($share->getNode()->getOwner()->getUID());
724
-			} else {
725
-				$share->setShareOwner($share->getSharedBy());
726
-			}
727
-		}
728
-
729
-		//Verify share type
730
-		if ($share->getShareType() === IShare::TYPE_USER) {
731
-			$this->userCreateChecks($share);
732
-
733
-			//Verify the expiration date
734
-			$share = $this->validateExpirationDateInternal($share);
735
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
736
-			$this->groupCreateChecks($share);
737
-
738
-			//Verify the expiration date
739
-			$share = $this->validateExpirationDateInternal($share);
740
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
741
-			$this->linkCreateChecks($share);
742
-			$this->setLinkParent($share);
743
-
744
-			/*
714
+        $storage = $share->getNode()->getStorage();
715
+        if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
716
+            $parent = $share->getNode()->getParent();
717
+            while ($parent->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
718
+                $parent = $parent->getParent();
719
+            }
720
+            $share->setShareOwner($parent->getOwner()->getUID());
721
+        } else {
722
+            if ($share->getNode()->getOwner()) {
723
+                $share->setShareOwner($share->getNode()->getOwner()->getUID());
724
+            } else {
725
+                $share->setShareOwner($share->getSharedBy());
726
+            }
727
+        }
728
+
729
+        //Verify share type
730
+        if ($share->getShareType() === IShare::TYPE_USER) {
731
+            $this->userCreateChecks($share);
732
+
733
+            //Verify the expiration date
734
+            $share = $this->validateExpirationDateInternal($share);
735
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
736
+            $this->groupCreateChecks($share);
737
+
738
+            //Verify the expiration date
739
+            $share = $this->validateExpirationDateInternal($share);
740
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
741
+            $this->linkCreateChecks($share);
742
+            $this->setLinkParent($share);
743
+
744
+            /*
745 745
 			 * For now ignore a set token.
746 746
 			 */
747
-			$share->setToken(
748
-				$this->secureRandom->generate(
749
-					\OC\Share\Constants::TOKEN_LENGTH,
750
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
751
-				)
752
-			);
753
-
754
-			//Verify the expiration date
755
-			$share = $this->validateExpirationDate($share);
756
-
757
-			//Verify the password
758
-			$this->verifyPassword($share->getPassword());
759
-
760
-			// If a password is set. Hash it!
761
-			if ($share->getPassword() !== null) {
762
-				$share->setPassword($this->hasher->hash($share->getPassword()));
763
-			}
764
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
765
-			$share->setToken(
766
-				$this->secureRandom->generate(
767
-					\OC\Share\Constants::TOKEN_LENGTH,
768
-					\OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
769
-				)
770
-			);
771
-		}
772
-
773
-		// Cannot share with the owner
774
-		if ($share->getShareType() === IShare::TYPE_USER &&
775
-			$share->getSharedWith() === $share->getShareOwner()) {
776
-			throw new \InvalidArgumentException('Can’t share with the share owner');
777
-		}
778
-
779
-		// Generate the target
780
-		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
781
-		$target = \OC\Files\Filesystem::normalizePath($target);
782
-		$share->setTarget($target);
783
-
784
-		// Pre share event
785
-		$event = new GenericEvent($share);
786
-		$this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
787
-		if ($event->isPropagationStopped() && $event->hasArgument('error')) {
788
-			throw new \Exception($event->getArgument('error'));
789
-		}
790
-
791
-		$oldShare = $share;
792
-		$provider = $this->factory->getProviderForType($share->getShareType());
793
-		$share = $provider->create($share);
794
-		//reuse the node we already have
795
-		$share->setNode($oldShare->getNode());
796
-
797
-		// Reset the target if it is null for the new share
798
-		if ($share->getTarget() === '') {
799
-			$share->setTarget($target);
800
-		}
801
-
802
-		// Post share event
803
-		$event = new GenericEvent($share);
804
-		$this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
805
-
806
-		$this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
807
-
808
-		if ($share->getShareType() === IShare::TYPE_USER) {
809
-			$mailSend = $share->getMailSend();
810
-			if ($mailSend === true) {
811
-				$user = $this->userManager->get($share->getSharedWith());
812
-				if ($user !== null) {
813
-					$emailAddress = $user->getEMailAddress();
814
-					if ($emailAddress !== null && $emailAddress !== '') {
815
-						$userLang = $this->l10nFactory->getUserLanguage($user);
816
-						$l = $this->l10nFactory->get('lib', $userLang);
817
-						$this->sendMailNotification(
818
-							$l,
819
-							$share->getNode()->getName(),
820
-							$this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
821
-							$share->getSharedBy(),
822
-							$emailAddress,
823
-							$share->getExpirationDate()
824
-						);
825
-						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
826
-					} else {
827
-						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
828
-					}
829
-				} else {
830
-					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
831
-				}
832
-			} else {
833
-				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
834
-			}
835
-		}
836
-
837
-		return $share;
838
-	}
839
-
840
-	/**
841
-	 * Send mail notifications
842
-	 *
843
-	 * This method will catch and log mail transmission errors
844
-	 *
845
-	 * @param IL10N $l Language of the recipient
846
-	 * @param string $filename file/folder name
847
-	 * @param string $link link to the file/folder
848
-	 * @param string $initiator user ID of share sender
849
-	 * @param string $shareWith email address of share receiver
850
-	 * @param \DateTime|null $expiration
851
-	 */
852
-	protected function sendMailNotification(IL10N $l,
853
-											$filename,
854
-											$link,
855
-											$initiator,
856
-											$shareWith,
857
-											\DateTime $expiration = null) {
858
-		$initiatorUser = $this->userManager->get($initiator);
859
-		$initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
860
-
861
-		$message = $this->mailer->createMessage();
862
-
863
-		$emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
864
-			'filename' => $filename,
865
-			'link' => $link,
866
-			'initiator' => $initiatorDisplayName,
867
-			'expiration' => $expiration,
868
-			'shareWith' => $shareWith,
869
-		]);
870
-
871
-		$emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
872
-		$emailTemplate->addHeader();
873
-		$emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
874
-		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
875
-
876
-		$emailTemplate->addBodyText(
877
-			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
878
-			$text
879
-		);
880
-		$emailTemplate->addBodyButton(
881
-			$l->t('Open »%s«', [$filename]),
882
-			$link
883
-		);
884
-
885
-		$message->setTo([$shareWith]);
886
-
887
-		// The "From" contains the sharers name
888
-		$instanceName = $this->defaults->getName();
889
-		$senderName = $l->t(
890
-			'%1$s via %2$s',
891
-			[
892
-				$initiatorDisplayName,
893
-				$instanceName
894
-			]
895
-		);
896
-		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
897
-
898
-		// The "Reply-To" is set to the sharer if an mail address is configured
899
-		// also the default footer contains a "Do not reply" which needs to be adjusted.
900
-		$initiatorEmail = $initiatorUser->getEMailAddress();
901
-		if ($initiatorEmail !== null) {
902
-			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
903
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
904
-		} else {
905
-			$emailTemplate->addFooter('', $l->getLanguageCode());
906
-		}
907
-
908
-		$message->useTemplate($emailTemplate);
909
-		try {
910
-			$failedRecipients = $this->mailer->send($message);
911
-			if (!empty($failedRecipients)) {
912
-				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
913
-				return;
914
-			}
915
-		} catch (\Exception $e) {
916
-			$this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
917
-		}
918
-	}
919
-
920
-	/**
921
-	 * Update a share
922
-	 *
923
-	 * @param IShare $share
924
-	 * @return IShare The share object
925
-	 * @throws \InvalidArgumentException
926
-	 */
927
-	public function updateShare(IShare $share) {
928
-		$expirationDateUpdated = false;
929
-
930
-		$this->canShare($share);
931
-
932
-		try {
933
-			$originalShare = $this->getShareById($share->getFullId());
934
-		} catch (\UnexpectedValueException $e) {
935
-			throw new \InvalidArgumentException('Share does not have a full id');
936
-		}
937
-
938
-		// We can't change the share type!
939
-		if ($share->getShareType() !== $originalShare->getShareType()) {
940
-			throw new \InvalidArgumentException('Can’t change share type');
941
-		}
942
-
943
-		// We can only change the recipient on user shares
944
-		if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
945
-			$share->getShareType() !== IShare::TYPE_USER) {
946
-			throw new \InvalidArgumentException('Can only update recipient on user shares');
947
-		}
948
-
949
-		// Cannot share with the owner
950
-		if ($share->getShareType() === IShare::TYPE_USER &&
951
-			$share->getSharedWith() === $share->getShareOwner()) {
952
-			throw new \InvalidArgumentException('Can’t share with the share owner');
953
-		}
954
-
955
-		$this->generalCreateChecks($share);
956
-
957
-		if ($share->getShareType() === IShare::TYPE_USER) {
958
-			$this->userCreateChecks($share);
959
-
960
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
961
-				//Verify the expiration date
962
-				$this->validateExpirationDate($share);
963
-				$expirationDateUpdated = true;
964
-			}
965
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
966
-			$this->groupCreateChecks($share);
967
-
968
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
969
-				//Verify the expiration date
970
-				$this->validateExpirationDate($share);
971
-				$expirationDateUpdated = true;
972
-			}
973
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
974
-			$this->linkCreateChecks($share);
975
-
976
-			$plainTextPassword = $share->getPassword();
977
-
978
-			$this->updateSharePasswordIfNeeded($share, $originalShare);
979
-
980
-			if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
981
-				throw new \InvalidArgumentException('Can’t enable sending the password by Talk with an empty password');
982
-			}
983
-
984
-			if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
985
-				//Verify the expiration date
986
-				$this->validateExpirationDate($share);
987
-				$expirationDateUpdated = true;
988
-			}
989
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
990
-			// The new password is not set again if it is the same as the old
991
-			// one.
992
-			$plainTextPassword = $share->getPassword();
993
-			if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare)) {
994
-				$plainTextPassword = null;
995
-			}
996
-			if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
997
-				// If the same password was already sent by mail the recipient
998
-				// would already have access to the share without having to call
999
-				// the sharer to verify her identity
1000
-				throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
1001
-			} elseif (empty($plainTextPassword) && $originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1002
-				throw new \InvalidArgumentException('Can’t disable sending the password by Talk without setting a new password');
1003
-			}
1004
-		}
1005
-
1006
-		$this->pathCreateChecks($share->getNode());
1007
-
1008
-		// Now update the share!
1009
-		$provider = $this->factory->getProviderForType($share->getShareType());
1010
-		if ($share->getShareType() === IShare::TYPE_EMAIL) {
1011
-			$share = $provider->update($share, $plainTextPassword);
1012
-		} else {
1013
-			$share = $provider->update($share);
1014
-		}
1015
-
1016
-		if ($expirationDateUpdated === true) {
1017
-			\OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1018
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1019
-				'itemSource' => $share->getNode()->getId(),
1020
-				'date' => $share->getExpirationDate(),
1021
-				'uidOwner' => $share->getSharedBy(),
1022
-			]);
1023
-		}
1024
-
1025
-		if ($share->getPassword() !== $originalShare->getPassword()) {
1026
-			\OC_Hook::emit(Share::class, 'post_update_password', [
1027
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1028
-				'itemSource' => $share->getNode()->getId(),
1029
-				'uidOwner' => $share->getSharedBy(),
1030
-				'token' => $share->getToken(),
1031
-				'disabled' => is_null($share->getPassword()),
1032
-			]);
1033
-		}
1034
-
1035
-		if ($share->getPermissions() !== $originalShare->getPermissions()) {
1036
-			if ($this->userManager->userExists($share->getShareOwner())) {
1037
-				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1038
-			} else {
1039
-				$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1040
-			}
1041
-			\OC_Hook::emit(Share::class, 'post_update_permissions', [
1042
-				'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1043
-				'itemSource' => $share->getNode()->getId(),
1044
-				'shareType' => $share->getShareType(),
1045
-				'shareWith' => $share->getSharedWith(),
1046
-				'uidOwner' => $share->getSharedBy(),
1047
-				'permissions' => $share->getPermissions(),
1048
-				'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1049
-			]);
1050
-		}
1051
-
1052
-		return $share;
1053
-	}
1054
-
1055
-	/**
1056
-	 * Accept a share.
1057
-	 *
1058
-	 * @param IShare $share
1059
-	 * @param string $recipientId
1060
-	 * @return IShare The share object
1061
-	 * @throws \InvalidArgumentException
1062
-	 * @since 9.0.0
1063
-	 */
1064
-	public function acceptShare(IShare $share, string $recipientId): IShare {
1065
-		[$providerId, ] = $this->splitFullId($share->getFullId());
1066
-		$provider = $this->factory->getProvider($providerId);
1067
-
1068
-		if (!method_exists($provider, 'acceptShare')) {
1069
-			// TODO FIX ME
1070
-			throw new \InvalidArgumentException('Share provider does not support accepting');
1071
-		}
1072
-		$provider->acceptShare($share, $recipientId);
1073
-		$event = new GenericEvent($share);
1074
-		$this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1075
-
1076
-		return $share;
1077
-	}
1078
-
1079
-	/**
1080
-	 * Updates the password of the given share if it is not the same as the
1081
-	 * password of the original share.
1082
-	 *
1083
-	 * @param IShare $share the share to update its password.
1084
-	 * @param IShare $originalShare the original share to compare its
1085
-	 *        password with.
1086
-	 * @return boolean whether the password was updated or not.
1087
-	 */
1088
-	private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1089
-		$passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1090
-									(($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1091
-									 ($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1092
-									 ($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1093
-										!$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1094
-
1095
-		// Password updated.
1096
-		if ($passwordsAreDifferent) {
1097
-			//Verify the password
1098
-			$this->verifyPassword($share->getPassword());
1099
-
1100
-			// If a password is set. Hash it!
1101
-			if ($share->getPassword() !== null) {
1102
-				$share->setPassword($this->hasher->hash($share->getPassword()));
1103
-
1104
-				return true;
1105
-			}
1106
-		} else {
1107
-			// Reset the password to the original one, as it is either the same
1108
-			// as the "new" password or a hashed version of it.
1109
-			$share->setPassword($originalShare->getPassword());
1110
-		}
1111
-
1112
-		return false;
1113
-	}
1114
-
1115
-	/**
1116
-	 * Delete all the children of this share
1117
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1118
-	 *
1119
-	 * @param IShare $share
1120
-	 * @return IShare[] List of deleted shares
1121
-	 */
1122
-	protected function deleteChildren(IShare $share) {
1123
-		$deletedShares = [];
1124
-
1125
-		$provider = $this->factory->getProviderForType($share->getShareType());
1126
-
1127
-		foreach ($provider->getChildren($share) as $child) {
1128
-			$deletedChildren = $this->deleteChildren($child);
1129
-			$deletedShares = array_merge($deletedShares, $deletedChildren);
1130
-
1131
-			$provider->delete($child);
1132
-			$deletedShares[] = $child;
1133
-		}
1134
-
1135
-		return $deletedShares;
1136
-	}
1137
-
1138
-	/**
1139
-	 * Delete a share
1140
-	 *
1141
-	 * @param IShare $share
1142
-	 * @throws ShareNotFound
1143
-	 * @throws \InvalidArgumentException
1144
-	 */
1145
-	public function deleteShare(IShare $share) {
1146
-		try {
1147
-			$share->getFullId();
1148
-		} catch (\UnexpectedValueException $e) {
1149
-			throw new \InvalidArgumentException('Share does not have a full id');
1150
-		}
1151
-
1152
-		$event = new GenericEvent($share);
1153
-		$this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1154
-
1155
-		// Get all children and delete them as well
1156
-		$deletedShares = $this->deleteChildren($share);
1157
-
1158
-		// Do the actual delete
1159
-		$provider = $this->factory->getProviderForType($share->getShareType());
1160
-		$provider->delete($share);
1161
-
1162
-		// All the deleted shares caused by this delete
1163
-		$deletedShares[] = $share;
1164
-
1165
-		// Emit post hook
1166
-		$event->setArgument('deletedShares', $deletedShares);
1167
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1168
-	}
1169
-
1170
-
1171
-	/**
1172
-	 * Unshare a file as the recipient.
1173
-	 * This can be different from a regular delete for example when one of
1174
-	 * the users in a groups deletes that share. But the provider should
1175
-	 * handle this.
1176
-	 *
1177
-	 * @param IShare $share
1178
-	 * @param string $recipientId
1179
-	 */
1180
-	public function deleteFromSelf(IShare $share, $recipientId) {
1181
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1182
-		$provider = $this->factory->getProvider($providerId);
1183
-
1184
-		$provider->deleteFromSelf($share, $recipientId);
1185
-		$event = new GenericEvent($share);
1186
-		$this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1187
-	}
1188
-
1189
-	public function restoreShare(IShare $share, string $recipientId): IShare {
1190
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1191
-		$provider = $this->factory->getProvider($providerId);
1192
-
1193
-		return $provider->restore($share, $recipientId);
1194
-	}
1195
-
1196
-	/**
1197
-	 * @inheritdoc
1198
-	 */
1199
-	public function moveShare(IShare $share, $recipientId) {
1200
-		if ($share->getShareType() === IShare::TYPE_LINK) {
1201
-			throw new \InvalidArgumentException('Can’t change target of link share');
1202
-		}
1203
-
1204
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1205
-			throw new \InvalidArgumentException('Invalid recipient');
1206
-		}
1207
-
1208
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1209
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1210
-			if (is_null($sharedWith)) {
1211
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1212
-			}
1213
-			$recipient = $this->userManager->get($recipientId);
1214
-			if (!$sharedWith->inGroup($recipient)) {
1215
-				throw new \InvalidArgumentException('Invalid recipient');
1216
-			}
1217
-		}
1218
-
1219
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1220
-		$provider = $this->factory->getProvider($providerId);
1221
-
1222
-		return $provider->move($share, $recipientId);
1223
-	}
1224
-
1225
-	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1226
-		$providers = $this->factory->getAllProviders();
1227
-
1228
-		return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1229
-			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1230
-			foreach ($newShares as $fid => $data) {
1231
-				if (!isset($shares[$fid])) {
1232
-					$shares[$fid] = [];
1233
-				}
1234
-
1235
-				$shares[$fid] = array_merge($shares[$fid], $data);
1236
-			}
1237
-			return $shares;
1238
-		}, []);
1239
-	}
1240
-
1241
-	/**
1242
-	 * @inheritdoc
1243
-	 */
1244
-	public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1245
-		if ($path !== null &&
1246
-				!($path instanceof \OCP\Files\File) &&
1247
-				!($path instanceof \OCP\Files\Folder)) {
1248
-			throw new \InvalidArgumentException('invalid path');
1249
-		}
1250
-
1251
-		try {
1252
-			$provider = $this->factory->getProviderForType($shareType);
1253
-		} catch (ProviderException $e) {
1254
-			return [];
1255
-		}
1256
-
1257
-		$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1258
-
1259
-		/*
747
+            $share->setToken(
748
+                $this->secureRandom->generate(
749
+                    \OC\Share\Constants::TOKEN_LENGTH,
750
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
751
+                )
752
+            );
753
+
754
+            //Verify the expiration date
755
+            $share = $this->validateExpirationDate($share);
756
+
757
+            //Verify the password
758
+            $this->verifyPassword($share->getPassword());
759
+
760
+            // If a password is set. Hash it!
761
+            if ($share->getPassword() !== null) {
762
+                $share->setPassword($this->hasher->hash($share->getPassword()));
763
+            }
764
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
765
+            $share->setToken(
766
+                $this->secureRandom->generate(
767
+                    \OC\Share\Constants::TOKEN_LENGTH,
768
+                    \OCP\Security\ISecureRandom::CHAR_HUMAN_READABLE
769
+                )
770
+            );
771
+        }
772
+
773
+        // Cannot share with the owner
774
+        if ($share->getShareType() === IShare::TYPE_USER &&
775
+            $share->getSharedWith() === $share->getShareOwner()) {
776
+            throw new \InvalidArgumentException('Can’t share with the share owner');
777
+        }
778
+
779
+        // Generate the target
780
+        $target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
781
+        $target = \OC\Files\Filesystem::normalizePath($target);
782
+        $share->setTarget($target);
783
+
784
+        // Pre share event
785
+        $event = new GenericEvent($share);
786
+        $this->legacyDispatcher->dispatch('OCP\Share::preShare', $event);
787
+        if ($event->isPropagationStopped() && $event->hasArgument('error')) {
788
+            throw new \Exception($event->getArgument('error'));
789
+        }
790
+
791
+        $oldShare = $share;
792
+        $provider = $this->factory->getProviderForType($share->getShareType());
793
+        $share = $provider->create($share);
794
+        //reuse the node we already have
795
+        $share->setNode($oldShare->getNode());
796
+
797
+        // Reset the target if it is null for the new share
798
+        if ($share->getTarget() === '') {
799
+            $share->setTarget($target);
800
+        }
801
+
802
+        // Post share event
803
+        $event = new GenericEvent($share);
804
+        $this->legacyDispatcher->dispatch('OCP\Share::postShare', $event);
805
+
806
+        $this->dispatcher->dispatchTyped(new Share\Events\ShareCreatedEvent($share));
807
+
808
+        if ($share->getShareType() === IShare::TYPE_USER) {
809
+            $mailSend = $share->getMailSend();
810
+            if ($mailSend === true) {
811
+                $user = $this->userManager->get($share->getSharedWith());
812
+                if ($user !== null) {
813
+                    $emailAddress = $user->getEMailAddress();
814
+                    if ($emailAddress !== null && $emailAddress !== '') {
815
+                        $userLang = $this->l10nFactory->getUserLanguage($user);
816
+                        $l = $this->l10nFactory->get('lib', $userLang);
817
+                        $this->sendMailNotification(
818
+                            $l,
819
+                            $share->getNode()->getName(),
820
+                            $this->urlGenerator->linkToRouteAbsolute('files_sharing.Accept.accept', ['shareId' => $share->getFullId()]),
821
+                            $share->getSharedBy(),
822
+                            $emailAddress,
823
+                            $share->getExpirationDate()
824
+                        );
825
+                        $this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
826
+                    } else {
827
+                        $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
828
+                    }
829
+                } else {
830
+                    $this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
831
+                }
832
+            } else {
833
+                $this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
834
+            }
835
+        }
836
+
837
+        return $share;
838
+    }
839
+
840
+    /**
841
+     * Send mail notifications
842
+     *
843
+     * This method will catch and log mail transmission errors
844
+     *
845
+     * @param IL10N $l Language of the recipient
846
+     * @param string $filename file/folder name
847
+     * @param string $link link to the file/folder
848
+     * @param string $initiator user ID of share sender
849
+     * @param string $shareWith email address of share receiver
850
+     * @param \DateTime|null $expiration
851
+     */
852
+    protected function sendMailNotification(IL10N $l,
853
+                                            $filename,
854
+                                            $link,
855
+                                            $initiator,
856
+                                            $shareWith,
857
+                                            \DateTime $expiration = null) {
858
+        $initiatorUser = $this->userManager->get($initiator);
859
+        $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
860
+
861
+        $message = $this->mailer->createMessage();
862
+
863
+        $emailTemplate = $this->mailer->createEMailTemplate('files_sharing.RecipientNotification', [
864
+            'filename' => $filename,
865
+            'link' => $link,
866
+            'initiator' => $initiatorDisplayName,
867
+            'expiration' => $expiration,
868
+            'shareWith' => $shareWith,
869
+        ]);
870
+
871
+        $emailTemplate->setSubject($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]));
872
+        $emailTemplate->addHeader();
873
+        $emailTemplate->addHeading($l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false);
874
+        $text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
875
+
876
+        $emailTemplate->addBodyText(
877
+            htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
878
+            $text
879
+        );
880
+        $emailTemplate->addBodyButton(
881
+            $l->t('Open »%s«', [$filename]),
882
+            $link
883
+        );
884
+
885
+        $message->setTo([$shareWith]);
886
+
887
+        // The "From" contains the sharers name
888
+        $instanceName = $this->defaults->getName();
889
+        $senderName = $l->t(
890
+            '%1$s via %2$s',
891
+            [
892
+                $initiatorDisplayName,
893
+                $instanceName
894
+            ]
895
+        );
896
+        $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
897
+
898
+        // The "Reply-To" is set to the sharer if an mail address is configured
899
+        // also the default footer contains a "Do not reply" which needs to be adjusted.
900
+        $initiatorEmail = $initiatorUser->getEMailAddress();
901
+        if ($initiatorEmail !== null) {
902
+            $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
903
+            $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
904
+        } else {
905
+            $emailTemplate->addFooter('', $l->getLanguageCode());
906
+        }
907
+
908
+        $message->useTemplate($emailTemplate);
909
+        try {
910
+            $failedRecipients = $this->mailer->send($message);
911
+            if (!empty($failedRecipients)) {
912
+                $this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
913
+                return;
914
+            }
915
+        } catch (\Exception $e) {
916
+            $this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
917
+        }
918
+    }
919
+
920
+    /**
921
+     * Update a share
922
+     *
923
+     * @param IShare $share
924
+     * @return IShare The share object
925
+     * @throws \InvalidArgumentException
926
+     */
927
+    public function updateShare(IShare $share) {
928
+        $expirationDateUpdated = false;
929
+
930
+        $this->canShare($share);
931
+
932
+        try {
933
+            $originalShare = $this->getShareById($share->getFullId());
934
+        } catch (\UnexpectedValueException $e) {
935
+            throw new \InvalidArgumentException('Share does not have a full id');
936
+        }
937
+
938
+        // We can't change the share type!
939
+        if ($share->getShareType() !== $originalShare->getShareType()) {
940
+            throw new \InvalidArgumentException('Can’t change share type');
941
+        }
942
+
943
+        // We can only change the recipient on user shares
944
+        if ($share->getSharedWith() !== $originalShare->getSharedWith() &&
945
+            $share->getShareType() !== IShare::TYPE_USER) {
946
+            throw new \InvalidArgumentException('Can only update recipient on user shares');
947
+        }
948
+
949
+        // Cannot share with the owner
950
+        if ($share->getShareType() === IShare::TYPE_USER &&
951
+            $share->getSharedWith() === $share->getShareOwner()) {
952
+            throw new \InvalidArgumentException('Can’t share with the share owner');
953
+        }
954
+
955
+        $this->generalCreateChecks($share);
956
+
957
+        if ($share->getShareType() === IShare::TYPE_USER) {
958
+            $this->userCreateChecks($share);
959
+
960
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
961
+                //Verify the expiration date
962
+                $this->validateExpirationDate($share);
963
+                $expirationDateUpdated = true;
964
+            }
965
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
966
+            $this->groupCreateChecks($share);
967
+
968
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
969
+                //Verify the expiration date
970
+                $this->validateExpirationDate($share);
971
+                $expirationDateUpdated = true;
972
+            }
973
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
974
+            $this->linkCreateChecks($share);
975
+
976
+            $plainTextPassword = $share->getPassword();
977
+
978
+            $this->updateSharePasswordIfNeeded($share, $originalShare);
979
+
980
+            if (empty($plainTextPassword) && $share->getSendPasswordByTalk()) {
981
+                throw new \InvalidArgumentException('Can’t enable sending the password by Talk with an empty password');
982
+            }
983
+
984
+            if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
985
+                //Verify the expiration date
986
+                $this->validateExpirationDate($share);
987
+                $expirationDateUpdated = true;
988
+            }
989
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
990
+            // The new password is not set again if it is the same as the old
991
+            // one.
992
+            $plainTextPassword = $share->getPassword();
993
+            if (!empty($plainTextPassword) && !$this->updateSharePasswordIfNeeded($share, $originalShare)) {
994
+                $plainTextPassword = null;
995
+            }
996
+            if (empty($plainTextPassword) && !$originalShare->getSendPasswordByTalk() && $share->getSendPasswordByTalk()) {
997
+                // If the same password was already sent by mail the recipient
998
+                // would already have access to the share without having to call
999
+                // the sharer to verify her identity
1000
+                throw new \InvalidArgumentException('Can’t enable sending the password by Talk without setting a new password');
1001
+            } elseif (empty($plainTextPassword) && $originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()) {
1002
+                throw new \InvalidArgumentException('Can’t disable sending the password by Talk without setting a new password');
1003
+            }
1004
+        }
1005
+
1006
+        $this->pathCreateChecks($share->getNode());
1007
+
1008
+        // Now update the share!
1009
+        $provider = $this->factory->getProviderForType($share->getShareType());
1010
+        if ($share->getShareType() === IShare::TYPE_EMAIL) {
1011
+            $share = $provider->update($share, $plainTextPassword);
1012
+        } else {
1013
+            $share = $provider->update($share);
1014
+        }
1015
+
1016
+        if ($expirationDateUpdated === true) {
1017
+            \OC_Hook::emit(Share::class, 'post_set_expiration_date', [
1018
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1019
+                'itemSource' => $share->getNode()->getId(),
1020
+                'date' => $share->getExpirationDate(),
1021
+                'uidOwner' => $share->getSharedBy(),
1022
+            ]);
1023
+        }
1024
+
1025
+        if ($share->getPassword() !== $originalShare->getPassword()) {
1026
+            \OC_Hook::emit(Share::class, 'post_update_password', [
1027
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1028
+                'itemSource' => $share->getNode()->getId(),
1029
+                'uidOwner' => $share->getSharedBy(),
1030
+                'token' => $share->getToken(),
1031
+                'disabled' => is_null($share->getPassword()),
1032
+            ]);
1033
+        }
1034
+
1035
+        if ($share->getPermissions() !== $originalShare->getPermissions()) {
1036
+            if ($this->userManager->userExists($share->getShareOwner())) {
1037
+                $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
1038
+            } else {
1039
+                $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1040
+            }
1041
+            \OC_Hook::emit(Share::class, 'post_update_permissions', [
1042
+                'itemType' => $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder',
1043
+                'itemSource' => $share->getNode()->getId(),
1044
+                'shareType' => $share->getShareType(),
1045
+                'shareWith' => $share->getSharedWith(),
1046
+                'uidOwner' => $share->getSharedBy(),
1047
+                'permissions' => $share->getPermissions(),
1048
+                'path' => $userFolder->getRelativePath($share->getNode()->getPath()),
1049
+            ]);
1050
+        }
1051
+
1052
+        return $share;
1053
+    }
1054
+
1055
+    /**
1056
+     * Accept a share.
1057
+     *
1058
+     * @param IShare $share
1059
+     * @param string $recipientId
1060
+     * @return IShare The share object
1061
+     * @throws \InvalidArgumentException
1062
+     * @since 9.0.0
1063
+     */
1064
+    public function acceptShare(IShare $share, string $recipientId): IShare {
1065
+        [$providerId, ] = $this->splitFullId($share->getFullId());
1066
+        $provider = $this->factory->getProvider($providerId);
1067
+
1068
+        if (!method_exists($provider, 'acceptShare')) {
1069
+            // TODO FIX ME
1070
+            throw new \InvalidArgumentException('Share provider does not support accepting');
1071
+        }
1072
+        $provider->acceptShare($share, $recipientId);
1073
+        $event = new GenericEvent($share);
1074
+        $this->legacyDispatcher->dispatch('OCP\Share::postAcceptShare', $event);
1075
+
1076
+        return $share;
1077
+    }
1078
+
1079
+    /**
1080
+     * Updates the password of the given share if it is not the same as the
1081
+     * password of the original share.
1082
+     *
1083
+     * @param IShare $share the share to update its password.
1084
+     * @param IShare $originalShare the original share to compare its
1085
+     *        password with.
1086
+     * @return boolean whether the password was updated or not.
1087
+     */
1088
+    private function updateSharePasswordIfNeeded(IShare $share, IShare $originalShare) {
1089
+        $passwordsAreDifferent = ($share->getPassword() !== $originalShare->getPassword()) &&
1090
+                                    (($share->getPassword() !== null && $originalShare->getPassword() === null) ||
1091
+                                     ($share->getPassword() === null && $originalShare->getPassword() !== null) ||
1092
+                                     ($share->getPassword() !== null && $originalShare->getPassword() !== null &&
1093
+                                        !$this->hasher->verify($share->getPassword(), $originalShare->getPassword())));
1094
+
1095
+        // Password updated.
1096
+        if ($passwordsAreDifferent) {
1097
+            //Verify the password
1098
+            $this->verifyPassword($share->getPassword());
1099
+
1100
+            // If a password is set. Hash it!
1101
+            if ($share->getPassword() !== null) {
1102
+                $share->setPassword($this->hasher->hash($share->getPassword()));
1103
+
1104
+                return true;
1105
+            }
1106
+        } else {
1107
+            // Reset the password to the original one, as it is either the same
1108
+            // as the "new" password or a hashed version of it.
1109
+            $share->setPassword($originalShare->getPassword());
1110
+        }
1111
+
1112
+        return false;
1113
+    }
1114
+
1115
+    /**
1116
+     * Delete all the children of this share
1117
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
1118
+     *
1119
+     * @param IShare $share
1120
+     * @return IShare[] List of deleted shares
1121
+     */
1122
+    protected function deleteChildren(IShare $share) {
1123
+        $deletedShares = [];
1124
+
1125
+        $provider = $this->factory->getProviderForType($share->getShareType());
1126
+
1127
+        foreach ($provider->getChildren($share) as $child) {
1128
+            $deletedChildren = $this->deleteChildren($child);
1129
+            $deletedShares = array_merge($deletedShares, $deletedChildren);
1130
+
1131
+            $provider->delete($child);
1132
+            $deletedShares[] = $child;
1133
+        }
1134
+
1135
+        return $deletedShares;
1136
+    }
1137
+
1138
+    /**
1139
+     * Delete a share
1140
+     *
1141
+     * @param IShare $share
1142
+     * @throws ShareNotFound
1143
+     * @throws \InvalidArgumentException
1144
+     */
1145
+    public function deleteShare(IShare $share) {
1146
+        try {
1147
+            $share->getFullId();
1148
+        } catch (\UnexpectedValueException $e) {
1149
+            throw new \InvalidArgumentException('Share does not have a full id');
1150
+        }
1151
+
1152
+        $event = new GenericEvent($share);
1153
+        $this->legacyDispatcher->dispatch('OCP\Share::preUnshare', $event);
1154
+
1155
+        // Get all children and delete them as well
1156
+        $deletedShares = $this->deleteChildren($share);
1157
+
1158
+        // Do the actual delete
1159
+        $provider = $this->factory->getProviderForType($share->getShareType());
1160
+        $provider->delete($share);
1161
+
1162
+        // All the deleted shares caused by this delete
1163
+        $deletedShares[] = $share;
1164
+
1165
+        // Emit post hook
1166
+        $event->setArgument('deletedShares', $deletedShares);
1167
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshare', $event);
1168
+    }
1169
+
1170
+
1171
+    /**
1172
+     * Unshare a file as the recipient.
1173
+     * This can be different from a regular delete for example when one of
1174
+     * the users in a groups deletes that share. But the provider should
1175
+     * handle this.
1176
+     *
1177
+     * @param IShare $share
1178
+     * @param string $recipientId
1179
+     */
1180
+    public function deleteFromSelf(IShare $share, $recipientId) {
1181
+        list($providerId, ) = $this->splitFullId($share->getFullId());
1182
+        $provider = $this->factory->getProvider($providerId);
1183
+
1184
+        $provider->deleteFromSelf($share, $recipientId);
1185
+        $event = new GenericEvent($share);
1186
+        $this->legacyDispatcher->dispatch('OCP\Share::postUnshareFromSelf', $event);
1187
+    }
1188
+
1189
+    public function restoreShare(IShare $share, string $recipientId): IShare {
1190
+        list($providerId, ) = $this->splitFullId($share->getFullId());
1191
+        $provider = $this->factory->getProvider($providerId);
1192
+
1193
+        return $provider->restore($share, $recipientId);
1194
+    }
1195
+
1196
+    /**
1197
+     * @inheritdoc
1198
+     */
1199
+    public function moveShare(IShare $share, $recipientId) {
1200
+        if ($share->getShareType() === IShare::TYPE_LINK) {
1201
+            throw new \InvalidArgumentException('Can’t change target of link share');
1202
+        }
1203
+
1204
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() !== $recipientId) {
1205
+            throw new \InvalidArgumentException('Invalid recipient');
1206
+        }
1207
+
1208
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1209
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1210
+            if (is_null($sharedWith)) {
1211
+                throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1212
+            }
1213
+            $recipient = $this->userManager->get($recipientId);
1214
+            if (!$sharedWith->inGroup($recipient)) {
1215
+                throw new \InvalidArgumentException('Invalid recipient');
1216
+            }
1217
+        }
1218
+
1219
+        list($providerId, ) = $this->splitFullId($share->getFullId());
1220
+        $provider = $this->factory->getProvider($providerId);
1221
+
1222
+        return $provider->move($share, $recipientId);
1223
+    }
1224
+
1225
+    public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1226
+        $providers = $this->factory->getAllProviders();
1227
+
1228
+        return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1229
+            $newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1230
+            foreach ($newShares as $fid => $data) {
1231
+                if (!isset($shares[$fid])) {
1232
+                    $shares[$fid] = [];
1233
+                }
1234
+
1235
+                $shares[$fid] = array_merge($shares[$fid], $data);
1236
+            }
1237
+            return $shares;
1238
+        }, []);
1239
+    }
1240
+
1241
+    /**
1242
+     * @inheritdoc
1243
+     */
1244
+    public function getSharesBy($userId, $shareType, $path = null, $reshares = false, $limit = 50, $offset = 0) {
1245
+        if ($path !== null &&
1246
+                !($path instanceof \OCP\Files\File) &&
1247
+                !($path instanceof \OCP\Files\Folder)) {
1248
+            throw new \InvalidArgumentException('invalid path');
1249
+        }
1250
+
1251
+        try {
1252
+            $provider = $this->factory->getProviderForType($shareType);
1253
+        } catch (ProviderException $e) {
1254
+            return [];
1255
+        }
1256
+
1257
+        $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1258
+
1259
+        /*
1260 1260
 		 * Work around so we don't return expired shares but still follow
1261 1261
 		 * proper pagination.
1262 1262
 		 */
1263 1263
 
1264
-		$shares2 = [];
1265
-
1266
-		while (true) {
1267
-			$added = 0;
1268
-			foreach ($shares as $share) {
1269
-				try {
1270
-					$this->checkExpireDate($share);
1271
-				} catch (ShareNotFound $e) {
1272
-					//Ignore since this basically means the share is deleted
1273
-					continue;
1274
-				}
1275
-
1276
-				$added++;
1277
-				$shares2[] = $share;
1278
-
1279
-				if (count($shares2) === $limit) {
1280
-					break;
1281
-				}
1282
-			}
1283
-
1284
-			// If we did not fetch more shares than the limit then there are no more shares
1285
-			if (count($shares) < $limit) {
1286
-				break;
1287
-			}
1288
-
1289
-			if (count($shares2) === $limit) {
1290
-				break;
1291
-			}
1292
-
1293
-			// If there was no limit on the select we are done
1294
-			if ($limit === -1) {
1295
-				break;
1296
-			}
1297
-
1298
-			$offset += $added;
1299
-
1300
-			// Fetch again $limit shares
1301
-			$shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1302
-
1303
-			// No more shares means we are done
1304
-			if (empty($shares)) {
1305
-				break;
1306
-			}
1307
-		}
1308
-
1309
-		$shares = $shares2;
1310
-
1311
-		return $shares;
1312
-	}
1313
-
1314
-	/**
1315
-	 * @inheritdoc
1316
-	 */
1317
-	public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1318
-		try {
1319
-			$provider = $this->factory->getProviderForType($shareType);
1320
-		} catch (ProviderException $e) {
1321
-			return [];
1322
-		}
1323
-
1324
-		$shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1325
-
1326
-		// remove all shares which are already expired
1327
-		foreach ($shares as $key => $share) {
1328
-			try {
1329
-				$this->checkExpireDate($share);
1330
-			} catch (ShareNotFound $e) {
1331
-				unset($shares[$key]);
1332
-			}
1333
-		}
1334
-
1335
-		return $shares;
1336
-	}
1337
-
1338
-	/**
1339
-	 * @inheritdoc
1340
-	 */
1341
-	public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1342
-		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1343
-
1344
-		// Only get deleted shares
1345
-		$shares = array_filter($shares, function (IShare $share) {
1346
-			return $share->getPermissions() === 0;
1347
-		});
1348
-
1349
-		// Only get shares where the owner still exists
1350
-		$shares = array_filter($shares, function (IShare $share) {
1351
-			return $this->userManager->userExists($share->getShareOwner());
1352
-		});
1353
-
1354
-		return $shares;
1355
-	}
1356
-
1357
-	/**
1358
-	 * @inheritdoc
1359
-	 */
1360
-	public function getShareById($id, $recipient = null) {
1361
-		if ($id === null) {
1362
-			throw new ShareNotFound();
1363
-		}
1364
-
1365
-		list($providerId, $id) = $this->splitFullId($id);
1366
-
1367
-		try {
1368
-			$provider = $this->factory->getProvider($providerId);
1369
-		} catch (ProviderException $e) {
1370
-			throw new ShareNotFound();
1371
-		}
1372
-
1373
-		$share = $provider->getShareById($id, $recipient);
1374
-
1375
-		$this->checkExpireDate($share);
1376
-
1377
-		return $share;
1378
-	}
1379
-
1380
-	/**
1381
-	 * Get all the shares for a given path
1382
-	 *
1383
-	 * @param \OCP\Files\Node $path
1384
-	 * @param int $page
1385
-	 * @param int $perPage
1386
-	 *
1387
-	 * @return Share[]
1388
-	 */
1389
-	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1390
-		return [];
1391
-	}
1392
-
1393
-	/**
1394
-	 * Get the share by token possible with password
1395
-	 *
1396
-	 * @param string $token
1397
-	 * @return IShare
1398
-	 *
1399
-	 * @throws ShareNotFound
1400
-	 */
1401
-	public function getShareByToken($token) {
1402
-		// tokens can't be valid local user names
1403
-		if ($this->userManager->userExists($token)) {
1404
-			throw new ShareNotFound();
1405
-		}
1406
-		$share = null;
1407
-		try {
1408
-			if ($this->shareApiAllowLinks()) {
1409
-				$provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1410
-				$share = $provider->getShareByToken($token);
1411
-			}
1412
-		} catch (ProviderException $e) {
1413
-		} catch (ShareNotFound $e) {
1414
-		}
1415
-
1416
-
1417
-		// If it is not a link share try to fetch a federated share by token
1418
-		if ($share === null) {
1419
-			try {
1420
-				$provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1421
-				$share = $provider->getShareByToken($token);
1422
-			} catch (ProviderException $e) {
1423
-			} catch (ShareNotFound $e) {
1424
-			}
1425
-		}
1426
-
1427
-		// If it is not a link share try to fetch a mail share by token
1428
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1429
-			try {
1430
-				$provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1431
-				$share = $provider->getShareByToken($token);
1432
-			} catch (ProviderException $e) {
1433
-			} catch (ShareNotFound $e) {
1434
-			}
1435
-		}
1436
-
1437
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1438
-			try {
1439
-				$provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1440
-				$share = $provider->getShareByToken($token);
1441
-			} catch (ProviderException $e) {
1442
-			} catch (ShareNotFound $e) {
1443
-			}
1444
-		}
1445
-
1446
-		if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1447
-			try {
1448
-				$provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1449
-				$share = $provider->getShareByToken($token);
1450
-			} catch (ProviderException $e) {
1451
-			} catch (ShareNotFound $e) {
1452
-			}
1453
-		}
1454
-
1455
-		if ($share === null) {
1456
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1457
-		}
1458
-
1459
-		$this->checkExpireDate($share);
1460
-
1461
-		/*
1264
+        $shares2 = [];
1265
+
1266
+        while (true) {
1267
+            $added = 0;
1268
+            foreach ($shares as $share) {
1269
+                try {
1270
+                    $this->checkExpireDate($share);
1271
+                } catch (ShareNotFound $e) {
1272
+                    //Ignore since this basically means the share is deleted
1273
+                    continue;
1274
+                }
1275
+
1276
+                $added++;
1277
+                $shares2[] = $share;
1278
+
1279
+                if (count($shares2) === $limit) {
1280
+                    break;
1281
+                }
1282
+            }
1283
+
1284
+            // If we did not fetch more shares than the limit then there are no more shares
1285
+            if (count($shares) < $limit) {
1286
+                break;
1287
+            }
1288
+
1289
+            if (count($shares2) === $limit) {
1290
+                break;
1291
+            }
1292
+
1293
+            // If there was no limit on the select we are done
1294
+            if ($limit === -1) {
1295
+                break;
1296
+            }
1297
+
1298
+            $offset += $added;
1299
+
1300
+            // Fetch again $limit shares
1301
+            $shares = $provider->getSharesBy($userId, $shareType, $path, $reshares, $limit, $offset);
1302
+
1303
+            // No more shares means we are done
1304
+            if (empty($shares)) {
1305
+                break;
1306
+            }
1307
+        }
1308
+
1309
+        $shares = $shares2;
1310
+
1311
+        return $shares;
1312
+    }
1313
+
1314
+    /**
1315
+     * @inheritdoc
1316
+     */
1317
+    public function getSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1318
+        try {
1319
+            $provider = $this->factory->getProviderForType($shareType);
1320
+        } catch (ProviderException $e) {
1321
+            return [];
1322
+        }
1323
+
1324
+        $shares = $provider->getSharedWith($userId, $shareType, $node, $limit, $offset);
1325
+
1326
+        // remove all shares which are already expired
1327
+        foreach ($shares as $key => $share) {
1328
+            try {
1329
+                $this->checkExpireDate($share);
1330
+            } catch (ShareNotFound $e) {
1331
+                unset($shares[$key]);
1332
+            }
1333
+        }
1334
+
1335
+        return $shares;
1336
+    }
1337
+
1338
+    /**
1339
+     * @inheritdoc
1340
+     */
1341
+    public function getDeletedSharedWith($userId, $shareType, $node = null, $limit = 50, $offset = 0) {
1342
+        $shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1343
+
1344
+        // Only get deleted shares
1345
+        $shares = array_filter($shares, function (IShare $share) {
1346
+            return $share->getPermissions() === 0;
1347
+        });
1348
+
1349
+        // Only get shares where the owner still exists
1350
+        $shares = array_filter($shares, function (IShare $share) {
1351
+            return $this->userManager->userExists($share->getShareOwner());
1352
+        });
1353
+
1354
+        return $shares;
1355
+    }
1356
+
1357
+    /**
1358
+     * @inheritdoc
1359
+     */
1360
+    public function getShareById($id, $recipient = null) {
1361
+        if ($id === null) {
1362
+            throw new ShareNotFound();
1363
+        }
1364
+
1365
+        list($providerId, $id) = $this->splitFullId($id);
1366
+
1367
+        try {
1368
+            $provider = $this->factory->getProvider($providerId);
1369
+        } catch (ProviderException $e) {
1370
+            throw new ShareNotFound();
1371
+        }
1372
+
1373
+        $share = $provider->getShareById($id, $recipient);
1374
+
1375
+        $this->checkExpireDate($share);
1376
+
1377
+        return $share;
1378
+    }
1379
+
1380
+    /**
1381
+     * Get all the shares for a given path
1382
+     *
1383
+     * @param \OCP\Files\Node $path
1384
+     * @param int $page
1385
+     * @param int $perPage
1386
+     *
1387
+     * @return Share[]
1388
+     */
1389
+    public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1390
+        return [];
1391
+    }
1392
+
1393
+    /**
1394
+     * Get the share by token possible with password
1395
+     *
1396
+     * @param string $token
1397
+     * @return IShare
1398
+     *
1399
+     * @throws ShareNotFound
1400
+     */
1401
+    public function getShareByToken($token) {
1402
+        // tokens can't be valid local user names
1403
+        if ($this->userManager->userExists($token)) {
1404
+            throw new ShareNotFound();
1405
+        }
1406
+        $share = null;
1407
+        try {
1408
+            if ($this->shareApiAllowLinks()) {
1409
+                $provider = $this->factory->getProviderForType(IShare::TYPE_LINK);
1410
+                $share = $provider->getShareByToken($token);
1411
+            }
1412
+        } catch (ProviderException $e) {
1413
+        } catch (ShareNotFound $e) {
1414
+        }
1415
+
1416
+
1417
+        // If it is not a link share try to fetch a federated share by token
1418
+        if ($share === null) {
1419
+            try {
1420
+                $provider = $this->factory->getProviderForType(IShare::TYPE_REMOTE);
1421
+                $share = $provider->getShareByToken($token);
1422
+            } catch (ProviderException $e) {
1423
+            } catch (ShareNotFound $e) {
1424
+            }
1425
+        }
1426
+
1427
+        // If it is not a link share try to fetch a mail share by token
1428
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_EMAIL)) {
1429
+            try {
1430
+                $provider = $this->factory->getProviderForType(IShare::TYPE_EMAIL);
1431
+                $share = $provider->getShareByToken($token);
1432
+            } catch (ProviderException $e) {
1433
+            } catch (ShareNotFound $e) {
1434
+            }
1435
+        }
1436
+
1437
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_CIRCLE)) {
1438
+            try {
1439
+                $provider = $this->factory->getProviderForType(IShare::TYPE_CIRCLE);
1440
+                $share = $provider->getShareByToken($token);
1441
+            } catch (ProviderException $e) {
1442
+            } catch (ShareNotFound $e) {
1443
+            }
1444
+        }
1445
+
1446
+        if ($share === null && $this->shareProviderExists(IShare::TYPE_ROOM)) {
1447
+            try {
1448
+                $provider = $this->factory->getProviderForType(IShare::TYPE_ROOM);
1449
+                $share = $provider->getShareByToken($token);
1450
+            } catch (ProviderException $e) {
1451
+            } catch (ShareNotFound $e) {
1452
+            }
1453
+        }
1454
+
1455
+        if ($share === null) {
1456
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1457
+        }
1458
+
1459
+        $this->checkExpireDate($share);
1460
+
1461
+        /*
1462 1462
 		 * Reduce the permissions for link shares if public upload is not enabled
1463 1463
 		 */
1464
-		if ($share->getShareType() === IShare::TYPE_LINK &&
1465
-			!$this->shareApiLinkAllowPublicUpload()) {
1466
-			$share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1467
-		}
1468
-
1469
-		return $share;
1470
-	}
1471
-
1472
-	protected function checkExpireDate($share) {
1473
-		if ($share->isExpired()) {
1474
-			$this->deleteShare($share);
1475
-			throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1476
-		}
1477
-	}
1478
-
1479
-	/**
1480
-	 * Verify the password of a public share
1481
-	 *
1482
-	 * @param IShare $share
1483
-	 * @param string $password
1484
-	 * @return bool
1485
-	 */
1486
-	public function checkPassword(IShare $share, $password) {
1487
-		$passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1488
-							 || $share->getShareType() !== IShare::TYPE_EMAIL
1489
-							 || $share->getShareType() !== IShare::TYPE_CIRCLE;
1490
-		if (!$passwordProtected) {
1491
-			//TODO maybe exception?
1492
-			return false;
1493
-		}
1494
-
1495
-		if ($password === null || $share->getPassword() === null) {
1496
-			return false;
1497
-		}
1498
-
1499
-		$newHash = '';
1500
-		if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1501
-			return false;
1502
-		}
1503
-
1504
-		if (!empty($newHash)) {
1505
-			$share->setPassword($newHash);
1506
-			$provider = $this->factory->getProviderForType($share->getShareType());
1507
-			$provider->update($share);
1508
-		}
1509
-
1510
-		return true;
1511
-	}
1512
-
1513
-	/**
1514
-	 * @inheritdoc
1515
-	 */
1516
-	public function userDeleted($uid) {
1517
-		$types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1518
-
1519
-		foreach ($types as $type) {
1520
-			try {
1521
-				$provider = $this->factory->getProviderForType($type);
1522
-			} catch (ProviderException $e) {
1523
-				continue;
1524
-			}
1525
-			$provider->userDeleted($uid, $type);
1526
-		}
1527
-	}
1528
-
1529
-	/**
1530
-	 * @inheritdoc
1531
-	 */
1532
-	public function groupDeleted($gid) {
1533
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1534
-		$provider->groupDeleted($gid);
1535
-
1536
-		$excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1537
-		if ($excludedGroups === '') {
1538
-			return;
1539
-		}
1540
-
1541
-		$excludedGroups = json_decode($excludedGroups, true);
1542
-		if (json_last_error() !== JSON_ERROR_NONE) {
1543
-			return;
1544
-		}
1545
-
1546
-		$excludedGroups = array_diff($excludedGroups, [$gid]);
1547
-		$this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1548
-	}
1549
-
1550
-	/**
1551
-	 * @inheritdoc
1552
-	 */
1553
-	public function userDeletedFromGroup($uid, $gid) {
1554
-		$provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1555
-		$provider->userDeletedFromGroup($uid, $gid);
1556
-	}
1557
-
1558
-	/**
1559
-	 * Get access list to a path. This means
1560
-	 * all the users that can access a given path.
1561
-	 *
1562
-	 * Consider:
1563
-	 * -root
1564
-	 * |-folder1 (23)
1565
-	 *  |-folder2 (32)
1566
-	 *   |-fileA (42)
1567
-	 *
1568
-	 * fileA is shared with user1 and user1@server1
1569
-	 * folder2 is shared with group2 (user4 is a member of group2)
1570
-	 * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1571
-	 *
1572
-	 * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1573
-	 * [
1574
-	 *  users  => [
1575
-	 *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1576
-	 *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1577
-	 *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1578
-	 *  ],
1579
-	 *  remote => [
1580
-	 *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1581
-	 *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1582
-	 *  ],
1583
-	 *  public => bool
1584
-	 *  mail => bool
1585
-	 * ]
1586
-	 *
1587
-	 * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1588
-	 * [
1589
-	 *  users  => ['user1', 'user2', 'user4'],
1590
-	 *  remote => bool,
1591
-	 *  public => bool
1592
-	 *  mail => bool
1593
-	 * ]
1594
-	 *
1595
-	 * This is required for encryption/activity
1596
-	 *
1597
-	 * @param \OCP\Files\Node $path
1598
-	 * @param bool $recursive Should we check all parent folders as well
1599
-	 * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1600
-	 * @return array
1601
-	 */
1602
-	public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1603
-		$owner = $path->getOwner();
1604
-
1605
-		if ($owner === null) {
1606
-			return [];
1607
-		}
1608
-
1609
-		$owner = $owner->getUID();
1610
-
1611
-		if ($currentAccess) {
1612
-			$al = ['users' => [], 'remote' => [], 'public' => false];
1613
-		} else {
1614
-			$al = ['users' => [], 'remote' => false, 'public' => false];
1615
-		}
1616
-		if (!$this->userManager->userExists($owner)) {
1617
-			return $al;
1618
-		}
1619
-
1620
-		//Get node for the owner and correct the owner in case of external storages
1621
-		$userFolder = $this->rootFolder->getUserFolder($owner);
1622
-		if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1623
-			$nodes = $userFolder->getById($path->getId());
1624
-			$path = array_shift($nodes);
1625
-			if ($path->getOwner() === null) {
1626
-				return [];
1627
-			}
1628
-			$owner = $path->getOwner()->getUID();
1629
-		}
1630
-
1631
-		$providers = $this->factory->getAllProviders();
1632
-
1633
-		/** @var Node[] $nodes */
1634
-		$nodes = [];
1635
-
1636
-
1637
-		if ($currentAccess) {
1638
-			$ownerPath = $path->getPath();
1639
-			$ownerPath = explode('/', $ownerPath, 4);
1640
-			if (count($ownerPath) < 4) {
1641
-				$ownerPath = '';
1642
-			} else {
1643
-				$ownerPath = $ownerPath[3];
1644
-			}
1645
-			$al['users'][$owner] = [
1646
-				'node_id' => $path->getId(),
1647
-				'node_path' => '/' . $ownerPath,
1648
-			];
1649
-		} else {
1650
-			$al['users'][] = $owner;
1651
-		}
1652
-
1653
-		// Collect all the shares
1654
-		while ($path->getPath() !== $userFolder->getPath()) {
1655
-			$nodes[] = $path;
1656
-			if (!$recursive) {
1657
-				break;
1658
-			}
1659
-			$path = $path->getParent();
1660
-		}
1661
-
1662
-		foreach ($providers as $provider) {
1663
-			$tmp = $provider->getAccessList($nodes, $currentAccess);
1664
-
1665
-			foreach ($tmp as $k => $v) {
1666
-				if (isset($al[$k])) {
1667
-					if (is_array($al[$k])) {
1668
-						if ($currentAccess) {
1669
-							$al[$k] += $v;
1670
-						} else {
1671
-							$al[$k] = array_merge($al[$k], $v);
1672
-							$al[$k] = array_unique($al[$k]);
1673
-							$al[$k] = array_values($al[$k]);
1674
-						}
1675
-					} else {
1676
-						$al[$k] = $al[$k] || $v;
1677
-					}
1678
-				} else {
1679
-					$al[$k] = $v;
1680
-				}
1681
-			}
1682
-		}
1683
-
1684
-		return $al;
1685
-	}
1686
-
1687
-	/**
1688
-	 * Create a new share
1689
-	 *
1690
-	 * @return IShare
1691
-	 */
1692
-	public function newShare() {
1693
-		return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1694
-	}
1695
-
1696
-	/**
1697
-	 * Is the share API enabled
1698
-	 *
1699
-	 * @return bool
1700
-	 */
1701
-	public function shareApiEnabled() {
1702
-		return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1703
-	}
1704
-
1705
-	/**
1706
-	 * Is public link sharing enabled
1707
-	 *
1708
-	 * @return bool
1709
-	 */
1710
-	public function shareApiAllowLinks() {
1711
-		return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1712
-	}
1713
-
1714
-	/**
1715
-	 * Is password on public link requires
1716
-	 *
1717
-	 * @return bool
1718
-	 */
1719
-	public function shareApiLinkEnforcePassword() {
1720
-		return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1721
-	}
1722
-
1723
-	/**
1724
-	 * Is default link expire date enabled
1725
-	 *
1726
-	 * @return bool
1727
-	 */
1728
-	public function shareApiLinkDefaultExpireDate() {
1729
-		return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1730
-	}
1731
-
1732
-	/**
1733
-	 * Is default link expire date enforced
1734
-	 *`
1735
-	 * @return bool
1736
-	 */
1737
-	public function shareApiLinkDefaultExpireDateEnforced() {
1738
-		return $this->shareApiLinkDefaultExpireDate() &&
1739
-			$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1740
-	}
1741
-
1742
-
1743
-	/**
1744
-	 * Number of default link expire days
1745
-	 * @return int
1746
-	 */
1747
-	public function shareApiLinkDefaultExpireDays() {
1748
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1749
-	}
1750
-
1751
-	/**
1752
-	 * Is default internal expire date enabled
1753
-	 *
1754
-	 * @return bool
1755
-	 */
1756
-	public function shareApiInternalDefaultExpireDate(): bool {
1757
-		return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1758
-	}
1759
-
1760
-	/**
1761
-	 * Is default expire date enforced
1762
-	 *`
1763
-	 * @return bool
1764
-	 */
1765
-	public function shareApiInternalDefaultExpireDateEnforced(): bool {
1766
-		return $this->shareApiInternalDefaultExpireDate() &&
1767
-			$this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1768
-	}
1769
-
1770
-
1771
-	/**
1772
-	 * Number of default expire days
1773
-	 * @return int
1774
-	 */
1775
-	public function shareApiInternalDefaultExpireDays(): int {
1776
-		return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1777
-	}
1778
-
1779
-	/**
1780
-	 * Allow public upload on link shares
1781
-	 *
1782
-	 * @return bool
1783
-	 */
1784
-	public function shareApiLinkAllowPublicUpload() {
1785
-		return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1786
-	}
1787
-
1788
-	/**
1789
-	 * check if user can only share with group members
1790
-	 * @return bool
1791
-	 */
1792
-	public function shareWithGroupMembersOnly() {
1793
-		return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1794
-	}
1795
-
1796
-	/**
1797
-	 * Check if users can share with groups
1798
-	 * @return bool
1799
-	 */
1800
-	public function allowGroupSharing() {
1801
-		return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1802
-	}
1803
-
1804
-	public function allowEnumeration(): bool {
1805
-		return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1806
-	}
1807
-
1808
-	public function limitEnumerationToGroups(): bool {
1809
-		return $this->allowEnumeration() &&
1810
-			$this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1811
-	}
1812
-
1813
-	/**
1814
-	 * Copied from \OC_Util::isSharingDisabledForUser
1815
-	 *
1816
-	 * TODO: Deprecate fuction from OC_Util
1817
-	 *
1818
-	 * @param string $userId
1819
-	 * @return bool
1820
-	 */
1821
-	public function sharingDisabledForUser($userId) {
1822
-		if ($userId === null) {
1823
-			return false;
1824
-		}
1825
-
1826
-		if (isset($this->sharingDisabledForUsersCache[$userId])) {
1827
-			return $this->sharingDisabledForUsersCache[$userId];
1828
-		}
1829
-
1830
-		if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1831
-			$groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1832
-			$excludedGroups = json_decode($groupsList);
1833
-			if (is_null($excludedGroups)) {
1834
-				$excludedGroups = explode(',', $groupsList);
1835
-				$newValue = json_encode($excludedGroups);
1836
-				$this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1837
-			}
1838
-			$user = $this->userManager->get($userId);
1839
-			$usersGroups = $this->groupManager->getUserGroupIds($user);
1840
-			if (!empty($usersGroups)) {
1841
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
1842
-				// if the user is only in groups which are disabled for sharing then
1843
-				// sharing is also disabled for the user
1844
-				if (empty($remainingGroups)) {
1845
-					$this->sharingDisabledForUsersCache[$userId] = true;
1846
-					return true;
1847
-				}
1848
-			}
1849
-		}
1850
-
1851
-		$this->sharingDisabledForUsersCache[$userId] = false;
1852
-		return false;
1853
-	}
1854
-
1855
-	/**
1856
-	 * @inheritdoc
1857
-	 */
1858
-	public function outgoingServer2ServerSharesAllowed() {
1859
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1860
-	}
1861
-
1862
-	/**
1863
-	 * @inheritdoc
1864
-	 */
1865
-	public function outgoingServer2ServerGroupSharesAllowed() {
1866
-		return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1867
-	}
1868
-
1869
-	/**
1870
-	 * @inheritdoc
1871
-	 */
1872
-	public function shareProviderExists($shareType) {
1873
-		try {
1874
-			$this->factory->getProviderForType($shareType);
1875
-		} catch (ProviderException $e) {
1876
-			return false;
1877
-		}
1878
-
1879
-		return true;
1880
-	}
1881
-
1882
-	public function getAllShares(): iterable {
1883
-		$providers = $this->factory->getAllProviders();
1884
-
1885
-		foreach ($providers as $provider) {
1886
-			yield from $provider->getAllShares();
1887
-		}
1888
-	}
1464
+        if ($share->getShareType() === IShare::TYPE_LINK &&
1465
+            !$this->shareApiLinkAllowPublicUpload()) {
1466
+            $share->setPermissions($share->getPermissions() & ~(\OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE));
1467
+        }
1468
+
1469
+        return $share;
1470
+    }
1471
+
1472
+    protected function checkExpireDate($share) {
1473
+        if ($share->isExpired()) {
1474
+            $this->deleteShare($share);
1475
+            throw new ShareNotFound($this->l->t('The requested share does not exist anymore'));
1476
+        }
1477
+    }
1478
+
1479
+    /**
1480
+     * Verify the password of a public share
1481
+     *
1482
+     * @param IShare $share
1483
+     * @param string $password
1484
+     * @return bool
1485
+     */
1486
+    public function checkPassword(IShare $share, $password) {
1487
+        $passwordProtected = $share->getShareType() !== IShare::TYPE_LINK
1488
+                             || $share->getShareType() !== IShare::TYPE_EMAIL
1489
+                             || $share->getShareType() !== IShare::TYPE_CIRCLE;
1490
+        if (!$passwordProtected) {
1491
+            //TODO maybe exception?
1492
+            return false;
1493
+        }
1494
+
1495
+        if ($password === null || $share->getPassword() === null) {
1496
+            return false;
1497
+        }
1498
+
1499
+        $newHash = '';
1500
+        if (!$this->hasher->verify($password, $share->getPassword(), $newHash)) {
1501
+            return false;
1502
+        }
1503
+
1504
+        if (!empty($newHash)) {
1505
+            $share->setPassword($newHash);
1506
+            $provider = $this->factory->getProviderForType($share->getShareType());
1507
+            $provider->update($share);
1508
+        }
1509
+
1510
+        return true;
1511
+    }
1512
+
1513
+    /**
1514
+     * @inheritdoc
1515
+     */
1516
+    public function userDeleted($uid) {
1517
+        $types = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK, IShare::TYPE_REMOTE, IShare::TYPE_EMAIL];
1518
+
1519
+        foreach ($types as $type) {
1520
+            try {
1521
+                $provider = $this->factory->getProviderForType($type);
1522
+            } catch (ProviderException $e) {
1523
+                continue;
1524
+            }
1525
+            $provider->userDeleted($uid, $type);
1526
+        }
1527
+    }
1528
+
1529
+    /**
1530
+     * @inheritdoc
1531
+     */
1532
+    public function groupDeleted($gid) {
1533
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1534
+        $provider->groupDeleted($gid);
1535
+
1536
+        $excludedGroups = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1537
+        if ($excludedGroups === '') {
1538
+            return;
1539
+        }
1540
+
1541
+        $excludedGroups = json_decode($excludedGroups, true);
1542
+        if (json_last_error() !== JSON_ERROR_NONE) {
1543
+            return;
1544
+        }
1545
+
1546
+        $excludedGroups = array_diff($excludedGroups, [$gid]);
1547
+        $this->config->setAppValue('core', 'shareapi_exclude_groups_list', json_encode($excludedGroups));
1548
+    }
1549
+
1550
+    /**
1551
+     * @inheritdoc
1552
+     */
1553
+    public function userDeletedFromGroup($uid, $gid) {
1554
+        $provider = $this->factory->getProviderForType(IShare::TYPE_GROUP);
1555
+        $provider->userDeletedFromGroup($uid, $gid);
1556
+    }
1557
+
1558
+    /**
1559
+     * Get access list to a path. This means
1560
+     * all the users that can access a given path.
1561
+     *
1562
+     * Consider:
1563
+     * -root
1564
+     * |-folder1 (23)
1565
+     *  |-folder2 (32)
1566
+     *   |-fileA (42)
1567
+     *
1568
+     * fileA is shared with user1 and user1@server1
1569
+     * folder2 is shared with group2 (user4 is a member of group2)
1570
+     * folder1 is shared with user2 (renamed to "folder (1)") and user2@server2
1571
+     *
1572
+     * Then the access list to '/folder1/folder2/fileA' with $currentAccess is:
1573
+     * [
1574
+     *  users  => [
1575
+     *      'user1' => ['node_id' => 42, 'node_path' => '/fileA'],
1576
+     *      'user4' => ['node_id' => 32, 'node_path' => '/folder2'],
1577
+     *      'user2' => ['node_id' => 23, 'node_path' => '/folder (1)'],
1578
+     *  ],
1579
+     *  remote => [
1580
+     *      'user1@server1' => ['node_id' => 42, 'token' => 'SeCr3t'],
1581
+     *      'user2@server2' => ['node_id' => 23, 'token' => 'FooBaR'],
1582
+     *  ],
1583
+     *  public => bool
1584
+     *  mail => bool
1585
+     * ]
1586
+     *
1587
+     * The access list to '/folder1/folder2/fileA' **without** $currentAccess is:
1588
+     * [
1589
+     *  users  => ['user1', 'user2', 'user4'],
1590
+     *  remote => bool,
1591
+     *  public => bool
1592
+     *  mail => bool
1593
+     * ]
1594
+     *
1595
+     * This is required for encryption/activity
1596
+     *
1597
+     * @param \OCP\Files\Node $path
1598
+     * @param bool $recursive Should we check all parent folders as well
1599
+     * @param bool $currentAccess Ensure the recipient has access to the file (e.g. did not unshare it)
1600
+     * @return array
1601
+     */
1602
+    public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
1603
+        $owner = $path->getOwner();
1604
+
1605
+        if ($owner === null) {
1606
+            return [];
1607
+        }
1608
+
1609
+        $owner = $owner->getUID();
1610
+
1611
+        if ($currentAccess) {
1612
+            $al = ['users' => [], 'remote' => [], 'public' => false];
1613
+        } else {
1614
+            $al = ['users' => [], 'remote' => false, 'public' => false];
1615
+        }
1616
+        if (!$this->userManager->userExists($owner)) {
1617
+            return $al;
1618
+        }
1619
+
1620
+        //Get node for the owner and correct the owner in case of external storages
1621
+        $userFolder = $this->rootFolder->getUserFolder($owner);
1622
+        if ($path->getId() !== $userFolder->getId() && !$userFolder->isSubNode($path)) {
1623
+            $nodes = $userFolder->getById($path->getId());
1624
+            $path = array_shift($nodes);
1625
+            if ($path->getOwner() === null) {
1626
+                return [];
1627
+            }
1628
+            $owner = $path->getOwner()->getUID();
1629
+        }
1630
+
1631
+        $providers = $this->factory->getAllProviders();
1632
+
1633
+        /** @var Node[] $nodes */
1634
+        $nodes = [];
1635
+
1636
+
1637
+        if ($currentAccess) {
1638
+            $ownerPath = $path->getPath();
1639
+            $ownerPath = explode('/', $ownerPath, 4);
1640
+            if (count($ownerPath) < 4) {
1641
+                $ownerPath = '';
1642
+            } else {
1643
+                $ownerPath = $ownerPath[3];
1644
+            }
1645
+            $al['users'][$owner] = [
1646
+                'node_id' => $path->getId(),
1647
+                'node_path' => '/' . $ownerPath,
1648
+            ];
1649
+        } else {
1650
+            $al['users'][] = $owner;
1651
+        }
1652
+
1653
+        // Collect all the shares
1654
+        while ($path->getPath() !== $userFolder->getPath()) {
1655
+            $nodes[] = $path;
1656
+            if (!$recursive) {
1657
+                break;
1658
+            }
1659
+            $path = $path->getParent();
1660
+        }
1661
+
1662
+        foreach ($providers as $provider) {
1663
+            $tmp = $provider->getAccessList($nodes, $currentAccess);
1664
+
1665
+            foreach ($tmp as $k => $v) {
1666
+                if (isset($al[$k])) {
1667
+                    if (is_array($al[$k])) {
1668
+                        if ($currentAccess) {
1669
+                            $al[$k] += $v;
1670
+                        } else {
1671
+                            $al[$k] = array_merge($al[$k], $v);
1672
+                            $al[$k] = array_unique($al[$k]);
1673
+                            $al[$k] = array_values($al[$k]);
1674
+                        }
1675
+                    } else {
1676
+                        $al[$k] = $al[$k] || $v;
1677
+                    }
1678
+                } else {
1679
+                    $al[$k] = $v;
1680
+                }
1681
+            }
1682
+        }
1683
+
1684
+        return $al;
1685
+    }
1686
+
1687
+    /**
1688
+     * Create a new share
1689
+     *
1690
+     * @return IShare
1691
+     */
1692
+    public function newShare() {
1693
+        return new \OC\Share20\Share($this->rootFolder, $this->userManager);
1694
+    }
1695
+
1696
+    /**
1697
+     * Is the share API enabled
1698
+     *
1699
+     * @return bool
1700
+     */
1701
+    public function shareApiEnabled() {
1702
+        return $this->config->getAppValue('core', 'shareapi_enabled', 'yes') === 'yes';
1703
+    }
1704
+
1705
+    /**
1706
+     * Is public link sharing enabled
1707
+     *
1708
+     * @return bool
1709
+     */
1710
+    public function shareApiAllowLinks() {
1711
+        return $this->config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes';
1712
+    }
1713
+
1714
+    /**
1715
+     * Is password on public link requires
1716
+     *
1717
+     * @return bool
1718
+     */
1719
+    public function shareApiLinkEnforcePassword() {
1720
+        return $this->config->getAppValue('core', 'shareapi_enforce_links_password', 'no') === 'yes';
1721
+    }
1722
+
1723
+    /**
1724
+     * Is default link expire date enabled
1725
+     *
1726
+     * @return bool
1727
+     */
1728
+    public function shareApiLinkDefaultExpireDate() {
1729
+        return $this->config->getAppValue('core', 'shareapi_default_expire_date', 'no') === 'yes';
1730
+    }
1731
+
1732
+    /**
1733
+     * Is default link expire date enforced
1734
+     *`
1735
+     * @return bool
1736
+     */
1737
+    public function shareApiLinkDefaultExpireDateEnforced() {
1738
+        return $this->shareApiLinkDefaultExpireDate() &&
1739
+            $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
1740
+    }
1741
+
1742
+
1743
+    /**
1744
+     * Number of default link expire days
1745
+     * @return int
1746
+     */
1747
+    public function shareApiLinkDefaultExpireDays() {
1748
+        return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1749
+    }
1750
+
1751
+    /**
1752
+     * Is default internal expire date enabled
1753
+     *
1754
+     * @return bool
1755
+     */
1756
+    public function shareApiInternalDefaultExpireDate(): bool {
1757
+        return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
1758
+    }
1759
+
1760
+    /**
1761
+     * Is default expire date enforced
1762
+     *`
1763
+     * @return bool
1764
+     */
1765
+    public function shareApiInternalDefaultExpireDateEnforced(): bool {
1766
+        return $this->shareApiInternalDefaultExpireDate() &&
1767
+            $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
1768
+    }
1769
+
1770
+
1771
+    /**
1772
+     * Number of default expire days
1773
+     * @return int
1774
+     */
1775
+    public function shareApiInternalDefaultExpireDays(): int {
1776
+        return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1777
+    }
1778
+
1779
+    /**
1780
+     * Allow public upload on link shares
1781
+     *
1782
+     * @return bool
1783
+     */
1784
+    public function shareApiLinkAllowPublicUpload() {
1785
+        return $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
1786
+    }
1787
+
1788
+    /**
1789
+     * check if user can only share with group members
1790
+     * @return bool
1791
+     */
1792
+    public function shareWithGroupMembersOnly() {
1793
+        return $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
1794
+    }
1795
+
1796
+    /**
1797
+     * Check if users can share with groups
1798
+     * @return bool
1799
+     */
1800
+    public function allowGroupSharing() {
1801
+        return $this->config->getAppValue('core', 'shareapi_allow_group_sharing', 'yes') === 'yes';
1802
+    }
1803
+
1804
+    public function allowEnumeration(): bool {
1805
+        return $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
1806
+    }
1807
+
1808
+    public function limitEnumerationToGroups(): bool {
1809
+        return $this->allowEnumeration() &&
1810
+            $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
1811
+    }
1812
+
1813
+    /**
1814
+     * Copied from \OC_Util::isSharingDisabledForUser
1815
+     *
1816
+     * TODO: Deprecate fuction from OC_Util
1817
+     *
1818
+     * @param string $userId
1819
+     * @return bool
1820
+     */
1821
+    public function sharingDisabledForUser($userId) {
1822
+        if ($userId === null) {
1823
+            return false;
1824
+        }
1825
+
1826
+        if (isset($this->sharingDisabledForUsersCache[$userId])) {
1827
+            return $this->sharingDisabledForUsersCache[$userId];
1828
+        }
1829
+
1830
+        if ($this->config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
1831
+            $groupsList = $this->config->getAppValue('core', 'shareapi_exclude_groups_list', '');
1832
+            $excludedGroups = json_decode($groupsList);
1833
+            if (is_null($excludedGroups)) {
1834
+                $excludedGroups = explode(',', $groupsList);
1835
+                $newValue = json_encode($excludedGroups);
1836
+                $this->config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
1837
+            }
1838
+            $user = $this->userManager->get($userId);
1839
+            $usersGroups = $this->groupManager->getUserGroupIds($user);
1840
+            if (!empty($usersGroups)) {
1841
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
1842
+                // if the user is only in groups which are disabled for sharing then
1843
+                // sharing is also disabled for the user
1844
+                if (empty($remainingGroups)) {
1845
+                    $this->sharingDisabledForUsersCache[$userId] = true;
1846
+                    return true;
1847
+                }
1848
+            }
1849
+        }
1850
+
1851
+        $this->sharingDisabledForUsersCache[$userId] = false;
1852
+        return false;
1853
+    }
1854
+
1855
+    /**
1856
+     * @inheritdoc
1857
+     */
1858
+    public function outgoingServer2ServerSharesAllowed() {
1859
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
1860
+    }
1861
+
1862
+    /**
1863
+     * @inheritdoc
1864
+     */
1865
+    public function outgoingServer2ServerGroupSharesAllowed() {
1866
+        return $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no') === 'yes';
1867
+    }
1868
+
1869
+    /**
1870
+     * @inheritdoc
1871
+     */
1872
+    public function shareProviderExists($shareType) {
1873
+        try {
1874
+            $this->factory->getProviderForType($shareType);
1875
+        } catch (ProviderException $e) {
1876
+            return false;
1877
+        }
1878
+
1879
+        return true;
1880
+    }
1881
+
1882
+    public function getAllShares(): iterable {
1883
+        $providers = $this->factory->getAllProviders();
1884
+
1885
+        foreach ($providers as $provider) {
1886
+            yield from $provider->getAllShares();
1887
+        }
1888
+    }
1889 1889
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
 			$userMountPoint = array_shift($userMountPoints);
310 310
 
311 311
 			if ($userMountPoint === null) {
312
-				throw new GenericShareException('Could not get proper user mount for ' . $userMountPointId . '. Failing since else the next calls are called with null');
312
+				throw new GenericShareException('Could not get proper user mount for '.$userMountPointId.'. Failing since else the next calls are called with null');
313 313
 			}
314 314
 
315 315
 			/* Check if this is an incoming share */
@@ -399,9 +399,9 @@  discard block
 block discarded – undo
399 399
 
400 400
 		if ($fullId === null && $expirationDate === null && $this->shareApiInternalDefaultExpireDate()) {
401 401
 			$expirationDate = new \DateTime();
402
-			$expirationDate->setTime(0,0,0);
402
+			$expirationDate->setTime(0, 0, 0);
403 403
 
404
-			$days = (int)$this->config->getAppValue('core', 'internal_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
404
+			$days = (int) $this->config->getAppValue('core', 'internal_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
405 405
 			if ($days > $this->shareApiLinkDefaultExpireDays()) {
406 406
 				$days = $this->shareApiLinkDefaultExpireDays();
407 407
 			}
@@ -416,7 +416,7 @@  discard block
 block discarded – undo
416 416
 
417 417
 			$date = new \DateTime();
418 418
 			$date->setTime(0, 0, 0);
419
-			$date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
419
+			$date->add(new \DateInterval('P'.$this->shareApiInternalDefaultExpireDays().'D'));
420 420
 			if ($date < $expirationDate) {
421 421
 				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
422 422
 				throw new GenericShareException($message, $message, 404);
@@ -475,9 +475,9 @@  discard block
 block discarded – undo
475 475
 
476 476
 		if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
477 477
 			$expirationDate = new \DateTime();
478
-			$expirationDate->setTime(0,0,0);
478
+			$expirationDate->setTime(0, 0, 0);
479 479
 
480
-			$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
480
+			$days = (int) $this->config->getAppValue('core', 'link_defaultExpDays', $this->shareApiLinkDefaultExpireDays());
481 481
 			if ($days > $this->shareApiLinkDefaultExpireDays()) {
482 482
 				$days = $this->shareApiLinkDefaultExpireDays();
483 483
 			}
@@ -492,7 +492,7 @@  discard block
 block discarded – undo
492 492
 
493 493
 			$date = new \DateTime();
494 494
 			$date->setTime(0, 0, 0);
495
-			$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
495
+			$date->add(new \DateInterval('P'.$this->shareApiLinkDefaultExpireDays().'D'));
496 496
 			if ($date < $expirationDate) {
497 497
 				$message = $this->l->t('Can’t set expiration date more than %s days in the future', [$this->shareApiLinkDefaultExpireDays()]);
498 498
 				throw new GenericShareException($message, $message, 404);
@@ -777,7 +777,7 @@  discard block
 block discarded – undo
777 777
 		}
778 778
 
779 779
 		// Generate the target
780
-		$target = $this->config->getSystemValue('share_folder', '/') .'/'. $share->getNode()->getName();
780
+		$target = $this->config->getSystemValue('share_folder', '/').'/'.$share->getNode()->getName();
781 781
 		$target = \OC\Files\Filesystem::normalizePath($target);
782 782
 		$share->setTarget($target);
783 783
 
@@ -822,12 +822,12 @@  discard block
 block discarded – undo
822 822
 							$emailAddress,
823 823
 							$share->getExpirationDate()
824 824
 						);
825
-						$this->logger->debug('Sent share notification to ' . $emailAddress . ' for share with ID ' . $share->getId(), ['app' => 'share']);
825
+						$this->logger->debug('Sent share notification to '.$emailAddress.' for share with ID '.$share->getId(), ['app' => 'share']);
826 826
 					} else {
827
-						$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because email address is not set.', ['app' => 'share']);
827
+						$this->logger->debug('Share notification not sent to '.$share->getSharedWith().' because email address is not set.', ['app' => 'share']);
828 828
 					}
829 829
 				} else {
830
-					$this->logger->debug('Share notification not sent to ' . $share->getSharedWith() . ' because user could not be found.', ['app' => 'share']);
830
+					$this->logger->debug('Share notification not sent to '.$share->getSharedWith().' because user could not be found.', ['app' => 'share']);
831 831
 				}
832 832
 			} else {
833 833
 				$this->logger->debug('Share notification not sent because mailsend is false.', ['app' => 'share']);
@@ -874,7 +874,7 @@  discard block
 block discarded – undo
874 874
 		$text = $l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]);
875 875
 
876 876
 		$emailTemplate->addBodyText(
877
-			htmlspecialchars($text . ' ' . $l->t('Click the button below to open it.')),
877
+			htmlspecialchars($text.' '.$l->t('Click the button below to open it.')),
878 878
 			$text
879 879
 		);
880 880
 		$emailTemplate->addBodyButton(
@@ -900,7 +900,7 @@  discard block
 block discarded – undo
900 900
 		$initiatorEmail = $initiatorUser->getEMailAddress();
901 901
 		if ($initiatorEmail !== null) {
902 902
 			$message->setReplyTo([$initiatorEmail => $initiatorDisplayName]);
903
-			$emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - ' . $this->defaults->getSlogan($l->getLanguageCode()) : ''));
903
+			$emailTemplate->addFooter($instanceName.($this->defaults->getSlogan($l->getLanguageCode()) !== '' ? ' - '.$this->defaults->getSlogan($l->getLanguageCode()) : ''));
904 904
 		} else {
905 905
 			$emailTemplate->addFooter('', $l->getLanguageCode());
906 906
 		}
@@ -909,7 +909,7 @@  discard block
 block discarded – undo
909 909
 		try {
910 910
 			$failedRecipients = $this->mailer->send($message);
911 911
 			if (!empty($failedRecipients)) {
912
-				$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
912
+				$this->logger->error('Share notification mail could not be sent to: '.implode(', ', $failedRecipients));
913 913
 				return;
914 914
 			}
915 915
 		} catch (\Exception $e) {
@@ -1178,7 +1178,7 @@  discard block
 block discarded – undo
1178 1178
 	 * @param string $recipientId
1179 1179
 	 */
1180 1180
 	public function deleteFromSelf(IShare $share, $recipientId) {
1181
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1181
+		list($providerId,) = $this->splitFullId($share->getFullId());
1182 1182
 		$provider = $this->factory->getProvider($providerId);
1183 1183
 
1184 1184
 		$provider->deleteFromSelf($share, $recipientId);
@@ -1187,7 +1187,7 @@  discard block
 block discarded – undo
1187 1187
 	}
1188 1188
 
1189 1189
 	public function restoreShare(IShare $share, string $recipientId): IShare {
1190
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1190
+		list($providerId,) = $this->splitFullId($share->getFullId());
1191 1191
 		$provider = $this->factory->getProvider($providerId);
1192 1192
 
1193 1193
 		return $provider->restore($share, $recipientId);
@@ -1208,7 +1208,7 @@  discard block
 block discarded – undo
1208 1208
 		if ($share->getShareType() === IShare::TYPE_GROUP) {
1209 1209
 			$sharedWith = $this->groupManager->get($share->getSharedWith());
1210 1210
 			if (is_null($sharedWith)) {
1211
-				throw new \InvalidArgumentException('Group "' . $share->getSharedWith() . '" does not exist');
1211
+				throw new \InvalidArgumentException('Group "'.$share->getSharedWith().'" does not exist');
1212 1212
 			}
1213 1213
 			$recipient = $this->userManager->get($recipientId);
1214 1214
 			if (!$sharedWith->inGroup($recipient)) {
@@ -1216,7 +1216,7 @@  discard block
 block discarded – undo
1216 1216
 			}
1217 1217
 		}
1218 1218
 
1219
-		list($providerId, ) = $this->splitFullId($share->getFullId());
1219
+		list($providerId,) = $this->splitFullId($share->getFullId());
1220 1220
 		$provider = $this->factory->getProvider($providerId);
1221 1221
 
1222 1222
 		return $provider->move($share, $recipientId);
@@ -1225,7 +1225,7 @@  discard block
 block discarded – undo
1225 1225
 	public function getSharesInFolder($userId, Folder $node, $reshares = false) {
1226 1226
 		$providers = $this->factory->getAllProviders();
1227 1227
 
1228
-		return array_reduce($providers, function ($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1228
+		return array_reduce($providers, function($shares, IShareProvider $provider) use ($userId, $node, $reshares) {
1229 1229
 			$newShares = $provider->getSharesInFolder($userId, $node, $reshares);
1230 1230
 			foreach ($newShares as $fid => $data) {
1231 1231
 				if (!isset($shares[$fid])) {
@@ -1342,12 +1342,12 @@  discard block
 block discarded – undo
1342 1342
 		$shares = $this->getSharedWith($userId, $shareType, $node, $limit, $offset);
1343 1343
 
1344 1344
 		// Only get deleted shares
1345
-		$shares = array_filter($shares, function (IShare $share) {
1345
+		$shares = array_filter($shares, function(IShare $share) {
1346 1346
 			return $share->getPermissions() === 0;
1347 1347
 		});
1348 1348
 
1349 1349
 		// Only get shares where the owner still exists
1350
-		$shares = array_filter($shares, function (IShare $share) {
1350
+		$shares = array_filter($shares, function(IShare $share) {
1351 1351
 			return $this->userManager->userExists($share->getShareOwner());
1352 1352
 		});
1353 1353
 
@@ -1386,7 +1386,7 @@  discard block
 block discarded – undo
1386 1386
 	 *
1387 1387
 	 * @return Share[]
1388 1388
 	 */
1389
-	public function getSharesByPath(\OCP\Files\Node $path, $page=0, $perPage=50) {
1389
+	public function getSharesByPath(\OCP\Files\Node $path, $page = 0, $perPage = 50) {
1390 1390
 		return [];
1391 1391
 	}
1392 1392
 
@@ -1644,7 +1644,7 @@  discard block
 block discarded – undo
1644 1644
 			}
1645 1645
 			$al['users'][$owner] = [
1646 1646
 				'node_id' => $path->getId(),
1647
-				'node_path' => '/' . $ownerPath,
1647
+				'node_path' => '/'.$ownerPath,
1648 1648
 			];
1649 1649
 		} else {
1650 1650
 			$al['users'][] = $owner;
@@ -1745,7 +1745,7 @@  discard block
 block discarded – undo
1745 1745
 	 * @return int
1746 1746
 	 */
1747 1747
 	public function shareApiLinkDefaultExpireDays() {
1748
-		return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1748
+		return (int) $this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
1749 1749
 	}
1750 1750
 
1751 1751
 	/**
@@ -1773,7 +1773,7 @@  discard block
 block discarded – undo
1773 1773
 	 * @return int
1774 1774
 	 */
1775 1775
 	public function shareApiInternalDefaultExpireDays(): int {
1776
-		return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1776
+		return (int) $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
1777 1777
 	}
1778 1778
 
1779 1779
 	/**
Please login to merge, or discard this patch.