Completed
Pull Request — master (#3770)
by Thomas
38:05 queued 14:21
created
lib/private/Archive/TAR.php 3 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -370,6 +370,7 @@
 block discarded – undo
370 370
 
371 371
 	/**
372 372
 	 * write back temporary files
373
+	 * @param string $path
373 374
 	 */
374 375
 	function writeBack($tmpFile, $path) {
375 376
 		$this->addFile($path, $tmpFile);
Please login to merge, or discard this patch.
Indentation   +331 added lines, -331 removed lines patch added patch discarded remove patch
@@ -36,355 +36,355 @@
 block discarded – undo
36 36
 use Icewind\Streams\CallbackWrapper;
37 37
 
38 38
 class TAR extends Archive {
39
-	const PLAIN = 0;
40
-	const GZIP = 1;
41
-	const BZIP = 2;
39
+    const PLAIN = 0;
40
+    const GZIP = 1;
41
+    const BZIP = 2;
42 42
 
43
-	private $fileList;
44
-	private $cachedHeaders;
43
+    private $fileList;
44
+    private $cachedHeaders;
45 45
 
46
-	/**
47
-	 * @var \Archive_Tar tar
48
-	 */
49
-	private $tar = null;
50
-	private $path;
46
+    /**
47
+     * @var \Archive_Tar tar
48
+     */
49
+    private $tar = null;
50
+    private $path;
51 51
 
52
-	/**
53
-	 * @param string $source
54
-	 */
55
-	function __construct($source) {
56
-		$types = array(null, 'gz', 'bz2');
57
-		$this->path = $source;
58
-		$this->tar = new \Archive_Tar($source, $types[self::getTarType($source)]);
59
-	}
52
+    /**
53
+     * @param string $source
54
+     */
55
+    function __construct($source) {
56
+        $types = array(null, 'gz', 'bz2');
57
+        $this->path = $source;
58
+        $this->tar = new \Archive_Tar($source, $types[self::getTarType($source)]);
59
+    }
60 60
 
61
-	/**
62
-	 * try to detect the type of tar compression
63
-	 *
64
-	 * @param string $file
65
-	 * @return integer
66
-	 */
67
-	static public function getTarType($file) {
68
-		if (strpos($file, '.')) {
69
-			$extension = substr($file, strrpos($file, '.'));
70
-			switch ($extension) {
71
-				case '.gz':
72
-				case '.tgz':
73
-					return self::GZIP;
74
-				case '.bz':
75
-				case '.bz2':
76
-					return self::BZIP;
77
-				case '.tar':
78
-					return self::PLAIN;
79
-				default:
80
-					return self::PLAIN;
81
-			}
82
-		} else {
83
-			return self::PLAIN;
84
-		}
85
-	}
61
+    /**
62
+     * try to detect the type of tar compression
63
+     *
64
+     * @param string $file
65
+     * @return integer
66
+     */
67
+    static public function getTarType($file) {
68
+        if (strpos($file, '.')) {
69
+            $extension = substr($file, strrpos($file, '.'));
70
+            switch ($extension) {
71
+                case '.gz':
72
+                case '.tgz':
73
+                    return self::GZIP;
74
+                case '.bz':
75
+                case '.bz2':
76
+                    return self::BZIP;
77
+                case '.tar':
78
+                    return self::PLAIN;
79
+                default:
80
+                    return self::PLAIN;
81
+            }
82
+        } else {
83
+            return self::PLAIN;
84
+        }
85
+    }
86 86
 
87
-	/**
88
-	 * add an empty folder to the archive
89
-	 *
90
-	 * @param string $path
91
-	 * @return bool
92
-	 */
93
-	function addFolder($path) {
94
-		$tmpBase = \OC::$server->getTempManager()->getTemporaryFolder();
95
-		if (substr($path, -1, 1) != '/') {
96
-			$path .= '/';
97
-		}
98
-		if ($this->fileExists($path)) {
99
-			return false;
100
-		}
101
-		$parts = explode('/', $path);
102
-		$folder = $tmpBase;
103
-		foreach ($parts as $part) {
104
-			$folder .= '/' . $part;
105
-			if (!is_dir($folder)) {
106
-				mkdir($folder);
107
-			}
108
-		}
109
-		$result = $this->tar->addModify(array($tmpBase . $path), '', $tmpBase);
110
-		rmdir($tmpBase . $path);
111
-		$this->fileList = false;
112
-		$this->cachedHeaders = false;
113
-		return $result;
114
-	}
87
+    /**
88
+     * add an empty folder to the archive
89
+     *
90
+     * @param string $path
91
+     * @return bool
92
+     */
93
+    function addFolder($path) {
94
+        $tmpBase = \OC::$server->getTempManager()->getTemporaryFolder();
95
+        if (substr($path, -1, 1) != '/') {
96
+            $path .= '/';
97
+        }
98
+        if ($this->fileExists($path)) {
99
+            return false;
100
+        }
101
+        $parts = explode('/', $path);
102
+        $folder = $tmpBase;
103
+        foreach ($parts as $part) {
104
+            $folder .= '/' . $part;
105
+            if (!is_dir($folder)) {
106
+                mkdir($folder);
107
+            }
108
+        }
109
+        $result = $this->tar->addModify(array($tmpBase . $path), '', $tmpBase);
110
+        rmdir($tmpBase . $path);
111
+        $this->fileList = false;
112
+        $this->cachedHeaders = false;
113
+        return $result;
114
+    }
115 115
 
116
-	/**
117
-	 * add a file to the archive
118
-	 *
119
-	 * @param string $path
120
-	 * @param string $source either a local file or string data
121
-	 * @return bool
122
-	 */
123
-	function addFile($path, $source = '') {
124
-		if ($this->fileExists($path)) {
125
-			$this->remove($path);
126
-		}
127
-		if ($source and $source[0] == '/' and file_exists($source)) {
128
-			$source = file_get_contents($source);
129
-		}
130
-		$result = $this->tar->addString($path, $source);
131
-		$this->fileList = false;
132
-		$this->cachedHeaders = false;
133
-		return $result;
134
-	}
116
+    /**
117
+     * add a file to the archive
118
+     *
119
+     * @param string $path
120
+     * @param string $source either a local file or string data
121
+     * @return bool
122
+     */
123
+    function addFile($path, $source = '') {
124
+        if ($this->fileExists($path)) {
125
+            $this->remove($path);
126
+        }
127
+        if ($source and $source[0] == '/' and file_exists($source)) {
128
+            $source = file_get_contents($source);
129
+        }
130
+        $result = $this->tar->addString($path, $source);
131
+        $this->fileList = false;
132
+        $this->cachedHeaders = false;
133
+        return $result;
134
+    }
135 135
 
136
-	/**
137
-	 * rename a file or folder in the archive
138
-	 *
139
-	 * @param string $source
140
-	 * @param string $dest
141
-	 * @return bool
142
-	 */
143
-	function rename($source, $dest) {
144
-		//no proper way to delete, rename entire archive, rename file and remake archive
145
-		$tmp = \OCP\Files::tmpFolder();
146
-		$this->tar->extract($tmp);
147
-		rename($tmp . $source, $tmp . $dest);
148
-		$this->tar = null;
149
-		unlink($this->path);
150
-		$types = array(null, 'gz', 'bz');
151
-		$this->tar = new \Archive_Tar($this->path, $types[self::getTarType($this->path)]);
152
-		$this->tar->createModify(array($tmp), '', $tmp . '/');
153
-		$this->fileList = false;
154
-		$this->cachedHeaders = false;
155
-		return true;
156
-	}
136
+    /**
137
+     * rename a file or folder in the archive
138
+     *
139
+     * @param string $source
140
+     * @param string $dest
141
+     * @return bool
142
+     */
143
+    function rename($source, $dest) {
144
+        //no proper way to delete, rename entire archive, rename file and remake archive
145
+        $tmp = \OCP\Files::tmpFolder();
146
+        $this->tar->extract($tmp);
147
+        rename($tmp . $source, $tmp . $dest);
148
+        $this->tar = null;
149
+        unlink($this->path);
150
+        $types = array(null, 'gz', 'bz');
151
+        $this->tar = new \Archive_Tar($this->path, $types[self::getTarType($this->path)]);
152
+        $this->tar->createModify(array($tmp), '', $tmp . '/');
153
+        $this->fileList = false;
154
+        $this->cachedHeaders = false;
155
+        return true;
156
+    }
157 157
 
158
-	/**
159
-	 * @param string $file
160
-	 */
161
-	private function getHeader($file) {
162
-		if (!$this->cachedHeaders) {
163
-			$this->cachedHeaders = $this->tar->listContent();
164
-		}
165
-		foreach ($this->cachedHeaders as $header) {
166
-			if ($file == $header['filename']
167
-				or $file . '/' == $header['filename']
168
-				or '/' . $file . '/' == $header['filename']
169
-				or '/' . $file == $header['filename']
170
-			) {
171
-				return $header;
172
-			}
173
-		}
174
-		return null;
175
-	}
158
+    /**
159
+     * @param string $file
160
+     */
161
+    private function getHeader($file) {
162
+        if (!$this->cachedHeaders) {
163
+            $this->cachedHeaders = $this->tar->listContent();
164
+        }
165
+        foreach ($this->cachedHeaders as $header) {
166
+            if ($file == $header['filename']
167
+                or $file . '/' == $header['filename']
168
+                or '/' . $file . '/' == $header['filename']
169
+                or '/' . $file == $header['filename']
170
+            ) {
171
+                return $header;
172
+            }
173
+        }
174
+        return null;
175
+    }
176 176
 
177
-	/**
178
-	 * get the uncompressed size of a file in the archive
179
-	 *
180
-	 * @param string $path
181
-	 * @return int
182
-	 */
183
-	function filesize($path) {
184
-		$stat = $this->getHeader($path);
185
-		return $stat['size'];
186
-	}
177
+    /**
178
+     * get the uncompressed size of a file in the archive
179
+     *
180
+     * @param string $path
181
+     * @return int
182
+     */
183
+    function filesize($path) {
184
+        $stat = $this->getHeader($path);
185
+        return $stat['size'];
186
+    }
187 187
 
188
-	/**
189
-	 * get the last modified time of a file in the archive
190
-	 *
191
-	 * @param string $path
192
-	 * @return int
193
-	 */
194
-	function mtime($path) {
195
-		$stat = $this->getHeader($path);
196
-		return $stat['mtime'];
197
-	}
188
+    /**
189
+     * get the last modified time of a file in the archive
190
+     *
191
+     * @param string $path
192
+     * @return int
193
+     */
194
+    function mtime($path) {
195
+        $stat = $this->getHeader($path);
196
+        return $stat['mtime'];
197
+    }
198 198
 
199
-	/**
200
-	 * get the files in a folder
201
-	 *
202
-	 * @param string $path
203
-	 * @return array
204
-	 */
205
-	function getFolder($path) {
206
-		$files = $this->getFiles();
207
-		$folderContent = array();
208
-		$pathLength = strlen($path);
209
-		foreach ($files as $file) {
210
-			if ($file[0] == '/') {
211
-				$file = substr($file, 1);
212
-			}
213
-			if (substr($file, 0, $pathLength) == $path and $file != $path) {
214
-				$result = substr($file, $pathLength);
215
-				if ($pos = strpos($result, '/')) {
216
-					$result = substr($result, 0, $pos + 1);
217
-				}
218
-				if (array_search($result, $folderContent) === false) {
219
-					$folderContent[] = $result;
220
-				}
221
-			}
222
-		}
223
-		return $folderContent;
224
-	}
199
+    /**
200
+     * get the files in a folder
201
+     *
202
+     * @param string $path
203
+     * @return array
204
+     */
205
+    function getFolder($path) {
206
+        $files = $this->getFiles();
207
+        $folderContent = array();
208
+        $pathLength = strlen($path);
209
+        foreach ($files as $file) {
210
+            if ($file[0] == '/') {
211
+                $file = substr($file, 1);
212
+            }
213
+            if (substr($file, 0, $pathLength) == $path and $file != $path) {
214
+                $result = substr($file, $pathLength);
215
+                if ($pos = strpos($result, '/')) {
216
+                    $result = substr($result, 0, $pos + 1);
217
+                }
218
+                if (array_search($result, $folderContent) === false) {
219
+                    $folderContent[] = $result;
220
+                }
221
+            }
222
+        }
223
+        return $folderContent;
224
+    }
225 225
 
226
-	/**
227
-	 * get all files in the archive
228
-	 *
229
-	 * @return array
230
-	 */
231
-	function getFiles() {
232
-		if ($this->fileList) {
233
-			return $this->fileList;
234
-		}
235
-		if (!$this->cachedHeaders) {
236
-			$this->cachedHeaders = $this->tar->listContent();
237
-		}
238
-		$files = array();
239
-		foreach ($this->cachedHeaders as $header) {
240
-			$files[] = $header['filename'];
241
-		}
242
-		$this->fileList = $files;
243
-		return $files;
244
-	}
226
+    /**
227
+     * get all files in the archive
228
+     *
229
+     * @return array
230
+     */
231
+    function getFiles() {
232
+        if ($this->fileList) {
233
+            return $this->fileList;
234
+        }
235
+        if (!$this->cachedHeaders) {
236
+            $this->cachedHeaders = $this->tar->listContent();
237
+        }
238
+        $files = array();
239
+        foreach ($this->cachedHeaders as $header) {
240
+            $files[] = $header['filename'];
241
+        }
242
+        $this->fileList = $files;
243
+        return $files;
244
+    }
245 245
 
246
-	/**
247
-	 * get the content of a file
248
-	 *
249
-	 * @param string $path
250
-	 * @return string
251
-	 */
252
-	function getFile($path) {
253
-		return $this->tar->extractInString($path);
254
-	}
246
+    /**
247
+     * get the content of a file
248
+     *
249
+     * @param string $path
250
+     * @return string
251
+     */
252
+    function getFile($path) {
253
+        return $this->tar->extractInString($path);
254
+    }
255 255
 
256
-	/**
257
-	 * extract a single file from the archive
258
-	 *
259
-	 * @param string $path
260
-	 * @param string $dest
261
-	 * @return bool
262
-	 */
263
-	function extractFile($path, $dest) {
264
-		$tmp = \OCP\Files::tmpFolder();
265
-		if (!$this->fileExists($path)) {
266
-			return false;
267
-		}
268
-		if ($this->fileExists('/' . $path)) {
269
-			$success = $this->tar->extractList(array('/' . $path), $tmp);
270
-		} else {
271
-			$success = $this->tar->extractList(array($path), $tmp);
272
-		}
273
-		if ($success) {
274
-			rename($tmp . $path, $dest);
275
-		}
276
-		\OCP\Files::rmdirr($tmp);
277
-		return $success;
278
-	}
256
+    /**
257
+     * extract a single file from the archive
258
+     *
259
+     * @param string $path
260
+     * @param string $dest
261
+     * @return bool
262
+     */
263
+    function extractFile($path, $dest) {
264
+        $tmp = \OCP\Files::tmpFolder();
265
+        if (!$this->fileExists($path)) {
266
+            return false;
267
+        }
268
+        if ($this->fileExists('/' . $path)) {
269
+            $success = $this->tar->extractList(array('/' . $path), $tmp);
270
+        } else {
271
+            $success = $this->tar->extractList(array($path), $tmp);
272
+        }
273
+        if ($success) {
274
+            rename($tmp . $path, $dest);
275
+        }
276
+        \OCP\Files::rmdirr($tmp);
277
+        return $success;
278
+    }
279 279
 
280
-	/**
281
-	 * extract the archive
282
-	 *
283
-	 * @param string $dest
284
-	 * @return bool
285
-	 */
286
-	function extract($dest) {
287
-		return $this->tar->extract($dest);
288
-	}
280
+    /**
281
+     * extract the archive
282
+     *
283
+     * @param string $dest
284
+     * @return bool
285
+     */
286
+    function extract($dest) {
287
+        return $this->tar->extract($dest);
288
+    }
289 289
 
290
-	/**
291
-	 * check if a file or folder exists in the archive
292
-	 *
293
-	 * @param string $path
294
-	 * @return bool
295
-	 */
296
-	function fileExists($path) {
297
-		$files = $this->getFiles();
298
-		if ((array_search($path, $files) !== false) or (array_search($path . '/', $files) !== false)) {
299
-			return true;
300
-		} else {
301
-			$folderPath = $path;
302
-			if (substr($folderPath, -1, 1) != '/') {
303
-				$folderPath .= '/';
304
-			}
305
-			$pathLength = strlen($folderPath);
306
-			foreach ($files as $file) {
307
-				if (strlen($file) > $pathLength and substr($file, 0, $pathLength) == $folderPath) {
308
-					return true;
309
-				}
310
-			}
311
-		}
312
-		if ($path[0] != '/') { //not all programs agree on the use of a leading /
313
-			return $this->fileExists('/' . $path);
314
-		} else {
315
-			return false;
316
-		}
317
-	}
290
+    /**
291
+     * check if a file or folder exists in the archive
292
+     *
293
+     * @param string $path
294
+     * @return bool
295
+     */
296
+    function fileExists($path) {
297
+        $files = $this->getFiles();
298
+        if ((array_search($path, $files) !== false) or (array_search($path . '/', $files) !== false)) {
299
+            return true;
300
+        } else {
301
+            $folderPath = $path;
302
+            if (substr($folderPath, -1, 1) != '/') {
303
+                $folderPath .= '/';
304
+            }
305
+            $pathLength = strlen($folderPath);
306
+            foreach ($files as $file) {
307
+                if (strlen($file) > $pathLength and substr($file, 0, $pathLength) == $folderPath) {
308
+                    return true;
309
+                }
310
+            }
311
+        }
312
+        if ($path[0] != '/') { //not all programs agree on the use of a leading /
313
+            return $this->fileExists('/' . $path);
314
+        } else {
315
+            return false;
316
+        }
317
+    }
318 318
 
319
-	/**
320
-	 * remove a file or folder from the archive
321
-	 *
322
-	 * @param string $path
323
-	 * @return bool
324
-	 */
325
-	function remove($path) {
326
-		if (!$this->fileExists($path)) {
327
-			return false;
328
-		}
329
-		$this->fileList = false;
330
-		$this->cachedHeaders = false;
331
-		//no proper way to delete, extract entire archive, delete file and remake archive
332
-		$tmp = \OCP\Files::tmpFolder();
333
-		$this->tar->extract($tmp);
334
-		\OCP\Files::rmdirr($tmp . $path);
335
-		$this->tar = null;
336
-		unlink($this->path);
337
-		$this->reopen();
338
-		$this->tar->createModify(array($tmp), '', $tmp);
339
-		return true;
340
-	}
319
+    /**
320
+     * remove a file or folder from the archive
321
+     *
322
+     * @param string $path
323
+     * @return bool
324
+     */
325
+    function remove($path) {
326
+        if (!$this->fileExists($path)) {
327
+            return false;
328
+        }
329
+        $this->fileList = false;
330
+        $this->cachedHeaders = false;
331
+        //no proper way to delete, extract entire archive, delete file and remake archive
332
+        $tmp = \OCP\Files::tmpFolder();
333
+        $this->tar->extract($tmp);
334
+        \OCP\Files::rmdirr($tmp . $path);
335
+        $this->tar = null;
336
+        unlink($this->path);
337
+        $this->reopen();
338
+        $this->tar->createModify(array($tmp), '', $tmp);
339
+        return true;
340
+    }
341 341
 
342
-	/**
343
-	 * get a file handler
344
-	 *
345
-	 * @param string $path
346
-	 * @param string $mode
347
-	 * @return resource
348
-	 */
349
-	function getStream($path, $mode) {
350
-		if (strrpos($path, '.') !== false) {
351
-			$ext = substr($path, strrpos($path, '.'));
352
-		} else {
353
-			$ext = '';
354
-		}
355
-		$tmpFile = \OCP\Files::tmpFile($ext);
356
-		if ($this->fileExists($path)) {
357
-			$this->extractFile($path, $tmpFile);
358
-		} elseif ($mode == 'r' or $mode == 'rb') {
359
-			return false;
360
-		}
361
-		if ($mode == 'r' or $mode == 'rb') {
362
-			return fopen($tmpFile, $mode);
363
-		} else {
364
-			$handle = fopen($tmpFile, $mode);
365
-			return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
366
-				$this->writeBack($tmpFile, $path);
367
-			});
368
-		}
369
-	}
342
+    /**
343
+     * get a file handler
344
+     *
345
+     * @param string $path
346
+     * @param string $mode
347
+     * @return resource
348
+     */
349
+    function getStream($path, $mode) {
350
+        if (strrpos($path, '.') !== false) {
351
+            $ext = substr($path, strrpos($path, '.'));
352
+        } else {
353
+            $ext = '';
354
+        }
355
+        $tmpFile = \OCP\Files::tmpFile($ext);
356
+        if ($this->fileExists($path)) {
357
+            $this->extractFile($path, $tmpFile);
358
+        } elseif ($mode == 'r' or $mode == 'rb') {
359
+            return false;
360
+        }
361
+        if ($mode == 'r' or $mode == 'rb') {
362
+            return fopen($tmpFile, $mode);
363
+        } else {
364
+            $handle = fopen($tmpFile, $mode);
365
+            return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
366
+                $this->writeBack($tmpFile, $path);
367
+            });
368
+        }
369
+    }
370 370
 
371
-	/**
372
-	 * write back temporary files
373
-	 */
374
-	function writeBack($tmpFile, $path) {
375
-		$this->addFile($path, $tmpFile);
376
-		unlink($tmpFile);
377
-	}
371
+    /**
372
+     * write back temporary files
373
+     */
374
+    function writeBack($tmpFile, $path) {
375
+        $this->addFile($path, $tmpFile);
376
+        unlink($tmpFile);
377
+    }
378 378
 
379
-	/**
380
-	 * reopen the archive to ensure everything is written
381
-	 */
382
-	private function reopen() {
383
-		if ($this->tar) {
384
-			$this->tar->_close();
385
-			$this->tar = null;
386
-		}
387
-		$types = array(null, 'gz', 'bz');
388
-		$this->tar = new \Archive_Tar($this->path, $types[self::getTarType($this->path)]);
389
-	}
379
+    /**
380
+     * reopen the archive to ensure everything is written
381
+     */
382
+    private function reopen() {
383
+        if ($this->tar) {
384
+            $this->tar->_close();
385
+            $this->tar = null;
386
+        }
387
+        $types = array(null, 'gz', 'bz');
388
+        $this->tar = new \Archive_Tar($this->path, $types[self::getTarType($this->path)]);
389
+    }
390 390
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -101,13 +101,13 @@  discard block
 block discarded – undo
101 101
 		$parts = explode('/', $path);
102 102
 		$folder = $tmpBase;
103 103
 		foreach ($parts as $part) {
104
-			$folder .= '/' . $part;
104
+			$folder .= '/'.$part;
105 105
 			if (!is_dir($folder)) {
106 106
 				mkdir($folder);
107 107
 			}
108 108
 		}
109
-		$result = $this->tar->addModify(array($tmpBase . $path), '', $tmpBase);
110
-		rmdir($tmpBase . $path);
109
+		$result = $this->tar->addModify(array($tmpBase.$path), '', $tmpBase);
110
+		rmdir($tmpBase.$path);
111 111
 		$this->fileList = false;
112 112
 		$this->cachedHeaders = false;
113 113
 		return $result;
@@ -144,12 +144,12 @@  discard block
 block discarded – undo
144 144
 		//no proper way to delete, rename entire archive, rename file and remake archive
145 145
 		$tmp = \OCP\Files::tmpFolder();
146 146
 		$this->tar->extract($tmp);
147
-		rename($tmp . $source, $tmp . $dest);
147
+		rename($tmp.$source, $tmp.$dest);
148 148
 		$this->tar = null;
149 149
 		unlink($this->path);
150 150
 		$types = array(null, 'gz', 'bz');
151 151
 		$this->tar = new \Archive_Tar($this->path, $types[self::getTarType($this->path)]);
152
-		$this->tar->createModify(array($tmp), '', $tmp . '/');
152
+		$this->tar->createModify(array($tmp), '', $tmp.'/');
153 153
 		$this->fileList = false;
154 154
 		$this->cachedHeaders = false;
155 155
 		return true;
@@ -164,9 +164,9 @@  discard block
 block discarded – undo
164 164
 		}
165 165
 		foreach ($this->cachedHeaders as $header) {
166 166
 			if ($file == $header['filename']
167
-				or $file . '/' == $header['filename']
168
-				or '/' . $file . '/' == $header['filename']
169
-				or '/' . $file == $header['filename']
167
+				or $file.'/' == $header['filename']
168
+				or '/'.$file.'/' == $header['filename']
169
+				or '/'.$file == $header['filename']
170 170
 			) {
171 171
 				return $header;
172 172
 			}
@@ -265,13 +265,13 @@  discard block
 block discarded – undo
265 265
 		if (!$this->fileExists($path)) {
266 266
 			return false;
267 267
 		}
268
-		if ($this->fileExists('/' . $path)) {
269
-			$success = $this->tar->extractList(array('/' . $path), $tmp);
268
+		if ($this->fileExists('/'.$path)) {
269
+			$success = $this->tar->extractList(array('/'.$path), $tmp);
270 270
 		} else {
271 271
 			$success = $this->tar->extractList(array($path), $tmp);
272 272
 		}
273 273
 		if ($success) {
274
-			rename($tmp . $path, $dest);
274
+			rename($tmp.$path, $dest);
275 275
 		}
276 276
 		\OCP\Files::rmdirr($tmp);
277 277
 		return $success;
@@ -295,7 +295,7 @@  discard block
 block discarded – undo
295 295
 	 */
296 296
 	function fileExists($path) {
297 297
 		$files = $this->getFiles();
298
-		if ((array_search($path, $files) !== false) or (array_search($path . '/', $files) !== false)) {
298
+		if ((array_search($path, $files) !== false) or (array_search($path.'/', $files) !== false)) {
299 299
 			return true;
300 300
 		} else {
301 301
 			$folderPath = $path;
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
 			}
311 311
 		}
312 312
 		if ($path[0] != '/') { //not all programs agree on the use of a leading /
313
-			return $this->fileExists('/' . $path);
313
+			return $this->fileExists('/'.$path);
314 314
 		} else {
315 315
 			return false;
316 316
 		}
@@ -331,7 +331,7 @@  discard block
 block discarded – undo
331 331
 		//no proper way to delete, extract entire archive, delete file and remake archive
332 332
 		$tmp = \OCP\Files::tmpFolder();
333 333
 		$this->tar->extract($tmp);
334
-		\OCP\Files::rmdirr($tmp . $path);
334
+		\OCP\Files::rmdirr($tmp.$path);
335 335
 		$this->tar = null;
336 336
 		unlink($this->path);
337 337
 		$this->reopen();
@@ -362,7 +362,7 @@  discard block
 block discarded – undo
362 362
 			return fopen($tmpFile, $mode);
363 363
 		} else {
364 364
 			$handle = fopen($tmpFile, $mode);
365
-			return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
365
+			return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
366 366
 				$this->writeBack($tmpFile, $path);
367 367
 			});
368 368
 		}
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/ObjectStoreStorage.php 3 patches
Doc Comments   +6 added lines patch added patch discarded remove patch
@@ -162,6 +162,9 @@  discard block
 block discarded – undo
162 162
 		return true;
163 163
 	}
164 164
 
165
+	/**
166
+	 * @param string $path
167
+	 */
165 168
 	private function rmObjects($path) {
166 169
 		$children = $this->getCache()->getFolderContents($path);
167 170
 		foreach ($children as $child) {
@@ -364,6 +367,9 @@  discard block
 block discarded – undo
364 367
 		return true;
365 368
 	}
366 369
 
370
+	/**
371
+	 * @param string $path
372
+	 */
367 373
 	public function writeBack($tmpFile, $path) {
368 374
 		$stat = $this->stat($path);
369 375
 		if (empty($stat)) {
Please login to merge, or discard this patch.
Indentation   +370 added lines, -370 removed lines patch added patch discarded remove patch
@@ -31,374 +31,374 @@
 block discarded – undo
31 31
 use OCP\Files\ObjectStore\IObjectStore;
32 32
 
33 33
 class ObjectStoreStorage extends \OC\Files\Storage\Common {
34
-	/**
35
-	 * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
36
-	 */
37
-	protected $objectStore;
38
-	/**
39
-	 * @var string $id
40
-	 */
41
-	protected $id;
42
-	/**
43
-	 * @var \OC\User\User $user
44
-	 */
45
-	protected $user;
46
-
47
-	private $objectPrefix = 'urn:oid:';
48
-
49
-	public function __construct($params) {
50
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
51
-			$this->objectStore = $params['objectstore'];
52
-		} else {
53
-			throw new \Exception('missing IObjectStore instance');
54
-		}
55
-		if (isset($params['storageid'])) {
56
-			$this->id = 'object::store:' . $params['storageid'];
57
-		} else {
58
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
59
-		}
60
-		if (isset($params['objectPrefix'])) {
61
-			$this->objectPrefix = $params['objectPrefix'];
62
-		}
63
-		//initialize cache with root directory in cache
64
-		if (!$this->is_dir('/')) {
65
-			$this->mkdir('/');
66
-		}
67
-	}
68
-
69
-	public function mkdir($path) {
70
-		$path = $this->normalizePath($path);
71
-
72
-		if ($this->file_exists($path)) {
73
-			return false;
74
-		}
75
-
76
-		$mTime = time();
77
-		$data = [
78
-			'mimetype' => 'httpd/unix-directory',
79
-			'size' => 0,
80
-			'mtime' => $mTime,
81
-			'storage_mtime' => $mTime,
82
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
83
-		];
84
-		if ($path === '') {
85
-			//create root on the fly
86
-			$data['etag'] = $this->getETag('');
87
-			$this->getCache()->put('', $data);
88
-			return true;
89
-		} else {
90
-			// if parent does not exist, create it
91
-			$parent = $this->normalizePath(dirname($path));
92
-			$parentType = $this->filetype($parent);
93
-			if ($parentType === false) {
94
-				if (!$this->mkdir($parent)) {
95
-					// something went wrong
96
-					return false;
97
-				}
98
-			} else if ($parentType === 'file') {
99
-				// parent is a file
100
-				return false;
101
-			}
102
-			// finally create the new dir
103
-			$mTime = time(); // update mtime
104
-			$data['mtime'] = $mTime;
105
-			$data['storage_mtime'] = $mTime;
106
-			$data['etag'] = $this->getETag($path);
107
-			$this->getCache()->put($path, $data);
108
-			return true;
109
-		}
110
-	}
111
-
112
-	/**
113
-	 * @param string $path
114
-	 * @return string
115
-	 */
116
-	private function normalizePath($path) {
117
-		$path = trim($path, '/');
118
-		//FIXME why do we sometimes get a path like 'files//username'?
119
-		$path = str_replace('//', '/', $path);
120
-
121
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
122
-		if (!$path || $path === '.') {
123
-			$path = '';
124
-		}
125
-
126
-		return $path;
127
-	}
128
-
129
-	/**
130
-	 * Object Stores use a NoopScanner because metadata is directly stored in
131
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
132
-	 *
133
-	 * @param string $path
134
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
135
-	 * @return \OC\Files\ObjectStore\NoopScanner
136
-	 */
137
-	public function getScanner($path = '', $storage = null) {
138
-		if (!$storage) {
139
-			$storage = $this;
140
-		}
141
-		if (!isset($this->scanner)) {
142
-			$this->scanner = new NoopScanner($storage);
143
-		}
144
-		return $this->scanner;
145
-	}
146
-
147
-	public function getId() {
148
-		return $this->id;
149
-	}
150
-
151
-	public function rmdir($path) {
152
-		$path = $this->normalizePath($path);
153
-
154
-		if (!$this->is_dir($path)) {
155
-			return false;
156
-		}
157
-
158
-		$this->rmObjects($path);
159
-
160
-		$this->getCache()->remove($path);
161
-
162
-		return true;
163
-	}
164
-
165
-	private function rmObjects($path) {
166
-		$children = $this->getCache()->getFolderContents($path);
167
-		foreach ($children as $child) {
168
-			if ($child['mimetype'] === 'httpd/unix-directory') {
169
-				$this->rmObjects($child['path']);
170
-			} else {
171
-				$this->unlink($child['path']);
172
-			}
173
-		}
174
-	}
175
-
176
-	public function unlink($path) {
177
-		$path = $this->normalizePath($path);
178
-		$stat = $this->stat($path);
179
-
180
-		if ($stat && isset($stat['fileid'])) {
181
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
182
-				return $this->rmdir($path);
183
-			}
184
-			try {
185
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
186
-			} catch (\Exception $ex) {
187
-				if ($ex->getCode() !== 404) {
188
-					\OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
189
-					return false;
190
-				} else {
191
-					//removing from cache is ok as it does not exist in the objectstore anyway
192
-				}
193
-			}
194
-			$this->getCache()->remove($path);
195
-			return true;
196
-		}
197
-		return false;
198
-	}
199
-
200
-	public function stat($path) {
201
-		$path = $this->normalizePath($path);
202
-		$cacheEntry = $this->getCache()->get($path);
203
-		if ($cacheEntry instanceof CacheEntry) {
204
-			return $cacheEntry->getData();
205
-		} else {
206
-			return false;
207
-		}
208
-	}
209
-
210
-	/**
211
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
212
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
213
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
214
-	 *
215
-	 * @param int $fileId the fileid
216
-	 * @return null|string the unified resource name used to identify the object
217
-	 */
218
-	protected function getURN($fileId) {
219
-		if (is_numeric($fileId)) {
220
-			return $this->objectPrefix . $fileId;
221
-		}
222
-		return null;
223
-	}
224
-
225
-	public function opendir($path) {
226
-		$path = $this->normalizePath($path);
227
-
228
-		try {
229
-			$files = array();
230
-			$folderContents = $this->getCache()->getFolderContents($path);
231
-			foreach ($folderContents as $file) {
232
-				$files[] = $file['name'];
233
-			}
234
-
235
-			return IteratorDirectory::wrap($files);
236
-		} catch (\Exception $e) {
237
-			\OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
238
-			return false;
239
-		}
240
-	}
241
-
242
-	public function filetype($path) {
243
-		$path = $this->normalizePath($path);
244
-		$stat = $this->stat($path);
245
-		if ($stat) {
246
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
247
-				return 'dir';
248
-			}
249
-			return 'file';
250
-		} else {
251
-			return false;
252
-		}
253
-	}
254
-
255
-	public function fopen($path, $mode) {
256
-		$path = $this->normalizePath($path);
257
-
258
-		switch ($mode) {
259
-			case 'r':
260
-			case 'rb':
261
-				$stat = $this->stat($path);
262
-				if (is_array($stat)) {
263
-					try {
264
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
265
-					} catch (\Exception $ex) {
266
-						\OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
267
-						return false;
268
-					}
269
-				} else {
270
-					return false;
271
-				}
272
-			case 'w':
273
-			case 'wb':
274
-			case 'a':
275
-			case 'ab':
276
-			case 'r+':
277
-			case 'w+':
278
-			case 'wb+':
279
-			case 'a+':
280
-			case 'x':
281
-			case 'x+':
282
-			case 'c':
283
-			case 'c+':
284
-				if (strrpos($path, '.') !== false) {
285
-					$ext = substr($path, strrpos($path, '.'));
286
-				} else {
287
-					$ext = '';
288
-				}
289
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
290
-				if ($this->file_exists($path)) {
291
-					$source = $this->fopen($path, 'r');
292
-					file_put_contents($tmpFile, $source);
293
-				}
294
-				$handle = fopen($tmpFile, $mode);
295
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
296
-					$this->writeBack($tmpFile, $path);
297
-				});
298
-		}
299
-		return false;
300
-	}
301
-
302
-	public function file_exists($path) {
303
-		$path = $this->normalizePath($path);
304
-		return (bool)$this->stat($path);
305
-	}
306
-
307
-	public function rename($source, $target) {
308
-		$source = $this->normalizePath($source);
309
-		$target = $this->normalizePath($target);
310
-		$this->remove($target);
311
-		$this->getCache()->move($source, $target);
312
-		$this->touch(dirname($target));
313
-		return true;
314
-	}
315
-
316
-	public function getMimeType($path) {
317
-		$path = $this->normalizePath($path);
318
-		$stat = $this->stat($path);
319
-		if (is_array($stat)) {
320
-			return $stat['mimetype'];
321
-		} else {
322
-			return false;
323
-		}
324
-	}
325
-
326
-	public function touch($path, $mtime = null) {
327
-		if (is_null($mtime)) {
328
-			$mtime = time();
329
-		}
330
-
331
-		$path = $this->normalizePath($path);
332
-		$dirName = dirname($path);
333
-		$parentExists = $this->is_dir($dirName);
334
-		if (!$parentExists) {
335
-			return false;
336
-		}
337
-
338
-		$stat = $this->stat($path);
339
-		if (is_array($stat)) {
340
-			// update existing mtime in db
341
-			$stat['mtime'] = $mtime;
342
-			$this->getCache()->update($stat['fileid'], $stat);
343
-		} else {
344
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
345
-			// create new file
346
-			$stat = array(
347
-				'etag' => $this->getETag($path),
348
-				'mimetype' => $mimeType,
349
-				'size' => 0,
350
-				'mtime' => $mtime,
351
-				'storage_mtime' => $mtime,
352
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
353
-			);
354
-			$fileId = $this->getCache()->put($path, $stat);
355
-			try {
356
-				//read an empty file from memory
357
-				$this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
358
-			} catch (\Exception $ex) {
359
-				$this->getCache()->remove($path);
360
-				\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
361
-				return false;
362
-			}
363
-		}
364
-		return true;
365
-	}
366
-
367
-	public function writeBack($tmpFile, $path) {
368
-		$stat = $this->stat($path);
369
-		if (empty($stat)) {
370
-			// create new file
371
-			$stat = array(
372
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
373
-			);
374
-		}
375
-		// update stat with new data
376
-		$mTime = time();
377
-		$stat['size'] = filesize($tmpFile);
378
-		$stat['mtime'] = $mTime;
379
-		$stat['storage_mtime'] = $mTime;
380
-		$stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
381
-		$stat['etag'] = $this->getETag($path);
382
-
383
-		$fileId = $this->getCache()->put($path, $stat);
384
-		try {
385
-			//upload to object storage
386
-			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
387
-		} catch (\Exception $ex) {
388
-			$this->getCache()->remove($path);
389
-			\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
390
-			throw $ex; // make this bubble up
391
-		}
392
-	}
393
-
394
-	/**
395
-	 * external changes are not supported, exclusive access to the object storage is assumed
396
-	 *
397
-	 * @param string $path
398
-	 * @param int $time
399
-	 * @return false
400
-	 */
401
-	public function hasUpdated($path, $time) {
402
-		return false;
403
-	}
34
+    /**
35
+     * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
36
+     */
37
+    protected $objectStore;
38
+    /**
39
+     * @var string $id
40
+     */
41
+    protected $id;
42
+    /**
43
+     * @var \OC\User\User $user
44
+     */
45
+    protected $user;
46
+
47
+    private $objectPrefix = 'urn:oid:';
48
+
49
+    public function __construct($params) {
50
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
51
+            $this->objectStore = $params['objectstore'];
52
+        } else {
53
+            throw new \Exception('missing IObjectStore instance');
54
+        }
55
+        if (isset($params['storageid'])) {
56
+            $this->id = 'object::store:' . $params['storageid'];
57
+        } else {
58
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
59
+        }
60
+        if (isset($params['objectPrefix'])) {
61
+            $this->objectPrefix = $params['objectPrefix'];
62
+        }
63
+        //initialize cache with root directory in cache
64
+        if (!$this->is_dir('/')) {
65
+            $this->mkdir('/');
66
+        }
67
+    }
68
+
69
+    public function mkdir($path) {
70
+        $path = $this->normalizePath($path);
71
+
72
+        if ($this->file_exists($path)) {
73
+            return false;
74
+        }
75
+
76
+        $mTime = time();
77
+        $data = [
78
+            'mimetype' => 'httpd/unix-directory',
79
+            'size' => 0,
80
+            'mtime' => $mTime,
81
+            'storage_mtime' => $mTime,
82
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
83
+        ];
84
+        if ($path === '') {
85
+            //create root on the fly
86
+            $data['etag'] = $this->getETag('');
87
+            $this->getCache()->put('', $data);
88
+            return true;
89
+        } else {
90
+            // if parent does not exist, create it
91
+            $parent = $this->normalizePath(dirname($path));
92
+            $parentType = $this->filetype($parent);
93
+            if ($parentType === false) {
94
+                if (!$this->mkdir($parent)) {
95
+                    // something went wrong
96
+                    return false;
97
+                }
98
+            } else if ($parentType === 'file') {
99
+                // parent is a file
100
+                return false;
101
+            }
102
+            // finally create the new dir
103
+            $mTime = time(); // update mtime
104
+            $data['mtime'] = $mTime;
105
+            $data['storage_mtime'] = $mTime;
106
+            $data['etag'] = $this->getETag($path);
107
+            $this->getCache()->put($path, $data);
108
+            return true;
109
+        }
110
+    }
111
+
112
+    /**
113
+     * @param string $path
114
+     * @return string
115
+     */
116
+    private function normalizePath($path) {
117
+        $path = trim($path, '/');
118
+        //FIXME why do we sometimes get a path like 'files//username'?
119
+        $path = str_replace('//', '/', $path);
120
+
121
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
122
+        if (!$path || $path === '.') {
123
+            $path = '';
124
+        }
125
+
126
+        return $path;
127
+    }
128
+
129
+    /**
130
+     * Object Stores use a NoopScanner because metadata is directly stored in
131
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
132
+     *
133
+     * @param string $path
134
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
135
+     * @return \OC\Files\ObjectStore\NoopScanner
136
+     */
137
+    public function getScanner($path = '', $storage = null) {
138
+        if (!$storage) {
139
+            $storage = $this;
140
+        }
141
+        if (!isset($this->scanner)) {
142
+            $this->scanner = new NoopScanner($storage);
143
+        }
144
+        return $this->scanner;
145
+    }
146
+
147
+    public function getId() {
148
+        return $this->id;
149
+    }
150
+
151
+    public function rmdir($path) {
152
+        $path = $this->normalizePath($path);
153
+
154
+        if (!$this->is_dir($path)) {
155
+            return false;
156
+        }
157
+
158
+        $this->rmObjects($path);
159
+
160
+        $this->getCache()->remove($path);
161
+
162
+        return true;
163
+    }
164
+
165
+    private function rmObjects($path) {
166
+        $children = $this->getCache()->getFolderContents($path);
167
+        foreach ($children as $child) {
168
+            if ($child['mimetype'] === 'httpd/unix-directory') {
169
+                $this->rmObjects($child['path']);
170
+            } else {
171
+                $this->unlink($child['path']);
172
+            }
173
+        }
174
+    }
175
+
176
+    public function unlink($path) {
177
+        $path = $this->normalizePath($path);
178
+        $stat = $this->stat($path);
179
+
180
+        if ($stat && isset($stat['fileid'])) {
181
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
182
+                return $this->rmdir($path);
183
+            }
184
+            try {
185
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
186
+            } catch (\Exception $ex) {
187
+                if ($ex->getCode() !== 404) {
188
+                    \OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
189
+                    return false;
190
+                } else {
191
+                    //removing from cache is ok as it does not exist in the objectstore anyway
192
+                }
193
+            }
194
+            $this->getCache()->remove($path);
195
+            return true;
196
+        }
197
+        return false;
198
+    }
199
+
200
+    public function stat($path) {
201
+        $path = $this->normalizePath($path);
202
+        $cacheEntry = $this->getCache()->get($path);
203
+        if ($cacheEntry instanceof CacheEntry) {
204
+            return $cacheEntry->getData();
205
+        } else {
206
+            return false;
207
+        }
208
+    }
209
+
210
+    /**
211
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
212
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
213
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
214
+     *
215
+     * @param int $fileId the fileid
216
+     * @return null|string the unified resource name used to identify the object
217
+     */
218
+    protected function getURN($fileId) {
219
+        if (is_numeric($fileId)) {
220
+            return $this->objectPrefix . $fileId;
221
+        }
222
+        return null;
223
+    }
224
+
225
+    public function opendir($path) {
226
+        $path = $this->normalizePath($path);
227
+
228
+        try {
229
+            $files = array();
230
+            $folderContents = $this->getCache()->getFolderContents($path);
231
+            foreach ($folderContents as $file) {
232
+                $files[] = $file['name'];
233
+            }
234
+
235
+            return IteratorDirectory::wrap($files);
236
+        } catch (\Exception $e) {
237
+            \OCP\Util::writeLog('objectstore', $e->getMessage(), \OCP\Util::ERROR);
238
+            return false;
239
+        }
240
+    }
241
+
242
+    public function filetype($path) {
243
+        $path = $this->normalizePath($path);
244
+        $stat = $this->stat($path);
245
+        if ($stat) {
246
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
247
+                return 'dir';
248
+            }
249
+            return 'file';
250
+        } else {
251
+            return false;
252
+        }
253
+    }
254
+
255
+    public function fopen($path, $mode) {
256
+        $path = $this->normalizePath($path);
257
+
258
+        switch ($mode) {
259
+            case 'r':
260
+            case 'rb':
261
+                $stat = $this->stat($path);
262
+                if (is_array($stat)) {
263
+                    try {
264
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
265
+                    } catch (\Exception $ex) {
266
+                        \OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
267
+                        return false;
268
+                    }
269
+                } else {
270
+                    return false;
271
+                }
272
+            case 'w':
273
+            case 'wb':
274
+            case 'a':
275
+            case 'ab':
276
+            case 'r+':
277
+            case 'w+':
278
+            case 'wb+':
279
+            case 'a+':
280
+            case 'x':
281
+            case 'x+':
282
+            case 'c':
283
+            case 'c+':
284
+                if (strrpos($path, '.') !== false) {
285
+                    $ext = substr($path, strrpos($path, '.'));
286
+                } else {
287
+                    $ext = '';
288
+                }
289
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
290
+                if ($this->file_exists($path)) {
291
+                    $source = $this->fopen($path, 'r');
292
+                    file_put_contents($tmpFile, $source);
293
+                }
294
+                $handle = fopen($tmpFile, $mode);
295
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
296
+                    $this->writeBack($tmpFile, $path);
297
+                });
298
+        }
299
+        return false;
300
+    }
301
+
302
+    public function file_exists($path) {
303
+        $path = $this->normalizePath($path);
304
+        return (bool)$this->stat($path);
305
+    }
306
+
307
+    public function rename($source, $target) {
308
+        $source = $this->normalizePath($source);
309
+        $target = $this->normalizePath($target);
310
+        $this->remove($target);
311
+        $this->getCache()->move($source, $target);
312
+        $this->touch(dirname($target));
313
+        return true;
314
+    }
315
+
316
+    public function getMimeType($path) {
317
+        $path = $this->normalizePath($path);
318
+        $stat = $this->stat($path);
319
+        if (is_array($stat)) {
320
+            return $stat['mimetype'];
321
+        } else {
322
+            return false;
323
+        }
324
+    }
325
+
326
+    public function touch($path, $mtime = null) {
327
+        if (is_null($mtime)) {
328
+            $mtime = time();
329
+        }
330
+
331
+        $path = $this->normalizePath($path);
332
+        $dirName = dirname($path);
333
+        $parentExists = $this->is_dir($dirName);
334
+        if (!$parentExists) {
335
+            return false;
336
+        }
337
+
338
+        $stat = $this->stat($path);
339
+        if (is_array($stat)) {
340
+            // update existing mtime in db
341
+            $stat['mtime'] = $mtime;
342
+            $this->getCache()->update($stat['fileid'], $stat);
343
+        } else {
344
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
345
+            // create new file
346
+            $stat = array(
347
+                'etag' => $this->getETag($path),
348
+                'mimetype' => $mimeType,
349
+                'size' => 0,
350
+                'mtime' => $mtime,
351
+                'storage_mtime' => $mtime,
352
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
353
+            );
354
+            $fileId = $this->getCache()->put($path, $stat);
355
+            try {
356
+                //read an empty file from memory
357
+                $this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
358
+            } catch (\Exception $ex) {
359
+                $this->getCache()->remove($path);
360
+                \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
361
+                return false;
362
+            }
363
+        }
364
+        return true;
365
+    }
366
+
367
+    public function writeBack($tmpFile, $path) {
368
+        $stat = $this->stat($path);
369
+        if (empty($stat)) {
370
+            // create new file
371
+            $stat = array(
372
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
373
+            );
374
+        }
375
+        // update stat with new data
376
+        $mTime = time();
377
+        $stat['size'] = filesize($tmpFile);
378
+        $stat['mtime'] = $mTime;
379
+        $stat['storage_mtime'] = $mTime;
380
+        $stat['mimetype'] = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
381
+        $stat['etag'] = $this->getETag($path);
382
+
383
+        $fileId = $this->getCache()->put($path, $stat);
384
+        try {
385
+            //upload to object storage
386
+            $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
387
+        } catch (\Exception $ex) {
388
+            $this->getCache()->remove($path);
389
+            \OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
390
+            throw $ex; // make this bubble up
391
+        }
392
+    }
393
+
394
+    /**
395
+     * external changes are not supported, exclusive access to the object storage is assumed
396
+     *
397
+     * @param string $path
398
+     * @param int $time
399
+     * @return false
400
+     */
401
+    public function hasUpdated($path, $time) {
402
+        return false;
403
+    }
404 404
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -53,9 +53,9 @@  discard block
 block discarded – undo
53 53
 			throw new \Exception('missing IObjectStore instance');
54 54
 		}
55 55
 		if (isset($params['storageid'])) {
56
-			$this->id = 'object::store:' . $params['storageid'];
56
+			$this->id = 'object::store:'.$params['storageid'];
57 57
 		} else {
58
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
58
+			$this->id = 'object::store:'.$this->objectStore->getStorageId();
59 59
 		}
60 60
 		if (isset($params['objectPrefix'])) {
61 61
 			$this->objectPrefix = $params['objectPrefix'];
@@ -185,7 +185,7 @@  discard block
 block discarded – undo
185 185
 				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
186 186
 			} catch (\Exception $ex) {
187 187
 				if ($ex->getCode() !== 404) {
188
-					\OCP\Util::writeLog('objectstore', 'Could not delete object: ' . $ex->getMessage(), \OCP\Util::ERROR);
188
+					\OCP\Util::writeLog('objectstore', 'Could not delete object: '.$ex->getMessage(), \OCP\Util::ERROR);
189 189
 					return false;
190 190
 				} else {
191 191
 					//removing from cache is ok as it does not exist in the objectstore anyway
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
 	 */
218 218
 	protected function getURN($fileId) {
219 219
 		if (is_numeric($fileId)) {
220
-			return $this->objectPrefix . $fileId;
220
+			return $this->objectPrefix.$fileId;
221 221
 		}
222 222
 		return null;
223 223
 	}
@@ -263,7 +263,7 @@  discard block
 block discarded – undo
263 263
 					try {
264 264
 						return $this->objectStore->readObject($this->getURN($stat['fileid']));
265 265
 					} catch (\Exception $ex) {
266
-						\OCP\Util::writeLog('objectstore', 'Could not get object: ' . $ex->getMessage(), \OCP\Util::ERROR);
266
+						\OCP\Util::writeLog('objectstore', 'Could not get object: '.$ex->getMessage(), \OCP\Util::ERROR);
267 267
 						return false;
268 268
 					}
269 269
 				} else {
@@ -292,7 +292,7 @@  discard block
 block discarded – undo
292 292
 					file_put_contents($tmpFile, $source);
293 293
 				}
294 294
 				$handle = fopen($tmpFile, $mode);
295
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
295
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
296 296
 					$this->writeBack($tmpFile, $path);
297 297
 				});
298 298
 		}
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
 
302 302
 	public function file_exists($path) {
303 303
 		$path = $this->normalizePath($path);
304
-		return (bool)$this->stat($path);
304
+		return (bool) $this->stat($path);
305 305
 	}
306 306
 
307 307
 	public function rename($source, $target) {
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 				$this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
358 358
 			} catch (\Exception $ex) {
359 359
 				$this->getCache()->remove($path);
360
-				\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
360
+				\OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
361 361
 				return false;
362 362
 			}
363 363
 		}
@@ -386,7 +386,7 @@  discard block
 block discarded – undo
386 386
 			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
387 387
 		} catch (\Exception $ex) {
388 388
 			$this->getCache()->remove($path);
389
-			\OCP\Util::writeLog('objectstore', 'Could not create object: ' . $ex->getMessage(), \OCP\Util::ERROR);
389
+			\OCP\Util::writeLog('objectstore', 'Could not create object: '.$ex->getMessage(), \OCP\Util::ERROR);
390 390
 			throw $ex; // make this bubble up
391 391
 		}
392 392
 	}
Please login to merge, or discard this patch.
lib/private/Files/Storage/DAV.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -38,7 +38,6 @@
 block discarded – undo
38 38
 use GuzzleHttp\Message\ResponseInterface;
39 39
 use Icewind\Streams\CallbackWrapper;
40 40
 use OC\Files\Filesystem;
41
-use OC\Files\Stream\Close;
42 41
 use Icewind\Streams\IteratorDirectory;
43 42
 use OC\MemCache\ArrayCache;
44 43
 use OCP\AppFramework\Http;
Please login to merge, or discard this patch.
Indentation   +785 added lines, -785 removed lines patch added patch discarded remove patch
@@ -59,790 +59,790 @@
 block discarded – undo
59 59
  * @package OC\Files\Storage
60 60
  */
61 61
 class DAV extends Common {
62
-	/** @var string */
63
-	protected $password;
64
-	/** @var string */
65
-	protected $user;
66
-	/** @var string */
67
-	protected $host;
68
-	/** @var bool */
69
-	protected $secure;
70
-	/** @var string */
71
-	protected $root;
72
-	/** @var string */
73
-	protected $certPath;
74
-	/** @var bool */
75
-	protected $ready;
76
-	/** @var Client */
77
-	protected $client;
78
-	/** @var ArrayCache */
79
-	protected $statCache;
80
-	/** @var \OCP\Http\Client\IClientService */
81
-	protected $httpClientService;
82
-
83
-	/**
84
-	 * @param array $params
85
-	 * @throws \Exception
86
-	 */
87
-	public function __construct($params) {
88
-		$this->statCache = new ArrayCache();
89
-		$this->httpClientService = \OC::$server->getHTTPClientService();
90
-		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
91
-			$host = $params['host'];
92
-			//remove leading http[s], will be generated in createBaseUri()
93
-			if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
94
-			else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
95
-			$this->host = $host;
96
-			$this->user = $params['user'];
97
-			$this->password = $params['password'];
98
-			if (isset($params['secure'])) {
99
-				if (is_string($params['secure'])) {
100
-					$this->secure = ($params['secure'] === 'true');
101
-				} else {
102
-					$this->secure = (bool)$params['secure'];
103
-				}
104
-			} else {
105
-				$this->secure = false;
106
-			}
107
-			if ($this->secure === true) {
108
-				// inject mock for testing
109
-				$certManager = \OC::$server->getCertificateManager();
110
-				if (is_null($certManager)) { //no user
111
-					$certManager = \OC::$server->getCertificateManager(null);
112
-				}
113
-				$certPath = $certManager->getAbsoluteBundlePath();
114
-				if (file_exists($certPath)) {
115
-					$this->certPath = $certPath;
116
-				}
117
-			}
118
-			$this->root = isset($params['root']) ? $params['root'] : '/';
119
-			if (!$this->root || $this->root[0] != '/') {
120
-				$this->root = '/' . $this->root;
121
-			}
122
-			if (substr($this->root, -1, 1) != '/') {
123
-				$this->root .= '/';
124
-			}
125
-		} else {
126
-			throw new \Exception('Invalid webdav storage configuration');
127
-		}
128
-	}
129
-
130
-	protected function init() {
131
-		if ($this->ready) {
132
-			return;
133
-		}
134
-		$this->ready = true;
135
-
136
-		$settings = array(
137
-			'baseUri' => $this->createBaseUri(),
138
-			'userName' => $this->user,
139
-			'password' => $this->password,
140
-		);
141
-
142
-		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
143
-		if($proxy !== '') {
144
-			$settings['proxy'] = $proxy;
145
-		}
146
-
147
-		$this->client = new Client($settings);
148
-		$this->client->setThrowExceptions(true);
149
-		if ($this->secure === true && $this->certPath) {
150
-			$this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
151
-		}
152
-	}
153
-
154
-	/**
155
-	 * Clear the stat cache
156
-	 */
157
-	public function clearStatCache() {
158
-		$this->statCache->clear();
159
-	}
160
-
161
-	/** {@inheritdoc} */
162
-	public function getId() {
163
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
164
-	}
165
-
166
-	/** {@inheritdoc} */
167
-	public function createBaseUri() {
168
-		$baseUri = 'http';
169
-		if ($this->secure) {
170
-			$baseUri .= 's';
171
-		}
172
-		$baseUri .= '://' . $this->host . $this->root;
173
-		return $baseUri;
174
-	}
175
-
176
-	/** {@inheritdoc} */
177
-	public function mkdir($path) {
178
-		$this->init();
179
-		$path = $this->cleanPath($path);
180
-		$result = $this->simpleResponse('MKCOL', $path, null, 201);
181
-		if ($result) {
182
-			$this->statCache->set($path, true);
183
-		}
184
-		return $result;
185
-	}
186
-
187
-	/** {@inheritdoc} */
188
-	public function rmdir($path) {
189
-		$this->init();
190
-		$path = $this->cleanPath($path);
191
-		// FIXME: some WebDAV impl return 403 when trying to DELETE
192
-		// a non-empty folder
193
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
194
-		$this->statCache->clear($path . '/');
195
-		$this->statCache->remove($path);
196
-		return $result;
197
-	}
198
-
199
-	/** {@inheritdoc} */
200
-	public function opendir($path) {
201
-		$this->init();
202
-		$path = $this->cleanPath($path);
203
-		try {
204
-			$response = $this->client->propFind(
205
-				$this->encodePath($path),
206
-				['{DAV:}href'],
207
-				1
208
-			);
209
-			if ($response === false) {
210
-				return false;
211
-			}
212
-			$content = [];
213
-			$files = array_keys($response);
214
-			array_shift($files); //the first entry is the current directory
215
-
216
-			if (!$this->statCache->hasKey($path)) {
217
-				$this->statCache->set($path, true);
218
-			}
219
-			foreach ($files as $file) {
220
-				$file = urldecode($file);
221
-				// do not store the real entry, we might not have all properties
222
-				if (!$this->statCache->hasKey($path)) {
223
-					$this->statCache->set($file, true);
224
-				}
225
-				$file = basename($file);
226
-				$content[] = $file;
227
-			}
228
-			return IteratorDirectory::wrap($content);
229
-		} catch (\Exception $e) {
230
-			$this->convertException($e, $path);
231
-		}
232
-		return false;
233
-	}
234
-
235
-	/**
236
-	 * Propfind call with cache handling.
237
-	 *
238
-	 * First checks if information is cached.
239
-	 * If not, request it from the server then store to cache.
240
-	 *
241
-	 * @param string $path path to propfind
242
-	 *
243
-	 * @return array|boolean propfind response or false if the entry was not found
244
-	 *
245
-	 * @throws ClientHttpException
246
-	 */
247
-	protected function propfind($path) {
248
-		$path = $this->cleanPath($path);
249
-		$cachedResponse = $this->statCache->get($path);
250
-		// we either don't know it, or we know it exists but need more details
251
-		if (is_null($cachedResponse) || $cachedResponse === true) {
252
-			$this->init();
253
-			try {
254
-				$response = $this->client->propFind(
255
-					$this->encodePath($path),
256
-					array(
257
-						'{DAV:}getlastmodified',
258
-						'{DAV:}getcontentlength',
259
-						'{DAV:}getcontenttype',
260
-						'{http://owncloud.org/ns}permissions',
261
-						'{http://open-collaboration-services.org/ns}share-permissions',
262
-						'{DAV:}resourcetype',
263
-						'{DAV:}getetag',
264
-					)
265
-				);
266
-				$this->statCache->set($path, $response);
267
-			} catch (ClientHttpException $e) {
268
-				if ($e->getHttpStatus() === 404) {
269
-					$this->statCache->clear($path . '/');
270
-					$this->statCache->set($path, false);
271
-					return false;
272
-				}
273
-				$this->convertException($e, $path);
274
-			} catch (\Exception $e) {
275
-				$this->convertException($e, $path);
276
-			}
277
-		} else {
278
-			$response = $cachedResponse;
279
-		}
280
-		return $response;
281
-	}
282
-
283
-	/** {@inheritdoc} */
284
-	public function filetype($path) {
285
-		try {
286
-			$response = $this->propfind($path);
287
-			if ($response === false) {
288
-				return false;
289
-			}
290
-			$responseType = [];
291
-			if (isset($response["{DAV:}resourcetype"])) {
292
-				/** @var ResourceType[] $response */
293
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
294
-			}
295
-			return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
296
-		} catch (\Exception $e) {
297
-			$this->convertException($e, $path);
298
-		}
299
-		return false;
300
-	}
301
-
302
-	/** {@inheritdoc} */
303
-	public function file_exists($path) {
304
-		try {
305
-			$path = $this->cleanPath($path);
306
-			$cachedState = $this->statCache->get($path);
307
-			if ($cachedState === false) {
308
-				// we know the file doesn't exist
309
-				return false;
310
-			} else if (!is_null($cachedState)) {
311
-				return true;
312
-			}
313
-			// need to get from server
314
-			return ($this->propfind($path) !== false);
315
-		} catch (\Exception $e) {
316
-			$this->convertException($e, $path);
317
-		}
318
-		return false;
319
-	}
320
-
321
-	/** {@inheritdoc} */
322
-	public function unlink($path) {
323
-		$this->init();
324
-		$path = $this->cleanPath($path);
325
-		$result = $this->simpleResponse('DELETE', $path, null, 204);
326
-		$this->statCache->clear($path . '/');
327
-		$this->statCache->remove($path);
328
-		return $result;
329
-	}
330
-
331
-	/** {@inheritdoc} */
332
-	public function fopen($path, $mode) {
333
-		$this->init();
334
-		$path = $this->cleanPath($path);
335
-		switch ($mode) {
336
-			case 'r':
337
-			case 'rb':
338
-				try {
339
-					$response = $this->httpClientService
340
-							->newClient()
341
-							->get($this->createBaseUri() . $this->encodePath($path), [
342
-									'auth' => [$this->user, $this->password],
343
-									'stream' => true
344
-							]);
345
-				} catch (RequestException $e) {
346
-					if ($e->getResponse() instanceof ResponseInterface
347
-						&& $e->getResponse()->getStatusCode() === 404) {
348
-						return false;
349
-					} else {
350
-						throw $e;
351
-					}
352
-				}
353
-
354
-				if ($response->getStatusCode() !== Http::STATUS_OK) {
355
-					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
356
-						throw new \OCP\Lock\LockedException($path);
357
-					} else {
358
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
359
-					}
360
-				}
361
-
362
-				return $response->getBody();
363
-			case 'w':
364
-			case 'wb':
365
-			case 'a':
366
-			case 'ab':
367
-			case 'r+':
368
-			case 'w+':
369
-			case 'wb+':
370
-			case 'a+':
371
-			case 'x':
372
-			case 'x+':
373
-			case 'c':
374
-			case 'c+':
375
-				//emulate these
376
-				$tempManager = \OC::$server->getTempManager();
377
-				if (strrpos($path, '.') !== false) {
378
-					$ext = substr($path, strrpos($path, '.'));
379
-				} else {
380
-					$ext = '';
381
-				}
382
-				if ($this->file_exists($path)) {
383
-					if (!$this->isUpdatable($path)) {
384
-						return false;
385
-					}
386
-					if ($mode === 'w' or $mode === 'w+') {
387
-						$tmpFile = $tempManager->getTemporaryFile($ext);
388
-					} else {
389
-						$tmpFile = $this->getCachedFile($path);
390
-					}
391
-				} else {
392
-					if (!$this->isCreatable(dirname($path))) {
393
-						return false;
394
-					}
395
-					$tmpFile = $tempManager->getTemporaryFile($ext);
396
-				}
397
-				$handle = fopen($tmpFile, $mode);
398
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
399
-					$this->writeBack($tmpFile, $path);
400
-				});
401
-		}
402
-	}
403
-
404
-	/**
405
-	 * @param string $tmpFile
406
-	 */
407
-	public function writeBack($tmpFile, $path) {
408
-		$this->uploadFile($tmpFile, $path);
409
-		unlink($tmpFile);
410
-	}
411
-
412
-	/** {@inheritdoc} */
413
-	public function free_space($path) {
414
-		$this->init();
415
-		$path = $this->cleanPath($path);
416
-		try {
417
-			// TODO: cacheable ?
418
-			$response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
419
-			if ($response === false) {
420
-				return FileInfo::SPACE_UNKNOWN;
421
-			}
422
-			if (isset($response['{DAV:}quota-available-bytes'])) {
423
-				return (int)$response['{DAV:}quota-available-bytes'];
424
-			} else {
425
-				return FileInfo::SPACE_UNKNOWN;
426
-			}
427
-		} catch (\Exception $e) {
428
-			return FileInfo::SPACE_UNKNOWN;
429
-		}
430
-	}
431
-
432
-	/** {@inheritdoc} */
433
-	public function touch($path, $mtime = null) {
434
-		$this->init();
435
-		if (is_null($mtime)) {
436
-			$mtime = time();
437
-		}
438
-		$path = $this->cleanPath($path);
439
-
440
-		// if file exists, update the mtime, else create a new empty file
441
-		if ($this->file_exists($path)) {
442
-			try {
443
-				$this->statCache->remove($path);
444
-				$this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
445
-				// non-owncloud clients might not have accepted the property, need to recheck it
446
-				$response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
447
-				if ($response === false) {
448
-					return false;
449
-				}
450
-				if (isset($response['{DAV:}getlastmodified'])) {
451
-					$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
452
-					if ($remoteMtime !== $mtime) {
453
-						// server has not accepted the mtime
454
-						return false;
455
-					}
456
-				}
457
-			} catch (ClientHttpException $e) {
458
-				if ($e->getHttpStatus() === 501) {
459
-					return false;
460
-				}
461
-				$this->convertException($e, $path);
462
-				return false;
463
-			} catch (\Exception $e) {
464
-				$this->convertException($e, $path);
465
-				return false;
466
-			}
467
-		} else {
468
-			$this->file_put_contents($path, '');
469
-		}
470
-		return true;
471
-	}
472
-
473
-	/**
474
-	 * @param string $path
475
-	 * @param string $data
476
-	 * @return int
477
-	 */
478
-	public function file_put_contents($path, $data) {
479
-		$path = $this->cleanPath($path);
480
-		$result = parent::file_put_contents($path, $data);
481
-		$this->statCache->remove($path);
482
-		return $result;
483
-	}
484
-
485
-	/**
486
-	 * @param string $path
487
-	 * @param string $target
488
-	 */
489
-	protected function uploadFile($path, $target) {
490
-		$this->init();
491
-
492
-		// invalidate
493
-		$target = $this->cleanPath($target);
494
-		$this->statCache->remove($target);
495
-		$source = fopen($path, 'r');
496
-
497
-		$this->httpClientService
498
-			->newClient()
499
-			->put($this->createBaseUri() . $this->encodePath($target), [
500
-				'body' => $source,
501
-				'auth' => [$this->user, $this->password]
502
-			]);
503
-
504
-		$this->removeCachedFile($target);
505
-	}
506
-
507
-	/** {@inheritdoc} */
508
-	public function rename($path1, $path2) {
509
-		$this->init();
510
-		$path1 = $this->cleanPath($path1);
511
-		$path2 = $this->cleanPath($path2);
512
-		try {
513
-			// overwrite directory ?
514
-			if ($this->is_dir($path2)) {
515
-				// needs trailing slash in destination
516
-				$path2 = rtrim($path2, '/') . '/';
517
-			}
518
-			$this->client->request(
519
-				'MOVE',
520
-				$this->encodePath($path1),
521
-				null,
522
-				[
523
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
524
-				]
525
-			);
526
-			$this->statCache->clear($path1 . '/');
527
-			$this->statCache->clear($path2 . '/');
528
-			$this->statCache->set($path1, false);
529
-			$this->statCache->set($path2, true);
530
-			$this->removeCachedFile($path1);
531
-			$this->removeCachedFile($path2);
532
-			return true;
533
-		} catch (\Exception $e) {
534
-			$this->convertException($e);
535
-		}
536
-		return false;
537
-	}
538
-
539
-	/** {@inheritdoc} */
540
-	public function copy($path1, $path2) {
541
-		$this->init();
542
-		$path1 = $this->cleanPath($path1);
543
-		$path2 = $this->cleanPath($path2);
544
-		try {
545
-			// overwrite directory ?
546
-			if ($this->is_dir($path2)) {
547
-				// needs trailing slash in destination
548
-				$path2 = rtrim($path2, '/') . '/';
549
-			}
550
-			$this->client->request(
551
-				'COPY',
552
-				$this->encodePath($path1),
553
-				null,
554
-				[
555
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
556
-				]
557
-			);
558
-			$this->statCache->clear($path2 . '/');
559
-			$this->statCache->set($path2, true);
560
-			$this->removeCachedFile($path2);
561
-			return true;
562
-		} catch (\Exception $e) {
563
-			$this->convertException($e);
564
-		}
565
-		return false;
566
-	}
567
-
568
-	/** {@inheritdoc} */
569
-	public function stat($path) {
570
-		try {
571
-			$response = $this->propfind($path);
572
-			if (!$response) {
573
-				return false;
574
-			}
575
-			return [
576
-				'mtime' => strtotime($response['{DAV:}getlastmodified']),
577
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
578
-			];
579
-		} catch (\Exception $e) {
580
-			$this->convertException($e, $path);
581
-		}
582
-		return array();
583
-	}
584
-
585
-	/** {@inheritdoc} */
586
-	public function getMimeType($path) {
587
-		try {
588
-			$response = $this->propfind($path);
589
-			if ($response === false) {
590
-				return false;
591
-			}
592
-			$responseType = [];
593
-			if (isset($response["{DAV:}resourcetype"])) {
594
-				/** @var ResourceType[] $response */
595
-				$responseType = $response["{DAV:}resourcetype"]->getValue();
596
-			}
597
-			$type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
598
-			if ($type == 'dir') {
599
-				return 'httpd/unix-directory';
600
-			} elseif (isset($response['{DAV:}getcontenttype'])) {
601
-				return $response['{DAV:}getcontenttype'];
602
-			} else {
603
-				return false;
604
-			}
605
-		} catch (\Exception $e) {
606
-			$this->convertException($e, $path);
607
-		}
608
-		return false;
609
-	}
610
-
611
-	/**
612
-	 * @param string $path
613
-	 * @return string
614
-	 */
615
-	public function cleanPath($path) {
616
-		if ($path === '') {
617
-			return $path;
618
-		}
619
-		$path = Filesystem::normalizePath($path);
620
-		// remove leading slash
621
-		return substr($path, 1);
622
-	}
623
-
624
-	/**
625
-	 * URL encodes the given path but keeps the slashes
626
-	 *
627
-	 * @param string $path to encode
628
-	 * @return string encoded path
629
-	 */
630
-	protected function encodePath($path) {
631
-		// slashes need to stay
632
-		return str_replace('%2F', '/', rawurlencode($path));
633
-	}
634
-
635
-	/**
636
-	 * @param string $method
637
-	 * @param string $path
638
-	 * @param string|resource|null $body
639
-	 * @param int $expected
640
-	 * @return bool
641
-	 * @throws StorageInvalidException
642
-	 * @throws StorageNotAvailableException
643
-	 */
644
-	protected function simpleResponse($method, $path, $body, $expected) {
645
-		$path = $this->cleanPath($path);
646
-		try {
647
-			$response = $this->client->request($method, $this->encodePath($path), $body);
648
-			return $response['statusCode'] == $expected;
649
-		} catch (ClientHttpException $e) {
650
-			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
651
-				$this->statCache->clear($path . '/');
652
-				$this->statCache->set($path, false);
653
-				return false;
654
-			}
655
-
656
-			$this->convertException($e, $path);
657
-		} catch (\Exception $e) {
658
-			$this->convertException($e, $path);
659
-		}
660
-		return false;
661
-	}
662
-
663
-	/**
664
-	 * check if curl is installed
665
-	 */
666
-	public static function checkDependencies() {
667
-		return true;
668
-	}
669
-
670
-	/** {@inheritdoc} */
671
-	public function isUpdatable($path) {
672
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
673
-	}
674
-
675
-	/** {@inheritdoc} */
676
-	public function isCreatable($path) {
677
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
678
-	}
679
-
680
-	/** {@inheritdoc} */
681
-	public function isSharable($path) {
682
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
683
-	}
684
-
685
-	/** {@inheritdoc} */
686
-	public function isDeletable($path) {
687
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
688
-	}
689
-
690
-	/** {@inheritdoc} */
691
-	public function getPermissions($path) {
692
-		$this->init();
693
-		$path = $this->cleanPath($path);
694
-		$response = $this->propfind($path);
695
-		if ($response === false) {
696
-			return 0;
697
-		}
698
-		if (isset($response['{http://owncloud.org/ns}permissions'])) {
699
-			return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
700
-		} else if ($this->is_dir($path)) {
701
-			return Constants::PERMISSION_ALL;
702
-		} else if ($this->file_exists($path)) {
703
-			return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
704
-		} else {
705
-			return 0;
706
-		}
707
-	}
708
-
709
-	/** {@inheritdoc} */
710
-	public function getETag($path) {
711
-		$this->init();
712
-		$path = $this->cleanPath($path);
713
-		$response = $this->propfind($path);
714
-		if ($response === false) {
715
-			return null;
716
-		}
717
-		if (isset($response['{DAV:}getetag'])) {
718
-			return trim($response['{DAV:}getetag'], '"');
719
-		}
720
-		return parent::getEtag($path);
721
-	}
722
-
723
-	/**
724
-	 * @param string $permissionsString
725
-	 * @return int
726
-	 */
727
-	protected function parsePermissions($permissionsString) {
728
-		$permissions = Constants::PERMISSION_READ;
729
-		if (strpos($permissionsString, 'R') !== false) {
730
-			$permissions |= Constants::PERMISSION_SHARE;
731
-		}
732
-		if (strpos($permissionsString, 'D') !== false) {
733
-			$permissions |= Constants::PERMISSION_DELETE;
734
-		}
735
-		if (strpos($permissionsString, 'W') !== false) {
736
-			$permissions |= Constants::PERMISSION_UPDATE;
737
-		}
738
-		if (strpos($permissionsString, 'CK') !== false) {
739
-			$permissions |= Constants::PERMISSION_CREATE;
740
-			$permissions |= Constants::PERMISSION_UPDATE;
741
-		}
742
-		return $permissions;
743
-	}
744
-
745
-	/**
746
-	 * check if a file or folder has been updated since $time
747
-	 *
748
-	 * @param string $path
749
-	 * @param int $time
750
-	 * @throws \OCP\Files\StorageNotAvailableException
751
-	 * @return bool
752
-	 */
753
-	public function hasUpdated($path, $time) {
754
-		$this->init();
755
-		$path = $this->cleanPath($path);
756
-		try {
757
-			// force refresh for $path
758
-			$this->statCache->remove($path);
759
-			$response = $this->propfind($path);
760
-			if ($response === false) {
761
-				if ($path === '') {
762
-					// if root is gone it means the storage is not available
763
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
764
-				}
765
-				return false;
766
-			}
767
-			if (isset($response['{DAV:}getetag'])) {
768
-				$cachedData = $this->getCache()->get($path);
769
-				$etag = null;
770
-				if (isset($response['{DAV:}getetag'])) {
771
-					$etag = trim($response['{DAV:}getetag'], '"');
772
-				}
773
-				if (!empty($etag) && $cachedData['etag'] !== $etag) {
774
-					return true;
775
-				} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
776
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
777
-					return $sharePermissions !== $cachedData['permissions'];
778
-				} else if (isset($response['{http://owncloud.org/ns}permissions'])) {
779
-					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
780
-					return $permissions !== $cachedData['permissions'];
781
-				} else {
782
-					return false;
783
-				}
784
-			} else {
785
-				$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
786
-				return $remoteMtime > $time;
787
-			}
788
-		} catch (ClientHttpException $e) {
789
-			if ($e->getHttpStatus() === 405) {
790
-				if ($path === '') {
791
-					// if root is gone it means the storage is not available
792
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
793
-				}
794
-				return false;
795
-			}
796
-			$this->convertException($e, $path);
797
-			return false;
798
-		} catch (\Exception $e) {
799
-			$this->convertException($e, $path);
800
-			return false;
801
-		}
802
-	}
803
-
804
-	/**
805
-	 * Interpret the given exception and decide whether it is due to an
806
-	 * unavailable storage, invalid storage or other.
807
-	 * This will either throw StorageInvalidException, StorageNotAvailableException
808
-	 * or do nothing.
809
-	 *
810
-	 * @param Exception $e sabre exception
811
-	 * @param string $path optional path from the operation
812
-	 *
813
-	 * @throws StorageInvalidException if the storage is invalid, for example
814
-	 * when the authentication expired or is invalid
815
-	 * @throws StorageNotAvailableException if the storage is not available,
816
-	 * which might be temporary
817
-	 */
818
-	protected function convertException(Exception $e, $path = '') {
819
-		\OC::$server->getLogger()->logException($e);
820
-		Util::writeLog('files_external', $e->getMessage(), Util::ERROR);
821
-		if ($e instanceof ClientHttpException) {
822
-			if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
823
-				throw new \OCP\Lock\LockedException($path);
824
-			}
825
-			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
826
-				// either password was changed or was invalid all along
827
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
828
-			} else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
829
-				// ignore exception for MethodNotAllowed, false will be returned
830
-				return;
831
-			}
832
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
833
-		} else if ($e instanceof ClientException) {
834
-			// connection timeout or refused, server could be temporarily down
835
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
836
-		} else if ($e instanceof \InvalidArgumentException) {
837
-			// parse error because the server returned HTML instead of XML,
838
-			// possibly temporarily down
839
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
840
-		} else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
841
-			// rethrow
842
-			throw $e;
843
-		}
844
-
845
-		// TODO: only log for now, but in the future need to wrap/rethrow exception
846
-	}
62
+    /** @var string */
63
+    protected $password;
64
+    /** @var string */
65
+    protected $user;
66
+    /** @var string */
67
+    protected $host;
68
+    /** @var bool */
69
+    protected $secure;
70
+    /** @var string */
71
+    protected $root;
72
+    /** @var string */
73
+    protected $certPath;
74
+    /** @var bool */
75
+    protected $ready;
76
+    /** @var Client */
77
+    protected $client;
78
+    /** @var ArrayCache */
79
+    protected $statCache;
80
+    /** @var \OCP\Http\Client\IClientService */
81
+    protected $httpClientService;
82
+
83
+    /**
84
+     * @param array $params
85
+     * @throws \Exception
86
+     */
87
+    public function __construct($params) {
88
+        $this->statCache = new ArrayCache();
89
+        $this->httpClientService = \OC::$server->getHTTPClientService();
90
+        if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
91
+            $host = $params['host'];
92
+            //remove leading http[s], will be generated in createBaseUri()
93
+            if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
94
+            else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
95
+            $this->host = $host;
96
+            $this->user = $params['user'];
97
+            $this->password = $params['password'];
98
+            if (isset($params['secure'])) {
99
+                if (is_string($params['secure'])) {
100
+                    $this->secure = ($params['secure'] === 'true');
101
+                } else {
102
+                    $this->secure = (bool)$params['secure'];
103
+                }
104
+            } else {
105
+                $this->secure = false;
106
+            }
107
+            if ($this->secure === true) {
108
+                // inject mock for testing
109
+                $certManager = \OC::$server->getCertificateManager();
110
+                if (is_null($certManager)) { //no user
111
+                    $certManager = \OC::$server->getCertificateManager(null);
112
+                }
113
+                $certPath = $certManager->getAbsoluteBundlePath();
114
+                if (file_exists($certPath)) {
115
+                    $this->certPath = $certPath;
116
+                }
117
+            }
118
+            $this->root = isset($params['root']) ? $params['root'] : '/';
119
+            if (!$this->root || $this->root[0] != '/') {
120
+                $this->root = '/' . $this->root;
121
+            }
122
+            if (substr($this->root, -1, 1) != '/') {
123
+                $this->root .= '/';
124
+            }
125
+        } else {
126
+            throw new \Exception('Invalid webdav storage configuration');
127
+        }
128
+    }
129
+
130
+    protected function init() {
131
+        if ($this->ready) {
132
+            return;
133
+        }
134
+        $this->ready = true;
135
+
136
+        $settings = array(
137
+            'baseUri' => $this->createBaseUri(),
138
+            'userName' => $this->user,
139
+            'password' => $this->password,
140
+        );
141
+
142
+        $proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
143
+        if($proxy !== '') {
144
+            $settings['proxy'] = $proxy;
145
+        }
146
+
147
+        $this->client = new Client($settings);
148
+        $this->client->setThrowExceptions(true);
149
+        if ($this->secure === true && $this->certPath) {
150
+            $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
151
+        }
152
+    }
153
+
154
+    /**
155
+     * Clear the stat cache
156
+     */
157
+    public function clearStatCache() {
158
+        $this->statCache->clear();
159
+    }
160
+
161
+    /** {@inheritdoc} */
162
+    public function getId() {
163
+        return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
164
+    }
165
+
166
+    /** {@inheritdoc} */
167
+    public function createBaseUri() {
168
+        $baseUri = 'http';
169
+        if ($this->secure) {
170
+            $baseUri .= 's';
171
+        }
172
+        $baseUri .= '://' . $this->host . $this->root;
173
+        return $baseUri;
174
+    }
175
+
176
+    /** {@inheritdoc} */
177
+    public function mkdir($path) {
178
+        $this->init();
179
+        $path = $this->cleanPath($path);
180
+        $result = $this->simpleResponse('MKCOL', $path, null, 201);
181
+        if ($result) {
182
+            $this->statCache->set($path, true);
183
+        }
184
+        return $result;
185
+    }
186
+
187
+    /** {@inheritdoc} */
188
+    public function rmdir($path) {
189
+        $this->init();
190
+        $path = $this->cleanPath($path);
191
+        // FIXME: some WebDAV impl return 403 when trying to DELETE
192
+        // a non-empty folder
193
+        $result = $this->simpleResponse('DELETE', $path . '/', null, 204);
194
+        $this->statCache->clear($path . '/');
195
+        $this->statCache->remove($path);
196
+        return $result;
197
+    }
198
+
199
+    /** {@inheritdoc} */
200
+    public function opendir($path) {
201
+        $this->init();
202
+        $path = $this->cleanPath($path);
203
+        try {
204
+            $response = $this->client->propFind(
205
+                $this->encodePath($path),
206
+                ['{DAV:}href'],
207
+                1
208
+            );
209
+            if ($response === false) {
210
+                return false;
211
+            }
212
+            $content = [];
213
+            $files = array_keys($response);
214
+            array_shift($files); //the first entry is the current directory
215
+
216
+            if (!$this->statCache->hasKey($path)) {
217
+                $this->statCache->set($path, true);
218
+            }
219
+            foreach ($files as $file) {
220
+                $file = urldecode($file);
221
+                // do not store the real entry, we might not have all properties
222
+                if (!$this->statCache->hasKey($path)) {
223
+                    $this->statCache->set($file, true);
224
+                }
225
+                $file = basename($file);
226
+                $content[] = $file;
227
+            }
228
+            return IteratorDirectory::wrap($content);
229
+        } catch (\Exception $e) {
230
+            $this->convertException($e, $path);
231
+        }
232
+        return false;
233
+    }
234
+
235
+    /**
236
+     * Propfind call with cache handling.
237
+     *
238
+     * First checks if information is cached.
239
+     * If not, request it from the server then store to cache.
240
+     *
241
+     * @param string $path path to propfind
242
+     *
243
+     * @return array|boolean propfind response or false if the entry was not found
244
+     *
245
+     * @throws ClientHttpException
246
+     */
247
+    protected function propfind($path) {
248
+        $path = $this->cleanPath($path);
249
+        $cachedResponse = $this->statCache->get($path);
250
+        // we either don't know it, or we know it exists but need more details
251
+        if (is_null($cachedResponse) || $cachedResponse === true) {
252
+            $this->init();
253
+            try {
254
+                $response = $this->client->propFind(
255
+                    $this->encodePath($path),
256
+                    array(
257
+                        '{DAV:}getlastmodified',
258
+                        '{DAV:}getcontentlength',
259
+                        '{DAV:}getcontenttype',
260
+                        '{http://owncloud.org/ns}permissions',
261
+                        '{http://open-collaboration-services.org/ns}share-permissions',
262
+                        '{DAV:}resourcetype',
263
+                        '{DAV:}getetag',
264
+                    )
265
+                );
266
+                $this->statCache->set($path, $response);
267
+            } catch (ClientHttpException $e) {
268
+                if ($e->getHttpStatus() === 404) {
269
+                    $this->statCache->clear($path . '/');
270
+                    $this->statCache->set($path, false);
271
+                    return false;
272
+                }
273
+                $this->convertException($e, $path);
274
+            } catch (\Exception $e) {
275
+                $this->convertException($e, $path);
276
+            }
277
+        } else {
278
+            $response = $cachedResponse;
279
+        }
280
+        return $response;
281
+    }
282
+
283
+    /** {@inheritdoc} */
284
+    public function filetype($path) {
285
+        try {
286
+            $response = $this->propfind($path);
287
+            if ($response === false) {
288
+                return false;
289
+            }
290
+            $responseType = [];
291
+            if (isset($response["{DAV:}resourcetype"])) {
292
+                /** @var ResourceType[] $response */
293
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
294
+            }
295
+            return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
296
+        } catch (\Exception $e) {
297
+            $this->convertException($e, $path);
298
+        }
299
+        return false;
300
+    }
301
+
302
+    /** {@inheritdoc} */
303
+    public function file_exists($path) {
304
+        try {
305
+            $path = $this->cleanPath($path);
306
+            $cachedState = $this->statCache->get($path);
307
+            if ($cachedState === false) {
308
+                // we know the file doesn't exist
309
+                return false;
310
+            } else if (!is_null($cachedState)) {
311
+                return true;
312
+            }
313
+            // need to get from server
314
+            return ($this->propfind($path) !== false);
315
+        } catch (\Exception $e) {
316
+            $this->convertException($e, $path);
317
+        }
318
+        return false;
319
+    }
320
+
321
+    /** {@inheritdoc} */
322
+    public function unlink($path) {
323
+        $this->init();
324
+        $path = $this->cleanPath($path);
325
+        $result = $this->simpleResponse('DELETE', $path, null, 204);
326
+        $this->statCache->clear($path . '/');
327
+        $this->statCache->remove($path);
328
+        return $result;
329
+    }
330
+
331
+    /** {@inheritdoc} */
332
+    public function fopen($path, $mode) {
333
+        $this->init();
334
+        $path = $this->cleanPath($path);
335
+        switch ($mode) {
336
+            case 'r':
337
+            case 'rb':
338
+                try {
339
+                    $response = $this->httpClientService
340
+                            ->newClient()
341
+                            ->get($this->createBaseUri() . $this->encodePath($path), [
342
+                                    'auth' => [$this->user, $this->password],
343
+                                    'stream' => true
344
+                            ]);
345
+                } catch (RequestException $e) {
346
+                    if ($e->getResponse() instanceof ResponseInterface
347
+                        && $e->getResponse()->getStatusCode() === 404) {
348
+                        return false;
349
+                    } else {
350
+                        throw $e;
351
+                    }
352
+                }
353
+
354
+                if ($response->getStatusCode() !== Http::STATUS_OK) {
355
+                    if ($response->getStatusCode() === Http::STATUS_LOCKED) {
356
+                        throw new \OCP\Lock\LockedException($path);
357
+                    } else {
358
+                        Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
359
+                    }
360
+                }
361
+
362
+                return $response->getBody();
363
+            case 'w':
364
+            case 'wb':
365
+            case 'a':
366
+            case 'ab':
367
+            case 'r+':
368
+            case 'w+':
369
+            case 'wb+':
370
+            case 'a+':
371
+            case 'x':
372
+            case 'x+':
373
+            case 'c':
374
+            case 'c+':
375
+                //emulate these
376
+                $tempManager = \OC::$server->getTempManager();
377
+                if (strrpos($path, '.') !== false) {
378
+                    $ext = substr($path, strrpos($path, '.'));
379
+                } else {
380
+                    $ext = '';
381
+                }
382
+                if ($this->file_exists($path)) {
383
+                    if (!$this->isUpdatable($path)) {
384
+                        return false;
385
+                    }
386
+                    if ($mode === 'w' or $mode === 'w+') {
387
+                        $tmpFile = $tempManager->getTemporaryFile($ext);
388
+                    } else {
389
+                        $tmpFile = $this->getCachedFile($path);
390
+                    }
391
+                } else {
392
+                    if (!$this->isCreatable(dirname($path))) {
393
+                        return false;
394
+                    }
395
+                    $tmpFile = $tempManager->getTemporaryFile($ext);
396
+                }
397
+                $handle = fopen($tmpFile, $mode);
398
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
399
+                    $this->writeBack($tmpFile, $path);
400
+                });
401
+        }
402
+    }
403
+
404
+    /**
405
+     * @param string $tmpFile
406
+     */
407
+    public function writeBack($tmpFile, $path) {
408
+        $this->uploadFile($tmpFile, $path);
409
+        unlink($tmpFile);
410
+    }
411
+
412
+    /** {@inheritdoc} */
413
+    public function free_space($path) {
414
+        $this->init();
415
+        $path = $this->cleanPath($path);
416
+        try {
417
+            // TODO: cacheable ?
418
+            $response = $this->client->propfind($this->encodePath($path), ['{DAV:}quota-available-bytes']);
419
+            if ($response === false) {
420
+                return FileInfo::SPACE_UNKNOWN;
421
+            }
422
+            if (isset($response['{DAV:}quota-available-bytes'])) {
423
+                return (int)$response['{DAV:}quota-available-bytes'];
424
+            } else {
425
+                return FileInfo::SPACE_UNKNOWN;
426
+            }
427
+        } catch (\Exception $e) {
428
+            return FileInfo::SPACE_UNKNOWN;
429
+        }
430
+    }
431
+
432
+    /** {@inheritdoc} */
433
+    public function touch($path, $mtime = null) {
434
+        $this->init();
435
+        if (is_null($mtime)) {
436
+            $mtime = time();
437
+        }
438
+        $path = $this->cleanPath($path);
439
+
440
+        // if file exists, update the mtime, else create a new empty file
441
+        if ($this->file_exists($path)) {
442
+            try {
443
+                $this->statCache->remove($path);
444
+                $this->client->proppatch($this->encodePath($path), ['{DAV:}lastmodified' => $mtime]);
445
+                // non-owncloud clients might not have accepted the property, need to recheck it
446
+                $response = $this->client->propfind($this->encodePath($path), ['{DAV:}getlastmodified'], 0);
447
+                if ($response === false) {
448
+                    return false;
449
+                }
450
+                if (isset($response['{DAV:}getlastmodified'])) {
451
+                    $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
452
+                    if ($remoteMtime !== $mtime) {
453
+                        // server has not accepted the mtime
454
+                        return false;
455
+                    }
456
+                }
457
+            } catch (ClientHttpException $e) {
458
+                if ($e->getHttpStatus() === 501) {
459
+                    return false;
460
+                }
461
+                $this->convertException($e, $path);
462
+                return false;
463
+            } catch (\Exception $e) {
464
+                $this->convertException($e, $path);
465
+                return false;
466
+            }
467
+        } else {
468
+            $this->file_put_contents($path, '');
469
+        }
470
+        return true;
471
+    }
472
+
473
+    /**
474
+     * @param string $path
475
+     * @param string $data
476
+     * @return int
477
+     */
478
+    public function file_put_contents($path, $data) {
479
+        $path = $this->cleanPath($path);
480
+        $result = parent::file_put_contents($path, $data);
481
+        $this->statCache->remove($path);
482
+        return $result;
483
+    }
484
+
485
+    /**
486
+     * @param string $path
487
+     * @param string $target
488
+     */
489
+    protected function uploadFile($path, $target) {
490
+        $this->init();
491
+
492
+        // invalidate
493
+        $target = $this->cleanPath($target);
494
+        $this->statCache->remove($target);
495
+        $source = fopen($path, 'r');
496
+
497
+        $this->httpClientService
498
+            ->newClient()
499
+            ->put($this->createBaseUri() . $this->encodePath($target), [
500
+                'body' => $source,
501
+                'auth' => [$this->user, $this->password]
502
+            ]);
503
+
504
+        $this->removeCachedFile($target);
505
+    }
506
+
507
+    /** {@inheritdoc} */
508
+    public function rename($path1, $path2) {
509
+        $this->init();
510
+        $path1 = $this->cleanPath($path1);
511
+        $path2 = $this->cleanPath($path2);
512
+        try {
513
+            // overwrite directory ?
514
+            if ($this->is_dir($path2)) {
515
+                // needs trailing slash in destination
516
+                $path2 = rtrim($path2, '/') . '/';
517
+            }
518
+            $this->client->request(
519
+                'MOVE',
520
+                $this->encodePath($path1),
521
+                null,
522
+                [
523
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
524
+                ]
525
+            );
526
+            $this->statCache->clear($path1 . '/');
527
+            $this->statCache->clear($path2 . '/');
528
+            $this->statCache->set($path1, false);
529
+            $this->statCache->set($path2, true);
530
+            $this->removeCachedFile($path1);
531
+            $this->removeCachedFile($path2);
532
+            return true;
533
+        } catch (\Exception $e) {
534
+            $this->convertException($e);
535
+        }
536
+        return false;
537
+    }
538
+
539
+    /** {@inheritdoc} */
540
+    public function copy($path1, $path2) {
541
+        $this->init();
542
+        $path1 = $this->cleanPath($path1);
543
+        $path2 = $this->cleanPath($path2);
544
+        try {
545
+            // overwrite directory ?
546
+            if ($this->is_dir($path2)) {
547
+                // needs trailing slash in destination
548
+                $path2 = rtrim($path2, '/') . '/';
549
+            }
550
+            $this->client->request(
551
+                'COPY',
552
+                $this->encodePath($path1),
553
+                null,
554
+                [
555
+                    'Destination' => $this->createBaseUri() . $this->encodePath($path2),
556
+                ]
557
+            );
558
+            $this->statCache->clear($path2 . '/');
559
+            $this->statCache->set($path2, true);
560
+            $this->removeCachedFile($path2);
561
+            return true;
562
+        } catch (\Exception $e) {
563
+            $this->convertException($e);
564
+        }
565
+        return false;
566
+    }
567
+
568
+    /** {@inheritdoc} */
569
+    public function stat($path) {
570
+        try {
571
+            $response = $this->propfind($path);
572
+            if (!$response) {
573
+                return false;
574
+            }
575
+            return [
576
+                'mtime' => strtotime($response['{DAV:}getlastmodified']),
577
+                'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
578
+            ];
579
+        } catch (\Exception $e) {
580
+            $this->convertException($e, $path);
581
+        }
582
+        return array();
583
+    }
584
+
585
+    /** {@inheritdoc} */
586
+    public function getMimeType($path) {
587
+        try {
588
+            $response = $this->propfind($path);
589
+            if ($response === false) {
590
+                return false;
591
+            }
592
+            $responseType = [];
593
+            if (isset($response["{DAV:}resourcetype"])) {
594
+                /** @var ResourceType[] $response */
595
+                $responseType = $response["{DAV:}resourcetype"]->getValue();
596
+            }
597
+            $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
598
+            if ($type == 'dir') {
599
+                return 'httpd/unix-directory';
600
+            } elseif (isset($response['{DAV:}getcontenttype'])) {
601
+                return $response['{DAV:}getcontenttype'];
602
+            } else {
603
+                return false;
604
+            }
605
+        } catch (\Exception $e) {
606
+            $this->convertException($e, $path);
607
+        }
608
+        return false;
609
+    }
610
+
611
+    /**
612
+     * @param string $path
613
+     * @return string
614
+     */
615
+    public function cleanPath($path) {
616
+        if ($path === '') {
617
+            return $path;
618
+        }
619
+        $path = Filesystem::normalizePath($path);
620
+        // remove leading slash
621
+        return substr($path, 1);
622
+    }
623
+
624
+    /**
625
+     * URL encodes the given path but keeps the slashes
626
+     *
627
+     * @param string $path to encode
628
+     * @return string encoded path
629
+     */
630
+    protected function encodePath($path) {
631
+        // slashes need to stay
632
+        return str_replace('%2F', '/', rawurlencode($path));
633
+    }
634
+
635
+    /**
636
+     * @param string $method
637
+     * @param string $path
638
+     * @param string|resource|null $body
639
+     * @param int $expected
640
+     * @return bool
641
+     * @throws StorageInvalidException
642
+     * @throws StorageNotAvailableException
643
+     */
644
+    protected function simpleResponse($method, $path, $body, $expected) {
645
+        $path = $this->cleanPath($path);
646
+        try {
647
+            $response = $this->client->request($method, $this->encodePath($path), $body);
648
+            return $response['statusCode'] == $expected;
649
+        } catch (ClientHttpException $e) {
650
+            if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
651
+                $this->statCache->clear($path . '/');
652
+                $this->statCache->set($path, false);
653
+                return false;
654
+            }
655
+
656
+            $this->convertException($e, $path);
657
+        } catch (\Exception $e) {
658
+            $this->convertException($e, $path);
659
+        }
660
+        return false;
661
+    }
662
+
663
+    /**
664
+     * check if curl is installed
665
+     */
666
+    public static function checkDependencies() {
667
+        return true;
668
+    }
669
+
670
+    /** {@inheritdoc} */
671
+    public function isUpdatable($path) {
672
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
673
+    }
674
+
675
+    /** {@inheritdoc} */
676
+    public function isCreatable($path) {
677
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
678
+    }
679
+
680
+    /** {@inheritdoc} */
681
+    public function isSharable($path) {
682
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
683
+    }
684
+
685
+    /** {@inheritdoc} */
686
+    public function isDeletable($path) {
687
+        return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
688
+    }
689
+
690
+    /** {@inheritdoc} */
691
+    public function getPermissions($path) {
692
+        $this->init();
693
+        $path = $this->cleanPath($path);
694
+        $response = $this->propfind($path);
695
+        if ($response === false) {
696
+            return 0;
697
+        }
698
+        if (isset($response['{http://owncloud.org/ns}permissions'])) {
699
+            return $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
700
+        } else if ($this->is_dir($path)) {
701
+            return Constants::PERMISSION_ALL;
702
+        } else if ($this->file_exists($path)) {
703
+            return Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
704
+        } else {
705
+            return 0;
706
+        }
707
+    }
708
+
709
+    /** {@inheritdoc} */
710
+    public function getETag($path) {
711
+        $this->init();
712
+        $path = $this->cleanPath($path);
713
+        $response = $this->propfind($path);
714
+        if ($response === false) {
715
+            return null;
716
+        }
717
+        if (isset($response['{DAV:}getetag'])) {
718
+            return trim($response['{DAV:}getetag'], '"');
719
+        }
720
+        return parent::getEtag($path);
721
+    }
722
+
723
+    /**
724
+     * @param string $permissionsString
725
+     * @return int
726
+     */
727
+    protected function parsePermissions($permissionsString) {
728
+        $permissions = Constants::PERMISSION_READ;
729
+        if (strpos($permissionsString, 'R') !== false) {
730
+            $permissions |= Constants::PERMISSION_SHARE;
731
+        }
732
+        if (strpos($permissionsString, 'D') !== false) {
733
+            $permissions |= Constants::PERMISSION_DELETE;
734
+        }
735
+        if (strpos($permissionsString, 'W') !== false) {
736
+            $permissions |= Constants::PERMISSION_UPDATE;
737
+        }
738
+        if (strpos($permissionsString, 'CK') !== false) {
739
+            $permissions |= Constants::PERMISSION_CREATE;
740
+            $permissions |= Constants::PERMISSION_UPDATE;
741
+        }
742
+        return $permissions;
743
+    }
744
+
745
+    /**
746
+     * check if a file or folder has been updated since $time
747
+     *
748
+     * @param string $path
749
+     * @param int $time
750
+     * @throws \OCP\Files\StorageNotAvailableException
751
+     * @return bool
752
+     */
753
+    public function hasUpdated($path, $time) {
754
+        $this->init();
755
+        $path = $this->cleanPath($path);
756
+        try {
757
+            // force refresh for $path
758
+            $this->statCache->remove($path);
759
+            $response = $this->propfind($path);
760
+            if ($response === false) {
761
+                if ($path === '') {
762
+                    // if root is gone it means the storage is not available
763
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
764
+                }
765
+                return false;
766
+            }
767
+            if (isset($response['{DAV:}getetag'])) {
768
+                $cachedData = $this->getCache()->get($path);
769
+                $etag = null;
770
+                if (isset($response['{DAV:}getetag'])) {
771
+                    $etag = trim($response['{DAV:}getetag'], '"');
772
+                }
773
+                if (!empty($etag) && $cachedData['etag'] !== $etag) {
774
+                    return true;
775
+                } else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
776
+                    $sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
777
+                    return $sharePermissions !== $cachedData['permissions'];
778
+                } else if (isset($response['{http://owncloud.org/ns}permissions'])) {
779
+                    $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
780
+                    return $permissions !== $cachedData['permissions'];
781
+                } else {
782
+                    return false;
783
+                }
784
+            } else {
785
+                $remoteMtime = strtotime($response['{DAV:}getlastmodified']);
786
+                return $remoteMtime > $time;
787
+            }
788
+        } catch (ClientHttpException $e) {
789
+            if ($e->getHttpStatus() === 405) {
790
+                if ($path === '') {
791
+                    // if root is gone it means the storage is not available
792
+                    throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
793
+                }
794
+                return false;
795
+            }
796
+            $this->convertException($e, $path);
797
+            return false;
798
+        } catch (\Exception $e) {
799
+            $this->convertException($e, $path);
800
+            return false;
801
+        }
802
+    }
803
+
804
+    /**
805
+     * Interpret the given exception and decide whether it is due to an
806
+     * unavailable storage, invalid storage or other.
807
+     * This will either throw StorageInvalidException, StorageNotAvailableException
808
+     * or do nothing.
809
+     *
810
+     * @param Exception $e sabre exception
811
+     * @param string $path optional path from the operation
812
+     *
813
+     * @throws StorageInvalidException if the storage is invalid, for example
814
+     * when the authentication expired or is invalid
815
+     * @throws StorageNotAvailableException if the storage is not available,
816
+     * which might be temporary
817
+     */
818
+    protected function convertException(Exception $e, $path = '') {
819
+        \OC::$server->getLogger()->logException($e);
820
+        Util::writeLog('files_external', $e->getMessage(), Util::ERROR);
821
+        if ($e instanceof ClientHttpException) {
822
+            if ($e->getHttpStatus() === Http::STATUS_LOCKED) {
823
+                throw new \OCP\Lock\LockedException($path);
824
+            }
825
+            if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
826
+                // either password was changed or was invalid all along
827
+                throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
828
+            } else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
829
+                // ignore exception for MethodNotAllowed, false will be returned
830
+                return;
831
+            }
832
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
833
+        } else if ($e instanceof ClientException) {
834
+            // connection timeout or refused, server could be temporarily down
835
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
836
+        } else if ($e instanceof \InvalidArgumentException) {
837
+            // parse error because the server returned HTML instead of XML,
838
+            // possibly temporarily down
839
+            throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
840
+        } else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
841
+            // rethrow
842
+            throw $e;
843
+        }
844
+
845
+        // TODO: only log for now, but in the future need to wrap/rethrow exception
846
+    }
847 847
 }
848 848
 
Please login to merge, or discard this patch.
Spacing   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
 				if (is_string($params['secure'])) {
100 100
 					$this->secure = ($params['secure'] === 'true');
101 101
 				} else {
102
-					$this->secure = (bool)$params['secure'];
102
+					$this->secure = (bool) $params['secure'];
103 103
 				}
104 104
 			} else {
105 105
 				$this->secure = false;
@@ -117,7 +117,7 @@  discard block
 block discarded – undo
117 117
 			}
118 118
 			$this->root = isset($params['root']) ? $params['root'] : '/';
119 119
 			if (!$this->root || $this->root[0] != '/') {
120
-				$this->root = '/' . $this->root;
120
+				$this->root = '/'.$this->root;
121 121
 			}
122 122
 			if (substr($this->root, -1, 1) != '/') {
123 123
 				$this->root .= '/';
@@ -140,7 +140,7 @@  discard block
 block discarded – undo
140 140
 		);
141 141
 
142 142
 		$proxy = \OC::$server->getConfig()->getSystemValue('proxy', '');
143
-		if($proxy !== '') {
143
+		if ($proxy !== '') {
144 144
 			$settings['proxy'] = $proxy;
145 145
 		}
146 146
 
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 
161 161
 	/** {@inheritdoc} */
162 162
 	public function getId() {
163
-		return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
163
+		return 'webdav::'.$this->user.'@'.$this->host.'/'.$this->root;
164 164
 	}
165 165
 
166 166
 	/** {@inheritdoc} */
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 		if ($this->secure) {
170 170
 			$baseUri .= 's';
171 171
 		}
172
-		$baseUri .= '://' . $this->host . $this->root;
172
+		$baseUri .= '://'.$this->host.$this->root;
173 173
 		return $baseUri;
174 174
 	}
175 175
 
@@ -190,8 +190,8 @@  discard block
 block discarded – undo
190 190
 		$path = $this->cleanPath($path);
191 191
 		// FIXME: some WebDAV impl return 403 when trying to DELETE
192 192
 		// a non-empty folder
193
-		$result = $this->simpleResponse('DELETE', $path . '/', null, 204);
194
-		$this->statCache->clear($path . '/');
193
+		$result = $this->simpleResponse('DELETE', $path.'/', null, 204);
194
+		$this->statCache->clear($path.'/');
195 195
 		$this->statCache->remove($path);
196 196
 		return $result;
197 197
 	}
@@ -266,7 +266,7 @@  discard block
 block discarded – undo
266 266
 				$this->statCache->set($path, $response);
267 267
 			} catch (ClientHttpException $e) {
268 268
 				if ($e->getHttpStatus() === 404) {
269
-					$this->statCache->clear($path . '/');
269
+					$this->statCache->clear($path.'/');
270 270
 					$this->statCache->set($path, false);
271 271
 					return false;
272 272
 				}
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
 		$this->init();
324 324
 		$path = $this->cleanPath($path);
325 325
 		$result = $this->simpleResponse('DELETE', $path, null, 204);
326
-		$this->statCache->clear($path . '/');
326
+		$this->statCache->clear($path.'/');
327 327
 		$this->statCache->remove($path);
328 328
 		return $result;
329 329
 	}
@@ -338,7 +338,7 @@  discard block
 block discarded – undo
338 338
 				try {
339 339
 					$response = $this->httpClientService
340 340
 							->newClient()
341
-							->get($this->createBaseUri() . $this->encodePath($path), [
341
+							->get($this->createBaseUri().$this->encodePath($path), [
342 342
 									'auth' => [$this->user, $this->password],
343 343
 									'stream' => true
344 344
 							]);
@@ -355,7 +355,7 @@  discard block
 block discarded – undo
355 355
 					if ($response->getStatusCode() === Http::STATUS_LOCKED) {
356 356
 						throw new \OCP\Lock\LockedException($path);
357 357
 					} else {
358
-						Util::writeLog("webdav client", 'Guzzle get returned status code ' . $response->getStatusCode(), Util::ERROR);
358
+						Util::writeLog("webdav client", 'Guzzle get returned status code '.$response->getStatusCode(), Util::ERROR);
359 359
 					}
360 360
 				}
361 361
 
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 					$tmpFile = $tempManager->getTemporaryFile($ext);
396 396
 				}
397 397
 				$handle = fopen($tmpFile, $mode);
398
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
398
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
399 399
 					$this->writeBack($tmpFile, $path);
400 400
 				});
401 401
 		}
@@ -420,7 +420,7 @@  discard block
 block discarded – undo
420 420
 				return FileInfo::SPACE_UNKNOWN;
421 421
 			}
422 422
 			if (isset($response['{DAV:}quota-available-bytes'])) {
423
-				return (int)$response['{DAV:}quota-available-bytes'];
423
+				return (int) $response['{DAV:}quota-available-bytes'];
424 424
 			} else {
425 425
 				return FileInfo::SPACE_UNKNOWN;
426 426
 			}
@@ -496,7 +496,7 @@  discard block
 block discarded – undo
496 496
 
497 497
 		$this->httpClientService
498 498
 			->newClient()
499
-			->put($this->createBaseUri() . $this->encodePath($target), [
499
+			->put($this->createBaseUri().$this->encodePath($target), [
500 500
 				'body' => $source,
501 501
 				'auth' => [$this->user, $this->password]
502 502
 			]);
@@ -513,18 +513,18 @@  discard block
 block discarded – undo
513 513
 			// overwrite directory ?
514 514
 			if ($this->is_dir($path2)) {
515 515
 				// needs trailing slash in destination
516
-				$path2 = rtrim($path2, '/') . '/';
516
+				$path2 = rtrim($path2, '/').'/';
517 517
 			}
518 518
 			$this->client->request(
519 519
 				'MOVE',
520 520
 				$this->encodePath($path1),
521 521
 				null,
522 522
 				[
523
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
523
+					'Destination' => $this->createBaseUri().$this->encodePath($path2),
524 524
 				]
525 525
 			);
526
-			$this->statCache->clear($path1 . '/');
527
-			$this->statCache->clear($path2 . '/');
526
+			$this->statCache->clear($path1.'/');
527
+			$this->statCache->clear($path2.'/');
528 528
 			$this->statCache->set($path1, false);
529 529
 			$this->statCache->set($path2, true);
530 530
 			$this->removeCachedFile($path1);
@@ -545,17 +545,17 @@  discard block
 block discarded – undo
545 545
 			// overwrite directory ?
546 546
 			if ($this->is_dir($path2)) {
547 547
 				// needs trailing slash in destination
548
-				$path2 = rtrim($path2, '/') . '/';
548
+				$path2 = rtrim($path2, '/').'/';
549 549
 			}
550 550
 			$this->client->request(
551 551
 				'COPY',
552 552
 				$this->encodePath($path1),
553 553
 				null,
554 554
 				[
555
-					'Destination' => $this->createBaseUri() . $this->encodePath($path2),
555
+					'Destination' => $this->createBaseUri().$this->encodePath($path2),
556 556
 				]
557 557
 			);
558
-			$this->statCache->clear($path2 . '/');
558
+			$this->statCache->clear($path2.'/');
559 559
 			$this->statCache->set($path2, true);
560 560
 			$this->removeCachedFile($path2);
561 561
 			return true;
@@ -574,7 +574,7 @@  discard block
 block discarded – undo
574 574
 			}
575 575
 			return [
576 576
 				'mtime' => strtotime($response['{DAV:}getlastmodified']),
577
-				'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
577
+				'size' => (int) isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
578 578
 			];
579 579
 		} catch (\Exception $e) {
580 580
 			$this->convertException($e, $path);
@@ -648,7 +648,7 @@  discard block
 block discarded – undo
648 648
 			return $response['statusCode'] == $expected;
649 649
 		} catch (ClientHttpException $e) {
650 650
 			if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
651
-				$this->statCache->clear($path . '/');
651
+				$this->statCache->clear($path.'/');
652 652
 				$this->statCache->set($path, false);
653 653
 				return false;
654 654
 			}
@@ -669,22 +669,22 @@  discard block
 block discarded – undo
669 669
 
670 670
 	/** {@inheritdoc} */
671 671
 	public function isUpdatable($path) {
672
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
672
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_UPDATE);
673 673
 	}
674 674
 
675 675
 	/** {@inheritdoc} */
676 676
 	public function isCreatable($path) {
677
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_CREATE);
677
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_CREATE);
678 678
 	}
679 679
 
680 680
 	/** {@inheritdoc} */
681 681
 	public function isSharable($path) {
682
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_SHARE);
682
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_SHARE);
683 683
 	}
684 684
 
685 685
 	/** {@inheritdoc} */
686 686
 	public function isDeletable($path) {
687
-		return (bool)($this->getPermissions($path) & Constants::PERMISSION_DELETE);
687
+		return (bool) ($this->getPermissions($path) & Constants::PERMISSION_DELETE);
688 688
 	}
689 689
 
690 690
 	/** {@inheritdoc} */
@@ -760,7 +760,7 @@  discard block
 block discarded – undo
760 760
 			if ($response === false) {
761 761
 				if ($path === '') {
762 762
 					// if root is gone it means the storage is not available
763
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
763
+					throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
764 764
 				}
765 765
 				return false;
766 766
 			}
@@ -773,7 +773,7 @@  discard block
 block discarded – undo
773 773
 				if (!empty($etag) && $cachedData['etag'] !== $etag) {
774 774
 					return true;
775 775
 				} else if (isset($response['{http://open-collaboration-services.org/ns}share-permissions'])) {
776
-					$sharePermissions = (int)$response['{http://open-collaboration-services.org/ns}share-permissions'];
776
+					$sharePermissions = (int) $response['{http://open-collaboration-services.org/ns}share-permissions'];
777 777
 					return $sharePermissions !== $cachedData['permissions'];
778 778
 				} else if (isset($response['{http://owncloud.org/ns}permissions'])) {
779 779
 					$permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']);
@@ -789,7 +789,7 @@  discard block
 block discarded – undo
789 789
 			if ($e->getHttpStatus() === 405) {
790 790
 				if ($path === '') {
791 791
 					// if root is gone it means the storage is not available
792
-					throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
792
+					throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
793 793
 				}
794 794
 				return false;
795 795
 			}
@@ -824,19 +824,19 @@  discard block
 block discarded – undo
824 824
 			}
825 825
 			if ($e->getHttpStatus() === Http::STATUS_UNAUTHORIZED) {
826 826
 				// either password was changed or was invalid all along
827
-				throw new StorageInvalidException(get_class($e) . ': ' . $e->getMessage());
827
+				throw new StorageInvalidException(get_class($e).': '.$e->getMessage());
828 828
 			} else if ($e->getHttpStatus() === Http::STATUS_METHOD_NOT_ALLOWED) {
829 829
 				// ignore exception for MethodNotAllowed, false will be returned
830 830
 				return;
831 831
 			}
832
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
832
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
833 833
 		} else if ($e instanceof ClientException) {
834 834
 			// connection timeout or refused, server could be temporarily down
835
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
835
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
836 836
 		} else if ($e instanceof \InvalidArgumentException) {
837 837
 			// parse error because the server returned HTML instead of XML,
838 838
 			// possibly temporarily down
839
-			throw new StorageNotAvailableException(get_class($e) . ': ' . $e->getMessage());
839
+			throw new StorageNotAvailableException(get_class($e).': '.$e->getMessage());
840 840
 		} else if (($e instanceof StorageNotAvailableException) || ($e instanceof StorageInvalidException)) {
841 841
 			// rethrow
842 842
 			throw $e;
Please login to merge, or discard this patch.
Braces   +5 added lines, -2 removed lines patch added patch discarded remove patch
@@ -90,8 +90,11 @@
 block discarded – undo
90 90
 		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
91 91
 			$host = $params['host'];
92 92
 			//remove leading http[s], will be generated in createBaseUri()
93
-			if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
94
-			else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
93
+			if (substr($host, 0, 8) == "https://") {
94
+			    $host = substr($host, 8);
95
+			} else if (substr($host, 0, 7) == "http://") {
96
+			    $host = substr($host, 7);
97
+			}
95 98
 			$this->host = $host;
96 99
 			$this->user = $params['user'];
97 100
 			$this->password = $params['password'];
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Notify/SMBNotifyHandler.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -102,7 +102,7 @@
 block discarded – undo
102 102
 
103 103
 	/**
104 104
 	 * @param \Icewind\SMB\Change $change
105
-	 * @return IChange|null
105
+	 * @return null|Change
106 106
 	 */
107 107
 	private function mapChange(\Icewind\SMB\Change $change) {
108 108
 		$path = $this->relativePath($change->getPath());
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -29,122 +29,122 @@
 block discarded – undo
29 29
 use OCP\Files\Notify\INotifyHandler;
30 30
 
31 31
 class SMBNotifyHandler implements INotifyHandler {
32
-	/**
33
-	 * @var \Icewind\SMB\INotifyHandler
34
-	 */
35
-	private $shareNotifyHandler;
32
+    /**
33
+     * @var \Icewind\SMB\INotifyHandler
34
+     */
35
+    private $shareNotifyHandler;
36 36
 
37
-	/**
38
-	 * @var string
39
-	 */
40
-	private $root;
37
+    /**
38
+     * @var string
39
+     */
40
+    private $root;
41 41
 
42
-	private $oldRenamePath = null;
42
+    private $oldRenamePath = null;
43 43
 
44
-	/**
45
-	 * SMBNotifyHandler constructor.
46
-	 *
47
-	 * @param \Icewind\SMB\INotifyHandler $shareNotifyHandler
48
-	 * @param string $root
49
-	 */
50
-	public function __construct(\Icewind\SMB\INotifyHandler $shareNotifyHandler, $root) {
51
-		$this->shareNotifyHandler = $shareNotifyHandler;
52
-		$this->root = $root;
53
-	}
44
+    /**
45
+     * SMBNotifyHandler constructor.
46
+     *
47
+     * @param \Icewind\SMB\INotifyHandler $shareNotifyHandler
48
+     * @param string $root
49
+     */
50
+    public function __construct(\Icewind\SMB\INotifyHandler $shareNotifyHandler, $root) {
51
+        $this->shareNotifyHandler = $shareNotifyHandler;
52
+        $this->root = $root;
53
+    }
54 54
 
55
-	private function relativePath($fullPath) {
56
-		if ($fullPath === $this->root) {
57
-			return '';
58
-		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
59
-			return substr($fullPath, strlen($this->root));
60
-		} else {
61
-			return null;
62
-		}
63
-	}
55
+    private function relativePath($fullPath) {
56
+        if ($fullPath === $this->root) {
57
+            return '';
58
+        } else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
59
+            return substr($fullPath, strlen($this->root));
60
+        } else {
61
+            return null;
62
+        }
63
+    }
64 64
 
65
-	public function listen(callable $callback) {
66
-		$oldRenamePath = null;
67
-		$this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
68
-			$change = $this->mapChange($shareChange);
69
-			if (!is_null($change)) {
70
-				return $callback($change);
71
-			} else {
72
-				return true;
73
-			}
74
-		});
75
-	}
65
+    public function listen(callable $callback) {
66
+        $oldRenamePath = null;
67
+        $this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
68
+            $change = $this->mapChange($shareChange);
69
+            if (!is_null($change)) {
70
+                return $callback($change);
71
+            } else {
72
+                return true;
73
+            }
74
+        });
75
+    }
76 76
 
77
-	/**
78
-	 * Get all changes detected since the start of the notify process or the last call to getChanges
79
-	 *
80
-	 * @return IChange[]
81
-	 */
82
-	public function getChanges() {
83
-		$shareChanges = $this->shareNotifyHandler->getChanges();
84
-		$changes = [];
85
-		foreach ($shareChanges as $shareChange) {
86
-			$change = $this->mapChange($shareChange);
87
-			if ($change) {
88
-				$changes[] = $change;
89
-			}
90
-		}
91
-		return $changes;
92
-	}
77
+    /**
78
+     * Get all changes detected since the start of the notify process or the last call to getChanges
79
+     *
80
+     * @return IChange[]
81
+     */
82
+    public function getChanges() {
83
+        $shareChanges = $this->shareNotifyHandler->getChanges();
84
+        $changes = [];
85
+        foreach ($shareChanges as $shareChange) {
86
+            $change = $this->mapChange($shareChange);
87
+            if ($change) {
88
+                $changes[] = $change;
89
+            }
90
+        }
91
+        return $changes;
92
+    }
93 93
 
94
-	/**
95
-	 * Stop listening for changes
96
-	 *
97
-	 * Note that any pending changes will be discarded
98
-	 */
99
-	public function stop() {
100
-		$this->shareNotifyHandler->stop();
101
-	}
94
+    /**
95
+     * Stop listening for changes
96
+     *
97
+     * Note that any pending changes will be discarded
98
+     */
99
+    public function stop() {
100
+        $this->shareNotifyHandler->stop();
101
+    }
102 102
 
103
-	/**
104
-	 * @param \Icewind\SMB\Change $change
105
-	 * @return IChange|null
106
-	 */
107
-	private function mapChange(\Icewind\SMB\Change $change) {
108
-		$path = $this->relativePath($change->getPath());
109
-		if (is_null($path)) {
110
-			return null;
111
-		}
112
-		if ($change->getCode() === \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_OLD) {
113
-			$this->oldRenamePath = $path;
114
-			return null;
115
-		}
116
-		$type = $this->mapNotifyType($change->getCode());
117
-		if (is_null($type)) {
118
-			return null;
119
-		}
120
-		if ($type === IChange::RENAMED) {
121
-			if (!is_null($this->oldRenamePath)) {
122
-				$result = new RenameChange($type, $this->oldRenamePath, $path);
123
-				$this->oldRenamePath = null;
124
-			} else {
125
-				$result = null;
126
-			}
127
-		} else {
128
-			$result = new Change($type, $path);
129
-		}
130
-		return $result;
131
-	}
103
+    /**
104
+     * @param \Icewind\SMB\Change $change
105
+     * @return IChange|null
106
+     */
107
+    private function mapChange(\Icewind\SMB\Change $change) {
108
+        $path = $this->relativePath($change->getPath());
109
+        if (is_null($path)) {
110
+            return null;
111
+        }
112
+        if ($change->getCode() === \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_OLD) {
113
+            $this->oldRenamePath = $path;
114
+            return null;
115
+        }
116
+        $type = $this->mapNotifyType($change->getCode());
117
+        if (is_null($type)) {
118
+            return null;
119
+        }
120
+        if ($type === IChange::RENAMED) {
121
+            if (!is_null($this->oldRenamePath)) {
122
+                $result = new RenameChange($type, $this->oldRenamePath, $path);
123
+                $this->oldRenamePath = null;
124
+            } else {
125
+                $result = null;
126
+            }
127
+        } else {
128
+            $result = new Change($type, $path);
129
+        }
130
+        return $result;
131
+    }
132 132
 
133
-	private function mapNotifyType($smbType) {
134
-		switch ($smbType) {
135
-			case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED:
136
-				return IChange::ADDED;
137
-			case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED:
138
-				return IChange::REMOVED;
139
-			case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED:
140
-			case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED_STREAM:
141
-			case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED_STREAM:
142
-			case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED_STREAM:
143
-				return IChange::MODIFIED;
144
-			case \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_NEW:
145
-				return IChange::RENAMED;
146
-			default:
147
-				return null;
148
-		}
149
-	}
133
+    private function mapNotifyType($smbType) {
134
+        switch ($smbType) {
135
+            case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED:
136
+                return IChange::ADDED;
137
+            case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED:
138
+                return IChange::REMOVED;
139
+            case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED:
140
+            case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED_STREAM:
141
+            case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED_STREAM:
142
+            case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED_STREAM:
143
+                return IChange::MODIFIED;
144
+            case \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_NEW:
145
+                return IChange::RENAMED;
146
+            default:
147
+                return null;
148
+        }
149
+    }
150 150
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@
 block discarded – undo
64 64
 
65 65
 	public function listen(callable $callback) {
66 66
 		$oldRenamePath = null;
67
-		$this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
67
+		$this->shareNotifyHandler->listen(function(\Icewind\SMB\Change $shareChange) use ($callback) {
68 68
 			$change = $this->mapChange($shareChange);
69 69
 			if (!is_null($change)) {
70 70
 				return $callback($change);
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/SMB.php 4 patches
Unused Use Statements   -3 removed lines patch added patch discarded remove patch
@@ -31,14 +31,11 @@
 block discarded – undo
31 31
 
32 32
 namespace OCA\Files_External\Lib\Storage;
33 33
 
34
-use Icewind\SMB\Change;
35 34
 use Icewind\SMB\Exception\ConnectException;
36 35
 use Icewind\SMB\Exception\Exception;
37 36
 use Icewind\SMB\Exception\ForbiddenException;
38 37
 use Icewind\SMB\Exception\NotFoundException;
39
-use Icewind\SMB\INotifyHandler;
40 38
 use Icewind\SMB\IFileInfo;
41
-use Icewind\SMB\IShare;
42 39
 use Icewind\SMB\NativeServer;
43 40
 use Icewind\SMB\Server;
44 41
 use Icewind\Streams\CallbackWrapper;
Please login to merge, or discard this patch.
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -498,6 +498,9 @@
 block discarded – undo
498 498
 		});
499 499
 	}
500 500
 
501
+	/**
502
+	 * @param string $path
503
+	 */
501 504
 	public function notify($path) {
502 505
 		$path = '/' . ltrim($path, '/');
503 506
 		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
Please login to merge, or discard this patch.
Indentation   +450 added lines, -450 removed lines patch added patch discarded remove patch
@@ -53,454 +53,454 @@
 block discarded – undo
53 53
 use OCP\Files\StorageNotAvailableException;
54 54
 
55 55
 class SMB extends Common implements INotifyStorage {
56
-	/**
57
-	 * @var \Icewind\SMB\Server
58
-	 */
59
-	protected $server;
60
-
61
-	/**
62
-	 * @var \Icewind\SMB\Share
63
-	 */
64
-	protected $share;
65
-
66
-	/**
67
-	 * @var string
68
-	 */
69
-	protected $root;
70
-
71
-	/**
72
-	 * @var \Icewind\SMB\FileInfo[]
73
-	 */
74
-	protected $statCache;
75
-
76
-	public function __construct($params) {
77
-		if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
78
-			if (Server::NativeAvailable()) {
79
-				$this->server = new NativeServer($params['host'], $params['user'], $params['password']);
80
-			} else {
81
-				$this->server = new Server($params['host'], $params['user'], $params['password']);
82
-			}
83
-			$this->share = $this->server->getShare(trim($params['share'], '/'));
84
-
85
-			$this->root = isset($params['root']) ? $params['root'] : '/';
86
-			if (!$this->root || $this->root[0] != '/') {
87
-				$this->root = '/' . $this->root;
88
-			}
89
-			if (substr($this->root, -1, 1) != '/') {
90
-				$this->root .= '/';
91
-			}
92
-		} else {
93
-			throw new \Exception('Invalid configuration');
94
-		}
95
-		$this->statCache = new CappedMemoryCache();
96
-	}
97
-
98
-	/**
99
-	 * @return string
100
-	 */
101
-	public function getId() {
102
-		// FIXME: double slash to keep compatible with the old storage ids,
103
-		// failure to do so will lead to creation of a new storage id and
104
-		// loss of shares from the storage
105
-		return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
106
-	}
107
-
108
-	/**
109
-	 * @param string $path
110
-	 * @return string
111
-	 */
112
-	protected function buildPath($path) {
113
-		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
114
-	}
115
-
116
-	protected function relativePath($fullPath) {
117
-		if ($fullPath === $this->root) {
118
-			return '';
119
-		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
120
-			return substr($fullPath, strlen($this->root));
121
-		} else {
122
-			return null;
123
-		}
124
-	}
125
-
126
-	/**
127
-	 * @param string $path
128
-	 * @return \Icewind\SMB\IFileInfo
129
-	 * @throws StorageNotAvailableException
130
-	 */
131
-	protected function getFileInfo($path) {
132
-		try {
133
-			$path = $this->buildPath($path);
134
-			if (!isset($this->statCache[$path])) {
135
-				$this->statCache[$path] = $this->share->stat($path);
136
-			}
137
-			return $this->statCache[$path];
138
-		} catch (ConnectException $e) {
139
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
140
-		}
141
-	}
142
-
143
-	/**
144
-	 * @param string $path
145
-	 * @return \Icewind\SMB\IFileInfo[]
146
-	 * @throws StorageNotAvailableException
147
-	 */
148
-	protected function getFolderContents($path) {
149
-		try {
150
-			$path = $this->buildPath($path);
151
-			$files = $this->share->dir($path);
152
-			foreach ($files as $file) {
153
-				$this->statCache[$path . '/' . $file->getName()] = $file;
154
-			}
155
-			return array_filter($files, function (IFileInfo $file) {
156
-				return !$file->isHidden();
157
-			});
158
-		} catch (ConnectException $e) {
159
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
160
-		}
161
-	}
162
-
163
-	/**
164
-	 * @param \Icewind\SMB\IFileInfo $info
165
-	 * @return array
166
-	 */
167
-	protected function formatInfo($info) {
168
-		return array(
169
-			'size' => $info->getSize(),
170
-			'mtime' => $info->getMTime()
171
-		);
172
-	}
173
-
174
-	/**
175
-	 * @param string $path
176
-	 * @return array
177
-	 */
178
-	public function stat($path) {
179
-		$result = $this->formatInfo($this->getFileInfo($path));
180
-		if ($this->remoteIsShare() && $this->isRootDir($path)) {
181
-			$result['mtime'] = $this->shareMTime();
182
-		}
183
-		return $result;
184
-	}
185
-
186
-	/**
187
-	 * get the best guess for the modification time of the share
188
-	 *
189
-	 * @return int
190
-	 */
191
-	private function shareMTime() {
192
-		$highestMTime = 0;
193
-		$files = $this->share->dir($this->root);
194
-		foreach ($files as $fileInfo) {
195
-			if ($fileInfo->getMTime() > $highestMTime) {
196
-				$highestMTime = $fileInfo->getMTime();
197
-			}
198
-		}
199
-		return $highestMTime;
200
-	}
201
-
202
-	/**
203
-	 * Check if the path is our root dir (not the smb one)
204
-	 *
205
-	 * @param string $path the path
206
-	 * @return bool
207
-	 */
208
-	private function isRootDir($path) {
209
-		return $path === '' || $path === '/' || $path === '.';
210
-	}
211
-
212
-	/**
213
-	 * Check if our root points to a smb share
214
-	 *
215
-	 * @return bool true if our root points to a share false otherwise
216
-	 */
217
-	private function remoteIsShare() {
218
-		return $this->share->getName() && (!$this->root || $this->root === '/');
219
-	}
220
-
221
-	/**
222
-	 * @param string $path
223
-	 * @return bool
224
-	 */
225
-	public function unlink($path) {
226
-		try {
227
-			if ($this->is_dir($path)) {
228
-				return $this->rmdir($path);
229
-			} else {
230
-				$path = $this->buildPath($path);
231
-				unset($this->statCache[$path]);
232
-				$this->share->del($path);
233
-				return true;
234
-			}
235
-		} catch (NotFoundException $e) {
236
-			return false;
237
-		} catch (ForbiddenException $e) {
238
-			return false;
239
-		} catch (ConnectException $e) {
240
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
241
-		}
242
-	}
243
-
244
-	/**
245
-	 * @param string $path1 the old name
246
-	 * @param string $path2 the new name
247
-	 * @return bool
248
-	 */
249
-	public function rename($path1, $path2) {
250
-		try {
251
-			$this->remove($path2);
252
-			$path1 = $this->buildPath($path1);
253
-			$path2 = $this->buildPath($path2);
254
-			return $this->share->rename($path1, $path2);
255
-		} catch (NotFoundException $e) {
256
-			return false;
257
-		} catch (ForbiddenException $e) {
258
-			return false;
259
-		} catch (ConnectException $e) {
260
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
261
-		}
262
-	}
263
-
264
-	/**
265
-	 * check if a file or folder has been updated since $time
266
-	 *
267
-	 * @param string $path
268
-	 * @param int $time
269
-	 * @return bool
270
-	 */
271
-	public function hasUpdated($path, $time) {
272
-		if (!$path and $this->root == '/') {
273
-			// mtime doesn't work for shares, but giving the nature of the backend,
274
-			// doing a full update is still just fast enough
275
-			return true;
276
-		} else {
277
-			$actualTime = $this->filemtime($path);
278
-			return $actualTime > $time;
279
-		}
280
-	}
281
-
282
-	/**
283
-	 * @param string $path
284
-	 * @param string $mode
285
-	 * @return resource|false
286
-	 */
287
-	public function fopen($path, $mode) {
288
-		$fullPath = $this->buildPath($path);
289
-		try {
290
-			switch ($mode) {
291
-				case 'r':
292
-				case 'rb':
293
-					if (!$this->file_exists($path)) {
294
-						return false;
295
-					}
296
-					return $this->share->read($fullPath);
297
-				case 'w':
298
-				case 'wb':
299
-					$source = $this->share->write($fullPath);
300
-					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
301
-						unset($this->statCache[$fullPath]);
302
-					});
303
-				case 'a':
304
-				case 'ab':
305
-				case 'r+':
306
-				case 'w+':
307
-				case 'wb+':
308
-				case 'a+':
309
-				case 'x':
310
-				case 'x+':
311
-				case 'c':
312
-				case 'c+':
313
-					//emulate these
314
-					if (strrpos($path, '.') !== false) {
315
-						$ext = substr($path, strrpos($path, '.'));
316
-					} else {
317
-						$ext = '';
318
-					}
319
-					if ($this->file_exists($path)) {
320
-						if (!$this->isUpdatable($path)) {
321
-							return false;
322
-						}
323
-						$tmpFile = $this->getCachedFile($path);
324
-					} else {
325
-						if (!$this->isCreatable(dirname($path))) {
326
-							return false;
327
-						}
328
-						$tmpFile = \OCP\Files::tmpFile($ext);
329
-					}
330
-					$source = fopen($tmpFile, $mode);
331
-					$share = $this->share;
332
-					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
333
-						unset($this->statCache[$fullPath]);
334
-						$share->put($tmpFile, $fullPath);
335
-						unlink($tmpFile);
336
-					});
337
-			}
338
-			return false;
339
-		} catch (NotFoundException $e) {
340
-			return false;
341
-		} catch (ForbiddenException $e) {
342
-			return false;
343
-		} catch (ConnectException $e) {
344
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
345
-		}
346
-	}
347
-
348
-	public function rmdir($path) {
349
-		try {
350
-			$this->statCache = array();
351
-			$content = $this->share->dir($this->buildPath($path));
352
-			foreach ($content as $file) {
353
-				if ($file->isDirectory()) {
354
-					$this->rmdir($path . '/' . $file->getName());
355
-				} else {
356
-					$this->share->del($file->getPath());
357
-				}
358
-			}
359
-			$this->share->rmdir($this->buildPath($path));
360
-			return true;
361
-		} catch (NotFoundException $e) {
362
-			return false;
363
-		} catch (ForbiddenException $e) {
364
-			return false;
365
-		} catch (ConnectException $e) {
366
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
367
-		}
368
-	}
369
-
370
-	public function touch($path, $time = null) {
371
-		try {
372
-			if (!$this->file_exists($path)) {
373
-				$fh = $this->share->write($this->buildPath($path));
374
-				fclose($fh);
375
-				return true;
376
-			}
377
-			return false;
378
-		} catch (ConnectException $e) {
379
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
380
-		}
381
-	}
382
-
383
-	public function opendir($path) {
384
-		try {
385
-			$files = $this->getFolderContents($path);
386
-		} catch (NotFoundException $e) {
387
-			return false;
388
-		} catch (ForbiddenException $e) {
389
-			return false;
390
-		}
391
-		$names = array_map(function ($info) {
392
-			/** @var \Icewind\SMB\IFileInfo $info */
393
-			return $info->getName();
394
-		}, $files);
395
-		return IteratorDirectory::wrap($names);
396
-	}
397
-
398
-	public function filetype($path) {
399
-		try {
400
-			return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
401
-		} catch (NotFoundException $e) {
402
-			return false;
403
-		} catch (ForbiddenException $e) {
404
-			return false;
405
-		}
406
-	}
407
-
408
-	public function mkdir($path) {
409
-		$path = $this->buildPath($path);
410
-		try {
411
-			$this->share->mkdir($path);
412
-			return true;
413
-		} catch (ConnectException $e) {
414
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
415
-		} catch (Exception $e) {
416
-			return false;
417
-		}
418
-	}
419
-
420
-	public function file_exists($path) {
421
-		try {
422
-			$this->getFileInfo($path);
423
-			return true;
424
-		} catch (NotFoundException $e) {
425
-			return false;
426
-		} catch (ForbiddenException $e) {
427
-			return false;
428
-		} catch (ConnectException $e) {
429
-			throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
430
-		}
431
-	}
432
-
433
-	public function isReadable($path) {
434
-		try {
435
-			$info = $this->getFileInfo($path);
436
-			return !$info->isHidden();
437
-		} catch (NotFoundException $e) {
438
-			return false;
439
-		} catch (ForbiddenException $e) {
440
-			return false;
441
-		}
442
-	}
443
-
444
-	public function isUpdatable($path) {
445
-		try {
446
-			$info = $this->getFileInfo($path);
447
-			// following windows behaviour for read-only folders: they can be written into
448
-			// (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
449
-			return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
450
-		} catch (NotFoundException $e) {
451
-			return false;
452
-		} catch (ForbiddenException $e) {
453
-			return false;
454
-		}
455
-	}
456
-
457
-	public function isDeletable($path) {
458
-		try {
459
-			$info = $this->getFileInfo($path);
460
-			return !$info->isHidden() && !$info->isReadOnly();
461
-		} catch (NotFoundException $e) {
462
-			return false;
463
-		} catch (ForbiddenException $e) {
464
-			return false;
465
-		}
466
-	}
467
-
468
-	/**
469
-	 * check if smbclient is installed
470
-	 */
471
-	public static function checkDependencies() {
472
-		return (
473
-			(bool)\OC_Helper::findBinaryPath('smbclient')
474
-			|| Server::NativeAvailable()
475
-		) ? true : ['smbclient'];
476
-	}
477
-
478
-	/**
479
-	 * Test a storage for availability
480
-	 *
481
-	 * @return bool
482
-	 */
483
-	public function test() {
484
-		try {
485
-			return parent::test();
486
-		} catch (Exception $e) {
487
-			return false;
488
-		}
489
-	}
490
-
491
-	public function listen($path, callable $callback) {
492
-		$this->notify($path)->listen(function (IChange $change) use ($callback) {
493
-			if ($change instanceof IRenameChange) {
494
-				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
495
-			} else {
496
-				return $callback($change->getType(), $change->getPath());
497
-			}
498
-		});
499
-	}
500
-
501
-	public function notify($path) {
502
-		$path = '/' . ltrim($path, '/');
503
-		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
504
-		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
505
-	}
56
+    /**
57
+     * @var \Icewind\SMB\Server
58
+     */
59
+    protected $server;
60
+
61
+    /**
62
+     * @var \Icewind\SMB\Share
63
+     */
64
+    protected $share;
65
+
66
+    /**
67
+     * @var string
68
+     */
69
+    protected $root;
70
+
71
+    /**
72
+     * @var \Icewind\SMB\FileInfo[]
73
+     */
74
+    protected $statCache;
75
+
76
+    public function __construct($params) {
77
+        if (isset($params['host']) && isset($params['user']) && isset($params['password']) && isset($params['share'])) {
78
+            if (Server::NativeAvailable()) {
79
+                $this->server = new NativeServer($params['host'], $params['user'], $params['password']);
80
+            } else {
81
+                $this->server = new Server($params['host'], $params['user'], $params['password']);
82
+            }
83
+            $this->share = $this->server->getShare(trim($params['share'], '/'));
84
+
85
+            $this->root = isset($params['root']) ? $params['root'] : '/';
86
+            if (!$this->root || $this->root[0] != '/') {
87
+                $this->root = '/' . $this->root;
88
+            }
89
+            if (substr($this->root, -1, 1) != '/') {
90
+                $this->root .= '/';
91
+            }
92
+        } else {
93
+            throw new \Exception('Invalid configuration');
94
+        }
95
+        $this->statCache = new CappedMemoryCache();
96
+    }
97
+
98
+    /**
99
+     * @return string
100
+     */
101
+    public function getId() {
102
+        // FIXME: double slash to keep compatible with the old storage ids,
103
+        // failure to do so will lead to creation of a new storage id and
104
+        // loss of shares from the storage
105
+        return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
106
+    }
107
+
108
+    /**
109
+     * @param string $path
110
+     * @return string
111
+     */
112
+    protected function buildPath($path) {
113
+        return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
114
+    }
115
+
116
+    protected function relativePath($fullPath) {
117
+        if ($fullPath === $this->root) {
118
+            return '';
119
+        } else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
120
+            return substr($fullPath, strlen($this->root));
121
+        } else {
122
+            return null;
123
+        }
124
+    }
125
+
126
+    /**
127
+     * @param string $path
128
+     * @return \Icewind\SMB\IFileInfo
129
+     * @throws StorageNotAvailableException
130
+     */
131
+    protected function getFileInfo($path) {
132
+        try {
133
+            $path = $this->buildPath($path);
134
+            if (!isset($this->statCache[$path])) {
135
+                $this->statCache[$path] = $this->share->stat($path);
136
+            }
137
+            return $this->statCache[$path];
138
+        } catch (ConnectException $e) {
139
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
140
+        }
141
+    }
142
+
143
+    /**
144
+     * @param string $path
145
+     * @return \Icewind\SMB\IFileInfo[]
146
+     * @throws StorageNotAvailableException
147
+     */
148
+    protected function getFolderContents($path) {
149
+        try {
150
+            $path = $this->buildPath($path);
151
+            $files = $this->share->dir($path);
152
+            foreach ($files as $file) {
153
+                $this->statCache[$path . '/' . $file->getName()] = $file;
154
+            }
155
+            return array_filter($files, function (IFileInfo $file) {
156
+                return !$file->isHidden();
157
+            });
158
+        } catch (ConnectException $e) {
159
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
160
+        }
161
+    }
162
+
163
+    /**
164
+     * @param \Icewind\SMB\IFileInfo $info
165
+     * @return array
166
+     */
167
+    protected function formatInfo($info) {
168
+        return array(
169
+            'size' => $info->getSize(),
170
+            'mtime' => $info->getMTime()
171
+        );
172
+    }
173
+
174
+    /**
175
+     * @param string $path
176
+     * @return array
177
+     */
178
+    public function stat($path) {
179
+        $result = $this->formatInfo($this->getFileInfo($path));
180
+        if ($this->remoteIsShare() && $this->isRootDir($path)) {
181
+            $result['mtime'] = $this->shareMTime();
182
+        }
183
+        return $result;
184
+    }
185
+
186
+    /**
187
+     * get the best guess for the modification time of the share
188
+     *
189
+     * @return int
190
+     */
191
+    private function shareMTime() {
192
+        $highestMTime = 0;
193
+        $files = $this->share->dir($this->root);
194
+        foreach ($files as $fileInfo) {
195
+            if ($fileInfo->getMTime() > $highestMTime) {
196
+                $highestMTime = $fileInfo->getMTime();
197
+            }
198
+        }
199
+        return $highestMTime;
200
+    }
201
+
202
+    /**
203
+     * Check if the path is our root dir (not the smb one)
204
+     *
205
+     * @param string $path the path
206
+     * @return bool
207
+     */
208
+    private function isRootDir($path) {
209
+        return $path === '' || $path === '/' || $path === '.';
210
+    }
211
+
212
+    /**
213
+     * Check if our root points to a smb share
214
+     *
215
+     * @return bool true if our root points to a share false otherwise
216
+     */
217
+    private function remoteIsShare() {
218
+        return $this->share->getName() && (!$this->root || $this->root === '/');
219
+    }
220
+
221
+    /**
222
+     * @param string $path
223
+     * @return bool
224
+     */
225
+    public function unlink($path) {
226
+        try {
227
+            if ($this->is_dir($path)) {
228
+                return $this->rmdir($path);
229
+            } else {
230
+                $path = $this->buildPath($path);
231
+                unset($this->statCache[$path]);
232
+                $this->share->del($path);
233
+                return true;
234
+            }
235
+        } catch (NotFoundException $e) {
236
+            return false;
237
+        } catch (ForbiddenException $e) {
238
+            return false;
239
+        } catch (ConnectException $e) {
240
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
241
+        }
242
+    }
243
+
244
+    /**
245
+     * @param string $path1 the old name
246
+     * @param string $path2 the new name
247
+     * @return bool
248
+     */
249
+    public function rename($path1, $path2) {
250
+        try {
251
+            $this->remove($path2);
252
+            $path1 = $this->buildPath($path1);
253
+            $path2 = $this->buildPath($path2);
254
+            return $this->share->rename($path1, $path2);
255
+        } catch (NotFoundException $e) {
256
+            return false;
257
+        } catch (ForbiddenException $e) {
258
+            return false;
259
+        } catch (ConnectException $e) {
260
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
261
+        }
262
+    }
263
+
264
+    /**
265
+     * check if a file or folder has been updated since $time
266
+     *
267
+     * @param string $path
268
+     * @param int $time
269
+     * @return bool
270
+     */
271
+    public function hasUpdated($path, $time) {
272
+        if (!$path and $this->root == '/') {
273
+            // mtime doesn't work for shares, but giving the nature of the backend,
274
+            // doing a full update is still just fast enough
275
+            return true;
276
+        } else {
277
+            $actualTime = $this->filemtime($path);
278
+            return $actualTime > $time;
279
+        }
280
+    }
281
+
282
+    /**
283
+     * @param string $path
284
+     * @param string $mode
285
+     * @return resource|false
286
+     */
287
+    public function fopen($path, $mode) {
288
+        $fullPath = $this->buildPath($path);
289
+        try {
290
+            switch ($mode) {
291
+                case 'r':
292
+                case 'rb':
293
+                    if (!$this->file_exists($path)) {
294
+                        return false;
295
+                    }
296
+                    return $this->share->read($fullPath);
297
+                case 'w':
298
+                case 'wb':
299
+                    $source = $this->share->write($fullPath);
300
+                    return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
301
+                        unset($this->statCache[$fullPath]);
302
+                    });
303
+                case 'a':
304
+                case 'ab':
305
+                case 'r+':
306
+                case 'w+':
307
+                case 'wb+':
308
+                case 'a+':
309
+                case 'x':
310
+                case 'x+':
311
+                case 'c':
312
+                case 'c+':
313
+                    //emulate these
314
+                    if (strrpos($path, '.') !== false) {
315
+                        $ext = substr($path, strrpos($path, '.'));
316
+                    } else {
317
+                        $ext = '';
318
+                    }
319
+                    if ($this->file_exists($path)) {
320
+                        if (!$this->isUpdatable($path)) {
321
+                            return false;
322
+                        }
323
+                        $tmpFile = $this->getCachedFile($path);
324
+                    } else {
325
+                        if (!$this->isCreatable(dirname($path))) {
326
+                            return false;
327
+                        }
328
+                        $tmpFile = \OCP\Files::tmpFile($ext);
329
+                    }
330
+                    $source = fopen($tmpFile, $mode);
331
+                    $share = $this->share;
332
+                    return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
333
+                        unset($this->statCache[$fullPath]);
334
+                        $share->put($tmpFile, $fullPath);
335
+                        unlink($tmpFile);
336
+                    });
337
+            }
338
+            return false;
339
+        } catch (NotFoundException $e) {
340
+            return false;
341
+        } catch (ForbiddenException $e) {
342
+            return false;
343
+        } catch (ConnectException $e) {
344
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
345
+        }
346
+    }
347
+
348
+    public function rmdir($path) {
349
+        try {
350
+            $this->statCache = array();
351
+            $content = $this->share->dir($this->buildPath($path));
352
+            foreach ($content as $file) {
353
+                if ($file->isDirectory()) {
354
+                    $this->rmdir($path . '/' . $file->getName());
355
+                } else {
356
+                    $this->share->del($file->getPath());
357
+                }
358
+            }
359
+            $this->share->rmdir($this->buildPath($path));
360
+            return true;
361
+        } catch (NotFoundException $e) {
362
+            return false;
363
+        } catch (ForbiddenException $e) {
364
+            return false;
365
+        } catch (ConnectException $e) {
366
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
367
+        }
368
+    }
369
+
370
+    public function touch($path, $time = null) {
371
+        try {
372
+            if (!$this->file_exists($path)) {
373
+                $fh = $this->share->write($this->buildPath($path));
374
+                fclose($fh);
375
+                return true;
376
+            }
377
+            return false;
378
+        } catch (ConnectException $e) {
379
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
380
+        }
381
+    }
382
+
383
+    public function opendir($path) {
384
+        try {
385
+            $files = $this->getFolderContents($path);
386
+        } catch (NotFoundException $e) {
387
+            return false;
388
+        } catch (ForbiddenException $e) {
389
+            return false;
390
+        }
391
+        $names = array_map(function ($info) {
392
+            /** @var \Icewind\SMB\IFileInfo $info */
393
+            return $info->getName();
394
+        }, $files);
395
+        return IteratorDirectory::wrap($names);
396
+    }
397
+
398
+    public function filetype($path) {
399
+        try {
400
+            return $this->getFileInfo($path)->isDirectory() ? 'dir' : 'file';
401
+        } catch (NotFoundException $e) {
402
+            return false;
403
+        } catch (ForbiddenException $e) {
404
+            return false;
405
+        }
406
+    }
407
+
408
+    public function mkdir($path) {
409
+        $path = $this->buildPath($path);
410
+        try {
411
+            $this->share->mkdir($path);
412
+            return true;
413
+        } catch (ConnectException $e) {
414
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
415
+        } catch (Exception $e) {
416
+            return false;
417
+        }
418
+    }
419
+
420
+    public function file_exists($path) {
421
+        try {
422
+            $this->getFileInfo($path);
423
+            return true;
424
+        } catch (NotFoundException $e) {
425
+            return false;
426
+        } catch (ForbiddenException $e) {
427
+            return false;
428
+        } catch (ConnectException $e) {
429
+            throw new StorageNotAvailableException($e->getMessage(), $e->getCode(), $e);
430
+        }
431
+    }
432
+
433
+    public function isReadable($path) {
434
+        try {
435
+            $info = $this->getFileInfo($path);
436
+            return !$info->isHidden();
437
+        } catch (NotFoundException $e) {
438
+            return false;
439
+        } catch (ForbiddenException $e) {
440
+            return false;
441
+        }
442
+    }
443
+
444
+    public function isUpdatable($path) {
445
+        try {
446
+            $info = $this->getFileInfo($path);
447
+            // following windows behaviour for read-only folders: they can be written into
448
+            // (https://support.microsoft.com/en-us/kb/326549 - "cause" section)
449
+            return !$info->isHidden() && (!$info->isReadOnly() || $this->is_dir($path));
450
+        } catch (NotFoundException $e) {
451
+            return false;
452
+        } catch (ForbiddenException $e) {
453
+            return false;
454
+        }
455
+    }
456
+
457
+    public function isDeletable($path) {
458
+        try {
459
+            $info = $this->getFileInfo($path);
460
+            return !$info->isHidden() && !$info->isReadOnly();
461
+        } catch (NotFoundException $e) {
462
+            return false;
463
+        } catch (ForbiddenException $e) {
464
+            return false;
465
+        }
466
+    }
467
+
468
+    /**
469
+     * check if smbclient is installed
470
+     */
471
+    public static function checkDependencies() {
472
+        return (
473
+            (bool)\OC_Helper::findBinaryPath('smbclient')
474
+            || Server::NativeAvailable()
475
+        ) ? true : ['smbclient'];
476
+    }
477
+
478
+    /**
479
+     * Test a storage for availability
480
+     *
481
+     * @return bool
482
+     */
483
+    public function test() {
484
+        try {
485
+            return parent::test();
486
+        } catch (Exception $e) {
487
+            return false;
488
+        }
489
+    }
490
+
491
+    public function listen($path, callable $callback) {
492
+        $this->notify($path)->listen(function (IChange $change) use ($callback) {
493
+            if ($change instanceof IRenameChange) {
494
+                return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
495
+            } else {
496
+                return $callback($change->getType(), $change->getPath());
497
+            }
498
+        });
499
+    }
500
+
501
+    public function notify($path) {
502
+        $path = '/' . ltrim($path, '/');
503
+        $shareNotifyHandler = $this->share->notify($this->buildPath($path));
504
+        return new SMBNotifyHandler($shareNotifyHandler, $this->root);
505
+    }
506 506
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 
85 85
 			$this->root = isset($params['root']) ? $params['root'] : '/';
86 86
 			if (!$this->root || $this->root[0] != '/') {
87
-				$this->root = '/' . $this->root;
87
+				$this->root = '/'.$this->root;
88 88
 			}
89 89
 			if (substr($this->root, -1, 1) != '/') {
90 90
 				$this->root .= '/';
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
 		// FIXME: double slash to keep compatible with the old storage ids,
103 103
 		// failure to do so will lead to creation of a new storage id and
104 104
 		// loss of shares from the storage
105
-		return 'smb::' . $this->server->getUser() . '@' . $this->server->getHost() . '//' . $this->share->getName() . '/' . $this->root;
105
+		return 'smb::'.$this->server->getUser().'@'.$this->server->getHost().'//'.$this->share->getName().'/'.$this->root;
106 106
 	}
107 107
 
108 108
 	/**
@@ -110,7 +110,7 @@  discard block
 block discarded – undo
110 110
 	 * @return string
111 111
 	 */
112 112
 	protected function buildPath($path) {
113
-		return Filesystem::normalizePath($this->root . '/' . $path, true, false, true);
113
+		return Filesystem::normalizePath($this->root.'/'.$path, true, false, true);
114 114
 	}
115 115
 
116 116
 	protected function relativePath($fullPath) {
@@ -150,9 +150,9 @@  discard block
 block discarded – undo
150 150
 			$path = $this->buildPath($path);
151 151
 			$files = $this->share->dir($path);
152 152
 			foreach ($files as $file) {
153
-				$this->statCache[$path . '/' . $file->getName()] = $file;
153
+				$this->statCache[$path.'/'.$file->getName()] = $file;
154 154
 			}
155
-			return array_filter($files, function (IFileInfo $file) {
155
+			return array_filter($files, function(IFileInfo $file) {
156 156
 				return !$file->isHidden();
157 157
 			});
158 158
 		} catch (ConnectException $e) {
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
 				case 'w':
298 298
 				case 'wb':
299 299
 					$source = $this->share->write($fullPath);
300
-					return CallBackWrapper::wrap($source, null, null, function () use ($fullPath) {
300
+					return CallBackWrapper::wrap($source, null, null, function() use ($fullPath) {
301 301
 						unset($this->statCache[$fullPath]);
302 302
 					});
303 303
 				case 'a':
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
 					}
330 330
 					$source = fopen($tmpFile, $mode);
331 331
 					$share = $this->share;
332
-					return CallbackWrapper::wrap($source, null, null, function () use ($tmpFile, $fullPath, $share) {
332
+					return CallbackWrapper::wrap($source, null, null, function() use ($tmpFile, $fullPath, $share) {
333 333
 						unset($this->statCache[$fullPath]);
334 334
 						$share->put($tmpFile, $fullPath);
335 335
 						unlink($tmpFile);
@@ -351,7 +351,7 @@  discard block
 block discarded – undo
351 351
 			$content = $this->share->dir($this->buildPath($path));
352 352
 			foreach ($content as $file) {
353 353
 				if ($file->isDirectory()) {
354
-					$this->rmdir($path . '/' . $file->getName());
354
+					$this->rmdir($path.'/'.$file->getName());
355 355
 				} else {
356 356
 					$this->share->del($file->getPath());
357 357
 				}
@@ -388,7 +388,7 @@  discard block
 block discarded – undo
388 388
 		} catch (ForbiddenException $e) {
389 389
 			return false;
390 390
 		}
391
-		$names = array_map(function ($info) {
391
+		$names = array_map(function($info) {
392 392
 			/** @var \Icewind\SMB\IFileInfo $info */
393 393
 			return $info->getName();
394 394
 		}, $files);
@@ -470,7 +470,7 @@  discard block
 block discarded – undo
470 470
 	 */
471 471
 	public static function checkDependencies() {
472 472
 		return (
473
-			(bool)\OC_Helper::findBinaryPath('smbclient')
473
+			(bool) \OC_Helper::findBinaryPath('smbclient')
474 474
 			|| Server::NativeAvailable()
475 475
 		) ? true : ['smbclient'];
476 476
 	}
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
 	}
490 490
 
491 491
 	public function listen($path, callable $callback) {
492
-		$this->notify($path)->listen(function (IChange $change) use ($callback) {
492
+		$this->notify($path)->listen(function(IChange $change) use ($callback) {
493 493
 			if ($change instanceof IRenameChange) {
494 494
 				return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
495 495
 			} else {
@@ -499,7 +499,7 @@  discard block
 block discarded – undo
499 499
 	}
500 500
 
501 501
 	public function notify($path) {
502
-		$path = '/' . ltrim($path, '/');
502
+		$path = '/'.ltrim($path, '/');
503 503
 		$shareNotifyHandler = $this->share->notify($this->buildPath($path));
504 504
 		return new SMBNotifyHandler($shareNotifyHandler, $this->root);
505 505
 	}
Please login to merge, or discard this patch.
lib/private/Files/Node/File.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -31,7 +31,7 @@
 block discarded – undo
31 31
 	 * Creates a Folder that represents a non-existing path
32 32
 	 *
33 33
 	 * @param string $path path
34
-	 * @return string non-existing node class
34
+	 * @return NonExistingFile non-existing node class
35 35
 	 */
36 36
 	protected function createNonExistingNode($path) {
37 37
 		return new NonExistingFile($this->root, $this->view, $path);
Please login to merge, or discard this patch.
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -29,113 +29,113 @@
 block discarded – undo
29 29
 use OCP\Files\NotPermittedException;
30 30
 
31 31
 class File extends Node implements \OCP\Files\File {
32
-	/**
33
-	 * Creates a Folder that represents a non-existing path
34
-	 *
35
-	 * @param string $path path
36
-	 * @return string non-existing node class
37
-	 */
38
-	protected function createNonExistingNode($path) {
39
-		return new NonExistingFile($this->root, $this->view, $path);
40
-	}
32
+    /**
33
+     * Creates a Folder that represents a non-existing path
34
+     *
35
+     * @param string $path path
36
+     * @return string non-existing node class
37
+     */
38
+    protected function createNonExistingNode($path) {
39
+        return new NonExistingFile($this->root, $this->view, $path);
40
+    }
41 41
 
42
-	/**
43
-	 * @return string
44
-	 * @throws \OCP\Files\NotPermittedException
45
-	 */
46
-	public function getContent() {
47
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
48
-			/**
49
-			 * @var \OC\Files\Storage\Storage $storage;
50
-			 */
51
-			return $this->view->file_get_contents($this->path);
52
-		} else {
53
-			throw new NotPermittedException();
54
-		}
55
-	}
42
+    /**
43
+     * @return string
44
+     * @throws \OCP\Files\NotPermittedException
45
+     */
46
+    public function getContent() {
47
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
48
+            /**
49
+             * @var \OC\Files\Storage\Storage $storage;
50
+             */
51
+            return $this->view->file_get_contents($this->path);
52
+        } else {
53
+            throw new NotPermittedException();
54
+        }
55
+    }
56 56
 
57
-	/**
58
-	 * @param string $data
59
-	 * @throws \OCP\Files\NotPermittedException
60
-	 */
61
-	public function putContent($data) {
62
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
63
-			$this->sendHooks(array('preWrite'));
64
-			$this->view->file_put_contents($this->path, $data);
65
-			$this->fileInfo = null;
66
-			$this->sendHooks(array('postWrite'));
67
-		} else {
68
-			throw new NotPermittedException();
69
-		}
70
-	}
57
+    /**
58
+     * @param string $data
59
+     * @throws \OCP\Files\NotPermittedException
60
+     */
61
+    public function putContent($data) {
62
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
63
+            $this->sendHooks(array('preWrite'));
64
+            $this->view->file_put_contents($this->path, $data);
65
+            $this->fileInfo = null;
66
+            $this->sendHooks(array('postWrite'));
67
+        } else {
68
+            throw new NotPermittedException();
69
+        }
70
+    }
71 71
 
72
-	/**
73
-	 * @param string $mode
74
-	 * @return resource
75
-	 * @throws \OCP\Files\NotPermittedException
76
-	 */
77
-	public function fopen($mode) {
78
-		$preHooks = array();
79
-		$postHooks = array();
80
-		$requiredPermissions = \OCP\Constants::PERMISSION_READ;
81
-		switch ($mode) {
82
-			case 'r+':
83
-			case 'rb+':
84
-			case 'w+':
85
-			case 'wb+':
86
-			case 'x+':
87
-			case 'xb+':
88
-			case 'a+':
89
-			case 'ab+':
90
-			case 'w':
91
-			case 'wb':
92
-			case 'x':
93
-			case 'xb':
94
-			case 'a':
95
-			case 'ab':
96
-				$preHooks[] = 'preWrite';
97
-				$postHooks[] = 'postWrite';
98
-				$requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
99
-				break;
100
-		}
72
+    /**
73
+     * @param string $mode
74
+     * @return resource
75
+     * @throws \OCP\Files\NotPermittedException
76
+     */
77
+    public function fopen($mode) {
78
+        $preHooks = array();
79
+        $postHooks = array();
80
+        $requiredPermissions = \OCP\Constants::PERMISSION_READ;
81
+        switch ($mode) {
82
+            case 'r+':
83
+            case 'rb+':
84
+            case 'w+':
85
+            case 'wb+':
86
+            case 'x+':
87
+            case 'xb+':
88
+            case 'a+':
89
+            case 'ab+':
90
+            case 'w':
91
+            case 'wb':
92
+            case 'x':
93
+            case 'xb':
94
+            case 'a':
95
+            case 'ab':
96
+                $preHooks[] = 'preWrite';
97
+                $postHooks[] = 'postWrite';
98
+                $requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
99
+                break;
100
+        }
101 101
 
102
-		if ($this->checkPermissions($requiredPermissions)) {
103
-			$this->sendHooks($preHooks);
104
-			$result = $this->view->fopen($this->path, $mode);
105
-			$this->sendHooks($postHooks);
106
-			return $result;
107
-		} else {
108
-			throw new NotPermittedException();
109
-		}
110
-	}
102
+        if ($this->checkPermissions($requiredPermissions)) {
103
+            $this->sendHooks($preHooks);
104
+            $result = $this->view->fopen($this->path, $mode);
105
+            $this->sendHooks($postHooks);
106
+            return $result;
107
+        } else {
108
+            throw new NotPermittedException();
109
+        }
110
+    }
111 111
 
112
-	public function delete() {
113
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
114
-			$this->sendHooks(array('preDelete'));
115
-			$fileInfo = $this->getFileInfo();
116
-			$this->view->unlink($this->path);
117
-			$nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
118
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
119
-			$this->exists = false;
120
-			$this->fileInfo = null;
121
-		} else {
122
-			throw new NotPermittedException();
123
-		}
124
-	}
112
+    public function delete() {
113
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
114
+            $this->sendHooks(array('preDelete'));
115
+            $fileInfo = $this->getFileInfo();
116
+            $this->view->unlink($this->path);
117
+            $nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
118
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
119
+            $this->exists = false;
120
+            $this->fileInfo = null;
121
+        } else {
122
+            throw new NotPermittedException();
123
+        }
124
+    }
125 125
 
126
-	/**
127
-	 * @param string $type
128
-	 * @param bool $raw
129
-	 * @return string
130
-	 */
131
-	public function hash($type, $raw = false) {
132
-		return $this->view->hash($type, $this->path, $raw);
133
-	}
126
+    /**
127
+     * @param string $type
128
+     * @param bool $raw
129
+     * @return string
130
+     */
131
+    public function hash($type, $raw = false) {
132
+        return $this->view->hash($type, $this->path, $raw);
133
+    }
134 134
 
135
-	/**
136
-	 * @inheritdoc
137
-	 */
138
-	public function getChecksum() {
139
-		return $this->getFileInfo()->getChecksum();
140
-	}
135
+    /**
136
+     * @inheritdoc
137
+     */
138
+    public function getChecksum() {
139
+        return $this->getFileInfo()->getChecksum();
140
+    }
141 141
 }
Please login to merge, or discard this patch.
lib/private/Files/Node/Folder.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@
 block discarded – undo
37 37
 	 * Creates a Folder that represents a non-existing path
38 38
 	 *
39 39
 	 * @param string $path path
40
-	 * @return string non-existing node class
40
+	 * @return NonExistingFolder non-existing node class
41 41
 	 */
42 42
 	protected function createNonExistingNode($path) {
43 43
 		return new NonExistingFolder($this->root, $this->view, $path);
Please login to merge, or discard this patch.
Indentation   +386 added lines, -386 removed lines patch added patch discarded remove patch
@@ -35,390 +35,390 @@
 block discarded – undo
35 35
 use OCP\Files\NotPermittedException;
36 36
 
37 37
 class Folder extends Node implements \OCP\Files\Folder {
38
-	/**
39
-	 * Creates a Folder that represents a non-existing path
40
-	 *
41
-	 * @param string $path path
42
-	 * @return string non-existing node class
43
-	 */
44
-	protected function createNonExistingNode($path) {
45
-		return new NonExistingFolder($this->root, $this->view, $path);
46
-	}
47
-
48
-	/**
49
-	 * @param string $path path relative to the folder
50
-	 * @return string
51
-	 * @throws \OCP\Files\NotPermittedException
52
-	 */
53
-	public function getFullPath($path) {
54
-		if (!$this->isValidPath($path)) {
55
-			throw new NotPermittedException('Invalid path');
56
-		}
57
-		return $this->path . $this->normalizePath($path);
58
-	}
59
-
60
-	/**
61
-	 * @param string $path
62
-	 * @return string
63
-	 */
64
-	public function getRelativePath($path) {
65
-		if ($this->path === '' or $this->path === '/') {
66
-			return $this->normalizePath($path);
67
-		}
68
-		if ($path === $this->path) {
69
-			return '/';
70
-		} else if (strpos($path, $this->path . '/') !== 0) {
71
-			return null;
72
-		} else {
73
-			$path = substr($path, strlen($this->path));
74
-			return $this->normalizePath($path);
75
-		}
76
-	}
77
-
78
-	/**
79
-	 * check if a node is a (grand-)child of the folder
80
-	 *
81
-	 * @param \OC\Files\Node\Node $node
82
-	 * @return bool
83
-	 */
84
-	public function isSubNode($node) {
85
-		return strpos($node->getPath(), $this->path . '/') === 0;
86
-	}
87
-
88
-	/**
89
-	 * get the content of this directory
90
-	 *
91
-	 * @throws \OCP\Files\NotFoundException
92
-	 * @return Node[]
93
-	 */
94
-	public function getDirectoryListing() {
95
-		$folderContent = $this->view->getDirectoryContent($this->path);
96
-
97
-		return array_map(function (FileInfo $info) {
98
-			if ($info->getMimetype() === 'httpd/unix-directory') {
99
-				return new Folder($this->root, $this->view, $info->getPath(), $info);
100
-			} else {
101
-				return new File($this->root, $this->view, $info->getPath(), $info);
102
-			}
103
-		}, $folderContent);
104
-	}
105
-
106
-	/**
107
-	 * @param string $path
108
-	 * @param FileInfo $info
109
-	 * @return File|Folder
110
-	 */
111
-	protected function createNode($path, FileInfo $info = null) {
112
-		if (is_null($info)) {
113
-			$isDir = $this->view->is_dir($path);
114
-		} else {
115
-			$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
116
-		}
117
-		if ($isDir) {
118
-			return new Folder($this->root, $this->view, $path, $info);
119
-		} else {
120
-			return new File($this->root, $this->view, $path, $info);
121
-		}
122
-	}
123
-
124
-	/**
125
-	 * Get the node at $path
126
-	 *
127
-	 * @param string $path
128
-	 * @return \OC\Files\Node\Node
129
-	 * @throws \OCP\Files\NotFoundException
130
-	 */
131
-	public function get($path) {
132
-		return $this->root->get($this->getFullPath($path));
133
-	}
134
-
135
-	/**
136
-	 * @param string $path
137
-	 * @return bool
138
-	 */
139
-	public function nodeExists($path) {
140
-		try {
141
-			$this->get($path);
142
-			return true;
143
-		} catch (NotFoundException $e) {
144
-			return false;
145
-		}
146
-	}
147
-
148
-	/**
149
-	 * @param string $path
150
-	 * @return \OC\Files\Node\Folder
151
-	 * @throws \OCP\Files\NotPermittedException
152
-	 */
153
-	public function newFolder($path) {
154
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
155
-			$fullPath = $this->getFullPath($path);
156
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
157
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
158
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
159
-			$this->view->mkdir($fullPath);
160
-			$node = new Folder($this->root, $this->view, $fullPath);
161
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
162
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
163
-			return $node;
164
-		} else {
165
-			throw new NotPermittedException('No create permission for folder');
166
-		}
167
-	}
168
-
169
-	/**
170
-	 * @param string $path
171
-	 * @return \OC\Files\Node\File
172
-	 * @throws \OCP\Files\NotPermittedException
173
-	 */
174
-	public function newFile($path) {
175
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
176
-			$fullPath = $this->getFullPath($path);
177
-			$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
178
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
179
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
180
-			$this->view->touch($fullPath);
181
-			$node = new File($this->root, $this->view, $fullPath);
182
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
183
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
184
-			return $node;
185
-		} else {
186
-			throw new NotPermittedException('No create permission for path');
187
-		}
188
-	}
189
-
190
-	/**
191
-	 * search for files with the name matching $query
192
-	 *
193
-	 * @param string $query
194
-	 * @return \OC\Files\Node\Node[]
195
-	 */
196
-	public function search($query) {
197
-		return $this->searchCommon('search', array('%' . $query . '%'));
198
-	}
199
-
200
-	/**
201
-	 * search for files by mimetype
202
-	 *
203
-	 * @param string $mimetype
204
-	 * @return Node[]
205
-	 */
206
-	public function searchByMime($mimetype) {
207
-		return $this->searchCommon('searchByMime', array($mimetype));
208
-	}
209
-
210
-	/**
211
-	 * search for files by tag
212
-	 *
213
-	 * @param string|int $tag name or tag id
214
-	 * @param string $userId owner of the tags
215
-	 * @return Node[]
216
-	 */
217
-	public function searchByTag($tag, $userId) {
218
-		return $this->searchCommon('searchByTag', array($tag, $userId));
219
-	}
220
-
221
-	/**
222
-	 * @param string $method cache method
223
-	 * @param array $args call args
224
-	 * @return \OC\Files\Node\Node[]
225
-	 */
226
-	private function searchCommon($method, $args) {
227
-		$files = array();
228
-		$rootLength = strlen($this->path);
229
-		$mount = $this->root->getMount($this->path);
230
-		$storage = $mount->getStorage();
231
-		$internalPath = $mount->getInternalPath($this->path);
232
-		$internalPath = rtrim($internalPath, '/');
233
-		if ($internalPath !== '') {
234
-			$internalPath = $internalPath . '/';
235
-		}
236
-		$internalRootLength = strlen($internalPath);
237
-
238
-		$cache = $storage->getCache('');
239
-
240
-		$results = call_user_func_array(array($cache, $method), $args);
241
-		foreach ($results as $result) {
242
-			if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
243
-				$result['internalPath'] = $result['path'];
244
-				$result['path'] = substr($result['path'], $internalRootLength);
245
-				$result['storage'] = $storage;
246
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
247
-			}
248
-		}
249
-
250
-		$mounts = $this->root->getMountsIn($this->path);
251
-		foreach ($mounts as $mount) {
252
-			$storage = $mount->getStorage();
253
-			if ($storage) {
254
-				$cache = $storage->getCache('');
255
-
256
-				$relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
257
-				$results = call_user_func_array(array($cache, $method), $args);
258
-				foreach ($results as $result) {
259
-					$result['internalPath'] = $result['path'];
260
-					$result['path'] = $relativeMountPoint . $result['path'];
261
-					$result['storage'] = $storage;
262
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
263
-				}
264
-			}
265
-		}
266
-
267
-		return array_map(function (FileInfo $file) {
268
-			return $this->createNode($file->getPath(), $file);
269
-		}, $files);
270
-	}
271
-
272
-	/**
273
-	 * @param int $id
274
-	 * @return \OC\Files\Node\Node[]
275
-	 */
276
-	public function getById($id) {
277
-		$mountCache = $this->root->getUserMountCache();
278
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id);
279
-		$mounts = $this->root->getMountsIn($this->path);
280
-		$mounts[] = $this->root->getMount($this->path);
281
-		/** @var IMountPoint[] $folderMounts */
282
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
283
-			return $mountPoint->getMountPoint();
284
-		}, $mounts), $mounts);
285
-
286
-		/** @var ICachedMountInfo[] $mountsContainingFile */
287
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
288
-			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
289
-		}));
290
-
291
-		if (count($mountsContainingFile) === 0) {
292
-			return [];
293
-		}
294
-
295
-		// we only need to get the cache info once, since all mounts we found point to the same storage
296
-
297
-		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
298
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
299
-		if (!$cacheEntry) {
300
-			return [];
301
-		}
302
-		// cache jails will hide the "true" internal path
303
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
304
-
305
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
306
-			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
307
-			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
308
-			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
309
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
310
-			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
311
-				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
312
-				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
313
-			));
314
-		}, $mountsContainingFile);
315
-
316
-		return array_filter($nodes, function (Node $node) {
317
-			return $this->getRelativePath($node->getPath());
318
-		});
319
-	}
320
-
321
-	public function getFreeSpace() {
322
-		return $this->view->free_space($this->path);
323
-	}
324
-
325
-	public function delete() {
326
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
327
-			$this->sendHooks(array('preDelete'));
328
-			$fileInfo = $this->getFileInfo();
329
-			$this->view->rmdir($this->path);
330
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
331
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
332
-			$this->exists = false;
333
-		} else {
334
-			throw new NotPermittedException('No delete permission for path');
335
-		}
336
-	}
337
-
338
-	/**
339
-	 * Add a suffix to the name in case the file exists
340
-	 *
341
-	 * @param string $name
342
-	 * @return string
343
-	 * @throws NotPermittedException
344
-	 */
345
-	public function getNonExistingName($name) {
346
-		$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
347
-		return trim($this->getRelativePath($uniqueName), '/');
348
-	}
349
-
350
-	/**
351
-	 * @param int $limit
352
-	 * @param int $offset
353
-	 * @return \OCP\Files\Node[]
354
-	 */
355
-	public function getRecent($limit, $offset = 0) {
356
-		$mimetypeLoader = \OC::$server->getMimeTypeLoader();
357
-		$mounts = $this->root->getMountsIn($this->path);
358
-		$mounts[] = $this->getMountPoint();
359
-
360
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
361
-			return $mount->getStorage();
362
-		});
363
-		$storageIds = array_map(function (IMountPoint $mount) {
364
-			return $mount->getStorage()->getCache()->getNumericStorageId();
365
-		}, $mounts);
366
-		/** @var IMountPoint[] $mountMap */
367
-		$mountMap = array_combine($storageIds, $mounts);
368
-		$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
369
-
370
-		//todo look into options of filtering path based on storage id (only search in files/ for home storage, filter by share root for shared, etc)
371
-
372
-		$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
373
-		$query = $builder
374
-			->select('f.*')
375
-			->from('filecache', 'f')
376
-			->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
377
-			->andWhere($builder->expr()->orX(
378
-			// handle non empty folders separate
379
-				$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
380
-				$builder->expr()->eq('f.size', new Literal(0))
381
-			))
382
-			->orderBy('f.mtime', 'DESC')
383
-			->setMaxResults($limit)
384
-			->setFirstResult($offset);
385
-
386
-		$result = $query->execute()->fetchAll();
387
-
388
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
389
-			$mount = $mountMap[$entry['storage']];
390
-			$entry['internalPath'] = $entry['path'];
391
-			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
392
-			$entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
393
-			$path = $this->getAbsolutePath($mount, $entry['path']);
394
-			if (is_null($path)) {
395
-				return null;
396
-			}
397
-			$fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
398
-			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
399
-		}, $result));
400
-
401
-		return array_values(array_filter($files, function (Node $node) {
402
-			$relative = $this->getRelativePath($node->getPath());
403
-			return $relative !== null && $relative !== '/';
404
-		}));
405
-	}
406
-
407
-	private function getAbsolutePath(IMountPoint $mount, $path) {
408
-		$storage = $mount->getStorage();
409
-		if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
410
-			/** @var \OC\Files\Storage\Wrapper\Jail $storage */
411
-			$jailRoot = $storage->getSourcePath('');
412
-			$rootLength = strlen($jailRoot) + 1;
413
-			if ($path === $jailRoot) {
414
-				return $mount->getMountPoint();
415
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
416
-				return $mount->getMountPoint() . substr($path, $rootLength);
417
-			} else {
418
-				return null;
419
-			}
420
-		} else {
421
-			return $mount->getMountPoint() . $path;
422
-		}
423
-	}
38
+    /**
39
+     * Creates a Folder that represents a non-existing path
40
+     *
41
+     * @param string $path path
42
+     * @return string non-existing node class
43
+     */
44
+    protected function createNonExistingNode($path) {
45
+        return new NonExistingFolder($this->root, $this->view, $path);
46
+    }
47
+
48
+    /**
49
+     * @param string $path path relative to the folder
50
+     * @return string
51
+     * @throws \OCP\Files\NotPermittedException
52
+     */
53
+    public function getFullPath($path) {
54
+        if (!$this->isValidPath($path)) {
55
+            throw new NotPermittedException('Invalid path');
56
+        }
57
+        return $this->path . $this->normalizePath($path);
58
+    }
59
+
60
+    /**
61
+     * @param string $path
62
+     * @return string
63
+     */
64
+    public function getRelativePath($path) {
65
+        if ($this->path === '' or $this->path === '/') {
66
+            return $this->normalizePath($path);
67
+        }
68
+        if ($path === $this->path) {
69
+            return '/';
70
+        } else if (strpos($path, $this->path . '/') !== 0) {
71
+            return null;
72
+        } else {
73
+            $path = substr($path, strlen($this->path));
74
+            return $this->normalizePath($path);
75
+        }
76
+    }
77
+
78
+    /**
79
+     * check if a node is a (grand-)child of the folder
80
+     *
81
+     * @param \OC\Files\Node\Node $node
82
+     * @return bool
83
+     */
84
+    public function isSubNode($node) {
85
+        return strpos($node->getPath(), $this->path . '/') === 0;
86
+    }
87
+
88
+    /**
89
+     * get the content of this directory
90
+     *
91
+     * @throws \OCP\Files\NotFoundException
92
+     * @return Node[]
93
+     */
94
+    public function getDirectoryListing() {
95
+        $folderContent = $this->view->getDirectoryContent($this->path);
96
+
97
+        return array_map(function (FileInfo $info) {
98
+            if ($info->getMimetype() === 'httpd/unix-directory') {
99
+                return new Folder($this->root, $this->view, $info->getPath(), $info);
100
+            } else {
101
+                return new File($this->root, $this->view, $info->getPath(), $info);
102
+            }
103
+        }, $folderContent);
104
+    }
105
+
106
+    /**
107
+     * @param string $path
108
+     * @param FileInfo $info
109
+     * @return File|Folder
110
+     */
111
+    protected function createNode($path, FileInfo $info = null) {
112
+        if (is_null($info)) {
113
+            $isDir = $this->view->is_dir($path);
114
+        } else {
115
+            $isDir = $info->getType() === FileInfo::TYPE_FOLDER;
116
+        }
117
+        if ($isDir) {
118
+            return new Folder($this->root, $this->view, $path, $info);
119
+        } else {
120
+            return new File($this->root, $this->view, $path, $info);
121
+        }
122
+    }
123
+
124
+    /**
125
+     * Get the node at $path
126
+     *
127
+     * @param string $path
128
+     * @return \OC\Files\Node\Node
129
+     * @throws \OCP\Files\NotFoundException
130
+     */
131
+    public function get($path) {
132
+        return $this->root->get($this->getFullPath($path));
133
+    }
134
+
135
+    /**
136
+     * @param string $path
137
+     * @return bool
138
+     */
139
+    public function nodeExists($path) {
140
+        try {
141
+            $this->get($path);
142
+            return true;
143
+        } catch (NotFoundException $e) {
144
+            return false;
145
+        }
146
+    }
147
+
148
+    /**
149
+     * @param string $path
150
+     * @return \OC\Files\Node\Folder
151
+     * @throws \OCP\Files\NotPermittedException
152
+     */
153
+    public function newFolder($path) {
154
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
155
+            $fullPath = $this->getFullPath($path);
156
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
157
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
158
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
159
+            $this->view->mkdir($fullPath);
160
+            $node = new Folder($this->root, $this->view, $fullPath);
161
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
162
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
163
+            return $node;
164
+        } else {
165
+            throw new NotPermittedException('No create permission for folder');
166
+        }
167
+    }
168
+
169
+    /**
170
+     * @param string $path
171
+     * @return \OC\Files\Node\File
172
+     * @throws \OCP\Files\NotPermittedException
173
+     */
174
+    public function newFile($path) {
175
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
176
+            $fullPath = $this->getFullPath($path);
177
+            $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
178
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
179
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
180
+            $this->view->touch($fullPath);
181
+            $node = new File($this->root, $this->view, $fullPath);
182
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
183
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
184
+            return $node;
185
+        } else {
186
+            throw new NotPermittedException('No create permission for path');
187
+        }
188
+    }
189
+
190
+    /**
191
+     * search for files with the name matching $query
192
+     *
193
+     * @param string $query
194
+     * @return \OC\Files\Node\Node[]
195
+     */
196
+    public function search($query) {
197
+        return $this->searchCommon('search', array('%' . $query . '%'));
198
+    }
199
+
200
+    /**
201
+     * search for files by mimetype
202
+     *
203
+     * @param string $mimetype
204
+     * @return Node[]
205
+     */
206
+    public function searchByMime($mimetype) {
207
+        return $this->searchCommon('searchByMime', array($mimetype));
208
+    }
209
+
210
+    /**
211
+     * search for files by tag
212
+     *
213
+     * @param string|int $tag name or tag id
214
+     * @param string $userId owner of the tags
215
+     * @return Node[]
216
+     */
217
+    public function searchByTag($tag, $userId) {
218
+        return $this->searchCommon('searchByTag', array($tag, $userId));
219
+    }
220
+
221
+    /**
222
+     * @param string $method cache method
223
+     * @param array $args call args
224
+     * @return \OC\Files\Node\Node[]
225
+     */
226
+    private function searchCommon($method, $args) {
227
+        $files = array();
228
+        $rootLength = strlen($this->path);
229
+        $mount = $this->root->getMount($this->path);
230
+        $storage = $mount->getStorage();
231
+        $internalPath = $mount->getInternalPath($this->path);
232
+        $internalPath = rtrim($internalPath, '/');
233
+        if ($internalPath !== '') {
234
+            $internalPath = $internalPath . '/';
235
+        }
236
+        $internalRootLength = strlen($internalPath);
237
+
238
+        $cache = $storage->getCache('');
239
+
240
+        $results = call_user_func_array(array($cache, $method), $args);
241
+        foreach ($results as $result) {
242
+            if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
243
+                $result['internalPath'] = $result['path'];
244
+                $result['path'] = substr($result['path'], $internalRootLength);
245
+                $result['storage'] = $storage;
246
+                $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
247
+            }
248
+        }
249
+
250
+        $mounts = $this->root->getMountsIn($this->path);
251
+        foreach ($mounts as $mount) {
252
+            $storage = $mount->getStorage();
253
+            if ($storage) {
254
+                $cache = $storage->getCache('');
255
+
256
+                $relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
257
+                $results = call_user_func_array(array($cache, $method), $args);
258
+                foreach ($results as $result) {
259
+                    $result['internalPath'] = $result['path'];
260
+                    $result['path'] = $relativeMountPoint . $result['path'];
261
+                    $result['storage'] = $storage;
262
+                    $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
263
+                }
264
+            }
265
+        }
266
+
267
+        return array_map(function (FileInfo $file) {
268
+            return $this->createNode($file->getPath(), $file);
269
+        }, $files);
270
+    }
271
+
272
+    /**
273
+     * @param int $id
274
+     * @return \OC\Files\Node\Node[]
275
+     */
276
+    public function getById($id) {
277
+        $mountCache = $this->root->getUserMountCache();
278
+        $mountsContainingFile = $mountCache->getMountsForFileId((int)$id);
279
+        $mounts = $this->root->getMountsIn($this->path);
280
+        $mounts[] = $this->root->getMount($this->path);
281
+        /** @var IMountPoint[] $folderMounts */
282
+        $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
283
+            return $mountPoint->getMountPoint();
284
+        }, $mounts), $mounts);
285
+
286
+        /** @var ICachedMountInfo[] $mountsContainingFile */
287
+        $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
288
+            return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
289
+        }));
290
+
291
+        if (count($mountsContainingFile) === 0) {
292
+            return [];
293
+        }
294
+
295
+        // we only need to get the cache info once, since all mounts we found point to the same storage
296
+
297
+        $mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
298
+        $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
299
+        if (!$cacheEntry) {
300
+            return [];
301
+        }
302
+        // cache jails will hide the "true" internal path
303
+        $internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
304
+
305
+        $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
306
+            $mount = $folderMounts[$cachedMountInfo->getMountPoint()];
307
+            $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
308
+            $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
309
+            $absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
310
+            return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
311
+                $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
312
+                \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
313
+            ));
314
+        }, $mountsContainingFile);
315
+
316
+        return array_filter($nodes, function (Node $node) {
317
+            return $this->getRelativePath($node->getPath());
318
+        });
319
+    }
320
+
321
+    public function getFreeSpace() {
322
+        return $this->view->free_space($this->path);
323
+    }
324
+
325
+    public function delete() {
326
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
327
+            $this->sendHooks(array('preDelete'));
328
+            $fileInfo = $this->getFileInfo();
329
+            $this->view->rmdir($this->path);
330
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
331
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
332
+            $this->exists = false;
333
+        } else {
334
+            throw new NotPermittedException('No delete permission for path');
335
+        }
336
+    }
337
+
338
+    /**
339
+     * Add a suffix to the name in case the file exists
340
+     *
341
+     * @param string $name
342
+     * @return string
343
+     * @throws NotPermittedException
344
+     */
345
+    public function getNonExistingName($name) {
346
+        $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
347
+        return trim($this->getRelativePath($uniqueName), '/');
348
+    }
349
+
350
+    /**
351
+     * @param int $limit
352
+     * @param int $offset
353
+     * @return \OCP\Files\Node[]
354
+     */
355
+    public function getRecent($limit, $offset = 0) {
356
+        $mimetypeLoader = \OC::$server->getMimeTypeLoader();
357
+        $mounts = $this->root->getMountsIn($this->path);
358
+        $mounts[] = $this->getMountPoint();
359
+
360
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
361
+            return $mount->getStorage();
362
+        });
363
+        $storageIds = array_map(function (IMountPoint $mount) {
364
+            return $mount->getStorage()->getCache()->getNumericStorageId();
365
+        }, $mounts);
366
+        /** @var IMountPoint[] $mountMap */
367
+        $mountMap = array_combine($storageIds, $mounts);
368
+        $folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
369
+
370
+        //todo look into options of filtering path based on storage id (only search in files/ for home storage, filter by share root for shared, etc)
371
+
372
+        $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
373
+        $query = $builder
374
+            ->select('f.*')
375
+            ->from('filecache', 'f')
376
+            ->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
377
+            ->andWhere($builder->expr()->orX(
378
+            // handle non empty folders separate
379
+                $builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
380
+                $builder->expr()->eq('f.size', new Literal(0))
381
+            ))
382
+            ->orderBy('f.mtime', 'DESC')
383
+            ->setMaxResults($limit)
384
+            ->setFirstResult($offset);
385
+
386
+        $result = $query->execute()->fetchAll();
387
+
388
+        $files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
389
+            $mount = $mountMap[$entry['storage']];
390
+            $entry['internalPath'] = $entry['path'];
391
+            $entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
392
+            $entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
393
+            $path = $this->getAbsolutePath($mount, $entry['path']);
394
+            if (is_null($path)) {
395
+                return null;
396
+            }
397
+            $fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
398
+            return $this->root->createNode($fileInfo->getPath(), $fileInfo);
399
+        }, $result));
400
+
401
+        return array_values(array_filter($files, function (Node $node) {
402
+            $relative = $this->getRelativePath($node->getPath());
403
+            return $relative !== null && $relative !== '/';
404
+        }));
405
+    }
406
+
407
+    private function getAbsolutePath(IMountPoint $mount, $path) {
408
+        $storage = $mount->getStorage();
409
+        if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
410
+            /** @var \OC\Files\Storage\Wrapper\Jail $storage */
411
+            $jailRoot = $storage->getSourcePath('');
412
+            $rootLength = strlen($jailRoot) + 1;
413
+            if ($path === $jailRoot) {
414
+                return $mount->getMountPoint();
415
+            } else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
416
+                return $mount->getMountPoint() . substr($path, $rootLength);
417
+            } else {
418
+                return null;
419
+            }
420
+        } else {
421
+            return $mount->getMountPoint() . $path;
422
+        }
423
+    }
424 424
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -54,7 +54,7 @@  discard block
 block discarded – undo
54 54
 		if (!$this->isValidPath($path)) {
55 55
 			throw new NotPermittedException('Invalid path');
56 56
 		}
57
-		return $this->path . $this->normalizePath($path);
57
+		return $this->path.$this->normalizePath($path);
58 58
 	}
59 59
 
60 60
 	/**
@@ -67,7 +67,7 @@  discard block
 block discarded – undo
67 67
 		}
68 68
 		if ($path === $this->path) {
69 69
 			return '/';
70
-		} else if (strpos($path, $this->path . '/') !== 0) {
70
+		} else if (strpos($path, $this->path.'/') !== 0) {
71 71
 			return null;
72 72
 		} else {
73 73
 			$path = substr($path, strlen($this->path));
@@ -82,7 +82,7 @@  discard block
 block discarded – undo
82 82
 	 * @return bool
83 83
 	 */
84 84
 	public function isSubNode($node) {
85
-		return strpos($node->getPath(), $this->path . '/') === 0;
85
+		return strpos($node->getPath(), $this->path.'/') === 0;
86 86
 	}
87 87
 
88 88
 	/**
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 	public function getDirectoryListing() {
95 95
 		$folderContent = $this->view->getDirectoryContent($this->path);
96 96
 
97
-		return array_map(function (FileInfo $info) {
97
+		return array_map(function(FileInfo $info) {
98 98
 			if ($info->getMimetype() === 'httpd/unix-directory') {
99 99
 				return new Folder($this->root, $this->view, $info->getPath(), $info);
100 100
 			} else {
@@ -194,7 +194,7 @@  discard block
 block discarded – undo
194 194
 	 * @return \OC\Files\Node\Node[]
195 195
 	 */
196 196
 	public function search($query) {
197
-		return $this->searchCommon('search', array('%' . $query . '%'));
197
+		return $this->searchCommon('search', array('%'.$query.'%'));
198 198
 	}
199 199
 
200 200
 	/**
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
 		$internalPath = $mount->getInternalPath($this->path);
232 232
 		$internalPath = rtrim($internalPath, '/');
233 233
 		if ($internalPath !== '') {
234
-			$internalPath = $internalPath . '/';
234
+			$internalPath = $internalPath.'/';
235 235
 		}
236 236
 		$internalRootLength = strlen($internalPath);
237 237
 
@@ -243,7 +243,7 @@  discard block
 block discarded – undo
243 243
 				$result['internalPath'] = $result['path'];
244 244
 				$result['path'] = substr($result['path'], $internalRootLength);
245 245
 				$result['storage'] = $storage;
246
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
246
+				$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
247 247
 			}
248 248
 		}
249 249
 
@@ -257,14 +257,14 @@  discard block
 block discarded – undo
257 257
 				$results = call_user_func_array(array($cache, $method), $args);
258 258
 				foreach ($results as $result) {
259 259
 					$result['internalPath'] = $result['path'];
260
-					$result['path'] = $relativeMountPoint . $result['path'];
260
+					$result['path'] = $relativeMountPoint.$result['path'];
261 261
 					$result['storage'] = $storage;
262
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
262
+					$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
263 263
 				}
264 264
 			}
265 265
 		}
266 266
 
267
-		return array_map(function (FileInfo $file) {
267
+		return array_map(function(FileInfo $file) {
268 268
 			return $this->createNode($file->getPath(), $file);
269 269
 		}, $files);
270 270
 	}
@@ -275,16 +275,16 @@  discard block
 block discarded – undo
275 275
 	 */
276 276
 	public function getById($id) {
277 277
 		$mountCache = $this->root->getUserMountCache();
278
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id);
278
+		$mountsContainingFile = $mountCache->getMountsForFileId((int) $id);
279 279
 		$mounts = $this->root->getMountsIn($this->path);
280 280
 		$mounts[] = $this->root->getMount($this->path);
281 281
 		/** @var IMountPoint[] $folderMounts */
282
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
282
+		$folderMounts = array_combine(array_map(function(IMountPoint $mountPoint) {
283 283
 			return $mountPoint->getMountPoint();
284 284
 		}, $mounts), $mounts);
285 285
 
286 286
 		/** @var ICachedMountInfo[] $mountsContainingFile */
287
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
287
+		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function(ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
288 288
 			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
289 289
 		}));
290 290
 
@@ -295,25 +295,25 @@  discard block
 block discarded – undo
295 295
 		// we only need to get the cache info once, since all mounts we found point to the same storage
296 296
 
297 297
 		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
298
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
298
+		$cacheEntry = $mount->getStorage()->getCache()->get((int) $id);
299 299
 		if (!$cacheEntry) {
300 300
 			return [];
301 301
 		}
302 302
 		// cache jails will hide the "true" internal path
303
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
303
+		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath().'/'.$cacheEntry->getPath(), '/');
304 304
 
305
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
305
+		$nodes = array_map(function(ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
306 306
 			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
307 307
 			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
308 308
 			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
309
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
309
+			$absolutePath = $cachedMountInfo->getMountPoint().$pathRelativeToMount;
310 310
 			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
311 311
 				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
312 312
 				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
313 313
 			));
314 314
 		}, $mountsContainingFile);
315 315
 
316
-		return array_filter($nodes, function (Node $node) {
316
+		return array_filter($nodes, function(Node $node) {
317 317
 			return $this->getRelativePath($node->getPath());
318 318
 		});
319 319
 	}
@@ -357,10 +357,10 @@  discard block
 block discarded – undo
357 357
 		$mounts = $this->root->getMountsIn($this->path);
358 358
 		$mounts[] = $this->getMountPoint();
359 359
 
360
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
360
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
361 361
 			return $mount->getStorage();
362 362
 		});
363
-		$storageIds = array_map(function (IMountPoint $mount) {
363
+		$storageIds = array_map(function(IMountPoint $mount) {
364 364
 			return $mount->getStorage()->getCache()->getNumericStorageId();
365 365
 		}, $mounts);
366 366
 		/** @var IMountPoint[] $mountMap */
@@ -385,7 +385,7 @@  discard block
 block discarded – undo
385 385
 
386 386
 		$result = $query->execute()->fetchAll();
387 387
 
388
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
388
+		$files = array_filter(array_map(function(array $entry) use ($mountMap, $mimetypeLoader) {
389 389
 			$mount = $mountMap[$entry['storage']];
390 390
 			$entry['internalPath'] = $entry['path'];
391 391
 			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
@@ -398,7 +398,7 @@  discard block
 block discarded – undo
398 398
 			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
399 399
 		}, $result));
400 400
 
401
-		return array_values(array_filter($files, function (Node $node) {
401
+		return array_values(array_filter($files, function(Node $node) {
402 402
 			$relative = $this->getRelativePath($node->getPath());
403 403
 			return $relative !== null && $relative !== '/';
404 404
 		}));
@@ -412,13 +412,13 @@  discard block
 block discarded – undo
412 412
 			$rootLength = strlen($jailRoot) + 1;
413 413
 			if ($path === $jailRoot) {
414 414
 				return $mount->getMountPoint();
415
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
416
-				return $mount->getMountPoint() . substr($path, $rootLength);
415
+			} else if (substr($path, 0, $rootLength) === $jailRoot.'/') {
416
+				return $mount->getMountPoint().substr($path, $rootLength);
417 417
 			} else {
418 418
 				return null;
419 419
 			}
420 420
 		} else {
421
-			return $mount->getMountPoint() . $path;
421
+			return $mount->getMountPoint().$path;
422 422
 		}
423 423
 	}
424 424
 }
Please login to merge, or discard this patch.
lib/public/Settings/IIconSection.php 2 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -33,6 +33,7 @@
 block discarded – undo
33 33
 	 *
34 34
 	 * @returns string
35 35
 	 * @since 12
36
+	 * @return string
36 37
 	 */
37 38
 	public function getIcon();
38 39
 }
Please login to merge, or discard this patch.
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -27,12 +27,12 @@
 block discarded – undo
27 27
  * @since 12
28 28
  */
29 29
 interface IIconSection extends ISection {
30
-	/**
31
-	 * returns the relative path to an 16*16 icon describing the section.
32
-	 * e.g. '/core/img/places/files.svg'
33
-	 *
34
-	 * @returns string
35
-	 * @since 12
36
-	 */
37
-	public function getIcon();
30
+    /**
31
+     * returns the relative path to an 16*16 icon describing the section.
32
+     * e.g. '/core/img/places/files.svg'
33
+     *
34
+     * @returns string
35
+     * @since 12
36
+     */
37
+    public function getIcon();
38 38
 }
Please login to merge, or discard this patch.
settings/Controller/UsersController.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -33,7 +33,6 @@
 block discarded – undo
33 33
 use OC\Accounts\AccountManager;
34 34
 use OC\AppFramework\Http;
35 35
 use OC\ForbiddenException;
36
-use OC\User\User;
37 36
 use OCP\App\IAppManager;
38 37
 use OCP\AppFramework\Controller;
39 38
 use OCP\AppFramework\Http\DataResponse;
Please login to merge, or discard this patch.
Indentation   +805 added lines, -805 removed lines patch added patch discarded remove patch
@@ -57,810 +57,810 @@
 block discarded – undo
57 57
  * @package OC\Settings\Controller
58 58
  */
59 59
 class UsersController extends Controller {
60
-	/** @var IL10N */
61
-	private $l10n;
62
-	/** @var IUserSession */
63
-	private $userSession;
64
-	/** @var bool */
65
-	private $isAdmin;
66
-	/** @var IUserManager */
67
-	private $userManager;
68
-	/** @var IGroupManager */
69
-	private $groupManager;
70
-	/** @var IConfig */
71
-	private $config;
72
-	/** @var ILogger */
73
-	private $log;
74
-	/** @var \OC_Defaults */
75
-	private $defaults;
76
-	/** @var IMailer */
77
-	private $mailer;
78
-	/** @var string */
79
-	private $fromMailAddress;
80
-	/** @var IURLGenerator */
81
-	private $urlGenerator;
82
-	/** @var bool contains the state of the encryption app */
83
-	private $isEncryptionAppEnabled;
84
-	/** @var bool contains the state of the admin recovery setting */
85
-	private $isRestoreEnabled = false;
86
-	/** @var IAvatarManager */
87
-	private $avatarManager;
88
-	/** @var AccountManager */
89
-	private $accountManager;
90
-	/** @var ISecureRandom */
91
-	private $secureRandom;
92
-	/** @var ITimeFactory */
93
-	private $timeFactory;
94
-	/** @var ICrypto */
95
-	private $crypto;
96
-
97
-
98
-	/**
99
-	 * @param string $appName
100
-	 * @param IRequest $request
101
-	 * @param IUserManager $userManager
102
-	 * @param IGroupManager $groupManager
103
-	 * @param IUserSession $userSession
104
-	 * @param IConfig $config
105
-	 * @param bool $isAdmin
106
-	 * @param IL10N $l10n
107
-	 * @param ILogger $log
108
-	 * @param \OC_Defaults $defaults
109
-	 * @param IMailer $mailer
110
-	 * @param string $fromMailAddress
111
-	 * @param IURLGenerator $urlGenerator
112
-	 * @param IAppManager $appManager
113
-	 * @param IAvatarManager $avatarManager
114
-	 * @param AccountManager $accountManager
115
-	 * @param ISecureRandom $secureRandom
116
-	 * @param ITimeFactory $timeFactory
117
-	 * @param ICrypto $crypto
118
-	 */
119
-	public function __construct($appName,
120
-								IRequest $request,
121
-								IUserManager $userManager,
122
-								IGroupManager $groupManager,
123
-								IUserSession $userSession,
124
-								IConfig $config,
125
-								$isAdmin,
126
-								IL10N $l10n,
127
-								ILogger $log,
128
-								\OC_Defaults $defaults,
129
-								IMailer $mailer,
130
-								$fromMailAddress,
131
-								IURLGenerator $urlGenerator,
132
-								IAppManager $appManager,
133
-								IAvatarManager $avatarManager,
134
-								AccountManager $accountManager,
135
-								ISecureRandom $secureRandom,
136
-								ITimeFactory $timeFactory,
137
-								ICrypto $crypto) {
138
-		parent::__construct($appName, $request);
139
-		$this->userManager = $userManager;
140
-		$this->groupManager = $groupManager;
141
-		$this->userSession = $userSession;
142
-		$this->config = $config;
143
-		$this->isAdmin = $isAdmin;
144
-		$this->l10n = $l10n;
145
-		$this->log = $log;
146
-		$this->defaults = $defaults;
147
-		$this->mailer = $mailer;
148
-		$this->fromMailAddress = $fromMailAddress;
149
-		$this->urlGenerator = $urlGenerator;
150
-		$this->avatarManager = $avatarManager;
151
-		$this->accountManager = $accountManager;
152
-		$this->secureRandom = $secureRandom;
153
-		$this->timeFactory = $timeFactory;
154
-		$this->crypto = $crypto;
155
-
156
-		// check for encryption state - TODO see formatUserForIndex
157
-		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
158
-		if($this->isEncryptionAppEnabled) {
159
-			// putting this directly in empty is possible in PHP 5.5+
160
-			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
161
-			$this->isRestoreEnabled = !empty($result);
162
-		}
163
-	}
164
-
165
-	/**
166
-	 * @param IUser $user
167
-	 * @param array $userGroups
168
-	 * @return array
169
-	 */
170
-	private function formatUserForIndex(IUser $user, array $userGroups = null) {
171
-
172
-		// TODO: eliminate this encryption specific code below and somehow
173
-		// hook in additional user info from other apps
174
-
175
-		// recovery isn't possible if admin or user has it disabled and encryption
176
-		// is enabled - so we eliminate the else paths in the conditional tree
177
-		// below
178
-		$restorePossible = false;
179
-
180
-		if ($this->isEncryptionAppEnabled) {
181
-			if ($this->isRestoreEnabled) {
182
-				// check for the users recovery setting
183
-				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
184
-				// method call inside empty is possible with PHP 5.5+
185
-				$recoveryModeEnabled = !empty($recoveryMode);
186
-				if ($recoveryModeEnabled) {
187
-					// user also has recovery mode enabled
188
-					$restorePossible = true;
189
-				}
190
-			}
191
-		} else {
192
-			// recovery is possible if encryption is disabled (plain files are
193
-			// available)
194
-			$restorePossible = true;
195
-		}
196
-
197
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
198
-		foreach($subAdminGroups as $key => $subAdminGroup) {
199
-			$subAdminGroups[$key] = $subAdminGroup->getGID();
200
-		}
201
-
202
-		$displayName = $user->getEMailAddress();
203
-		if (is_null($displayName)) {
204
-			$displayName = '';
205
-		}
206
-
207
-		$avatarAvailable = false;
208
-		try {
209
-			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
210
-		} catch (\Exception $e) {
211
-			//No avatar yet
212
-		}
213
-
214
-		return [
215
-			'name' => $user->getUID(),
216
-			'displayname' => $user->getDisplayName(),
217
-			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
218
-			'subadmin' => $subAdminGroups,
219
-			'quota' => $user->getQuota(),
220
-			'storageLocation' => $user->getHome(),
221
-			'lastLogin' => $user->getLastLogin() * 1000,
222
-			'backend' => $user->getBackendClassName(),
223
-			'email' => $displayName,
224
-			'isRestoreDisabled' => !$restorePossible,
225
-			'isAvatarAvailable' => $avatarAvailable,
226
-		];
227
-	}
228
-
229
-	/**
230
-	 * @param array $userIDs Array with schema [$uid => $displayName]
231
-	 * @return IUser[]
232
-	 */
233
-	private function getUsersForUID(array $userIDs) {
234
-		$users = [];
235
-		foreach ($userIDs as $uid => $displayName) {
236
-			$users[$uid] = $this->userManager->get($uid);
237
-		}
238
-		return $users;
239
-	}
240
-
241
-	/**
242
-	 * @NoAdminRequired
243
-	 *
244
-	 * @param int $offset
245
-	 * @param int $limit
246
-	 * @param string $gid GID to filter for
247
-	 * @param string $pattern Pattern to search for in the username
248
-	 * @param string $backend Backend to filter for (class-name)
249
-	 * @return DataResponse
250
-	 *
251
-	 * TODO: Tidy up and write unit tests - code is mainly static method calls
252
-	 */
253
-	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
254
-		// FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
255
-		if($gid === '_everyone') {
256
-			$gid = '';
257
-		}
258
-
259
-		// Remove backends
260
-		if(!empty($backend)) {
261
-			$activeBackends = $this->userManager->getBackends();
262
-			$this->userManager->clearBackends();
263
-			foreach($activeBackends as $singleActiveBackend) {
264
-				if($backend === get_class($singleActiveBackend)) {
265
-					$this->userManager->registerBackend($singleActiveBackend);
266
-					break;
267
-				}
268
-			}
269
-		}
270
-
271
-		$users = [];
272
-		if ($this->isAdmin) {
273
-
274
-			if($gid !== '') {
275
-				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
276
-			} else {
277
-				$batch = $this->userManager->search($pattern, $limit, $offset);
278
-			}
279
-
280
-			foreach ($batch as $user) {
281
-				$users[] = $this->formatUserForIndex($user);
282
-			}
283
-
284
-		} else {
285
-			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
286
-			// New class returns IGroup[] so convert back
287
-			$gids = [];
288
-			foreach ($subAdminOfGroups as $group) {
289
-				$gids[] = $group->getGID();
290
-			}
291
-			$subAdminOfGroups = $gids;
292
-
293
-			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
294
-			if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
295
-				$gid = '';
296
-			}
297
-
298
-			// Batch all groups the user is subadmin of when a group is specified
299
-			$batch = [];
300
-			if($gid === '') {
301
-				foreach($subAdminOfGroups as $group) {
302
-					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
303
-
304
-					foreach($groupUsers as $uid => $displayName) {
305
-						$batch[$uid] = $displayName;
306
-					}
307
-				}
308
-			} else {
309
-				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
310
-			}
311
-			$batch = $this->getUsersForUID($batch);
312
-
313
-			foreach ($batch as $user) {
314
-				// Only add the groups, this user is a subadmin of
315
-				$userGroups = array_values(array_intersect(
316
-					$this->groupManager->getUserGroupIds($user),
317
-					$subAdminOfGroups
318
-				));
319
-				$users[] = $this->formatUserForIndex($user, $userGroups);
320
-			}
321
-		}
322
-
323
-		return new DataResponse($users);
324
-	}
325
-
326
-	/**
327
-	 * @NoAdminRequired
328
-	 * @PasswordConfirmationRequired
329
-	 *
330
-	 * @param string $username
331
-	 * @param string $password
332
-	 * @param array $groups
333
-	 * @param string $email
334
-	 * @return DataResponse
335
-	 */
336
-	public function create($username, $password, array $groups=array(), $email='') {
337
-		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
338
-			return new DataResponse(
339
-				array(
340
-					'message' => (string)$this->l10n->t('Invalid mail address')
341
-				),
342
-				Http::STATUS_UNPROCESSABLE_ENTITY
343
-			);
344
-		}
345
-
346
-		$currentUser = $this->userSession->getUser();
347
-
348
-		if (!$this->isAdmin) {
349
-			if (!empty($groups)) {
350
-				foreach ($groups as $key => $group) {
351
-					$groupObject = $this->groupManager->get($group);
352
-					if($groupObject === null) {
353
-						unset($groups[$key]);
354
-						continue;
355
-					}
356
-
357
-					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
358
-						unset($groups[$key]);
359
-					}
360
-				}
361
-			}
362
-
363
-			if (empty($groups)) {
364
-				return new DataResponse(
365
-					array(
366
-						'message' => $this->l10n->t('No valid group selected'),
367
-					),
368
-					Http::STATUS_FORBIDDEN
369
-				);
370
-			}
371
-		}
372
-
373
-		if ($this->userManager->userExists($username)) {
374
-			return new DataResponse(
375
-				array(
376
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
377
-				),
378
-				Http::STATUS_CONFLICT
379
-			);
380
-		}
381
-
382
-		$generatedPassword = false;
383
-		if ($password === '') {
384
-			if ($email === '') {
385
-				return new DataResponse(
386
-					array(
387
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
388
-					),
389
-					Http::STATUS_UNPROCESSABLE_ENTITY
390
-				);
391
-			}
392
-
393
-			$password = $this->secureRandom->generate(32);
394
-			$generatedPassword = true;
395
-		}
396
-
397
-		try {
398
-			$user = $this->userManager->createUser($username, $password);
399
-		} catch (\Exception $exception) {
400
-			$message = $exception->getMessage();
401
-			if (!$message) {
402
-				$message = $this->l10n->t('Unable to create user.');
403
-			}
404
-			return new DataResponse(
405
-				array(
406
-					'message' => (string) $message,
407
-				),
408
-				Http::STATUS_FORBIDDEN
409
-			);
410
-		}
411
-
412
-		if($user instanceof IUser) {
413
-			if($groups !== null) {
414
-				foreach($groups as $groupName) {
415
-					$group = $this->groupManager->get($groupName);
416
-
417
-					if(empty($group)) {
418
-						$group = $this->groupManager->createGroup($groupName);
419
-					}
420
-					$group->addUser($user);
421
-				}
422
-			}
423
-			/**
424
-			 * Send new user mail only if a mail is set
425
-			 */
426
-			if($email !== '') {
427
-				$user->setEMailAddress($email);
428
-
429
-				if ($generatedPassword) {
430
-					$token = $this->secureRandom->generate(
431
-						21,
432
-						ISecureRandom::CHAR_DIGITS .
433
-						ISecureRandom::CHAR_LOWER .
434
-						ISecureRandom::CHAR_UPPER
435
-					);
436
-					$tokenValue = $this->timeFactory->getTime() . ':' . $token;
437
-					$mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
438
-					$encryptedValue = $this->crypto->encrypt($tokenValue, $mailAddress . $this->config->getSystemValue('secret'));
439
-					$this->config->setUserValue($username, 'core', 'lostpassword', $encryptedValue);
440
-
441
-					$link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $username, 'token' => $token]);
442
-				} else {
443
-					$link = $this->urlGenerator->getAbsoluteURL('/');
444
-				}
445
-
446
-				// data for the mail template
447
-				$mailData = array(
448
-					'username' => $username,
449
-					'url' => $link
450
-				);
451
-
452
-				$mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank');
453
-				$mailContent = $mail->render();
454
-
455
-				$mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank');
456
-				$plainTextMailContent = $mail->render();
457
-
458
-				$subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]);
459
-
460
-				try {
461
-					$message = $this->mailer->createMessage();
462
-					$message->setTo([$email => $username]);
463
-					$message->setSubject($subject);
464
-					$message->setHtmlBody($mailContent);
465
-					$message->setPlainBody($plainTextMailContent);
466
-					$message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
467
-					$this->mailer->send($message);
468
-				} catch(\Exception $e) {
469
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
470
-				}
471
-			}
472
-			// fetch users groups
473
-			$userGroups = $this->groupManager->getUserGroupIds($user);
474
-
475
-			return new DataResponse(
476
-				$this->formatUserForIndex($user, $userGroups),
477
-				Http::STATUS_CREATED
478
-			);
479
-		}
480
-
481
-		return new DataResponse(
482
-			array(
483
-				'message' => (string)$this->l10n->t('Unable to create user.')
484
-			),
485
-			Http::STATUS_FORBIDDEN
486
-		);
487
-
488
-	}
489
-
490
-	/**
491
-	 * @NoAdminRequired
492
-	 * @PasswordConfirmationRequired
493
-	 *
494
-	 * @param string $id
495
-	 * @return DataResponse
496
-	 */
497
-	public function destroy($id) {
498
-		$userId = $this->userSession->getUser()->getUID();
499
-		$user = $this->userManager->get($id);
500
-
501
-		if($userId === $id) {
502
-			return new DataResponse(
503
-				array(
504
-					'status' => 'error',
505
-					'data' => array(
506
-						'message' => (string)$this->l10n->t('Unable to delete user.')
507
-					)
508
-				),
509
-				Http::STATUS_FORBIDDEN
510
-			);
511
-		}
512
-
513
-		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
514
-			return new DataResponse(
515
-				array(
516
-					'status' => 'error',
517
-					'data' => array(
518
-						'message' => (string)$this->l10n->t('Authentication error')
519
-					)
520
-				),
521
-				Http::STATUS_FORBIDDEN
522
-			);
523
-		}
524
-
525
-		if($user) {
526
-			if($user->delete()) {
527
-				return new DataResponse(
528
-					array(
529
-						'status' => 'success',
530
-						'data' => array(
531
-							'username' => $id
532
-						)
533
-					),
534
-					Http::STATUS_NO_CONTENT
535
-				);
536
-			}
537
-		}
538
-
539
-		return new DataResponse(
540
-			array(
541
-				'status' => 'error',
542
-				'data' => array(
543
-					'message' => (string)$this->l10n->t('Unable to delete user.')
544
-				)
545
-			),
546
-			Http::STATUS_FORBIDDEN
547
-		);
548
-	}
549
-
550
-	/**
551
-	 * @NoAdminRequired
552
-	 * @NoSubadminRequired
553
-	 * @PasswordConfirmationRequired
554
-	 *
555
-	 * @param string $avatarScope
556
-	 * @param string $displayname
557
-	 * @param string $displaynameScope
558
-	 * @param string $phone
559
-	 * @param string $phoneScope
560
-	 * @param string $email
561
-	 * @param string $emailScope
562
-	 * @param string $website
563
-	 * @param string $websiteScope
564
-	 * @param string $address
565
-	 * @param string $addressScope
566
-	 * @param string $twitter
567
-	 * @param string $twitterScope
568
-	 * @return DataResponse
569
-	 */
570
-	public function setUserSettings($avatarScope,
571
-									$displayname,
572
-									$displaynameScope,
573
-									$phone,
574
-									$phoneScope,
575
-									$email,
576
-									$emailScope,
577
-									$website,
578
-									$websiteScope,
579
-									$address,
580
-									$addressScope,
581
-									$twitter,
582
-									$twitterScope
583
-	) {
584
-
585
-		if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
586
-			return new DataResponse(
587
-				array(
588
-					'status' => 'error',
589
-					'data' => array(
590
-						'message' => (string)$this->l10n->t('Invalid mail address')
591
-					)
592
-				),
593
-				Http::STATUS_UNPROCESSABLE_ENTITY
594
-			);
595
-		}
596
-
597
-		$data = [
598
-			AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
599
-			AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
600
-			AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
601
-			AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
602
-			AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
603
-			AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
604
-			AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
605
-		];
606
-
607
-		$user = $this->userSession->getUser();
608
-
609
-		try {
610
-			$this->saveUserSettings($user, $data);
611
-			return new DataResponse(
612
-				array(
613
-					'status' => 'success',
614
-					'data' => array(
615
-						'userId' => $user->getUID(),
616
-						'avatarScope' => $avatarScope,
617
-						'displayname' => $displayname,
618
-						'displaynameScope' => $displaynameScope,
619
-						'email' => $email,
620
-						'emailScope' => $emailScope,
621
-						'website' => $website,
622
-						'websiteScope' => $websiteScope,
623
-						'address' => $address,
624
-						'addressScope' => $addressScope,
625
-						'message' => (string)$this->l10n->t('Settings saved')
626
-					)
627
-				),
628
-				Http::STATUS_OK
629
-			);
630
-		} catch (ForbiddenException $e) {
631
-			return new DataResponse([
632
-				'status' => 'error',
633
-				'data' => [
634
-					'message' => $e->getMessage()
635
-				],
636
-			]);
637
-		}
638
-
639
-	}
640
-
641
-
642
-	/**
643
-	 * update account manager with new user data
644
-	 *
645
-	 * @param IUser $user
646
-	 * @param array $data
647
-	 * @throws ForbiddenException
648
-	 */
649
-	protected function saveUserSettings(IUser $user, $data) {
650
-
651
-		// keep the user back-end up-to-date with the latest display name and email
652
-		// address
653
-		$oldDisplayName = $user->getDisplayName();
654
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
655
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
656
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
657
-		) {
658
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
659
-			if ($result === false) {
660
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
661
-			}
662
-		}
663
-
664
-		$oldEmailAddress = $user->getEMailAddress();
665
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
666
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
667
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
668
-		) {
669
-			// this is the only permission a backend provides and is also used
670
-			// for the permission of setting a email address
671
-			if (!$user->canChangeDisplayName()) {
672
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
673
-			}
674
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
675
-		}
676
-
677
-		$this->accountManager->updateUser($user, $data);
678
-	}
679
-
680
-	/**
681
-	 * Count all unique users visible for the current admin/subadmin.
682
-	 *
683
-	 * @NoAdminRequired
684
-	 *
685
-	 * @return DataResponse
686
-	 */
687
-	public function stats() {
688
-		$userCount = 0;
689
-		if ($this->isAdmin) {
690
-			$countByBackend = $this->userManager->countUsers();
691
-
692
-			if (!empty($countByBackend)) {
693
-				foreach ($countByBackend as $count) {
694
-					$userCount += $count;
695
-				}
696
-			}
697
-		} else {
698
-			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
699
-
700
-			$uniqueUsers = [];
701
-			foreach ($groups as $group) {
702
-				foreach($group->getUsers() as $uid => $displayName) {
703
-					$uniqueUsers[$uid] = true;
704
-				}
705
-			}
706
-
707
-			$userCount = count($uniqueUsers);
708
-		}
709
-
710
-		return new DataResponse(
711
-			[
712
-				'totalUsers' => $userCount
713
-			]
714
-		);
715
-	}
716
-
717
-
718
-	/**
719
-	 * Set the displayName of a user
720
-	 *
721
-	 * @NoAdminRequired
722
-	 * @NoSubadminRequired
723
-	 * @PasswordConfirmationRequired
724
-	 * @todo merge into saveUserSettings
725
-	 *
726
-	 * @param string $username
727
-	 * @param string $displayName
728
-	 * @return DataResponse
729
-	 */
730
-	public function setDisplayName($username, $displayName) {
731
-		$currentUser = $this->userSession->getUser();
732
-		$user = $this->userManager->get($username);
733
-
734
-		if ($user === null ||
735
-			!$user->canChangeDisplayName() ||
736
-			(
737
-				!$this->groupManager->isAdmin($currentUser->getUID()) &&
738
-				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
739
-				$currentUser->getUID() !== $username
740
-
741
-			)
742
-		) {
743
-			return new DataResponse([
744
-				'status' => 'error',
745
-				'data' => [
746
-					'message' => $this->l10n->t('Authentication error'),
747
-				],
748
-			]);
749
-		}
750
-
751
-		$userData = $this->accountManager->getUser($user);
752
-		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
753
-
754
-
755
-		try {
756
-			$this->saveUserSettings($user, $userData);
757
-			return new DataResponse([
758
-				'status' => 'success',
759
-				'data' => [
760
-					'message' => $this->l10n->t('Your full name has been changed.'),
761
-					'username' => $username,
762
-					'displayName' => $displayName,
763
-				],
764
-			]);
765
-		} catch (ForbiddenException $e) {
766
-			return new DataResponse([
767
-				'status' => 'error',
768
-				'data' => [
769
-					'message' => $e->getMessage(),
770
-					'displayName' => $user->getDisplayName(),
771
-				],
772
-			]);
773
-		}
774
-	}
775
-
776
-	/**
777
-	 * Set the mail address of a user
778
-	 *
779
-	 * @NoAdminRequired
780
-	 * @NoSubadminRequired
781
-	 * @PasswordConfirmationRequired
782
-	 *
783
-	 * @param string $id
784
-	 * @param string $mailAddress
785
-	 * @return DataResponse
786
-	 */
787
-	public function setEMailAddress($id, $mailAddress) {
788
-		$user = $this->userManager->get($id);
789
-		if (!$this->isAdmin
790
-			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
791
-		) {
792
-			return new DataResponse(
793
-				array(
794
-					'status' => 'error',
795
-					'data' => array(
796
-						'message' => (string)$this->l10n->t('Forbidden')
797
-					)
798
-				),
799
-				Http::STATUS_FORBIDDEN
800
-			);
801
-		}
802
-
803
-		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
804
-			return new DataResponse(
805
-				array(
806
-					'status' => 'error',
807
-					'data' => array(
808
-						'message' => (string)$this->l10n->t('Invalid mail address')
809
-					)
810
-				),
811
-				Http::STATUS_UNPROCESSABLE_ENTITY
812
-			);
813
-		}
814
-
815
-		if (!$user) {
816
-			return new DataResponse(
817
-				array(
818
-					'status' => 'error',
819
-					'data' => array(
820
-						'message' => (string)$this->l10n->t('Invalid user')
821
-					)
822
-				),
823
-				Http::STATUS_UNPROCESSABLE_ENTITY
824
-			);
825
-		}
826
-		// this is the only permission a backend provides and is also used
827
-		// for the permission of setting a email address
828
-		if (!$user->canChangeDisplayName()) {
829
-			return new DataResponse(
830
-				array(
831
-					'status' => 'error',
832
-					'data' => array(
833
-						'message' => (string)$this->l10n->t('Unable to change mail address')
834
-					)
835
-				),
836
-				Http::STATUS_FORBIDDEN
837
-			);
838
-		}
839
-
840
-		$userData = $this->accountManager->getUser($user);
841
-		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
842
-
843
-		try {
844
-			$this->saveUserSettings($user, $userData);
845
-			return new DataResponse(
846
-				array(
847
-					'status' => 'success',
848
-					'data' => array(
849
-						'username' => $id,
850
-						'mailAddress' => $mailAddress,
851
-						'message' => (string)$this->l10n->t('Email saved')
852
-					)
853
-				),
854
-				Http::STATUS_OK
855
-			);
856
-		} catch (ForbiddenException $e) {
857
-			return new DataResponse([
858
-				'status' => 'error',
859
-				'data' => [
860
-					'message' => $e->getMessage()
861
-				],
862
-			]);
863
-		}
864
-	}
60
+    /** @var IL10N */
61
+    private $l10n;
62
+    /** @var IUserSession */
63
+    private $userSession;
64
+    /** @var bool */
65
+    private $isAdmin;
66
+    /** @var IUserManager */
67
+    private $userManager;
68
+    /** @var IGroupManager */
69
+    private $groupManager;
70
+    /** @var IConfig */
71
+    private $config;
72
+    /** @var ILogger */
73
+    private $log;
74
+    /** @var \OC_Defaults */
75
+    private $defaults;
76
+    /** @var IMailer */
77
+    private $mailer;
78
+    /** @var string */
79
+    private $fromMailAddress;
80
+    /** @var IURLGenerator */
81
+    private $urlGenerator;
82
+    /** @var bool contains the state of the encryption app */
83
+    private $isEncryptionAppEnabled;
84
+    /** @var bool contains the state of the admin recovery setting */
85
+    private $isRestoreEnabled = false;
86
+    /** @var IAvatarManager */
87
+    private $avatarManager;
88
+    /** @var AccountManager */
89
+    private $accountManager;
90
+    /** @var ISecureRandom */
91
+    private $secureRandom;
92
+    /** @var ITimeFactory */
93
+    private $timeFactory;
94
+    /** @var ICrypto */
95
+    private $crypto;
96
+
97
+
98
+    /**
99
+     * @param string $appName
100
+     * @param IRequest $request
101
+     * @param IUserManager $userManager
102
+     * @param IGroupManager $groupManager
103
+     * @param IUserSession $userSession
104
+     * @param IConfig $config
105
+     * @param bool $isAdmin
106
+     * @param IL10N $l10n
107
+     * @param ILogger $log
108
+     * @param \OC_Defaults $defaults
109
+     * @param IMailer $mailer
110
+     * @param string $fromMailAddress
111
+     * @param IURLGenerator $urlGenerator
112
+     * @param IAppManager $appManager
113
+     * @param IAvatarManager $avatarManager
114
+     * @param AccountManager $accountManager
115
+     * @param ISecureRandom $secureRandom
116
+     * @param ITimeFactory $timeFactory
117
+     * @param ICrypto $crypto
118
+     */
119
+    public function __construct($appName,
120
+                                IRequest $request,
121
+                                IUserManager $userManager,
122
+                                IGroupManager $groupManager,
123
+                                IUserSession $userSession,
124
+                                IConfig $config,
125
+                                $isAdmin,
126
+                                IL10N $l10n,
127
+                                ILogger $log,
128
+                                \OC_Defaults $defaults,
129
+                                IMailer $mailer,
130
+                                $fromMailAddress,
131
+                                IURLGenerator $urlGenerator,
132
+                                IAppManager $appManager,
133
+                                IAvatarManager $avatarManager,
134
+                                AccountManager $accountManager,
135
+                                ISecureRandom $secureRandom,
136
+                                ITimeFactory $timeFactory,
137
+                                ICrypto $crypto) {
138
+        parent::__construct($appName, $request);
139
+        $this->userManager = $userManager;
140
+        $this->groupManager = $groupManager;
141
+        $this->userSession = $userSession;
142
+        $this->config = $config;
143
+        $this->isAdmin = $isAdmin;
144
+        $this->l10n = $l10n;
145
+        $this->log = $log;
146
+        $this->defaults = $defaults;
147
+        $this->mailer = $mailer;
148
+        $this->fromMailAddress = $fromMailAddress;
149
+        $this->urlGenerator = $urlGenerator;
150
+        $this->avatarManager = $avatarManager;
151
+        $this->accountManager = $accountManager;
152
+        $this->secureRandom = $secureRandom;
153
+        $this->timeFactory = $timeFactory;
154
+        $this->crypto = $crypto;
155
+
156
+        // check for encryption state - TODO see formatUserForIndex
157
+        $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
158
+        if($this->isEncryptionAppEnabled) {
159
+            // putting this directly in empty is possible in PHP 5.5+
160
+            $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
161
+            $this->isRestoreEnabled = !empty($result);
162
+        }
163
+    }
164
+
165
+    /**
166
+     * @param IUser $user
167
+     * @param array $userGroups
168
+     * @return array
169
+     */
170
+    private function formatUserForIndex(IUser $user, array $userGroups = null) {
171
+
172
+        // TODO: eliminate this encryption specific code below and somehow
173
+        // hook in additional user info from other apps
174
+
175
+        // recovery isn't possible if admin or user has it disabled and encryption
176
+        // is enabled - so we eliminate the else paths in the conditional tree
177
+        // below
178
+        $restorePossible = false;
179
+
180
+        if ($this->isEncryptionAppEnabled) {
181
+            if ($this->isRestoreEnabled) {
182
+                // check for the users recovery setting
183
+                $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
184
+                // method call inside empty is possible with PHP 5.5+
185
+                $recoveryModeEnabled = !empty($recoveryMode);
186
+                if ($recoveryModeEnabled) {
187
+                    // user also has recovery mode enabled
188
+                    $restorePossible = true;
189
+                }
190
+            }
191
+        } else {
192
+            // recovery is possible if encryption is disabled (plain files are
193
+            // available)
194
+            $restorePossible = true;
195
+        }
196
+
197
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
198
+        foreach($subAdminGroups as $key => $subAdminGroup) {
199
+            $subAdminGroups[$key] = $subAdminGroup->getGID();
200
+        }
201
+
202
+        $displayName = $user->getEMailAddress();
203
+        if (is_null($displayName)) {
204
+            $displayName = '';
205
+        }
206
+
207
+        $avatarAvailable = false;
208
+        try {
209
+            $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
210
+        } catch (\Exception $e) {
211
+            //No avatar yet
212
+        }
213
+
214
+        return [
215
+            'name' => $user->getUID(),
216
+            'displayname' => $user->getDisplayName(),
217
+            'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
218
+            'subadmin' => $subAdminGroups,
219
+            'quota' => $user->getQuota(),
220
+            'storageLocation' => $user->getHome(),
221
+            'lastLogin' => $user->getLastLogin() * 1000,
222
+            'backend' => $user->getBackendClassName(),
223
+            'email' => $displayName,
224
+            'isRestoreDisabled' => !$restorePossible,
225
+            'isAvatarAvailable' => $avatarAvailable,
226
+        ];
227
+    }
228
+
229
+    /**
230
+     * @param array $userIDs Array with schema [$uid => $displayName]
231
+     * @return IUser[]
232
+     */
233
+    private function getUsersForUID(array $userIDs) {
234
+        $users = [];
235
+        foreach ($userIDs as $uid => $displayName) {
236
+            $users[$uid] = $this->userManager->get($uid);
237
+        }
238
+        return $users;
239
+    }
240
+
241
+    /**
242
+     * @NoAdminRequired
243
+     *
244
+     * @param int $offset
245
+     * @param int $limit
246
+     * @param string $gid GID to filter for
247
+     * @param string $pattern Pattern to search for in the username
248
+     * @param string $backend Backend to filter for (class-name)
249
+     * @return DataResponse
250
+     *
251
+     * TODO: Tidy up and write unit tests - code is mainly static method calls
252
+     */
253
+    public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
254
+        // FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
255
+        if($gid === '_everyone') {
256
+            $gid = '';
257
+        }
258
+
259
+        // Remove backends
260
+        if(!empty($backend)) {
261
+            $activeBackends = $this->userManager->getBackends();
262
+            $this->userManager->clearBackends();
263
+            foreach($activeBackends as $singleActiveBackend) {
264
+                if($backend === get_class($singleActiveBackend)) {
265
+                    $this->userManager->registerBackend($singleActiveBackend);
266
+                    break;
267
+                }
268
+            }
269
+        }
270
+
271
+        $users = [];
272
+        if ($this->isAdmin) {
273
+
274
+            if($gid !== '') {
275
+                $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
276
+            } else {
277
+                $batch = $this->userManager->search($pattern, $limit, $offset);
278
+            }
279
+
280
+            foreach ($batch as $user) {
281
+                $users[] = $this->formatUserForIndex($user);
282
+            }
283
+
284
+        } else {
285
+            $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
286
+            // New class returns IGroup[] so convert back
287
+            $gids = [];
288
+            foreach ($subAdminOfGroups as $group) {
289
+                $gids[] = $group->getGID();
290
+            }
291
+            $subAdminOfGroups = $gids;
292
+
293
+            // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
294
+            if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
295
+                $gid = '';
296
+            }
297
+
298
+            // Batch all groups the user is subadmin of when a group is specified
299
+            $batch = [];
300
+            if($gid === '') {
301
+                foreach($subAdminOfGroups as $group) {
302
+                    $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
303
+
304
+                    foreach($groupUsers as $uid => $displayName) {
305
+                        $batch[$uid] = $displayName;
306
+                    }
307
+                }
308
+            } else {
309
+                $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
310
+            }
311
+            $batch = $this->getUsersForUID($batch);
312
+
313
+            foreach ($batch as $user) {
314
+                // Only add the groups, this user is a subadmin of
315
+                $userGroups = array_values(array_intersect(
316
+                    $this->groupManager->getUserGroupIds($user),
317
+                    $subAdminOfGroups
318
+                ));
319
+                $users[] = $this->formatUserForIndex($user, $userGroups);
320
+            }
321
+        }
322
+
323
+        return new DataResponse($users);
324
+    }
325
+
326
+    /**
327
+     * @NoAdminRequired
328
+     * @PasswordConfirmationRequired
329
+     *
330
+     * @param string $username
331
+     * @param string $password
332
+     * @param array $groups
333
+     * @param string $email
334
+     * @return DataResponse
335
+     */
336
+    public function create($username, $password, array $groups=array(), $email='') {
337
+        if($email !== '' && !$this->mailer->validateMailAddress($email)) {
338
+            return new DataResponse(
339
+                array(
340
+                    'message' => (string)$this->l10n->t('Invalid mail address')
341
+                ),
342
+                Http::STATUS_UNPROCESSABLE_ENTITY
343
+            );
344
+        }
345
+
346
+        $currentUser = $this->userSession->getUser();
347
+
348
+        if (!$this->isAdmin) {
349
+            if (!empty($groups)) {
350
+                foreach ($groups as $key => $group) {
351
+                    $groupObject = $this->groupManager->get($group);
352
+                    if($groupObject === null) {
353
+                        unset($groups[$key]);
354
+                        continue;
355
+                    }
356
+
357
+                    if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
358
+                        unset($groups[$key]);
359
+                    }
360
+                }
361
+            }
362
+
363
+            if (empty($groups)) {
364
+                return new DataResponse(
365
+                    array(
366
+                        'message' => $this->l10n->t('No valid group selected'),
367
+                    ),
368
+                    Http::STATUS_FORBIDDEN
369
+                );
370
+            }
371
+        }
372
+
373
+        if ($this->userManager->userExists($username)) {
374
+            return new DataResponse(
375
+                array(
376
+                    'message' => (string)$this->l10n->t('A user with that name already exists.')
377
+                ),
378
+                Http::STATUS_CONFLICT
379
+            );
380
+        }
381
+
382
+        $generatedPassword = false;
383
+        if ($password === '') {
384
+            if ($email === '') {
385
+                return new DataResponse(
386
+                    array(
387
+                        'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
388
+                    ),
389
+                    Http::STATUS_UNPROCESSABLE_ENTITY
390
+                );
391
+            }
392
+
393
+            $password = $this->secureRandom->generate(32);
394
+            $generatedPassword = true;
395
+        }
396
+
397
+        try {
398
+            $user = $this->userManager->createUser($username, $password);
399
+        } catch (\Exception $exception) {
400
+            $message = $exception->getMessage();
401
+            if (!$message) {
402
+                $message = $this->l10n->t('Unable to create user.');
403
+            }
404
+            return new DataResponse(
405
+                array(
406
+                    'message' => (string) $message,
407
+                ),
408
+                Http::STATUS_FORBIDDEN
409
+            );
410
+        }
411
+
412
+        if($user instanceof IUser) {
413
+            if($groups !== null) {
414
+                foreach($groups as $groupName) {
415
+                    $group = $this->groupManager->get($groupName);
416
+
417
+                    if(empty($group)) {
418
+                        $group = $this->groupManager->createGroup($groupName);
419
+                    }
420
+                    $group->addUser($user);
421
+                }
422
+            }
423
+            /**
424
+             * Send new user mail only if a mail is set
425
+             */
426
+            if($email !== '') {
427
+                $user->setEMailAddress($email);
428
+
429
+                if ($generatedPassword) {
430
+                    $token = $this->secureRandom->generate(
431
+                        21,
432
+                        ISecureRandom::CHAR_DIGITS .
433
+                        ISecureRandom::CHAR_LOWER .
434
+                        ISecureRandom::CHAR_UPPER
435
+                    );
436
+                    $tokenValue = $this->timeFactory->getTime() . ':' . $token;
437
+                    $mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
438
+                    $encryptedValue = $this->crypto->encrypt($tokenValue, $mailAddress . $this->config->getSystemValue('secret'));
439
+                    $this->config->setUserValue($username, 'core', 'lostpassword', $encryptedValue);
440
+
441
+                    $link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $username, 'token' => $token]);
442
+                } else {
443
+                    $link = $this->urlGenerator->getAbsoluteURL('/');
444
+                }
445
+
446
+                // data for the mail template
447
+                $mailData = array(
448
+                    'username' => $username,
449
+                    'url' => $link
450
+                );
451
+
452
+                $mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank');
453
+                $mailContent = $mail->render();
454
+
455
+                $mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank');
456
+                $plainTextMailContent = $mail->render();
457
+
458
+                $subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]);
459
+
460
+                try {
461
+                    $message = $this->mailer->createMessage();
462
+                    $message->setTo([$email => $username]);
463
+                    $message->setSubject($subject);
464
+                    $message->setHtmlBody($mailContent);
465
+                    $message->setPlainBody($plainTextMailContent);
466
+                    $message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
467
+                    $this->mailer->send($message);
468
+                } catch(\Exception $e) {
469
+                    $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
470
+                }
471
+            }
472
+            // fetch users groups
473
+            $userGroups = $this->groupManager->getUserGroupIds($user);
474
+
475
+            return new DataResponse(
476
+                $this->formatUserForIndex($user, $userGroups),
477
+                Http::STATUS_CREATED
478
+            );
479
+        }
480
+
481
+        return new DataResponse(
482
+            array(
483
+                'message' => (string)$this->l10n->t('Unable to create user.')
484
+            ),
485
+            Http::STATUS_FORBIDDEN
486
+        );
487
+
488
+    }
489
+
490
+    /**
491
+     * @NoAdminRequired
492
+     * @PasswordConfirmationRequired
493
+     *
494
+     * @param string $id
495
+     * @return DataResponse
496
+     */
497
+    public function destroy($id) {
498
+        $userId = $this->userSession->getUser()->getUID();
499
+        $user = $this->userManager->get($id);
500
+
501
+        if($userId === $id) {
502
+            return new DataResponse(
503
+                array(
504
+                    'status' => 'error',
505
+                    'data' => array(
506
+                        'message' => (string)$this->l10n->t('Unable to delete user.')
507
+                    )
508
+                ),
509
+                Http::STATUS_FORBIDDEN
510
+            );
511
+        }
512
+
513
+        if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
514
+            return new DataResponse(
515
+                array(
516
+                    'status' => 'error',
517
+                    'data' => array(
518
+                        'message' => (string)$this->l10n->t('Authentication error')
519
+                    )
520
+                ),
521
+                Http::STATUS_FORBIDDEN
522
+            );
523
+        }
524
+
525
+        if($user) {
526
+            if($user->delete()) {
527
+                return new DataResponse(
528
+                    array(
529
+                        'status' => 'success',
530
+                        'data' => array(
531
+                            'username' => $id
532
+                        )
533
+                    ),
534
+                    Http::STATUS_NO_CONTENT
535
+                );
536
+            }
537
+        }
538
+
539
+        return new DataResponse(
540
+            array(
541
+                'status' => 'error',
542
+                'data' => array(
543
+                    'message' => (string)$this->l10n->t('Unable to delete user.')
544
+                )
545
+            ),
546
+            Http::STATUS_FORBIDDEN
547
+        );
548
+    }
549
+
550
+    /**
551
+     * @NoAdminRequired
552
+     * @NoSubadminRequired
553
+     * @PasswordConfirmationRequired
554
+     *
555
+     * @param string $avatarScope
556
+     * @param string $displayname
557
+     * @param string $displaynameScope
558
+     * @param string $phone
559
+     * @param string $phoneScope
560
+     * @param string $email
561
+     * @param string $emailScope
562
+     * @param string $website
563
+     * @param string $websiteScope
564
+     * @param string $address
565
+     * @param string $addressScope
566
+     * @param string $twitter
567
+     * @param string $twitterScope
568
+     * @return DataResponse
569
+     */
570
+    public function setUserSettings($avatarScope,
571
+                                    $displayname,
572
+                                    $displaynameScope,
573
+                                    $phone,
574
+                                    $phoneScope,
575
+                                    $email,
576
+                                    $emailScope,
577
+                                    $website,
578
+                                    $websiteScope,
579
+                                    $address,
580
+                                    $addressScope,
581
+                                    $twitter,
582
+                                    $twitterScope
583
+    ) {
584
+
585
+        if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
586
+            return new DataResponse(
587
+                array(
588
+                    'status' => 'error',
589
+                    'data' => array(
590
+                        'message' => (string)$this->l10n->t('Invalid mail address')
591
+                    )
592
+                ),
593
+                Http::STATUS_UNPROCESSABLE_ENTITY
594
+            );
595
+        }
596
+
597
+        $data = [
598
+            AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
599
+            AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
600
+            AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
601
+            AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
602
+            AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
603
+            AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
604
+            AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
605
+        ];
606
+
607
+        $user = $this->userSession->getUser();
608
+
609
+        try {
610
+            $this->saveUserSettings($user, $data);
611
+            return new DataResponse(
612
+                array(
613
+                    'status' => 'success',
614
+                    'data' => array(
615
+                        'userId' => $user->getUID(),
616
+                        'avatarScope' => $avatarScope,
617
+                        'displayname' => $displayname,
618
+                        'displaynameScope' => $displaynameScope,
619
+                        'email' => $email,
620
+                        'emailScope' => $emailScope,
621
+                        'website' => $website,
622
+                        'websiteScope' => $websiteScope,
623
+                        'address' => $address,
624
+                        'addressScope' => $addressScope,
625
+                        'message' => (string)$this->l10n->t('Settings saved')
626
+                    )
627
+                ),
628
+                Http::STATUS_OK
629
+            );
630
+        } catch (ForbiddenException $e) {
631
+            return new DataResponse([
632
+                'status' => 'error',
633
+                'data' => [
634
+                    'message' => $e->getMessage()
635
+                ],
636
+            ]);
637
+        }
638
+
639
+    }
640
+
641
+
642
+    /**
643
+     * update account manager with new user data
644
+     *
645
+     * @param IUser $user
646
+     * @param array $data
647
+     * @throws ForbiddenException
648
+     */
649
+    protected function saveUserSettings(IUser $user, $data) {
650
+
651
+        // keep the user back-end up-to-date with the latest display name and email
652
+        // address
653
+        $oldDisplayName = $user->getDisplayName();
654
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
655
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
656
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
657
+        ) {
658
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
659
+            if ($result === false) {
660
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
661
+            }
662
+        }
663
+
664
+        $oldEmailAddress = $user->getEMailAddress();
665
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
666
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
667
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
668
+        ) {
669
+            // this is the only permission a backend provides and is also used
670
+            // for the permission of setting a email address
671
+            if (!$user->canChangeDisplayName()) {
672
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
673
+            }
674
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
675
+        }
676
+
677
+        $this->accountManager->updateUser($user, $data);
678
+    }
679
+
680
+    /**
681
+     * Count all unique users visible for the current admin/subadmin.
682
+     *
683
+     * @NoAdminRequired
684
+     *
685
+     * @return DataResponse
686
+     */
687
+    public function stats() {
688
+        $userCount = 0;
689
+        if ($this->isAdmin) {
690
+            $countByBackend = $this->userManager->countUsers();
691
+
692
+            if (!empty($countByBackend)) {
693
+                foreach ($countByBackend as $count) {
694
+                    $userCount += $count;
695
+                }
696
+            }
697
+        } else {
698
+            $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
699
+
700
+            $uniqueUsers = [];
701
+            foreach ($groups as $group) {
702
+                foreach($group->getUsers() as $uid => $displayName) {
703
+                    $uniqueUsers[$uid] = true;
704
+                }
705
+            }
706
+
707
+            $userCount = count($uniqueUsers);
708
+        }
709
+
710
+        return new DataResponse(
711
+            [
712
+                'totalUsers' => $userCount
713
+            ]
714
+        );
715
+    }
716
+
717
+
718
+    /**
719
+     * Set the displayName of a user
720
+     *
721
+     * @NoAdminRequired
722
+     * @NoSubadminRequired
723
+     * @PasswordConfirmationRequired
724
+     * @todo merge into saveUserSettings
725
+     *
726
+     * @param string $username
727
+     * @param string $displayName
728
+     * @return DataResponse
729
+     */
730
+    public function setDisplayName($username, $displayName) {
731
+        $currentUser = $this->userSession->getUser();
732
+        $user = $this->userManager->get($username);
733
+
734
+        if ($user === null ||
735
+            !$user->canChangeDisplayName() ||
736
+            (
737
+                !$this->groupManager->isAdmin($currentUser->getUID()) &&
738
+                !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
739
+                $currentUser->getUID() !== $username
740
+
741
+            )
742
+        ) {
743
+            return new DataResponse([
744
+                'status' => 'error',
745
+                'data' => [
746
+                    'message' => $this->l10n->t('Authentication error'),
747
+                ],
748
+            ]);
749
+        }
750
+
751
+        $userData = $this->accountManager->getUser($user);
752
+        $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
753
+
754
+
755
+        try {
756
+            $this->saveUserSettings($user, $userData);
757
+            return new DataResponse([
758
+                'status' => 'success',
759
+                'data' => [
760
+                    'message' => $this->l10n->t('Your full name has been changed.'),
761
+                    'username' => $username,
762
+                    'displayName' => $displayName,
763
+                ],
764
+            ]);
765
+        } catch (ForbiddenException $e) {
766
+            return new DataResponse([
767
+                'status' => 'error',
768
+                'data' => [
769
+                    'message' => $e->getMessage(),
770
+                    'displayName' => $user->getDisplayName(),
771
+                ],
772
+            ]);
773
+        }
774
+    }
775
+
776
+    /**
777
+     * Set the mail address of a user
778
+     *
779
+     * @NoAdminRequired
780
+     * @NoSubadminRequired
781
+     * @PasswordConfirmationRequired
782
+     *
783
+     * @param string $id
784
+     * @param string $mailAddress
785
+     * @return DataResponse
786
+     */
787
+    public function setEMailAddress($id, $mailAddress) {
788
+        $user = $this->userManager->get($id);
789
+        if (!$this->isAdmin
790
+            && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
791
+        ) {
792
+            return new DataResponse(
793
+                array(
794
+                    'status' => 'error',
795
+                    'data' => array(
796
+                        'message' => (string)$this->l10n->t('Forbidden')
797
+                    )
798
+                ),
799
+                Http::STATUS_FORBIDDEN
800
+            );
801
+        }
802
+
803
+        if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
804
+            return new DataResponse(
805
+                array(
806
+                    'status' => 'error',
807
+                    'data' => array(
808
+                        'message' => (string)$this->l10n->t('Invalid mail address')
809
+                    )
810
+                ),
811
+                Http::STATUS_UNPROCESSABLE_ENTITY
812
+            );
813
+        }
814
+
815
+        if (!$user) {
816
+            return new DataResponse(
817
+                array(
818
+                    'status' => 'error',
819
+                    'data' => array(
820
+                        'message' => (string)$this->l10n->t('Invalid user')
821
+                    )
822
+                ),
823
+                Http::STATUS_UNPROCESSABLE_ENTITY
824
+            );
825
+        }
826
+        // this is the only permission a backend provides and is also used
827
+        // for the permission of setting a email address
828
+        if (!$user->canChangeDisplayName()) {
829
+            return new DataResponse(
830
+                array(
831
+                    'status' => 'error',
832
+                    'data' => array(
833
+                        'message' => (string)$this->l10n->t('Unable to change mail address')
834
+                    )
835
+                ),
836
+                Http::STATUS_FORBIDDEN
837
+            );
838
+        }
839
+
840
+        $userData = $this->accountManager->getUser($user);
841
+        $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
842
+
843
+        try {
844
+            $this->saveUserSettings($user, $userData);
845
+            return new DataResponse(
846
+                array(
847
+                    'status' => 'success',
848
+                    'data' => array(
849
+                        'username' => $id,
850
+                        'mailAddress' => $mailAddress,
851
+                        'message' => (string)$this->l10n->t('Email saved')
852
+                    )
853
+                ),
854
+                Http::STATUS_OK
855
+            );
856
+        } catch (ForbiddenException $e) {
857
+            return new DataResponse([
858
+                'status' => 'error',
859
+                'data' => [
860
+                    'message' => $e->getMessage()
861
+                ],
862
+            ]);
863
+        }
864
+    }
865 865
 
866 866
 }
Please login to merge, or discard this patch.
Spacing   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 
156 156
 		// check for encryption state - TODO see formatUserForIndex
157 157
 		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
158
-		if($this->isEncryptionAppEnabled) {
158
+		if ($this->isEncryptionAppEnabled) {
159 159
 			// putting this directly in empty is possible in PHP 5.5+
160 160
 			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
161 161
 			$this->isRestoreEnabled = !empty($result);
@@ -195,7 +195,7 @@  discard block
 block discarded – undo
195 195
 		}
196 196
 
197 197
 		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
198
-		foreach($subAdminGroups as $key => $subAdminGroup) {
198
+		foreach ($subAdminGroups as $key => $subAdminGroup) {
199 199
 			$subAdminGroups[$key] = $subAdminGroup->getGID();
200 200
 		}
201 201
 
@@ -252,16 +252,16 @@  discard block
 block discarded – undo
252 252
 	 */
253 253
 	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
254 254
 		// FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
255
-		if($gid === '_everyone') {
255
+		if ($gid === '_everyone') {
256 256
 			$gid = '';
257 257
 		}
258 258
 
259 259
 		// Remove backends
260
-		if(!empty($backend)) {
260
+		if (!empty($backend)) {
261 261
 			$activeBackends = $this->userManager->getBackends();
262 262
 			$this->userManager->clearBackends();
263
-			foreach($activeBackends as $singleActiveBackend) {
264
-				if($backend === get_class($singleActiveBackend)) {
263
+			foreach ($activeBackends as $singleActiveBackend) {
264
+				if ($backend === get_class($singleActiveBackend)) {
265 265
 					$this->userManager->registerBackend($singleActiveBackend);
266 266
 					break;
267 267
 				}
@@ -271,7 +271,7 @@  discard block
 block discarded – undo
271 271
 		$users = [];
272 272
 		if ($this->isAdmin) {
273 273
 
274
-			if($gid !== '') {
274
+			if ($gid !== '') {
275 275
 				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
276 276
 			} else {
277 277
 				$batch = $this->userManager->search($pattern, $limit, $offset);
@@ -291,17 +291,17 @@  discard block
 block discarded – undo
291 291
 			$subAdminOfGroups = $gids;
292 292
 
293 293
 			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
294
-			if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
294
+			if ($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
295 295
 				$gid = '';
296 296
 			}
297 297
 
298 298
 			// Batch all groups the user is subadmin of when a group is specified
299 299
 			$batch = [];
300
-			if($gid === '') {
301
-				foreach($subAdminOfGroups as $group) {
300
+			if ($gid === '') {
301
+				foreach ($subAdminOfGroups as $group) {
302 302
 					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
303 303
 
304
-					foreach($groupUsers as $uid => $displayName) {
304
+					foreach ($groupUsers as $uid => $displayName) {
305 305
 						$batch[$uid] = $displayName;
306 306
 					}
307 307
 				}
@@ -333,11 +333,11 @@  discard block
 block discarded – undo
333 333
 	 * @param string $email
334 334
 	 * @return DataResponse
335 335
 	 */
336
-	public function create($username, $password, array $groups=array(), $email='') {
337
-		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
336
+	public function create($username, $password, array $groups = array(), $email = '') {
337
+		if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
338 338
 			return new DataResponse(
339 339
 				array(
340
-					'message' => (string)$this->l10n->t('Invalid mail address')
340
+					'message' => (string) $this->l10n->t('Invalid mail address')
341 341
 				),
342 342
 				Http::STATUS_UNPROCESSABLE_ENTITY
343 343
 			);
@@ -349,7 +349,7 @@  discard block
 block discarded – undo
349 349
 			if (!empty($groups)) {
350 350
 				foreach ($groups as $key => $group) {
351 351
 					$groupObject = $this->groupManager->get($group);
352
-					if($groupObject === null) {
352
+					if ($groupObject === null) {
353 353
 						unset($groups[$key]);
354 354
 						continue;
355 355
 					}
@@ -373,7 +373,7 @@  discard block
 block discarded – undo
373 373
 		if ($this->userManager->userExists($username)) {
374 374
 			return new DataResponse(
375 375
 				array(
376
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
376
+					'message' => (string) $this->l10n->t('A user with that name already exists.')
377 377
 				),
378 378
 				Http::STATUS_CONFLICT
379 379
 			);
@@ -384,7 +384,7 @@  discard block
 block discarded – undo
384 384
 			if ($email === '') {
385 385
 				return new DataResponse(
386 386
 					array(
387
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
387
+						'message' => (string) $this->l10n->t('To send a password link to the user an email address is required.')
388 388
 					),
389 389
 					Http::STATUS_UNPROCESSABLE_ENTITY
390 390
 				);
@@ -409,12 +409,12 @@  discard block
 block discarded – undo
409 409
 			);
410 410
 		}
411 411
 
412
-		if($user instanceof IUser) {
413
-			if($groups !== null) {
414
-				foreach($groups as $groupName) {
412
+		if ($user instanceof IUser) {
413
+			if ($groups !== null) {
414
+				foreach ($groups as $groupName) {
415 415
 					$group = $this->groupManager->get($groupName);
416 416
 
417
-					if(empty($group)) {
417
+					if (empty($group)) {
418 418
 						$group = $this->groupManager->createGroup($groupName);
419 419
 					}
420 420
 					$group->addUser($user);
@@ -423,19 +423,19 @@  discard block
 block discarded – undo
423 423
 			/**
424 424
 			 * Send new user mail only if a mail is set
425 425
 			 */
426
-			if($email !== '') {
426
+			if ($email !== '') {
427 427
 				$user->setEMailAddress($email);
428 428
 
429 429
 				if ($generatedPassword) {
430 430
 					$token = $this->secureRandom->generate(
431 431
 						21,
432
-						ISecureRandom::CHAR_DIGITS .
433
-						ISecureRandom::CHAR_LOWER .
432
+						ISecureRandom::CHAR_DIGITS.
433
+						ISecureRandom::CHAR_LOWER.
434 434
 						ISecureRandom::CHAR_UPPER
435 435
 					);
436
-					$tokenValue = $this->timeFactory->getTime() . ':' . $token;
436
+					$tokenValue = $this->timeFactory->getTime().':'.$token;
437 437
 					$mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
438
-					$encryptedValue = $this->crypto->encrypt($tokenValue, $mailAddress . $this->config->getSystemValue('secret'));
438
+					$encryptedValue = $this->crypto->encrypt($tokenValue, $mailAddress.$this->config->getSystemValue('secret'));
439 439
 					$this->config->setUserValue($username, 'core', 'lostpassword', $encryptedValue);
440 440
 
441 441
 					$link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $username, 'token' => $token]);
@@ -465,8 +465,8 @@  discard block
 block discarded – undo
465 465
 					$message->setPlainBody($plainTextMailContent);
466 466
 					$message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
467 467
 					$this->mailer->send($message);
468
-				} catch(\Exception $e) {
469
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
468
+				} catch (\Exception $e) {
469
+					$this->log->error("Can't send new user mail to $email: ".$e->getMessage(), array('app' => 'settings'));
470 470
 				}
471 471
 			}
472 472
 			// fetch users groups
@@ -480,7 +480,7 @@  discard block
 block discarded – undo
480 480
 
481 481
 		return new DataResponse(
482 482
 			array(
483
-				'message' => (string)$this->l10n->t('Unable to create user.')
483
+				'message' => (string) $this->l10n->t('Unable to create user.')
484 484
 			),
485 485
 			Http::STATUS_FORBIDDEN
486 486
 		);
@@ -498,32 +498,32 @@  discard block
 block discarded – undo
498 498
 		$userId = $this->userSession->getUser()->getUID();
499 499
 		$user = $this->userManager->get($id);
500 500
 
501
-		if($userId === $id) {
501
+		if ($userId === $id) {
502 502
 			return new DataResponse(
503 503
 				array(
504 504
 					'status' => 'error',
505 505
 					'data' => array(
506
-						'message' => (string)$this->l10n->t('Unable to delete user.')
506
+						'message' => (string) $this->l10n->t('Unable to delete user.')
507 507
 					)
508 508
 				),
509 509
 				Http::STATUS_FORBIDDEN
510 510
 			);
511 511
 		}
512 512
 
513
-		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
513
+		if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
514 514
 			return new DataResponse(
515 515
 				array(
516 516
 					'status' => 'error',
517 517
 					'data' => array(
518
-						'message' => (string)$this->l10n->t('Authentication error')
518
+						'message' => (string) $this->l10n->t('Authentication error')
519 519
 					)
520 520
 				),
521 521
 				Http::STATUS_FORBIDDEN
522 522
 			);
523 523
 		}
524 524
 
525
-		if($user) {
526
-			if($user->delete()) {
525
+		if ($user) {
526
+			if ($user->delete()) {
527 527
 				return new DataResponse(
528 528
 					array(
529 529
 						'status' => 'success',
@@ -540,7 +540,7 @@  discard block
 block discarded – undo
540 540
 			array(
541 541
 				'status' => 'error',
542 542
 				'data' => array(
543
-					'message' => (string)$this->l10n->t('Unable to delete user.')
543
+					'message' => (string) $this->l10n->t('Unable to delete user.')
544 544
 				)
545 545
 			),
546 546
 			Http::STATUS_FORBIDDEN
@@ -582,12 +582,12 @@  discard block
 block discarded – undo
582 582
 									$twitterScope
583 583
 	) {
584 584
 
585
-		if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
585
+		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
586 586
 			return new DataResponse(
587 587
 				array(
588 588
 					'status' => 'error',
589 589
 					'data' => array(
590
-						'message' => (string)$this->l10n->t('Invalid mail address')
590
+						'message' => (string) $this->l10n->t('Invalid mail address')
591 591
 					)
592 592
 				),
593 593
 				Http::STATUS_UNPROCESSABLE_ENTITY
@@ -622,7 +622,7 @@  discard block
 block discarded – undo
622 622
 						'websiteScope' => $websiteScope,
623 623
 						'address' => $address,
624 624
 						'addressScope' => $addressScope,
625
-						'message' => (string)$this->l10n->t('Settings saved')
625
+						'message' => (string) $this->l10n->t('Settings saved')
626 626
 					)
627 627
 				),
628 628
 				Http::STATUS_OK
@@ -699,7 +699,7 @@  discard block
 block discarded – undo
699 699
 
700 700
 			$uniqueUsers = [];
701 701
 			foreach ($groups as $group) {
702
-				foreach($group->getUsers() as $uid => $displayName) {
702
+				foreach ($group->getUsers() as $uid => $displayName) {
703 703
 					$uniqueUsers[$uid] = true;
704 704
 				}
705 705
 			}
@@ -793,19 +793,19 @@  discard block
 block discarded – undo
793 793
 				array(
794 794
 					'status' => 'error',
795 795
 					'data' => array(
796
-						'message' => (string)$this->l10n->t('Forbidden')
796
+						'message' => (string) $this->l10n->t('Forbidden')
797 797
 					)
798 798
 				),
799 799
 				Http::STATUS_FORBIDDEN
800 800
 			);
801 801
 		}
802 802
 
803
-		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
803
+		if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
804 804
 			return new DataResponse(
805 805
 				array(
806 806
 					'status' => 'error',
807 807
 					'data' => array(
808
-						'message' => (string)$this->l10n->t('Invalid mail address')
808
+						'message' => (string) $this->l10n->t('Invalid mail address')
809 809
 					)
810 810
 				),
811 811
 				Http::STATUS_UNPROCESSABLE_ENTITY
@@ -817,7 +817,7 @@  discard block
 block discarded – undo
817 817
 				array(
818 818
 					'status' => 'error',
819 819
 					'data' => array(
820
-						'message' => (string)$this->l10n->t('Invalid user')
820
+						'message' => (string) $this->l10n->t('Invalid user')
821 821
 					)
822 822
 				),
823 823
 				Http::STATUS_UNPROCESSABLE_ENTITY
@@ -830,7 +830,7 @@  discard block
 block discarded – undo
830 830
 				array(
831 831
 					'status' => 'error',
832 832
 					'data' => array(
833
-						'message' => (string)$this->l10n->t('Unable to change mail address')
833
+						'message' => (string) $this->l10n->t('Unable to change mail address')
834 834
 					)
835 835
 				),
836 836
 				Http::STATUS_FORBIDDEN
@@ -848,7 +848,7 @@  discard block
 block discarded – undo
848 848
 					'data' => array(
849 849
 						'username' => $id,
850 850
 						'mailAddress' => $mailAddress,
851
-						'message' => (string)$this->l10n->t('Email saved')
851
+						'message' => (string) $this->l10n->t('Email saved')
852 852
 					)
853 853
 				),
854 854
 				Http::STATUS_OK
Please login to merge, or discard this patch.