Completed
Pull Request — master (#5462)
by Thomas
23:08 queued 06:43
created
apps/files_external/lib/Lib/Storage/Dropbox.php 3 patches
Doc Comments   +6 added lines patch added patch discarded remove patch
@@ -76,6 +76,9 @@  discard block
 block discarded – undo
76 76
 		return false;
77 77
 	}
78 78
 
79
+	/**
80
+	 * @param string $path
81
+	 */
79 82
 	private function setMetaData($path, $metaData) {
80 83
 		$this->metaData[ltrim($path, '/')] = $metaData;
81 84
 	}
@@ -316,6 +319,9 @@  discard block
 block discarded – undo
316 319
 		return false;
317 320
 	}
318 321
 
322
+	/**
323
+	 * @param string $path
324
+	 */
319 325
 	public function writeBack($tmpFile, $path) {
320 326
 		$handle = fopen($tmpFile, 'r');
321 327
 		try {
Please login to merge, or discard this patch.
Indentation   +290 added lines, -290 removed lines patch added patch discarded remove patch
@@ -40,317 +40,317 @@
 block discarded – undo
40 40
 
41 41
 class Dropbox extends \OC\Files\Storage\Common {
42 42
 
43
-	private $dropbox;
44
-	private $root;
45
-	private $id;
46
-	private $metaData = array();
47
-	private $oauth;
43
+    private $dropbox;
44
+    private $root;
45
+    private $id;
46
+    private $metaData = array();
47
+    private $oauth;
48 48
 
49
-	public function __construct($params) {
50
-		if (isset($params['configured']) && $params['configured'] == 'true'
51
-			&& isset($params['app_key'])
52
-			&& isset($params['app_secret'])
53
-			&& isset($params['token'])
54
-			&& isset($params['token_secret'])
55
-		) {
56
-			$this->root = isset($params['root']) ? $params['root'] : '';
57
-			$this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root;
58
-			$this->oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']);
59
-			$this->oauth->setToken($params['token'], $params['token_secret']);
60
-			// note: Dropbox_API connection is lazy
61
-			$this->dropbox = new \Dropbox_API($this->oauth, 'auto');
62
-		} else {
63
-			throw new \Exception('Creating Dropbox storage failed');
64
-		}
65
-	}
49
+    public function __construct($params) {
50
+        if (isset($params['configured']) && $params['configured'] == 'true'
51
+            && isset($params['app_key'])
52
+            && isset($params['app_secret'])
53
+            && isset($params['token'])
54
+            && isset($params['token_secret'])
55
+        ) {
56
+            $this->root = isset($params['root']) ? $params['root'] : '';
57
+            $this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root;
58
+            $this->oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']);
59
+            $this->oauth->setToken($params['token'], $params['token_secret']);
60
+            // note: Dropbox_API connection is lazy
61
+            $this->dropbox = new \Dropbox_API($this->oauth, 'auto');
62
+        } else {
63
+            throw new \Exception('Creating Dropbox storage failed');
64
+        }
65
+    }
66 66
 
67
-	/**
68
-	 * @param string $path
69
-	 */
70
-	private function deleteMetaData($path) {
71
-		$path = ltrim($this->root.$path, '/');
72
-		if (isset($this->metaData[$path])) {
73
-			unset($this->metaData[$path]);
74
-			return true;
75
-		}
76
-		return false;
77
-	}
67
+    /**
68
+     * @param string $path
69
+     */
70
+    private function deleteMetaData($path) {
71
+        $path = ltrim($this->root.$path, '/');
72
+        if (isset($this->metaData[$path])) {
73
+            unset($this->metaData[$path]);
74
+            return true;
75
+        }
76
+        return false;
77
+    }
78 78
 
79
-	private function setMetaData($path, $metaData) {
80
-		$this->metaData[ltrim($path, '/')] = $metaData;
81
-	}
79
+    private function setMetaData($path, $metaData) {
80
+        $this->metaData[ltrim($path, '/')] = $metaData;
81
+    }
82 82
 
83
-	/**
84
-	 * Returns the path's metadata
85
-	 * @param string $path path for which to return the metadata
86
-	 * @param bool $list if true, also return the directory's contents
87
-	 * @return mixed directory contents if $list is true, file metadata if $list is
88
-	 * false, null if the file doesn't exist or "false" if the operation failed
89
-	 */
90
-	private function getDropBoxMetaData($path, $list = false) {
91
-		$path = ltrim($this->root.$path, '/');
92
-		if ( ! $list && isset($this->metaData[$path])) {
93
-			return $this->metaData[$path];
94
-		} else {
95
-			if ($list) {
96
-				try {
97
-					$response = $this->dropbox->getMetaData($path);
98
-				} catch (\Dropbox_Exception_Forbidden $e) {
99
-					throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
100
-				} catch (\Exception $exception) {
101
-					\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
102
-					return false;
103
-				}
104
-				$contents = array();
105
-				if ($response && isset($response['contents'])) {
106
-					// Cache folder's contents
107
-					foreach ($response['contents'] as $file) {
108
-						if (!isset($file['is_deleted']) || !$file['is_deleted']) {
109
-							$this->setMetaData($path.'/'.basename($file['path']), $file);
110
-							$contents[] = $file;
111
-						}
112
-					}
113
-					unset($response['contents']);
114
-				}
115
-				if (!isset($response['is_deleted']) || !$response['is_deleted']) {
116
-					$this->setMetaData($path, $response);
117
-				}
118
-				// Return contents of folder only
119
-				return $contents;
120
-			} else {
121
-				try {
122
-					$requestPath = $path;
123
-					if ($path === '.') {
124
-						$requestPath = '';
125
-					}
83
+    /**
84
+     * Returns the path's metadata
85
+     * @param string $path path for which to return the metadata
86
+     * @param bool $list if true, also return the directory's contents
87
+     * @return mixed directory contents if $list is true, file metadata if $list is
88
+     * false, null if the file doesn't exist or "false" if the operation failed
89
+     */
90
+    private function getDropBoxMetaData($path, $list = false) {
91
+        $path = ltrim($this->root.$path, '/');
92
+        if ( ! $list && isset($this->metaData[$path])) {
93
+            return $this->metaData[$path];
94
+        } else {
95
+            if ($list) {
96
+                try {
97
+                    $response = $this->dropbox->getMetaData($path);
98
+                } catch (\Dropbox_Exception_Forbidden $e) {
99
+                    throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
100
+                } catch (\Exception $exception) {
101
+                    \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
102
+                    return false;
103
+                }
104
+                $contents = array();
105
+                if ($response && isset($response['contents'])) {
106
+                    // Cache folder's contents
107
+                    foreach ($response['contents'] as $file) {
108
+                        if (!isset($file['is_deleted']) || !$file['is_deleted']) {
109
+                            $this->setMetaData($path.'/'.basename($file['path']), $file);
110
+                            $contents[] = $file;
111
+                        }
112
+                    }
113
+                    unset($response['contents']);
114
+                }
115
+                if (!isset($response['is_deleted']) || !$response['is_deleted']) {
116
+                    $this->setMetaData($path, $response);
117
+                }
118
+                // Return contents of folder only
119
+                return $contents;
120
+            } else {
121
+                try {
122
+                    $requestPath = $path;
123
+                    if ($path === '.') {
124
+                        $requestPath = '';
125
+                    }
126 126
 
127
-					$response = $this->dropbox->getMetaData($requestPath, 'false');
128
-					if (!isset($response['is_deleted']) || !$response['is_deleted']) {
129
-						$this->setMetaData($path, $response);
130
-						return $response;
131
-					}
132
-					return null;
133
-				} catch (\Dropbox_Exception_Forbidden $e) {
134
-					throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
135
-				} catch (\Exception $exception) {
136
-					if ($exception instanceof \Dropbox_Exception_NotFound) {
137
-						// don't log, might be a file_exist check
138
-						return false;
139
-					}
140
-					\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
141
-					return false;
142
-				}
143
-			}
144
-		}
145
-	}
127
+                    $response = $this->dropbox->getMetaData($requestPath, 'false');
128
+                    if (!isset($response['is_deleted']) || !$response['is_deleted']) {
129
+                        $this->setMetaData($path, $response);
130
+                        return $response;
131
+                    }
132
+                    return null;
133
+                } catch (\Dropbox_Exception_Forbidden $e) {
134
+                    throw new StorageNotAvailableException('Dropbox API rate limit exceeded', StorageNotAvailableException::STATUS_ERROR, $e);
135
+                } catch (\Exception $exception) {
136
+                    if ($exception instanceof \Dropbox_Exception_NotFound) {
137
+                        // don't log, might be a file_exist check
138
+                        return false;
139
+                    }
140
+                    \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
141
+                    return false;
142
+                }
143
+            }
144
+        }
145
+    }
146 146
 
147
-	public function getId(){
148
-		return $this->id;
149
-	}
147
+    public function getId(){
148
+        return $this->id;
149
+    }
150 150
 
151
-	public function mkdir($path) {
152
-		$path = $this->root.$path;
153
-		try {
154
-			$this->dropbox->createFolder($path);
155
-			return true;
156
-		} catch (\Exception $exception) {
157
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
158
-			return false;
159
-		}
160
-	}
151
+    public function mkdir($path) {
152
+        $path = $this->root.$path;
153
+        try {
154
+            $this->dropbox->createFolder($path);
155
+            return true;
156
+        } catch (\Exception $exception) {
157
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
158
+            return false;
159
+        }
160
+    }
161 161
 
162
-	public function rmdir($path) {
163
-		return $this->unlink($path);
164
-	}
162
+    public function rmdir($path) {
163
+        return $this->unlink($path);
164
+    }
165 165
 
166
-	public function opendir($path) {
167
-		$contents = $this->getDropBoxMetaData($path, true);
168
-		if ($contents !== false) {
169
-			$files = array();
170
-			foreach ($contents as $file) {
171
-				$files[] = basename($file['path']);
172
-			}
173
-			return IteratorDirectory::wrap($files);
174
-		}
175
-		return false;
176
-	}
166
+    public function opendir($path) {
167
+        $contents = $this->getDropBoxMetaData($path, true);
168
+        if ($contents !== false) {
169
+            $files = array();
170
+            foreach ($contents as $file) {
171
+                $files[] = basename($file['path']);
172
+            }
173
+            return IteratorDirectory::wrap($files);
174
+        }
175
+        return false;
176
+    }
177 177
 
178
-	public function stat($path) {
179
-		$metaData = $this->getDropBoxMetaData($path);
180
-		if ($metaData) {
181
-			$stat['size'] = $metaData['bytes'];
182
-			$stat['atime'] = time();
183
-			$stat['mtime'] = (isset($metaData['modified'])) ? strtotime($metaData['modified']) : time();
184
-			return $stat;
185
-		}
186
-		return false;
187
-	}
178
+    public function stat($path) {
179
+        $metaData = $this->getDropBoxMetaData($path);
180
+        if ($metaData) {
181
+            $stat['size'] = $metaData['bytes'];
182
+            $stat['atime'] = time();
183
+            $stat['mtime'] = (isset($metaData['modified'])) ? strtotime($metaData['modified']) : time();
184
+            return $stat;
185
+        }
186
+        return false;
187
+    }
188 188
 
189
-	public function filetype($path) {
190
-		if ($path == '' || $path == '/') {
191
-			return 'dir';
192
-		} else {
193
-			$metaData = $this->getDropBoxMetaData($path);
194
-			if ($metaData) {
195
-				if ($metaData['is_dir'] == 'true') {
196
-					return 'dir';
197
-				} else {
198
-					return 'file';
199
-				}
200
-			}
201
-		}
202
-		return false;
203
-	}
189
+    public function filetype($path) {
190
+        if ($path == '' || $path == '/') {
191
+            return 'dir';
192
+        } else {
193
+            $metaData = $this->getDropBoxMetaData($path);
194
+            if ($metaData) {
195
+                if ($metaData['is_dir'] == 'true') {
196
+                    return 'dir';
197
+                } else {
198
+                    return 'file';
199
+                }
200
+            }
201
+        }
202
+        return false;
203
+    }
204 204
 
205
-	public function file_exists($path) {
206
-		if ($path == '' || $path == '/') {
207
-			return true;
208
-		}
209
-		if ($this->getDropBoxMetaData($path)) {
210
-			return true;
211
-		}
212
-		return false;
213
-	}
205
+    public function file_exists($path) {
206
+        if ($path == '' || $path == '/') {
207
+            return true;
208
+        }
209
+        if ($this->getDropBoxMetaData($path)) {
210
+            return true;
211
+        }
212
+        return false;
213
+    }
214 214
 
215
-	public function unlink($path) {
216
-		try {
217
-			$this->dropbox->delete($this->root.$path);
218
-			$this->deleteMetaData($path);
219
-			return true;
220
-		} catch (\Exception $exception) {
221
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
222
-			return false;
223
-		}
224
-	}
215
+    public function unlink($path) {
216
+        try {
217
+            $this->dropbox->delete($this->root.$path);
218
+            $this->deleteMetaData($path);
219
+            return true;
220
+        } catch (\Exception $exception) {
221
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
222
+            return false;
223
+        }
224
+    }
225 225
 
226
-	public function rename($path1, $path2) {
227
-		try {
228
-			// overwrite if target file exists and is not a directory
229
-			$destMetaData = $this->getDropBoxMetaData($path2);
230
-			if (isset($destMetaData) && $destMetaData !== false && !$destMetaData['is_dir']) {
231
-				$this->unlink($path2);
232
-			}
233
-			$this->dropbox->move($this->root.$path1, $this->root.$path2);
234
-			$this->deleteMetaData($path1);
235
-			return true;
236
-		} catch (\Exception $exception) {
237
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
238
-			return false;
239
-		}
240
-	}
226
+    public function rename($path1, $path2) {
227
+        try {
228
+            // overwrite if target file exists and is not a directory
229
+            $destMetaData = $this->getDropBoxMetaData($path2);
230
+            if (isset($destMetaData) && $destMetaData !== false && !$destMetaData['is_dir']) {
231
+                $this->unlink($path2);
232
+            }
233
+            $this->dropbox->move($this->root.$path1, $this->root.$path2);
234
+            $this->deleteMetaData($path1);
235
+            return true;
236
+        } catch (\Exception $exception) {
237
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
238
+            return false;
239
+        }
240
+    }
241 241
 
242
-	public function copy($path1, $path2) {
243
-		$path1 = $this->root.$path1;
244
-		$path2 = $this->root.$path2;
245
-		try {
246
-			$this->dropbox->copy($path1, $path2);
247
-			return true;
248
-		} catch (\Exception $exception) {
249
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
250
-			return false;
251
-		}
252
-	}
242
+    public function copy($path1, $path2) {
243
+        $path1 = $this->root.$path1;
244
+        $path2 = $this->root.$path2;
245
+        try {
246
+            $this->dropbox->copy($path1, $path2);
247
+            return true;
248
+        } catch (\Exception $exception) {
249
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
250
+            return false;
251
+        }
252
+    }
253 253
 
254
-	public function fopen($path, $mode) {
255
-		$path = $this->root.$path;
256
-		switch ($mode) {
257
-			case 'r':
258
-			case 'rb':
259
-				try {
260
-					// slashes need to stay
261
-					$encodedPath = str_replace('%2F', '/', rawurlencode(trim($path, '/')));
262
-					$downloadUrl = 'https://api-content.dropbox.com/1/files/auto/' . $encodedPath;
263
-					$headers = $this->oauth->getOAuthHeader($downloadUrl, [], 'GET');
254
+    public function fopen($path, $mode) {
255
+        $path = $this->root.$path;
256
+        switch ($mode) {
257
+            case 'r':
258
+            case 'rb':
259
+                try {
260
+                    // slashes need to stay
261
+                    $encodedPath = str_replace('%2F', '/', rawurlencode(trim($path, '/')));
262
+                    $downloadUrl = 'https://api-content.dropbox.com/1/files/auto/' . $encodedPath;
263
+                    $headers = $this->oauth->getOAuthHeader($downloadUrl, [], 'GET');
264 264
 
265
-					$client = \OC::$server->getHTTPClientService()->newClient();
266
-					try {
267
-						$response = $client->get($downloadUrl, [
268
-							'headers' => $headers,
269
-							'stream' => true,
270
-						]);
271
-					} catch (RequestException $e) {
272
-						if (!is_null($e->getResponse())) {
273
-							if ($e->getResponse()->getStatusCode() === 404) {
274
-								return false;
275
-							} else {
276
-								throw $e;
277
-							}
278
-						} else {
279
-							throw $e;
280
-						}
281
-					}
265
+                    $client = \OC::$server->getHTTPClientService()->newClient();
266
+                    try {
267
+                        $response = $client->get($downloadUrl, [
268
+                            'headers' => $headers,
269
+                            'stream' => true,
270
+                        ]);
271
+                    } catch (RequestException $e) {
272
+                        if (!is_null($e->getResponse())) {
273
+                            if ($e->getResponse()->getStatusCode() === 404) {
274
+                                return false;
275
+                            } else {
276
+                                throw $e;
277
+                            }
278
+                        } else {
279
+                            throw $e;
280
+                        }
281
+                    }
282 282
 
283
-					$handle = $response->getBody();
284
-					return RetryWrapper::wrap($handle);
285
-				} catch (\Exception $exception) {
286
-					\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
287
-					return false;
288
-				}
289
-			case 'w':
290
-			case 'wb':
291
-			case 'a':
292
-			case 'ab':
293
-			case 'r+':
294
-			case 'w+':
295
-			case 'wb+':
296
-			case 'a+':
297
-			case 'x':
298
-			case 'x+':
299
-			case 'c':
300
-			case 'c+':
301
-				if (strrpos($path, '.') !== false) {
302
-					$ext = substr($path, strrpos($path, '.'));
303
-				} else {
304
-					$ext = '';
305
-				}
306
-				$tmpFile = \OCP\Files::tmpFile($ext);
307
-				if ($this->file_exists($path)) {
308
-					$source = $this->fopen($path, 'r');
309
-					file_put_contents($tmpFile, $source);
310
-				}
311
-			$handle = fopen($tmpFile, $mode);
312
-			return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
313
-				$this->writeBack($tmpFile, $path);
314
-			});
315
-		}
316
-		return false;
317
-	}
283
+                    $handle = $response->getBody();
284
+                    return RetryWrapper::wrap($handle);
285
+                } catch (\Exception $exception) {
286
+                    \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
287
+                    return false;
288
+                }
289
+            case 'w':
290
+            case 'wb':
291
+            case 'a':
292
+            case 'ab':
293
+            case 'r+':
294
+            case 'w+':
295
+            case 'wb+':
296
+            case 'a+':
297
+            case 'x':
298
+            case 'x+':
299
+            case 'c':
300
+            case 'c+':
301
+                if (strrpos($path, '.') !== false) {
302
+                    $ext = substr($path, strrpos($path, '.'));
303
+                } else {
304
+                    $ext = '';
305
+                }
306
+                $tmpFile = \OCP\Files::tmpFile($ext);
307
+                if ($this->file_exists($path)) {
308
+                    $source = $this->fopen($path, 'r');
309
+                    file_put_contents($tmpFile, $source);
310
+                }
311
+            $handle = fopen($tmpFile, $mode);
312
+            return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
313
+                $this->writeBack($tmpFile, $path);
314
+            });
315
+        }
316
+        return false;
317
+    }
318 318
 
319
-	public function writeBack($tmpFile, $path) {
320
-		$handle = fopen($tmpFile, 'r');
321
-		try {
322
-			$this->dropbox->putFile($path, $handle);
323
-			unlink($tmpFile);
324
-			$this->deleteMetaData($path);
325
-		} catch (\Exception $exception) {
326
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
327
-		}
328
-	}
319
+    public function writeBack($tmpFile, $path) {
320
+        $handle = fopen($tmpFile, 'r');
321
+        try {
322
+            $this->dropbox->putFile($path, $handle);
323
+            unlink($tmpFile);
324
+            $this->deleteMetaData($path);
325
+        } catch (\Exception $exception) {
326
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
327
+        }
328
+    }
329 329
 
330
-	public function free_space($path) {
331
-		try {
332
-			$info = $this->dropbox->getAccountInfo();
333
-			return $info['quota_info']['quota'] - $info['quota_info']['normal'];
334
-		} catch (\Exception $exception) {
335
-			\OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
336
-			return false;
337
-		}
338
-	}
330
+    public function free_space($path) {
331
+        try {
332
+            $info = $this->dropbox->getAccountInfo();
333
+            return $info['quota_info']['quota'] - $info['quota_info']['normal'];
334
+        } catch (\Exception $exception) {
335
+            \OCP\Util::writeLog('files_external', $exception->getMessage(), \OCP\Util::ERROR);
336
+            return false;
337
+        }
338
+    }
339 339
 
340
-	public function touch($path, $mtime = null) {
341
-		if ($this->file_exists($path)) {
342
-			return false;
343
-		} else {
344
-			$this->file_put_contents($path, '');
345
-		}
346
-		return true;
347
-	}
340
+    public function touch($path, $mtime = null) {
341
+        if ($this->file_exists($path)) {
342
+            return false;
343
+        } else {
344
+            $this->file_put_contents($path, '');
345
+        }
346
+        return true;
347
+    }
348 348
 
349
-	/**
350
-	 * check if curl is installed
351
-	 */
352
-	public static function checkDependencies() {
353
-		return true;
354
-	}
349
+    /**
350
+     * check if curl is installed
351
+     */
352
+    public static function checkDependencies() {
353
+        return true;
354
+    }
355 355
 
356 356
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -36,7 +36,7 @@  discard block
 block discarded – undo
36 36
 use Icewind\Streams\RetryWrapper;
37 37
 use OCP\Files\StorageNotAvailableException;
38 38
 
39
-require_once __DIR__ . '/../../../3rdparty/Dropbox/autoload.php';
39
+require_once __DIR__.'/../../../3rdparty/Dropbox/autoload.php';
40 40
 
41 41
 class Dropbox extends \OC\Files\Storage\Common {
42 42
 
@@ -54,7 +54,7 @@  discard block
 block discarded – undo
54 54
 			&& isset($params['token_secret'])
55 55
 		) {
56 56
 			$this->root = isset($params['root']) ? $params['root'] : '';
57
-			$this->id = 'dropbox::'.$params['app_key'] . $params['token']. '/' . $this->root;
57
+			$this->id = 'dropbox::'.$params['app_key'].$params['token'].'/'.$this->root;
58 58
 			$this->oauth = new \Dropbox_OAuth_Curl($params['app_key'], $params['app_secret']);
59 59
 			$this->oauth->setToken($params['token'], $params['token_secret']);
60 60
 			// note: Dropbox_API connection is lazy
@@ -89,7 +89,7 @@  discard block
 block discarded – undo
89 89
 	 */
90 90
 	private function getDropBoxMetaData($path, $list = false) {
91 91
 		$path = ltrim($this->root.$path, '/');
92
-		if ( ! $list && isset($this->metaData[$path])) {
92
+		if (!$list && isset($this->metaData[$path])) {
93 93
 			return $this->metaData[$path];
94 94
 		} else {
95 95
 			if ($list) {
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 		}
145 145
 	}
146 146
 
147
-	public function getId(){
147
+	public function getId() {
148 148
 		return $this->id;
149 149
 	}
150 150
 
@@ -259,7 +259,7 @@  discard block
 block discarded – undo
259 259
 				try {
260 260
 					// slashes need to stay
261 261
 					$encodedPath = str_replace('%2F', '/', rawurlencode(trim($path, '/')));
262
-					$downloadUrl = 'https://api-content.dropbox.com/1/files/auto/' . $encodedPath;
262
+					$downloadUrl = 'https://api-content.dropbox.com/1/files/auto/'.$encodedPath;
263 263
 					$headers = $this->oauth->getOAuthHeader($downloadUrl, [], 'GET');
264 264
 
265 265
 					$client = \OC::$server->getHTTPClientService()->newClient();
@@ -309,7 +309,7 @@  discard block
 block discarded – undo
309 309
 					file_put_contents($tmpFile, $source);
310 310
 				}
311 311
 			$handle = fopen($tmpFile, $mode);
312
-			return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
312
+			return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
313 313
 				$this->writeBack($tmpFile, $path);
314 314
 			});
315 315
 		}
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/Google.php 3 patches
Doc Comments   +4 added lines, -1 removed lines patch added patch discarded remove patch
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 	 *
217 217
 	 * @param \Google_Service_Drive_DriveFile
218 218
 	 *
219
-	 * @return true if the file is a Google Doc file, false otherwise
219
+	 * @return boolean if the file is a Google Doc file, false otherwise
220 220
 	 */
221 221
 	private function isGoogleDocFile($file) {
222 222
 		return $this->getGoogleDocExtension($file->getMimeType()) !== '';
@@ -505,6 +505,9 @@  discard block
 block discarded – undo
505 505
 		}
506 506
 	}
507 507
 
508
+	/**
509
+	 * @param string $path
510
+	 */
508 511
 	public function writeBack($tmpFile, $path) {
509 512
 		$parentFolder = $this->getDriveFile(dirname($path));
510 513
 		if ($parentFolder) {
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
 				if (isset($this->driveFiles[$path])) {
124 124
 					$parentId = $this->driveFiles[$path]->getId();
125 125
 				} else {
126
-					$q = "title='" . str_replace("'","\\'", $name) . "' and '" . str_replace("'","\\'", $parentId) . "' in parents and trashed = false";
126
+					$q = "title='".str_replace("'", "\\'", $name)."' and '".str_replace("'", "\\'", $parentId)."' in parents and trashed = false";
127 127
 					$result = $this->service->files->listFiles(array('q' => $q))->getItems();
128 128
 					if (!empty($result)) {
129 129
 						// Google Drive allows files with the same name, Nextcloud doesn't
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
 				if ($result) {
237 237
 					$this->setDriveFile($path, $result);
238 238
 				}
239
-				return (bool)$result;
239
+				return (bool) $result;
240 240
 			}
241 241
 		}
242 242
 		return false;
@@ -248,7 +248,7 @@  discard block
 block discarded – undo
248 248
 		}
249 249
 		if (trim($path, '/') === '') {
250 250
 			$dir = $this->opendir($path);
251
-			if(is_resource($dir)) {
251
+			if (is_resource($dir)) {
252 252
 				while (($file = readdir($dir)) !== false) {
253 253
 					if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
254 254
 						if (!$this->unlink($path.'/'.$file)) {
@@ -276,7 +276,7 @@  discard block
 block discarded – undo
276 276
 				if ($pageToken !== true) {
277 277
 					$params['pageToken'] = $pageToken;
278 278
 				}
279
-				$params['q'] = "'" . str_replace("'","\\'", $folder->getId()) . "' in parents and trashed = false";
279
+				$params['q'] = "'".str_replace("'", "\\'", $folder->getId())."' in parents and trashed = false";
280 280
 				$children = $this->service->files->listFiles($params);
281 281
 				foreach ($children->getItems() as $child) {
282 282
 					$name = $child->getTitle();
@@ -369,7 +369,7 @@  discard block
 block discarded – undo
369 369
 	}
370 370
 
371 371
 	public function file_exists($path) {
372
-		return (bool)$this->getDriveFile($path);
372
+		return (bool) $this->getDriveFile($path);
373 373
 	}
374 374
 
375 375
 	public function unlink($path) {
@@ -379,7 +379,7 @@  discard block
 block discarded – undo
379 379
 			if ($result) {
380 380
 				$this->setDriveFile($path, false);
381 381
 			}
382
-			return (bool)$result;
382
+			return (bool) $result;
383 383
 		} else {
384 384
 			return false;
385 385
 		}
@@ -427,7 +427,7 @@  discard block
 block discarded – undo
427 427
 					}
428 428
 				}
429 429
 			}
430
-			return (bool)$result;
430
+			return (bool) $result;
431 431
 		} else {
432 432
 			return false;
433 433
 		}
@@ -462,10 +462,10 @@  discard block
 block discarded – undo
462 462
 							$response = $client->get($downloadUrl, [
463 463
 								'headers' => $httpRequest->getRequestHeaders(),
464 464
 								'stream' => true,
465
-								'verify' => realpath(__DIR__ . '/../../../3rdparty/google-api-php-client/src/Google/IO/cacerts.pem'),
465
+								'verify' => realpath(__DIR__.'/../../../3rdparty/google-api-php-client/src/Google/IO/cacerts.pem'),
466 466
 							]);
467 467
 						} catch (RequestException $e) {
468
-							if(!is_null($e->getResponse())) {
468
+							if (!is_null($e->getResponse())) {
469 469
 								if ($e->getResponse()->getStatusCode() === 404) {
470 470
 									return false;
471 471
 								} else {
@@ -499,7 +499,7 @@  discard block
 block discarded – undo
499 499
 					file_put_contents($tmpFile, $source);
500 500
 				}
501 501
 				$handle = fopen($tmpFile, $mode);
502
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
502
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
503 503
 					$this->writeBack($tmpFile, $path);
504 504
 				});
505 505
 		}
@@ -641,7 +641,7 @@  discard block
 block discarded – undo
641 641
 		if ($result) {
642 642
 			$this->setDriveFile($path, $result);
643 643
 		}
644
-		return (bool)$result;
644
+		return (bool) $result;
645 645
 	}
646 646
 
647 647
 	public function test() {
@@ -668,7 +668,7 @@  discard block
 block discarded – undo
668 668
 					'includeSubscribed' => true,
669 669
 				);
670 670
 				if (isset($startChangeId)) {
671
-					$startChangeId = (int)$startChangeId;
671
+					$startChangeId = (int) $startChangeId;
672 672
 					$largestChangeId = $startChangeId;
673 673
 					$params['startChangeId'] = $startChangeId + 1;
674 674
 				} else {
Please login to merge, or discard this patch.
Indentation   +676 added lines, -676 removed lines patch added patch discarded remove patch
@@ -41,352 +41,352 @@  discard block
 block discarded – undo
41 41
 use Icewind\Streams\RetryWrapper;
42 42
 
43 43
 set_include_path(get_include_path().PATH_SEPARATOR.
44
-	\OC_App::getAppPath('files_external').'/3rdparty/google-api-php-client/src');
44
+    \OC_App::getAppPath('files_external').'/3rdparty/google-api-php-client/src');
45 45
 require_once 'Google/autoload.php';
46 46
 
47 47
 class Google extends \OC\Files\Storage\Common {
48 48
 
49
-	private $client;
50
-	private $id;
51
-	private $service;
52
-	private $driveFiles;
53
-
54
-	// Google Doc mimetypes
55
-	const FOLDER = 'application/vnd.google-apps.folder';
56
-	const DOCUMENT = 'application/vnd.google-apps.document';
57
-	const SPREADSHEET = 'application/vnd.google-apps.spreadsheet';
58
-	const DRAWING = 'application/vnd.google-apps.drawing';
59
-	const PRESENTATION = 'application/vnd.google-apps.presentation';
60
-	const MAP = 'application/vnd.google-apps.map';
61
-
62
-	public function __construct($params) {
63
-		if (isset($params['configured']) && $params['configured'] === 'true'
64
-			&& isset($params['client_id']) && isset($params['client_secret'])
65
-			&& isset($params['token'])
66
-		) {
67
-			$this->client = new \Google_Client();
68
-			$this->client->setClientId($params['client_id']);
69
-			$this->client->setClientSecret($params['client_secret']);
70
-			$this->client->setScopes(array('https://www.googleapis.com/auth/drive'));
71
-			$this->client->setAccessToken($params['token']);
72
-			// if curl isn't available we're likely to run into
73
-			// https://github.com/google/google-api-php-client/issues/59
74
-			// - disable gzip to avoid it.
75
-			if (!function_exists('curl_version') || !function_exists('curl_exec')) {
76
-				$this->client->setClassConfig("Google_Http_Request", "disable_gzip", true);
77
-			}
78
-			// note: API connection is lazy
79
-			$this->service = new \Google_Service_Drive($this->client);
80
-			$token = json_decode($params['token'], true);
81
-			$this->id = 'google::'.substr($params['client_id'], 0, 30).$token['created'];
82
-		} else {
83
-			throw new \Exception('Creating Google storage failed');
84
-		}
85
-	}
86
-
87
-	public function getId() {
88
-		return $this->id;
89
-	}
90
-
91
-	/**
92
-	 * Get the Google_Service_Drive_DriveFile object for the specified path.
93
-	 * Returns false on failure.
94
-	 * @param string $path
95
-	 * @return \Google_Service_Drive_DriveFile|false
96
-	 */
97
-	private function getDriveFile($path) {
98
-		// Remove leading and trailing slashes
99
-		$path = trim($path, '/');
100
-		if ($path === '.') {
101
-			$path = '';
102
-		}
103
-		if (isset($this->driveFiles[$path])) {
104
-			return $this->driveFiles[$path];
105
-		} else if ($path === '') {
106
-			$root = $this->service->files->get('root');
107
-			$this->driveFiles[$path] = $root;
108
-			return $root;
109
-		} else {
110
-			// Google Drive SDK does not have methods for retrieving files by path
111
-			// Instead we must find the id of the parent folder of the file
112
-			$parentId = $this->getDriveFile('')->getId();
113
-			$folderNames = explode('/', $path);
114
-			$path = '';
115
-			// Loop through each folder of this path to get to the file
116
-			foreach ($folderNames as $name) {
117
-				// Reconstruct path from beginning
118
-				if ($path === '') {
119
-					$path .= $name;
120
-				} else {
121
-					$path .= '/'.$name;
122
-				}
123
-				if (isset($this->driveFiles[$path])) {
124
-					$parentId = $this->driveFiles[$path]->getId();
125
-				} else {
126
-					$q = "title='" . str_replace("'","\\'", $name) . "' and '" . str_replace("'","\\'", $parentId) . "' in parents and trashed = false";
127
-					$result = $this->service->files->listFiles(array('q' => $q))->getItems();
128
-					if (!empty($result)) {
129
-						// Google Drive allows files with the same name, Nextcloud doesn't
130
-						if (count($result) > 1) {
131
-							$this->onDuplicateFileDetected($path);
132
-							return false;
133
-						} else {
134
-							$file = current($result);
135
-							$this->driveFiles[$path] = $file;
136
-							$parentId = $file->getId();
137
-						}
138
-					} else {
139
-						// Google Docs have no extension in their title, so try without extension
140
-						$pos = strrpos($path, '.');
141
-						if ($pos !== false) {
142
-							$pathWithoutExt = substr($path, 0, $pos);
143
-							$file = $this->getDriveFile($pathWithoutExt);
144
-							if ($file && $this->isGoogleDocFile($file)) {
145
-								// Switch cached Google_Service_Drive_DriveFile to the correct index
146
-								unset($this->driveFiles[$pathWithoutExt]);
147
-								$this->driveFiles[$path] = $file;
148
-								$parentId = $file->getId();
149
-							} else {
150
-								return false;
151
-							}
152
-						} else {
153
-							return false;
154
-						}
155
-					}
156
-				}
157
-			}
158
-			return $this->driveFiles[$path];
159
-		}
160
-	}
161
-
162
-	/**
163
-	 * Set the Google_Service_Drive_DriveFile object in the cache
164
-	 * @param string $path
165
-	 * @param \Google_Service_Drive_DriveFile|false $file
166
-	 */
167
-	private function setDriveFile($path, $file) {
168
-		$path = trim($path, '/');
169
-		$this->driveFiles[$path] = $file;
170
-		if ($file === false) {
171
-			// Remove all children
172
-			$len = strlen($path);
173
-			foreach ($this->driveFiles as $key => $file) {
174
-				if (substr($key, 0, $len) === $path) {
175
-					unset($this->driveFiles[$key]);
176
-				}
177
-			}
178
-		}
179
-	}
180
-
181
-	/**
182
-	 * Write a log message to inform about duplicate file names
183
-	 * @param string $path
184
-	 */
185
-	private function onDuplicateFileDetected($path) {
186
-		$about = $this->service->about->get();
187
-		$user = $about->getName();
188
-		\OCP\Util::writeLog('files_external',
189
-			'Ignoring duplicate file name: '.$path.' on Google Drive for Google user: '.$user,
190
-			\OCP\Util::INFO
191
-		);
192
-	}
193
-
194
-	/**
195
-	 * Generate file extension for a Google Doc, choosing Open Document formats for download
196
-	 * @param string $mimetype
197
-	 * @return string
198
-	 */
199
-	private function getGoogleDocExtension($mimetype) {
200
-		if ($mimetype === self::DOCUMENT) {
201
-			return 'odt';
202
-		} else if ($mimetype === self::SPREADSHEET) {
203
-			return 'ods';
204
-		} else if ($mimetype === self::DRAWING) {
205
-			return 'jpg';
206
-		} else if ($mimetype === self::PRESENTATION) {
207
-			// Download as .odp is not available
208
-			return 'pdf';
209
-		} else {
210
-			return '';
211
-		}
212
-	}
213
-
214
-	/**
215
-	 * Returns whether the given drive file is a Google Doc file
216
-	 *
217
-	 * @param \Google_Service_Drive_DriveFile
218
-	 *
219
-	 * @return true if the file is a Google Doc file, false otherwise
220
-	 */
221
-	private function isGoogleDocFile($file) {
222
-		return $this->getGoogleDocExtension($file->getMimeType()) !== '';
223
-	}
224
-
225
-	public function mkdir($path) {
226
-		if (!$this->is_dir($path)) {
227
-			$parentFolder = $this->getDriveFile(dirname($path));
228
-			if ($parentFolder) {
229
-				$folder = new \Google_Service_Drive_DriveFile();
230
-				$folder->setTitle(basename($path));
231
-				$folder->setMimeType(self::FOLDER);
232
-				$parent = new \Google_Service_Drive_ParentReference();
233
-				$parent->setId($parentFolder->getId());
234
-				$folder->setParents(array($parent));
235
-				$result = $this->service->files->insert($folder);
236
-				if ($result) {
237
-					$this->setDriveFile($path, $result);
238
-				}
239
-				return (bool)$result;
240
-			}
241
-		}
242
-		return false;
243
-	}
244
-
245
-	public function rmdir($path) {
246
-		if (!$this->isDeletable($path)) {
247
-			return false;
248
-		}
249
-		if (trim($path, '/') === '') {
250
-			$dir = $this->opendir($path);
251
-			if(is_resource($dir)) {
252
-				while (($file = readdir($dir)) !== false) {
253
-					if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
254
-						if (!$this->unlink($path.'/'.$file)) {
255
-							return false;
256
-						}
257
-					}
258
-				}
259
-				closedir($dir);
260
-			}
261
-			$this->driveFiles = array();
262
-			return true;
263
-		} else {
264
-			return $this->unlink($path);
265
-		}
266
-	}
267
-
268
-	public function opendir($path) {
269
-		$folder = $this->getDriveFile($path);
270
-		if ($folder) {
271
-			$files = array();
272
-			$duplicates = array();
273
-			$pageToken = true;
274
-			while ($pageToken) {
275
-				$params = array();
276
-				if ($pageToken !== true) {
277
-					$params['pageToken'] = $pageToken;
278
-				}
279
-				$params['q'] = "'" . str_replace("'","\\'", $folder->getId()) . "' in parents and trashed = false";
280
-				$children = $this->service->files->listFiles($params);
281
-				foreach ($children->getItems() as $child) {
282
-					$name = $child->getTitle();
283
-					// Check if this is a Google Doc i.e. no extension in name
284
-					$extension = $child->getFileExtension();
285
-					if (empty($extension)) {
286
-						if ($child->getMimeType() === self::MAP) {
287
-							continue; // No method known to transfer map files, ignore it
288
-						} else if ($child->getMimeType() !== self::FOLDER) {
289
-							$name .= '.'.$this->getGoogleDocExtension($child->getMimeType());
290
-						}
291
-					}
292
-					if ($path === '') {
293
-						$filepath = $name;
294
-					} else {
295
-						$filepath = $path.'/'.$name;
296
-					}
297
-					// Google Drive allows files with the same name, Nextcloud doesn't
298
-					// Prevent opendir() from returning any duplicate files
299
-					$key = array_search($name, $files);
300
-					if ($key !== false || isset($duplicates[$filepath])) {
301
-						if (!isset($duplicates[$filepath])) {
302
-							$duplicates[$filepath] = true;
303
-							$this->setDriveFile($filepath, false);
304
-							unset($files[$key]);
305
-							$this->onDuplicateFileDetected($filepath);
306
-						}
307
-					} else {
308
-						// Cache the Google_Service_Drive_DriveFile for future use
309
-						$this->setDriveFile($filepath, $child);
310
-						$files[] = $name;
311
-					}
312
-				}
313
-				$pageToken = $children->getNextPageToken();
314
-			}
315
-			return IteratorDirectory::wrap($files);
316
-		} else {
317
-			return false;
318
-		}
319
-	}
320
-
321
-	public function stat($path) {
322
-		$file = $this->getDriveFile($path);
323
-		if ($file) {
324
-			$stat = array();
325
-			if ($this->filetype($path) === 'dir') {
326
-				$stat['size'] = 0;
327
-			} else {
328
-				// Check if this is a Google Doc
329
-				if ($this->isGoogleDocFile($file)) {
330
-					// Return unknown file size
331
-					$stat['size'] = \OCP\Files\FileInfo::SPACE_UNKNOWN;
332
-				} else {
333
-					$stat['size'] = $file->getFileSize();
334
-				}
335
-			}
336
-			$stat['atime'] = strtotime($file->getLastViewedByMeDate());
337
-			$stat['mtime'] = strtotime($file->getModifiedDate());
338
-			$stat['ctime'] = strtotime($file->getCreatedDate());
339
-			return $stat;
340
-		} else {
341
-			return false;
342
-		}
343
-	}
344
-
345
-	public function filetype($path) {
346
-		if ($path === '') {
347
-			return 'dir';
348
-		} else {
349
-			$file = $this->getDriveFile($path);
350
-			if ($file) {
351
-				if ($file->getMimeType() === self::FOLDER) {
352
-					return 'dir';
353
-				} else {
354
-					return 'file';
355
-				}
356
-			} else {
357
-				return false;
358
-			}
359
-		}
360
-	}
361
-
362
-	public function isUpdatable($path) {
363
-		$file = $this->getDriveFile($path);
364
-		if ($file) {
365
-			return $file->getEditable();
366
-		} else {
367
-			return false;
368
-		}
369
-	}
370
-
371
-	public function file_exists($path) {
372
-		return (bool)$this->getDriveFile($path);
373
-	}
374
-
375
-	public function unlink($path) {
376
-		$file = $this->getDriveFile($path);
377
-		if ($file) {
378
-			$result = $this->service->files->trash($file->getId());
379
-			if ($result) {
380
-				$this->setDriveFile($path, false);
381
-			}
382
-			return (bool)$result;
383
-		} else {
384
-			return false;
385
-		}
386
-	}
387
-
388
-	public function rename($path1, $path2) {
389
-		// Avoid duplicate files with the same name
49
+    private $client;
50
+    private $id;
51
+    private $service;
52
+    private $driveFiles;
53
+
54
+    // Google Doc mimetypes
55
+    const FOLDER = 'application/vnd.google-apps.folder';
56
+    const DOCUMENT = 'application/vnd.google-apps.document';
57
+    const SPREADSHEET = 'application/vnd.google-apps.spreadsheet';
58
+    const DRAWING = 'application/vnd.google-apps.drawing';
59
+    const PRESENTATION = 'application/vnd.google-apps.presentation';
60
+    const MAP = 'application/vnd.google-apps.map';
61
+
62
+    public function __construct($params) {
63
+        if (isset($params['configured']) && $params['configured'] === 'true'
64
+            && isset($params['client_id']) && isset($params['client_secret'])
65
+            && isset($params['token'])
66
+        ) {
67
+            $this->client = new \Google_Client();
68
+            $this->client->setClientId($params['client_id']);
69
+            $this->client->setClientSecret($params['client_secret']);
70
+            $this->client->setScopes(array('https://www.googleapis.com/auth/drive'));
71
+            $this->client->setAccessToken($params['token']);
72
+            // if curl isn't available we're likely to run into
73
+            // https://github.com/google/google-api-php-client/issues/59
74
+            // - disable gzip to avoid it.
75
+            if (!function_exists('curl_version') || !function_exists('curl_exec')) {
76
+                $this->client->setClassConfig("Google_Http_Request", "disable_gzip", true);
77
+            }
78
+            // note: API connection is lazy
79
+            $this->service = new \Google_Service_Drive($this->client);
80
+            $token = json_decode($params['token'], true);
81
+            $this->id = 'google::'.substr($params['client_id'], 0, 30).$token['created'];
82
+        } else {
83
+            throw new \Exception('Creating Google storage failed');
84
+        }
85
+    }
86
+
87
+    public function getId() {
88
+        return $this->id;
89
+    }
90
+
91
+    /**
92
+     * Get the Google_Service_Drive_DriveFile object for the specified path.
93
+     * Returns false on failure.
94
+     * @param string $path
95
+     * @return \Google_Service_Drive_DriveFile|false
96
+     */
97
+    private function getDriveFile($path) {
98
+        // Remove leading and trailing slashes
99
+        $path = trim($path, '/');
100
+        if ($path === '.') {
101
+            $path = '';
102
+        }
103
+        if (isset($this->driveFiles[$path])) {
104
+            return $this->driveFiles[$path];
105
+        } else if ($path === '') {
106
+            $root = $this->service->files->get('root');
107
+            $this->driveFiles[$path] = $root;
108
+            return $root;
109
+        } else {
110
+            // Google Drive SDK does not have methods for retrieving files by path
111
+            // Instead we must find the id of the parent folder of the file
112
+            $parentId = $this->getDriveFile('')->getId();
113
+            $folderNames = explode('/', $path);
114
+            $path = '';
115
+            // Loop through each folder of this path to get to the file
116
+            foreach ($folderNames as $name) {
117
+                // Reconstruct path from beginning
118
+                if ($path === '') {
119
+                    $path .= $name;
120
+                } else {
121
+                    $path .= '/'.$name;
122
+                }
123
+                if (isset($this->driveFiles[$path])) {
124
+                    $parentId = $this->driveFiles[$path]->getId();
125
+                } else {
126
+                    $q = "title='" . str_replace("'","\\'", $name) . "' and '" . str_replace("'","\\'", $parentId) . "' in parents and trashed = false";
127
+                    $result = $this->service->files->listFiles(array('q' => $q))->getItems();
128
+                    if (!empty($result)) {
129
+                        // Google Drive allows files with the same name, Nextcloud doesn't
130
+                        if (count($result) > 1) {
131
+                            $this->onDuplicateFileDetected($path);
132
+                            return false;
133
+                        } else {
134
+                            $file = current($result);
135
+                            $this->driveFiles[$path] = $file;
136
+                            $parentId = $file->getId();
137
+                        }
138
+                    } else {
139
+                        // Google Docs have no extension in their title, so try without extension
140
+                        $pos = strrpos($path, '.');
141
+                        if ($pos !== false) {
142
+                            $pathWithoutExt = substr($path, 0, $pos);
143
+                            $file = $this->getDriveFile($pathWithoutExt);
144
+                            if ($file && $this->isGoogleDocFile($file)) {
145
+                                // Switch cached Google_Service_Drive_DriveFile to the correct index
146
+                                unset($this->driveFiles[$pathWithoutExt]);
147
+                                $this->driveFiles[$path] = $file;
148
+                                $parentId = $file->getId();
149
+                            } else {
150
+                                return false;
151
+                            }
152
+                        } else {
153
+                            return false;
154
+                        }
155
+                    }
156
+                }
157
+            }
158
+            return $this->driveFiles[$path];
159
+        }
160
+    }
161
+
162
+    /**
163
+     * Set the Google_Service_Drive_DriveFile object in the cache
164
+     * @param string $path
165
+     * @param \Google_Service_Drive_DriveFile|false $file
166
+     */
167
+    private function setDriveFile($path, $file) {
168
+        $path = trim($path, '/');
169
+        $this->driveFiles[$path] = $file;
170
+        if ($file === false) {
171
+            // Remove all children
172
+            $len = strlen($path);
173
+            foreach ($this->driveFiles as $key => $file) {
174
+                if (substr($key, 0, $len) === $path) {
175
+                    unset($this->driveFiles[$key]);
176
+                }
177
+            }
178
+        }
179
+    }
180
+
181
+    /**
182
+     * Write a log message to inform about duplicate file names
183
+     * @param string $path
184
+     */
185
+    private function onDuplicateFileDetected($path) {
186
+        $about = $this->service->about->get();
187
+        $user = $about->getName();
188
+        \OCP\Util::writeLog('files_external',
189
+            'Ignoring duplicate file name: '.$path.' on Google Drive for Google user: '.$user,
190
+            \OCP\Util::INFO
191
+        );
192
+    }
193
+
194
+    /**
195
+     * Generate file extension for a Google Doc, choosing Open Document formats for download
196
+     * @param string $mimetype
197
+     * @return string
198
+     */
199
+    private function getGoogleDocExtension($mimetype) {
200
+        if ($mimetype === self::DOCUMENT) {
201
+            return 'odt';
202
+        } else if ($mimetype === self::SPREADSHEET) {
203
+            return 'ods';
204
+        } else if ($mimetype === self::DRAWING) {
205
+            return 'jpg';
206
+        } else if ($mimetype === self::PRESENTATION) {
207
+            // Download as .odp is not available
208
+            return 'pdf';
209
+        } else {
210
+            return '';
211
+        }
212
+    }
213
+
214
+    /**
215
+     * Returns whether the given drive file is a Google Doc file
216
+     *
217
+     * @param \Google_Service_Drive_DriveFile
218
+     *
219
+     * @return true if the file is a Google Doc file, false otherwise
220
+     */
221
+    private function isGoogleDocFile($file) {
222
+        return $this->getGoogleDocExtension($file->getMimeType()) !== '';
223
+    }
224
+
225
+    public function mkdir($path) {
226
+        if (!$this->is_dir($path)) {
227
+            $parentFolder = $this->getDriveFile(dirname($path));
228
+            if ($parentFolder) {
229
+                $folder = new \Google_Service_Drive_DriveFile();
230
+                $folder->setTitle(basename($path));
231
+                $folder->setMimeType(self::FOLDER);
232
+                $parent = new \Google_Service_Drive_ParentReference();
233
+                $parent->setId($parentFolder->getId());
234
+                $folder->setParents(array($parent));
235
+                $result = $this->service->files->insert($folder);
236
+                if ($result) {
237
+                    $this->setDriveFile($path, $result);
238
+                }
239
+                return (bool)$result;
240
+            }
241
+        }
242
+        return false;
243
+    }
244
+
245
+    public function rmdir($path) {
246
+        if (!$this->isDeletable($path)) {
247
+            return false;
248
+        }
249
+        if (trim($path, '/') === '') {
250
+            $dir = $this->opendir($path);
251
+            if(is_resource($dir)) {
252
+                while (($file = readdir($dir)) !== false) {
253
+                    if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
254
+                        if (!$this->unlink($path.'/'.$file)) {
255
+                            return false;
256
+                        }
257
+                    }
258
+                }
259
+                closedir($dir);
260
+            }
261
+            $this->driveFiles = array();
262
+            return true;
263
+        } else {
264
+            return $this->unlink($path);
265
+        }
266
+    }
267
+
268
+    public function opendir($path) {
269
+        $folder = $this->getDriveFile($path);
270
+        if ($folder) {
271
+            $files = array();
272
+            $duplicates = array();
273
+            $pageToken = true;
274
+            while ($pageToken) {
275
+                $params = array();
276
+                if ($pageToken !== true) {
277
+                    $params['pageToken'] = $pageToken;
278
+                }
279
+                $params['q'] = "'" . str_replace("'","\\'", $folder->getId()) . "' in parents and trashed = false";
280
+                $children = $this->service->files->listFiles($params);
281
+                foreach ($children->getItems() as $child) {
282
+                    $name = $child->getTitle();
283
+                    // Check if this is a Google Doc i.e. no extension in name
284
+                    $extension = $child->getFileExtension();
285
+                    if (empty($extension)) {
286
+                        if ($child->getMimeType() === self::MAP) {
287
+                            continue; // No method known to transfer map files, ignore it
288
+                        } else if ($child->getMimeType() !== self::FOLDER) {
289
+                            $name .= '.'.$this->getGoogleDocExtension($child->getMimeType());
290
+                        }
291
+                    }
292
+                    if ($path === '') {
293
+                        $filepath = $name;
294
+                    } else {
295
+                        $filepath = $path.'/'.$name;
296
+                    }
297
+                    // Google Drive allows files with the same name, Nextcloud doesn't
298
+                    // Prevent opendir() from returning any duplicate files
299
+                    $key = array_search($name, $files);
300
+                    if ($key !== false || isset($duplicates[$filepath])) {
301
+                        if (!isset($duplicates[$filepath])) {
302
+                            $duplicates[$filepath] = true;
303
+                            $this->setDriveFile($filepath, false);
304
+                            unset($files[$key]);
305
+                            $this->onDuplicateFileDetected($filepath);
306
+                        }
307
+                    } else {
308
+                        // Cache the Google_Service_Drive_DriveFile for future use
309
+                        $this->setDriveFile($filepath, $child);
310
+                        $files[] = $name;
311
+                    }
312
+                }
313
+                $pageToken = $children->getNextPageToken();
314
+            }
315
+            return IteratorDirectory::wrap($files);
316
+        } else {
317
+            return false;
318
+        }
319
+    }
320
+
321
+    public function stat($path) {
322
+        $file = $this->getDriveFile($path);
323
+        if ($file) {
324
+            $stat = array();
325
+            if ($this->filetype($path) === 'dir') {
326
+                $stat['size'] = 0;
327
+            } else {
328
+                // Check if this is a Google Doc
329
+                if ($this->isGoogleDocFile($file)) {
330
+                    // Return unknown file size
331
+                    $stat['size'] = \OCP\Files\FileInfo::SPACE_UNKNOWN;
332
+                } else {
333
+                    $stat['size'] = $file->getFileSize();
334
+                }
335
+            }
336
+            $stat['atime'] = strtotime($file->getLastViewedByMeDate());
337
+            $stat['mtime'] = strtotime($file->getModifiedDate());
338
+            $stat['ctime'] = strtotime($file->getCreatedDate());
339
+            return $stat;
340
+        } else {
341
+            return false;
342
+        }
343
+    }
344
+
345
+    public function filetype($path) {
346
+        if ($path === '') {
347
+            return 'dir';
348
+        } else {
349
+            $file = $this->getDriveFile($path);
350
+            if ($file) {
351
+                if ($file->getMimeType() === self::FOLDER) {
352
+                    return 'dir';
353
+                } else {
354
+                    return 'file';
355
+                }
356
+            } else {
357
+                return false;
358
+            }
359
+        }
360
+    }
361
+
362
+    public function isUpdatable($path) {
363
+        $file = $this->getDriveFile($path);
364
+        if ($file) {
365
+            return $file->getEditable();
366
+        } else {
367
+            return false;
368
+        }
369
+    }
370
+
371
+    public function file_exists($path) {
372
+        return (bool)$this->getDriveFile($path);
373
+    }
374
+
375
+    public function unlink($path) {
376
+        $file = $this->getDriveFile($path);
377
+        if ($file) {
378
+            $result = $this->service->files->trash($file->getId());
379
+            if ($result) {
380
+                $this->setDriveFile($path, false);
381
+            }
382
+            return (bool)$result;
383
+        } else {
384
+            return false;
385
+        }
386
+    }
387
+
388
+    public function rename($path1, $path2) {
389
+        // Avoid duplicate files with the same name
390 390
                 $testRegex = '/^.+\.ocTransferId\d+\.part$/';
391 391
                 if (preg_match($testRegex, $path1)) {
392 392
                         if ($this->is_file($path2)) {
@@ -399,339 +399,339 @@  discard block
 block discarded – undo
399 399
                         }
400 400
                 }
401 401
 		
402
-		$file = $this->getDriveFile($path1);
403
-		if ($file) {
404
-			$newFile = $this->getDriveFile($path2);
405
-			if (dirname($path1) === dirname($path2)) {
406
-				if ($newFile) {
407
-					// rename to the name of the target file, could be an office file without extension
408
-					$file->setTitle($newFile->getTitle());
409
-				} else {
410
-					$file->setTitle(basename(($path2)));
411
-				}
412
-			} else {
413
-				// Change file parent
414
-				$parentFolder2 = $this->getDriveFile(dirname($path2));
415
-				if ($parentFolder2) {
416
-					$parent = new \Google_Service_Drive_ParentReference();
417
-					$parent->setId($parentFolder2->getId());
418
-					$file->setParents(array($parent));
419
-				} else {
420
-					return false;
421
-				}
422
-			}
423
-			// We need to get the object for the existing file with the same
424
-			// name (if there is one) before we do the patch. If oldfile
425
-			// exists and is a directory we have to delete it before we
426
-			// do the rename too.
427
-			$oldfile = $this->getDriveFile($path2);
428
-			if ($oldfile && $this->is_dir($path2)) {
429
-				$this->rmdir($path2);
430
-				$oldfile = false;
431
-			}
432
-			$result = $this->service->files->patch($file->getId(), $file);
433
-			if ($result) {
434
-				$this->setDriveFile($path1, false);
435
-				$this->setDriveFile($path2, $result);
436
-				if ($oldfile && $newFile) {
437
-					// only delete if they have a different id (same id can happen for part files)
438
-					if ($newFile->getId() !== $oldfile->getId()) {
439
-						$this->service->files->delete($oldfile->getId());
440
-					}
441
-				}
442
-			}
443
-			return (bool)$result;
444
-		} else {
445
-			return false;
446
-		}
447
-	}
448
-
449
-	public function fopen($path, $mode) {
450
-		$pos = strrpos($path, '.');
451
-		if ($pos !== false) {
452
-			$ext = substr($path, $pos);
453
-		} else {
454
-			$ext = '';
455
-		}
456
-		switch ($mode) {
457
-			case 'r':
458
-			case 'rb':
459
-				$file = $this->getDriveFile($path);
460
-				if ($file) {
461
-					$exportLinks = $file->getExportLinks();
462
-					$mimetype = $this->getMimeType($path);
463
-					$downloadUrl = null;
464
-					if ($exportLinks && isset($exportLinks[$mimetype])) {
465
-						$downloadUrl = $exportLinks[$mimetype];
466
-					} else {
467
-						$downloadUrl = $file->getDownloadUrl();
468
-					}
469
-					if (isset($downloadUrl)) {
470
-						$request = new \Google_Http_Request($downloadUrl, 'GET', null, null);
471
-						$httpRequest = $this->client->getAuth()->sign($request);
472
-						// the library's service doesn't support streaming, so we use Guzzle instead
473
-						$client = \OC::$server->getHTTPClientService()->newClient();
474
-						try {
475
-							$response = $client->get($downloadUrl, [
476
-								'headers' => $httpRequest->getRequestHeaders(),
477
-								'stream' => true,
478
-								'verify' => realpath(__DIR__ . '/../../../3rdparty/google-api-php-client/src/Google/IO/cacerts.pem'),
479
-							]);
480
-						} catch (RequestException $e) {
481
-							if(!is_null($e->getResponse())) {
482
-								if ($e->getResponse()->getStatusCode() === 404) {
483
-									return false;
484
-								} else {
485
-									throw $e;
486
-								}
487
-							} else {
488
-								throw $e;
489
-							}
490
-						}
491
-
492
-						$handle = $response->getBody();
493
-						return RetryWrapper::wrap($handle);
494
-					}
495
-				}
496
-				return false;
497
-			case 'w':
498
-			case 'wb':
499
-			case 'a':
500
-			case 'ab':
501
-			case 'r+':
502
-			case 'w+':
503
-			case 'wb+':
504
-			case 'a+':
505
-			case 'x':
506
-			case 'x+':
507
-			case 'c':
508
-			case 'c+':
509
-				$tmpFile = \OCP\Files::tmpFile($ext);
510
-				if ($this->file_exists($path)) {
511
-					$source = $this->fopen($path, 'rb');
512
-					file_put_contents($tmpFile, $source);
513
-				}
514
-				$handle = fopen($tmpFile, $mode);
515
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
516
-					$this->writeBack($tmpFile, $path);
517
-				});
518
-		}
519
-	}
520
-
521
-	public function writeBack($tmpFile, $path) {
522
-		$parentFolder = $this->getDriveFile(dirname($path));
523
-		if ($parentFolder) {
524
-			$mimetype = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
525
-			$params = array(
526
-				'mimeType' => $mimetype,
527
-				'uploadType' => 'media'
528
-			);
529
-			$result = false;
530
-
531
-			$chunkSizeBytes = 10 * 1024 * 1024;
532
-
533
-			$useChunking = false;
534
-			$size = filesize($tmpFile);
535
-			if ($size > $chunkSizeBytes) {
536
-				$useChunking = true;
537
-			} else {
538
-				$params['data'] = file_get_contents($tmpFile);
539
-			}
540
-
541
-			if ($this->file_exists($path)) {
542
-				$file = $this->getDriveFile($path);
543
-				$this->client->setDefer($useChunking);
544
-				$request = $this->service->files->update($file->getId(), $file, $params);
545
-			} else {
546
-				$file = new \Google_Service_Drive_DriveFile();
547
-				$file->setTitle(basename($path));
548
-				$file->setMimeType($mimetype);
549
-				$parent = new \Google_Service_Drive_ParentReference();
550
-				$parent->setId($parentFolder->getId());
551
-				$file->setParents(array($parent));
552
-				$this->client->setDefer($useChunking);
553
-				$request = $this->service->files->insert($file, $params);
554
-			}
555
-
556
-			if ($useChunking) {
557
-				// Create a media file upload to represent our upload process.
558
-				$media = new \Google_Http_MediaFileUpload(
559
-					$this->client,
560
-					$request,
561
-					'text/plain',
562
-					null,
563
-					true,
564
-					$chunkSizeBytes
565
-				);
566
-				$media->setFileSize($size);
567
-
568
-				// Upload the various chunks. $status will be false until the process is
569
-				// complete.
570
-				$status = false;
571
-				$handle = fopen($tmpFile, 'rb');
572
-				while (!$status && !feof($handle)) {
573
-					$chunk = fread($handle, $chunkSizeBytes);
574
-					$status = $media->nextChunk($chunk);
575
-				}
576
-
577
-				// The final value of $status will be the data from the API for the object
578
-				// that has been uploaded.
579
-				$result = false;
580
-				if ($status !== false) {
581
-					$result = $status;
582
-				}
583
-
584
-				fclose($handle);
585
-			} else {
586
-				$result = $request;
587
-			}
588
-
589
-			// Reset to the client to execute requests immediately in the future.
590
-			$this->client->setDefer(false);
591
-
592
-			if ($result) {
593
-				$this->setDriveFile($path, $result);
594
-			}
595
-		}
596
-	}
597
-
598
-	public function getMimeType($path) {
599
-		$file = $this->getDriveFile($path);
600
-		if ($file) {
601
-			$mimetype = $file->getMimeType();
602
-			// Convert Google Doc mimetypes, choosing Open Document formats for download
603
-			if ($mimetype === self::FOLDER) {
604
-				return 'httpd/unix-directory';
605
-			} else if ($mimetype === self::DOCUMENT) {
606
-				return 'application/vnd.oasis.opendocument.text';
607
-			} else if ($mimetype === self::SPREADSHEET) {
608
-				return 'application/x-vnd.oasis.opendocument.spreadsheet';
609
-			} else if ($mimetype === self::DRAWING) {
610
-				return 'image/jpeg';
611
-			} else if ($mimetype === self::PRESENTATION) {
612
-				// Download as .odp is not available
613
-				return 'application/pdf';
614
-			} else {
615
-				// use extension-based detection, could be an encrypted file
616
-				return parent::getMimeType($path);
617
-			}
618
-		} else {
619
-			return false;
620
-		}
621
-	}
622
-
623
-	public function free_space($path) {
624
-		$about = $this->service->about->get();
625
-		return $about->getQuotaBytesTotal() - $about->getQuotaBytesUsed();
626
-	}
627
-
628
-	public function touch($path, $mtime = null) {
629
-		$file = $this->getDriveFile($path);
630
-		$result = false;
631
-		if ($file) {
632
-			if (isset($mtime)) {
633
-				// This is just RFC3339, but frustratingly, GDrive's API *requires*
634
-				// the fractions portion be present, while no handy PHP constant
635
-				// for RFC3339 or ISO8601 includes it. So we do it ourselves.
636
-				$file->setModifiedDate(date('Y-m-d\TH:i:s.uP', $mtime));
637
-				$result = $this->service->files->patch($file->getId(), $file, array(
638
-					'setModifiedDate' => true,
639
-				));
640
-			} else {
641
-				$result = $this->service->files->touch($file->getId());
642
-			}
643
-		} else {
644
-			$parentFolder = $this->getDriveFile(dirname($path));
645
-			if ($parentFolder) {
646
-				$file = new \Google_Service_Drive_DriveFile();
647
-				$file->setTitle(basename($path));
648
-				$parent = new \Google_Service_Drive_ParentReference();
649
-				$parent->setId($parentFolder->getId());
650
-				$file->setParents(array($parent));
651
-				$result = $this->service->files->insert($file);
652
-			}
653
-		}
654
-		if ($result) {
655
-			$this->setDriveFile($path, $result);
656
-		}
657
-		return (bool)$result;
658
-	}
659
-
660
-	public function test() {
661
-		if ($this->free_space('')) {
662
-			return true;
663
-		}
664
-		return false;
665
-	}
666
-
667
-	public function hasUpdated($path, $time) {
668
-		$appConfig = \OC::$server->getAppConfig();
669
-		if ($this->is_file($path)) {
670
-			return parent::hasUpdated($path, $time);
671
-		} else {
672
-			// Google Drive doesn't change modified times of folders when files inside are updated
673
-			// Instead we use the Changes API to see if folders have been updated, and it's a pain
674
-			$folder = $this->getDriveFile($path);
675
-			if ($folder) {
676
-				$result = false;
677
-				$folderId = $folder->getId();
678
-				$startChangeId = $appConfig->getValue('files_external', $this->getId().'cId');
679
-				$params = array(
680
-					'includeDeleted' => true,
681
-					'includeSubscribed' => true,
682
-				);
683
-				if (isset($startChangeId)) {
684
-					$startChangeId = (int)$startChangeId;
685
-					$largestChangeId = $startChangeId;
686
-					$params['startChangeId'] = $startChangeId + 1;
687
-				} else {
688
-					$largestChangeId = 0;
689
-				}
690
-				$pageToken = true;
691
-				while ($pageToken) {
692
-					if ($pageToken !== true) {
693
-						$params['pageToken'] = $pageToken;
694
-					}
695
-					$changes = $this->service->changes->listChanges($params);
696
-					if ($largestChangeId === 0 || $largestChangeId === $startChangeId) {
697
-						$largestChangeId = $changes->getLargestChangeId();
698
-					}
699
-					if (isset($startChangeId)) {
700
-						// Check if a file in this folder has been updated
701
-						// There is no way to filter by folder at the API level...
702
-						foreach ($changes->getItems() as $change) {
703
-							$file = $change->getFile();
704
-							if ($file) {
705
-								foreach ($file->getParents() as $parent) {
706
-									if ($parent->getId() === $folderId) {
707
-										$result = true;
708
-									// Check if there are changes in different folders
709
-									} else if ($change->getId() <= $largestChangeId) {
710
-										// Decrement id so this change is fetched when called again
711
-										$largestChangeId = $change->getId();
712
-										$largestChangeId--;
713
-									}
714
-								}
715
-							}
716
-						}
717
-						$pageToken = $changes->getNextPageToken();
718
-					} else {
719
-						// Assuming the initial scan just occurred and changes are negligible
720
-						break;
721
-					}
722
-				}
723
-				$appConfig->setValue('files_external', $this->getId().'cId', $largestChangeId);
724
-				return $result;
725
-			}
726
-		}
727
-		return false;
728
-	}
729
-
730
-	/**
731
-	 * check if curl is installed
732
-	 */
733
-	public static function checkDependencies() {
734
-		return true;
735
-	}
402
+        $file = $this->getDriveFile($path1);
403
+        if ($file) {
404
+            $newFile = $this->getDriveFile($path2);
405
+            if (dirname($path1) === dirname($path2)) {
406
+                if ($newFile) {
407
+                    // rename to the name of the target file, could be an office file without extension
408
+                    $file->setTitle($newFile->getTitle());
409
+                } else {
410
+                    $file->setTitle(basename(($path2)));
411
+                }
412
+            } else {
413
+                // Change file parent
414
+                $parentFolder2 = $this->getDriveFile(dirname($path2));
415
+                if ($parentFolder2) {
416
+                    $parent = new \Google_Service_Drive_ParentReference();
417
+                    $parent->setId($parentFolder2->getId());
418
+                    $file->setParents(array($parent));
419
+                } else {
420
+                    return false;
421
+                }
422
+            }
423
+            // We need to get the object for the existing file with the same
424
+            // name (if there is one) before we do the patch. If oldfile
425
+            // exists and is a directory we have to delete it before we
426
+            // do the rename too.
427
+            $oldfile = $this->getDriveFile($path2);
428
+            if ($oldfile && $this->is_dir($path2)) {
429
+                $this->rmdir($path2);
430
+                $oldfile = false;
431
+            }
432
+            $result = $this->service->files->patch($file->getId(), $file);
433
+            if ($result) {
434
+                $this->setDriveFile($path1, false);
435
+                $this->setDriveFile($path2, $result);
436
+                if ($oldfile && $newFile) {
437
+                    // only delete if they have a different id (same id can happen for part files)
438
+                    if ($newFile->getId() !== $oldfile->getId()) {
439
+                        $this->service->files->delete($oldfile->getId());
440
+                    }
441
+                }
442
+            }
443
+            return (bool)$result;
444
+        } else {
445
+            return false;
446
+        }
447
+    }
448
+
449
+    public function fopen($path, $mode) {
450
+        $pos = strrpos($path, '.');
451
+        if ($pos !== false) {
452
+            $ext = substr($path, $pos);
453
+        } else {
454
+            $ext = '';
455
+        }
456
+        switch ($mode) {
457
+            case 'r':
458
+            case 'rb':
459
+                $file = $this->getDriveFile($path);
460
+                if ($file) {
461
+                    $exportLinks = $file->getExportLinks();
462
+                    $mimetype = $this->getMimeType($path);
463
+                    $downloadUrl = null;
464
+                    if ($exportLinks && isset($exportLinks[$mimetype])) {
465
+                        $downloadUrl = $exportLinks[$mimetype];
466
+                    } else {
467
+                        $downloadUrl = $file->getDownloadUrl();
468
+                    }
469
+                    if (isset($downloadUrl)) {
470
+                        $request = new \Google_Http_Request($downloadUrl, 'GET', null, null);
471
+                        $httpRequest = $this->client->getAuth()->sign($request);
472
+                        // the library's service doesn't support streaming, so we use Guzzle instead
473
+                        $client = \OC::$server->getHTTPClientService()->newClient();
474
+                        try {
475
+                            $response = $client->get($downloadUrl, [
476
+                                'headers' => $httpRequest->getRequestHeaders(),
477
+                                'stream' => true,
478
+                                'verify' => realpath(__DIR__ . '/../../../3rdparty/google-api-php-client/src/Google/IO/cacerts.pem'),
479
+                            ]);
480
+                        } catch (RequestException $e) {
481
+                            if(!is_null($e->getResponse())) {
482
+                                if ($e->getResponse()->getStatusCode() === 404) {
483
+                                    return false;
484
+                                } else {
485
+                                    throw $e;
486
+                                }
487
+                            } else {
488
+                                throw $e;
489
+                            }
490
+                        }
491
+
492
+                        $handle = $response->getBody();
493
+                        return RetryWrapper::wrap($handle);
494
+                    }
495
+                }
496
+                return false;
497
+            case 'w':
498
+            case 'wb':
499
+            case 'a':
500
+            case 'ab':
501
+            case 'r+':
502
+            case 'w+':
503
+            case 'wb+':
504
+            case 'a+':
505
+            case 'x':
506
+            case 'x+':
507
+            case 'c':
508
+            case 'c+':
509
+                $tmpFile = \OCP\Files::tmpFile($ext);
510
+                if ($this->file_exists($path)) {
511
+                    $source = $this->fopen($path, 'rb');
512
+                    file_put_contents($tmpFile, $source);
513
+                }
514
+                $handle = fopen($tmpFile, $mode);
515
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
516
+                    $this->writeBack($tmpFile, $path);
517
+                });
518
+        }
519
+    }
520
+
521
+    public function writeBack($tmpFile, $path) {
522
+        $parentFolder = $this->getDriveFile(dirname($path));
523
+        if ($parentFolder) {
524
+            $mimetype = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
525
+            $params = array(
526
+                'mimeType' => $mimetype,
527
+                'uploadType' => 'media'
528
+            );
529
+            $result = false;
530
+
531
+            $chunkSizeBytes = 10 * 1024 * 1024;
532
+
533
+            $useChunking = false;
534
+            $size = filesize($tmpFile);
535
+            if ($size > $chunkSizeBytes) {
536
+                $useChunking = true;
537
+            } else {
538
+                $params['data'] = file_get_contents($tmpFile);
539
+            }
540
+
541
+            if ($this->file_exists($path)) {
542
+                $file = $this->getDriveFile($path);
543
+                $this->client->setDefer($useChunking);
544
+                $request = $this->service->files->update($file->getId(), $file, $params);
545
+            } else {
546
+                $file = new \Google_Service_Drive_DriveFile();
547
+                $file->setTitle(basename($path));
548
+                $file->setMimeType($mimetype);
549
+                $parent = new \Google_Service_Drive_ParentReference();
550
+                $parent->setId($parentFolder->getId());
551
+                $file->setParents(array($parent));
552
+                $this->client->setDefer($useChunking);
553
+                $request = $this->service->files->insert($file, $params);
554
+            }
555
+
556
+            if ($useChunking) {
557
+                // Create a media file upload to represent our upload process.
558
+                $media = new \Google_Http_MediaFileUpload(
559
+                    $this->client,
560
+                    $request,
561
+                    'text/plain',
562
+                    null,
563
+                    true,
564
+                    $chunkSizeBytes
565
+                );
566
+                $media->setFileSize($size);
567
+
568
+                // Upload the various chunks. $status will be false until the process is
569
+                // complete.
570
+                $status = false;
571
+                $handle = fopen($tmpFile, 'rb');
572
+                while (!$status && !feof($handle)) {
573
+                    $chunk = fread($handle, $chunkSizeBytes);
574
+                    $status = $media->nextChunk($chunk);
575
+                }
576
+
577
+                // The final value of $status will be the data from the API for the object
578
+                // that has been uploaded.
579
+                $result = false;
580
+                if ($status !== false) {
581
+                    $result = $status;
582
+                }
583
+
584
+                fclose($handle);
585
+            } else {
586
+                $result = $request;
587
+            }
588
+
589
+            // Reset to the client to execute requests immediately in the future.
590
+            $this->client->setDefer(false);
591
+
592
+            if ($result) {
593
+                $this->setDriveFile($path, $result);
594
+            }
595
+        }
596
+    }
597
+
598
+    public function getMimeType($path) {
599
+        $file = $this->getDriveFile($path);
600
+        if ($file) {
601
+            $mimetype = $file->getMimeType();
602
+            // Convert Google Doc mimetypes, choosing Open Document formats for download
603
+            if ($mimetype === self::FOLDER) {
604
+                return 'httpd/unix-directory';
605
+            } else if ($mimetype === self::DOCUMENT) {
606
+                return 'application/vnd.oasis.opendocument.text';
607
+            } else if ($mimetype === self::SPREADSHEET) {
608
+                return 'application/x-vnd.oasis.opendocument.spreadsheet';
609
+            } else if ($mimetype === self::DRAWING) {
610
+                return 'image/jpeg';
611
+            } else if ($mimetype === self::PRESENTATION) {
612
+                // Download as .odp is not available
613
+                return 'application/pdf';
614
+            } else {
615
+                // use extension-based detection, could be an encrypted file
616
+                return parent::getMimeType($path);
617
+            }
618
+        } else {
619
+            return false;
620
+        }
621
+    }
622
+
623
+    public function free_space($path) {
624
+        $about = $this->service->about->get();
625
+        return $about->getQuotaBytesTotal() - $about->getQuotaBytesUsed();
626
+    }
627
+
628
+    public function touch($path, $mtime = null) {
629
+        $file = $this->getDriveFile($path);
630
+        $result = false;
631
+        if ($file) {
632
+            if (isset($mtime)) {
633
+                // This is just RFC3339, but frustratingly, GDrive's API *requires*
634
+                // the fractions portion be present, while no handy PHP constant
635
+                // for RFC3339 or ISO8601 includes it. So we do it ourselves.
636
+                $file->setModifiedDate(date('Y-m-d\TH:i:s.uP', $mtime));
637
+                $result = $this->service->files->patch($file->getId(), $file, array(
638
+                    'setModifiedDate' => true,
639
+                ));
640
+            } else {
641
+                $result = $this->service->files->touch($file->getId());
642
+            }
643
+        } else {
644
+            $parentFolder = $this->getDriveFile(dirname($path));
645
+            if ($parentFolder) {
646
+                $file = new \Google_Service_Drive_DriveFile();
647
+                $file->setTitle(basename($path));
648
+                $parent = new \Google_Service_Drive_ParentReference();
649
+                $parent->setId($parentFolder->getId());
650
+                $file->setParents(array($parent));
651
+                $result = $this->service->files->insert($file);
652
+            }
653
+        }
654
+        if ($result) {
655
+            $this->setDriveFile($path, $result);
656
+        }
657
+        return (bool)$result;
658
+    }
659
+
660
+    public function test() {
661
+        if ($this->free_space('')) {
662
+            return true;
663
+        }
664
+        return false;
665
+    }
666
+
667
+    public function hasUpdated($path, $time) {
668
+        $appConfig = \OC::$server->getAppConfig();
669
+        if ($this->is_file($path)) {
670
+            return parent::hasUpdated($path, $time);
671
+        } else {
672
+            // Google Drive doesn't change modified times of folders when files inside are updated
673
+            // Instead we use the Changes API to see if folders have been updated, and it's a pain
674
+            $folder = $this->getDriveFile($path);
675
+            if ($folder) {
676
+                $result = false;
677
+                $folderId = $folder->getId();
678
+                $startChangeId = $appConfig->getValue('files_external', $this->getId().'cId');
679
+                $params = array(
680
+                    'includeDeleted' => true,
681
+                    'includeSubscribed' => true,
682
+                );
683
+                if (isset($startChangeId)) {
684
+                    $startChangeId = (int)$startChangeId;
685
+                    $largestChangeId = $startChangeId;
686
+                    $params['startChangeId'] = $startChangeId + 1;
687
+                } else {
688
+                    $largestChangeId = 0;
689
+                }
690
+                $pageToken = true;
691
+                while ($pageToken) {
692
+                    if ($pageToken !== true) {
693
+                        $params['pageToken'] = $pageToken;
694
+                    }
695
+                    $changes = $this->service->changes->listChanges($params);
696
+                    if ($largestChangeId === 0 || $largestChangeId === $startChangeId) {
697
+                        $largestChangeId = $changes->getLargestChangeId();
698
+                    }
699
+                    if (isset($startChangeId)) {
700
+                        // Check if a file in this folder has been updated
701
+                        // There is no way to filter by folder at the API level...
702
+                        foreach ($changes->getItems() as $change) {
703
+                            $file = $change->getFile();
704
+                            if ($file) {
705
+                                foreach ($file->getParents() as $parent) {
706
+                                    if ($parent->getId() === $folderId) {
707
+                                        $result = true;
708
+                                    // Check if there are changes in different folders
709
+                                    } else if ($change->getId() <= $largestChangeId) {
710
+                                        // Decrement id so this change is fetched when called again
711
+                                        $largestChangeId = $change->getId();
712
+                                        $largestChangeId--;
713
+                                    }
714
+                                }
715
+                            }
716
+                        }
717
+                        $pageToken = $changes->getNextPageToken();
718
+                    } else {
719
+                        // Assuming the initial scan just occurred and changes are negligible
720
+                        break;
721
+                    }
722
+                }
723
+                $appConfig->setValue('files_external', $this->getId().'cId', $largestChangeId);
724
+                return $result;
725
+            }
726
+        }
727
+        return false;
728
+    }
729
+
730
+    /**
731
+     * check if curl is installed
732
+     */
733
+    public static function checkDependencies() {
734
+        return true;
735
+    }
736 736
 
737 737
 }
Please login to merge, or discard this patch.
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.
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.
lib/private/legacy/app.php 3 patches
Doc Comments   +6 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1063,7 +1063,7 @@  discard block
 block discarded – undo
1063 1063
 	 * @param string $app
1064 1064
 	 * @param \OCP\IConfig $config
1065 1065
 	 * @param \OCP\IL10N $l
1066
-	 * @return bool
1066
+	 * @return string
1067 1067
 	 *
1068 1068
 	 * @throws Exception if app is not compatible with this version of ownCloud
1069 1069
 	 * @throws Exception if no app-name was specified
@@ -1243,6 +1243,11 @@  discard block
 block discarded – undo
1243 1243
 		}
1244 1244
 	}
1245 1245
 
1246
+	/**
1247
+	 * @param string $lang
1248
+	 *
1249
+	 * @return string
1250
+	 */
1246 1251
 	protected static function findBestL10NOption($options, $lang) {
1247 1252
 		$fallback = $similarLangFallback = $englishFallback = false;
1248 1253
 
Please login to merge, or discard this patch.
Indentation   +1184 added lines, -1184 removed lines patch added patch discarded remove patch
@@ -60,1188 +60,1188 @@
 block discarded – undo
60 60
  * upgrading and removing apps.
61 61
  */
62 62
 class OC_App {
63
-	static private $appVersion = [];
64
-	static private $adminForms = array();
65
-	static private $personalForms = array();
66
-	static private $appInfo = array();
67
-	static private $appTypes = array();
68
-	static private $loadedApps = array();
69
-	static private $altLogin = array();
70
-	static private $alreadyRegistered = [];
71
-	const officialApp = 200;
72
-
73
-	/**
74
-	 * clean the appId
75
-	 *
76
-	 * @param string|boolean $app AppId that needs to be cleaned
77
-	 * @return string
78
-	 */
79
-	public static function cleanAppId($app) {
80
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
-	}
82
-
83
-	/**
84
-	 * Check if an app is loaded
85
-	 *
86
-	 * @param string $app
87
-	 * @return bool
88
-	 */
89
-	public static function isAppLoaded($app) {
90
-		return in_array($app, self::$loadedApps, true);
91
-	}
92
-
93
-	/**
94
-	 * loads all apps
95
-	 *
96
-	 * @param string[] | string | null $types
97
-	 * @return bool
98
-	 *
99
-	 * This function walks through the ownCloud directory and loads all apps
100
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
101
-	 * exists.
102
-	 *
103
-	 * if $types is set, only apps of those types will be loaded
104
-	 */
105
-	public static function loadApps($types = null) {
106
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
-			return false;
108
-		}
109
-		// Load the enabled apps here
110
-		$apps = self::getEnabledApps();
111
-
112
-		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
114
-			$path = self::getAppPath($app);
115
-			if($path !== false) {
116
-				self::registerAutoloading($app, $path);
117
-			}
118
-		}
119
-
120
-		// prevent app.php from printing output
121
-		ob_start();
122
-		foreach ($apps as $app) {
123
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
-				self::loadApp($app);
125
-			}
126
-		}
127
-		ob_end_clean();
128
-
129
-		return true;
130
-	}
131
-
132
-	/**
133
-	 * load a single app
134
-	 *
135
-	 * @param string $app
136
-	 */
137
-	public static function loadApp($app) {
138
-		self::$loadedApps[] = $app;
139
-		$appPath = self::getAppPath($app);
140
-		if($appPath === false) {
141
-			return;
142
-		}
143
-
144
-		// in case someone calls loadApp() directly
145
-		self::registerAutoloading($app, $appPath);
146
-
147
-		if (is_file($appPath . '/appinfo/app.php')) {
148
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
149
-			self::requireAppFile($app);
150
-			if (self::isType($app, array('authentication'))) {
151
-				// since authentication apps affect the "is app enabled for group" check,
152
-				// the enabled apps cache needs to be cleared to make sure that the
153
-				// next time getEnableApps() is called it will also include apps that were
154
-				// enabled for groups
155
-				self::$enabledAppsCache = array();
156
-			}
157
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
158
-		}
159
-
160
-		$info = self::getAppInfo($app);
161
-		if (!empty($info['activity']['filters'])) {
162
-			foreach ($info['activity']['filters'] as $filter) {
163
-				\OC::$server->getActivityManager()->registerFilter($filter);
164
-			}
165
-		}
166
-		if (!empty($info['activity']['settings'])) {
167
-			foreach ($info['activity']['settings'] as $setting) {
168
-				\OC::$server->getActivityManager()->registerSetting($setting);
169
-			}
170
-		}
171
-		if (!empty($info['activity']['providers'])) {
172
-			foreach ($info['activity']['providers'] as $provider) {
173
-				\OC::$server->getActivityManager()->registerProvider($provider);
174
-			}
175
-		}
176
-	}
177
-
178
-	/**
179
-	 * @internal
180
-	 * @param string $app
181
-	 * @param string $path
182
-	 */
183
-	public static function registerAutoloading($app, $path) {
184
-		$key = $app . '-' . $path;
185
-		if(isset(self::$alreadyRegistered[$key])) {
186
-			return;
187
-		}
188
-		self::$alreadyRegistered[$key] = true;
189
-		// Register on PSR-4 composer autoloader
190
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
191
-		\OC::$server->registerNamespace($app, $appNamespace);
192
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
193
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
194
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
195
-		}
196
-
197
-		// Register on legacy autoloader
198
-		\OC::$loader->addValidRoot($path);
199
-	}
200
-
201
-	/**
202
-	 * Load app.php from the given app
203
-	 *
204
-	 * @param string $app app name
205
-	 */
206
-	private static function requireAppFile($app) {
207
-		try {
208
-			// encapsulated here to avoid variable scope conflicts
209
-			require_once $app . '/appinfo/app.php';
210
-		} catch (Error $ex) {
211
-			\OC::$server->getLogger()->logException($ex);
212
-			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
213
-			if (!in_array($app, $blacklist)) {
214
-				self::disable($app);
215
-			}
216
-		}
217
-	}
218
-
219
-	/**
220
-	 * check if an app is of a specific type
221
-	 *
222
-	 * @param string $app
223
-	 * @param string|array $types
224
-	 * @return bool
225
-	 */
226
-	public static function isType($app, $types) {
227
-		if (is_string($types)) {
228
-			$types = array($types);
229
-		}
230
-		$appTypes = self::getAppTypes($app);
231
-		foreach ($types as $type) {
232
-			if (array_search($type, $appTypes) !== false) {
233
-				return true;
234
-			}
235
-		}
236
-		return false;
237
-	}
238
-
239
-	/**
240
-	 * get the types of an app
241
-	 *
242
-	 * @param string $app
243
-	 * @return array
244
-	 */
245
-	private static function getAppTypes($app) {
246
-		//load the cache
247
-		if (count(self::$appTypes) == 0) {
248
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
249
-		}
250
-
251
-		if (isset(self::$appTypes[$app])) {
252
-			return explode(',', self::$appTypes[$app]);
253
-		} else {
254
-			return array();
255
-		}
256
-	}
257
-
258
-	/**
259
-	 * read app types from info.xml and cache them in the database
260
-	 */
261
-	public static function setAppTypes($app) {
262
-		$appData = self::getAppInfo($app);
263
-		if(!is_array($appData)) {
264
-			return;
265
-		}
266
-
267
-		if (isset($appData['types'])) {
268
-			$appTypes = implode(',', $appData['types']);
269
-		} else {
270
-			$appTypes = '';
271
-			$appData['types'] = [];
272
-		}
273
-
274
-		\OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
275
-
276
-		if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
277
-			$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
278
-			if ($enabled !== 'yes' && $enabled !== 'no') {
279
-				\OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
280
-			}
281
-		}
282
-	}
283
-
284
-	/**
285
-	 * check if app is shipped
286
-	 *
287
-	 * @param string $appId the id of the app to check
288
-	 * @return bool
289
-	 *
290
-	 * Check if an app that is installed is a shipped app or installed from the appstore.
291
-	 */
292
-	public static function isShipped($appId) {
293
-		return \OC::$server->getAppManager()->isShipped($appId);
294
-	}
295
-
296
-	/**
297
-	 * get all enabled apps
298
-	 */
299
-	protected static $enabledAppsCache = array();
300
-
301
-	/**
302
-	 * Returns apps enabled for the current user.
303
-	 *
304
-	 * @param bool $forceRefresh whether to refresh the cache
305
-	 * @param bool $all whether to return apps for all users, not only the
306
-	 * currently logged in one
307
-	 * @return string[]
308
-	 */
309
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
310
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
311
-			return array();
312
-		}
313
-		// in incognito mode or when logged out, $user will be false,
314
-		// which is also the case during an upgrade
315
-		$appManager = \OC::$server->getAppManager();
316
-		if ($all) {
317
-			$user = null;
318
-		} else {
319
-			$user = \OC::$server->getUserSession()->getUser();
320
-		}
321
-
322
-		if (is_null($user)) {
323
-			$apps = $appManager->getInstalledApps();
324
-		} else {
325
-			$apps = $appManager->getEnabledAppsForUser($user);
326
-		}
327
-		$apps = array_filter($apps, function ($app) {
328
-			return $app !== 'files';//we add this manually
329
-		});
330
-		sort($apps);
331
-		array_unshift($apps, 'files');
332
-		return $apps;
333
-	}
334
-
335
-	/**
336
-	 * checks whether or not an app is enabled
337
-	 *
338
-	 * @param string $app app
339
-	 * @return bool
340
-	 *
341
-	 * This function checks whether or not an app is enabled.
342
-	 */
343
-	public static function isEnabled($app) {
344
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
345
-	}
346
-
347
-	/**
348
-	 * enables an app
349
-	 *
350
-	 * @param string $appId
351
-	 * @param array $groups (optional) when set, only these groups will have access to the app
352
-	 * @throws \Exception
353
-	 * @return void
354
-	 *
355
-	 * This function set an app as enabled in appconfig.
356
-	 */
357
-	public function enable($appId,
358
-						   $groups = null) {
359
-		self::$enabledAppsCache = []; // flush
360
-
361
-		// Check if app is already downloaded
362
-		$installer = new Installer(
363
-			\OC::$server->getAppFetcher(),
364
-			\OC::$server->getHTTPClientService(),
365
-			\OC::$server->getTempManager(),
366
-			\OC::$server->getLogger(),
367
-			\OC::$server->getConfig()
368
-		);
369
-		$isDownloaded = $installer->isDownloaded($appId);
370
-
371
-		if(!$isDownloaded) {
372
-			$installer->downloadApp($appId);
373
-		}
374
-
375
-		$installer->installApp($appId);
376
-
377
-		$appManager = \OC::$server->getAppManager();
378
-		if (!is_null($groups)) {
379
-			$groupManager = \OC::$server->getGroupManager();
380
-			$groupsList = [];
381
-			foreach ($groups as $group) {
382
-				$groupItem = $groupManager->get($group);
383
-				if ($groupItem instanceof \OCP\IGroup) {
384
-					$groupsList[] = $groupManager->get($group);
385
-				}
386
-			}
387
-			$appManager->enableAppForGroups($appId, $groupsList);
388
-		} else {
389
-			$appManager->enableApp($appId);
390
-		}
391
-	}
392
-
393
-	/**
394
-	 * @param string $app
395
-	 * @return bool
396
-	 */
397
-	public static function removeApp($app) {
398
-		if (self::isShipped($app)) {
399
-			return false;
400
-		}
401
-
402
-		$installer = new Installer(
403
-			\OC::$server->getAppFetcher(),
404
-			\OC::$server->getHTTPClientService(),
405
-			\OC::$server->getTempManager(),
406
-			\OC::$server->getLogger(),
407
-			\OC::$server->getConfig()
408
-		);
409
-		return $installer->removeApp($app);
410
-	}
411
-
412
-	/**
413
-	 * This function set an app as disabled in appconfig.
414
-	 *
415
-	 * @param string $app app
416
-	 * @throws Exception
417
-	 */
418
-	public static function disable($app) {
419
-		// flush
420
-		self::$enabledAppsCache = array();
421
-
422
-		// run uninstall steps
423
-		$appData = OC_App::getAppInfo($app);
424
-		if (!is_null($appData)) {
425
-			OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
426
-		}
427
-
428
-		// emit disable hook - needed anymore ?
429
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
430
-
431
-		// finally disable it
432
-		$appManager = \OC::$server->getAppManager();
433
-		$appManager->disableApp($app);
434
-	}
435
-
436
-	// This is private as well. It simply works, so don't ask for more details
437
-	private static function proceedNavigation($list) {
438
-		usort($list, function($a, $b) {
439
-			if (isset($a['order']) && isset($b['order'])) {
440
-				return ($a['order'] < $b['order']) ? -1 : 1;
441
-			} else if (isset($a['order']) || isset($b['order'])) {
442
-				return isset($a['order']) ? -1 : 1;
443
-			} else {
444
-				return ($a['name'] < $b['name']) ? -1 : 1;
445
-			}
446
-		});
447
-
448
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
449
-		foreach ($list as $index => &$navEntry) {
450
-			if ($navEntry['id'] == $activeApp) {
451
-				$navEntry['active'] = true;
452
-			} else {
453
-				$navEntry['active'] = false;
454
-			}
455
-		}
456
-		unset($navEntry);
457
-
458
-		return $list;
459
-	}
460
-
461
-	/**
462
-	 * Get the path where to install apps
463
-	 *
464
-	 * @return string|false
465
-	 */
466
-	public static function getInstallPath() {
467
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
468
-			return false;
469
-		}
470
-
471
-		foreach (OC::$APPSROOTS as $dir) {
472
-			if (isset($dir['writable']) && $dir['writable'] === true) {
473
-				return $dir['path'];
474
-			}
475
-		}
476
-
477
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
478
-		return null;
479
-	}
480
-
481
-
482
-	/**
483
-	 * search for an app in all app-directories
484
-	 *
485
-	 * @param string $appId
486
-	 * @return false|string
487
-	 */
488
-	public static function findAppInDirectories($appId) {
489
-		$sanitizedAppId = self::cleanAppId($appId);
490
-		if($sanitizedAppId !== $appId) {
491
-			return false;
492
-		}
493
-		static $app_dir = array();
494
-
495
-		if (isset($app_dir[$appId])) {
496
-			return $app_dir[$appId];
497
-		}
498
-
499
-		$possibleApps = array();
500
-		foreach (OC::$APPSROOTS as $dir) {
501
-			if (file_exists($dir['path'] . '/' . $appId)) {
502
-				$possibleApps[] = $dir;
503
-			}
504
-		}
505
-
506
-		if (empty($possibleApps)) {
507
-			return false;
508
-		} elseif (count($possibleApps) === 1) {
509
-			$dir = array_shift($possibleApps);
510
-			$app_dir[$appId] = $dir;
511
-			return $dir;
512
-		} else {
513
-			$versionToLoad = array();
514
-			foreach ($possibleApps as $possibleApp) {
515
-				$version = self::getAppVersionByPath($possibleApp['path']);
516
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
517
-					$versionToLoad = array(
518
-						'dir' => $possibleApp,
519
-						'version' => $version,
520
-					);
521
-				}
522
-			}
523
-			$app_dir[$appId] = $versionToLoad['dir'];
524
-			return $versionToLoad['dir'];
525
-			//TODO - write test
526
-		}
527
-	}
528
-
529
-	/**
530
-	 * Get the directory for the given app.
531
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
532
-	 *
533
-	 * @param string $appId
534
-	 * @return string|false
535
-	 */
536
-	public static function getAppPath($appId) {
537
-		if ($appId === null || trim($appId) === '') {
538
-			return false;
539
-		}
540
-
541
-		if (($dir = self::findAppInDirectories($appId)) != false) {
542
-			return $dir['path'] . '/' . $appId;
543
-		}
544
-		return false;
545
-	}
546
-
547
-	/**
548
-	 * Get the path for the given app on the access
549
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
550
-	 *
551
-	 * @param string $appId
552
-	 * @return string|false
553
-	 */
554
-	public static function getAppWebPath($appId) {
555
-		if (($dir = self::findAppInDirectories($appId)) != false) {
556
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
557
-		}
558
-		return false;
559
-	}
560
-
561
-	/**
562
-	 * get the last version of the app from appinfo/info.xml
563
-	 *
564
-	 * @param string $appId
565
-	 * @param bool $useCache
566
-	 * @return string
567
-	 */
568
-	public static function getAppVersion($appId, $useCache = true) {
569
-		if($useCache && isset(self::$appVersion[$appId])) {
570
-			return self::$appVersion[$appId];
571
-		}
572
-
573
-		$file = self::getAppPath($appId);
574
-		self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
575
-		return self::$appVersion[$appId];
576
-	}
577
-
578
-	/**
579
-	 * get app's version based on it's path
580
-	 *
581
-	 * @param string $path
582
-	 * @return string
583
-	 */
584
-	public static function getAppVersionByPath($path) {
585
-		$infoFile = $path . '/appinfo/info.xml';
586
-		$appData = self::getAppInfo($infoFile, true);
587
-		return isset($appData['version']) ? $appData['version'] : '';
588
-	}
589
-
590
-
591
-	/**
592
-	 * Read all app metadata from the info.xml file
593
-	 *
594
-	 * @param string $appId id of the app or the path of the info.xml file
595
-	 * @param bool $path
596
-	 * @param string $lang
597
-	 * @return array|null
598
-	 * @note all data is read from info.xml, not just pre-defined fields
599
-	 */
600
-	public static function getAppInfo($appId, $path = false, $lang = null) {
601
-		if ($path) {
602
-			$file = $appId;
603
-		} else {
604
-			if ($lang === null && isset(self::$appInfo[$appId])) {
605
-				return self::$appInfo[$appId];
606
-			}
607
-			$appPath = self::getAppPath($appId);
608
-			if($appPath === false) {
609
-				return null;
610
-			}
611
-			$file = $appPath . '/appinfo/info.xml';
612
-		}
613
-
614
-		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
615
-		$data = $parser->parse($file);
616
-
617
-		if (is_array($data)) {
618
-			$data = OC_App::parseAppInfo($data, $lang);
619
-		}
620
-		if(isset($data['ocsid'])) {
621
-			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
622
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
623
-				$data['ocsid'] = $storedId;
624
-			}
625
-		}
626
-
627
-		if ($lang === null) {
628
-			self::$appInfo[$appId] = $data;
629
-		}
630
-
631
-		return $data;
632
-	}
633
-
634
-	/**
635
-	 * Returns the navigation
636
-	 *
637
-	 * @return array
638
-	 *
639
-	 * This function returns an array containing all entries added. The
640
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
641
-	 * given for each app the following keys exist:
642
-	 *   - active: boolean, signals if the user is on this navigation entry
643
-	 */
644
-	public static function getNavigation() {
645
-		$entries = OC::$server->getNavigationManager()->getAll();
646
-		return self::proceedNavigation($entries);
647
-	}
648
-
649
-	/**
650
-	 * Returns the Settings Navigation
651
-	 *
652
-	 * @return string[]
653
-	 *
654
-	 * This function returns an array containing all settings pages added. The
655
-	 * entries are sorted by the key 'order' ascending.
656
-	 */
657
-	public static function getSettingsNavigation() {
658
-		$entries = OC::$server->getNavigationManager()->getAll('settings');
659
-		return self::proceedNavigation($entries);
660
-	}
661
-
662
-	/**
663
-	 * get the id of loaded app
664
-	 *
665
-	 * @return string
666
-	 */
667
-	public static function getCurrentApp() {
668
-		$request = \OC::$server->getRequest();
669
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
670
-		$topFolder = substr($script, 0, strpos($script, '/'));
671
-		if (empty($topFolder)) {
672
-			$path_info = $request->getPathInfo();
673
-			if ($path_info) {
674
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
675
-			}
676
-		}
677
-		if ($topFolder == 'apps') {
678
-			$length = strlen($topFolder);
679
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
680
-		} else {
681
-			return $topFolder;
682
-		}
683
-	}
684
-
685
-	/**
686
-	 * @param string $type
687
-	 * @return array
688
-	 */
689
-	public static function getForms($type) {
690
-		$forms = array();
691
-		switch ($type) {
692
-			case 'admin':
693
-				$source = self::$adminForms;
694
-				break;
695
-			case 'personal':
696
-				$source = self::$personalForms;
697
-				break;
698
-			default:
699
-				return array();
700
-		}
701
-		foreach ($source as $form) {
702
-			$forms[] = include $form;
703
-		}
704
-		return $forms;
705
-	}
706
-
707
-	/**
708
-	 * register an admin form to be shown
709
-	 *
710
-	 * @param string $app
711
-	 * @param string $page
712
-	 */
713
-	public static function registerAdmin($app, $page) {
714
-		self::$adminForms[] = $app . '/' . $page . '.php';
715
-	}
716
-
717
-	/**
718
-	 * register a personal form to be shown
719
-	 * @param string $app
720
-	 * @param string $page
721
-	 */
722
-	public static function registerPersonal($app, $page) {
723
-		self::$personalForms[] = $app . '/' . $page . '.php';
724
-	}
725
-
726
-	/**
727
-	 * @param array $entry
728
-	 */
729
-	public static function registerLogIn(array $entry) {
730
-		self::$altLogin[] = $entry;
731
-	}
732
-
733
-	/**
734
-	 * @return array
735
-	 */
736
-	public static function getAlternativeLogIns() {
737
-		return self::$altLogin;
738
-	}
739
-
740
-	/**
741
-	 * get a list of all apps in the apps folder
742
-	 *
743
-	 * @return array an array of app names (string IDs)
744
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
745
-	 */
746
-	public static function getAllApps() {
747
-
748
-		$apps = array();
749
-
750
-		foreach (OC::$APPSROOTS as $apps_dir) {
751
-			if (!is_readable($apps_dir['path'])) {
752
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
753
-				continue;
754
-			}
755
-			$dh = opendir($apps_dir['path']);
756
-
757
-			if (is_resource($dh)) {
758
-				while (($file = readdir($dh)) !== false) {
759
-
760
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
761
-
762
-						$apps[] = $file;
763
-					}
764
-				}
765
-			}
766
-		}
767
-
768
-		return $apps;
769
-	}
770
-
771
-	/**
772
-	 * List all apps, this is used in apps.php
773
-	 *
774
-	 * @return array
775
-	 */
776
-	public function listAllApps() {
777
-		$installedApps = OC_App::getAllApps();
778
-
779
-		//we don't want to show configuration for these
780
-		$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
781
-		$appList = array();
782
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
783
-		$urlGenerator = \OC::$server->getURLGenerator();
784
-
785
-		foreach ($installedApps as $app) {
786
-			if (array_search($app, $blacklist) === false) {
787
-
788
-				$info = OC_App::getAppInfo($app, false, $langCode);
789
-				if (!is_array($info)) {
790
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
791
-					continue;
792
-				}
793
-
794
-				if (!isset($info['name'])) {
795
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
796
-					continue;
797
-				}
798
-
799
-				$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
800
-				$info['groups'] = null;
801
-				if ($enabled === 'yes') {
802
-					$active = true;
803
-				} else if ($enabled === 'no') {
804
-					$active = false;
805
-				} else {
806
-					$active = true;
807
-					$info['groups'] = $enabled;
808
-				}
809
-
810
-				$info['active'] = $active;
811
-
812
-				if (self::isShipped($app)) {
813
-					$info['internal'] = true;
814
-					$info['level'] = self::officialApp;
815
-					$info['removable'] = false;
816
-				} else {
817
-					$info['internal'] = false;
818
-					$info['removable'] = true;
819
-				}
820
-
821
-				$appPath = self::getAppPath($app);
822
-				if($appPath !== false) {
823
-					$appIcon = $appPath . '/img/' . $app . '.svg';
824
-					if (file_exists($appIcon)) {
825
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
826
-						$info['previewAsIcon'] = true;
827
-					} else {
828
-						$appIcon = $appPath . '/img/app.svg';
829
-						if (file_exists($appIcon)) {
830
-							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
831
-							$info['previewAsIcon'] = true;
832
-						}
833
-					}
834
-				}
835
-				// fix documentation
836
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
837
-					foreach ($info['documentation'] as $key => $url) {
838
-						// If it is not an absolute URL we assume it is a key
839
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
840
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
841
-							$url = $urlGenerator->linkToDocs($url);
842
-						}
843
-
844
-						$info['documentation'][$key] = $url;
845
-					}
846
-				}
847
-
848
-				$info['version'] = OC_App::getAppVersion($app);
849
-				$appList[] = $info;
850
-			}
851
-		}
852
-
853
-		return $appList;
854
-	}
855
-
856
-	/**
857
-	 * Returns the internal app ID or false
858
-	 * @param string $ocsID
859
-	 * @return string|false
860
-	 */
861
-	public static function getInternalAppIdByOcs($ocsID) {
862
-		if(is_numeric($ocsID)) {
863
-			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
864
-			if(array_search($ocsID, $idArray)) {
865
-				return array_search($ocsID, $idArray);
866
-			}
867
-		}
868
-		return false;
869
-	}
870
-
871
-	public static function shouldUpgrade($app) {
872
-		$versions = self::getAppVersions();
873
-		$currentVersion = OC_App::getAppVersion($app);
874
-		if ($currentVersion && isset($versions[$app])) {
875
-			$installedVersion = $versions[$app];
876
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
877
-				return true;
878
-			}
879
-		}
880
-		return false;
881
-	}
882
-
883
-	/**
884
-	 * Adjust the number of version parts of $version1 to match
885
-	 * the number of version parts of $version2.
886
-	 *
887
-	 * @param string $version1 version to adjust
888
-	 * @param string $version2 version to take the number of parts from
889
-	 * @return string shortened $version1
890
-	 */
891
-	private static function adjustVersionParts($version1, $version2) {
892
-		$version1 = explode('.', $version1);
893
-		$version2 = explode('.', $version2);
894
-		// reduce $version1 to match the number of parts in $version2
895
-		while (count($version1) > count($version2)) {
896
-			array_pop($version1);
897
-		}
898
-		// if $version1 does not have enough parts, add some
899
-		while (count($version1) < count($version2)) {
900
-			$version1[] = '0';
901
-		}
902
-		return implode('.', $version1);
903
-	}
904
-
905
-	/**
906
-	 * Check whether the current ownCloud version matches the given
907
-	 * application's version requirements.
908
-	 *
909
-	 * The comparison is made based on the number of parts that the
910
-	 * app info version has. For example for ownCloud 6.0.3 if the
911
-	 * app info version is expecting version 6.0, the comparison is
912
-	 * made on the first two parts of the ownCloud version.
913
-	 * This means that it's possible to specify "requiremin" => 6
914
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
915
-	 *
916
-	 * @param string $ocVersion ownCloud version to check against
917
-	 * @param array $appInfo app info (from xml)
918
-	 *
919
-	 * @return boolean true if compatible, otherwise false
920
-	 */
921
-	public static function isAppCompatible($ocVersion, $appInfo) {
922
-		$requireMin = '';
923
-		$requireMax = '';
924
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
925
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
926
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
927
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
928
-		} else if (isset($appInfo['requiremin'])) {
929
-			$requireMin = $appInfo['requiremin'];
930
-		} else if (isset($appInfo['require'])) {
931
-			$requireMin = $appInfo['require'];
932
-		}
933
-
934
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
935
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
936
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
937
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
938
-		} else if (isset($appInfo['requiremax'])) {
939
-			$requireMax = $appInfo['requiremax'];
940
-		}
941
-
942
-		if (is_array($ocVersion)) {
943
-			$ocVersion = implode('.', $ocVersion);
944
-		}
945
-
946
-		if (!empty($requireMin)
947
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
948
-		) {
949
-
950
-			return false;
951
-		}
952
-
953
-		if (!empty($requireMax)
954
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
955
-		) {
956
-			return false;
957
-		}
958
-
959
-		return true;
960
-	}
961
-
962
-	/**
963
-	 * get the installed version of all apps
964
-	 */
965
-	public static function getAppVersions() {
966
-		static $versions;
967
-
968
-		if(!$versions) {
969
-			$appConfig = \OC::$server->getAppConfig();
970
-			$versions = $appConfig->getValues(false, 'installed_version');
971
-		}
972
-		return $versions;
973
-	}
974
-
975
-	/**
976
-	 * @param string $app
977
-	 * @param \OCP\IConfig $config
978
-	 * @param \OCP\IL10N $l
979
-	 * @return bool
980
-	 *
981
-	 * @throws Exception if app is not compatible with this version of ownCloud
982
-	 * @throws Exception if no app-name was specified
983
-	 */
984
-	public function installApp($app,
985
-							   \OCP\IConfig $config,
986
-							   \OCP\IL10N $l) {
987
-		if ($app !== false) {
988
-			// check if the app is compatible with this version of ownCloud
989
-			$info = self::getAppInfo($app);
990
-			if(!is_array($info)) {
991
-				throw new \Exception(
992
-					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
993
-						[$info['name']]
994
-					)
995
-				);
996
-			}
997
-
998
-			$version = \OCP\Util::getVersion();
999
-			if (!self::isAppCompatible($version, $info)) {
1000
-				throw new \Exception(
1001
-					$l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1002
-						array($info['name'])
1003
-					)
1004
-				);
1005
-			}
1006
-
1007
-			// check for required dependencies
1008
-			self::checkAppDependencies($config, $l, $info);
1009
-
1010
-			$config->setAppValue($app, 'enabled', 'yes');
1011
-			if (isset($appData['id'])) {
1012
-				$config->setAppValue($app, 'ocsid', $appData['id']);
1013
-			}
1014
-
1015
-			if(isset($info['settings']) && is_array($info['settings'])) {
1016
-				$appPath = self::getAppPath($app);
1017
-				self::registerAutoloading($app, $appPath);
1018
-				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
1019
-			}
1020
-
1021
-			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1022
-		} else {
1023
-			if(empty($appName) ) {
1024
-				throw new \Exception($l->t("No app name specified"));
1025
-			} else {
1026
-				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1027
-			}
1028
-		}
1029
-
1030
-		return $app;
1031
-	}
1032
-
1033
-	/**
1034
-	 * update the database for the app and call the update script
1035
-	 *
1036
-	 * @param string $appId
1037
-	 * @return bool
1038
-	 */
1039
-	public static function updateApp($appId) {
1040
-		$appPath = self::getAppPath($appId);
1041
-		if($appPath === false) {
1042
-			return false;
1043
-		}
1044
-		$appData = self::getAppInfo($appId);
1045
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1046
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1047
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1048
-		}
1049
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1050
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1051
-		unset(self::$appVersion[$appId]);
1052
-		// run upgrade code
1053
-		if (file_exists($appPath . '/appinfo/update.php')) {
1054
-			self::loadApp($appId);
1055
-			include $appPath . '/appinfo/update.php';
1056
-		}
1057
-		self::registerAutoloading($appId, $appPath);
1058
-		self::setupBackgroundJobs($appData['background-jobs']);
1059
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1060
-			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1061
-		}
1062
-
1063
-		//set remote/public handlers
1064
-		if (array_key_exists('ocsid', $appData)) {
1065
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1066
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1067
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1068
-		}
1069
-		foreach ($appData['remote'] as $name => $path) {
1070
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1071
-		}
1072
-		foreach ($appData['public'] as $name => $path) {
1073
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1074
-		}
1075
-
1076
-		self::setAppTypes($appId);
1077
-
1078
-		$version = \OC_App::getAppVersion($appId);
1079
-		\OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1080
-
1081
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1082
-			ManagerEvent::EVENT_APP_UPDATE, $appId
1083
-		));
1084
-
1085
-		return true;
1086
-	}
1087
-
1088
-	/**
1089
-	 * @param string $appId
1090
-	 * @param string[] $steps
1091
-	 * @throws \OC\NeedsUpdateException
1092
-	 */
1093
-	public static function executeRepairSteps($appId, array $steps) {
1094
-		if (empty($steps)) {
1095
-			return;
1096
-		}
1097
-		// load the app
1098
-		self::loadApp($appId);
1099
-
1100
-		$dispatcher = OC::$server->getEventDispatcher();
1101
-
1102
-		// load the steps
1103
-		$r = new Repair([], $dispatcher);
1104
-		foreach ($steps as $step) {
1105
-			try {
1106
-				$r->addStep($step);
1107
-			} catch (Exception $ex) {
1108
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1109
-				\OC::$server->getLogger()->logException($ex);
1110
-			}
1111
-		}
1112
-		// run the steps
1113
-		$r->run();
1114
-	}
1115
-
1116
-	public static function setupBackgroundJobs(array $jobs) {
1117
-		$queue = \OC::$server->getJobList();
1118
-		foreach ($jobs as $job) {
1119
-			$queue->add($job);
1120
-		}
1121
-	}
1122
-
1123
-	/**
1124
-	 * @param string $appId
1125
-	 * @param string[] $steps
1126
-	 */
1127
-	private static function setupLiveMigrations($appId, array $steps) {
1128
-		$queue = \OC::$server->getJobList();
1129
-		foreach ($steps as $step) {
1130
-			$queue->add('OC\Migration\BackgroundRepair', [
1131
-				'app' => $appId,
1132
-				'step' => $step]);
1133
-		}
1134
-	}
1135
-
1136
-	/**
1137
-	 * @param string $appId
1138
-	 * @return \OC\Files\View|false
1139
-	 */
1140
-	public static function getStorage($appId) {
1141
-		if (OC_App::isEnabled($appId)) { //sanity check
1142
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1143
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1144
-				if (!$view->file_exists($appId)) {
1145
-					$view->mkdir($appId);
1146
-				}
1147
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1148
-			} else {
1149
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1150
-				return false;
1151
-			}
1152
-		} else {
1153
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1154
-			return false;
1155
-		}
1156
-	}
1157
-
1158
-	protected static function findBestL10NOption($options, $lang) {
1159
-		$fallback = $similarLangFallback = $englishFallback = false;
1160
-
1161
-		$lang = strtolower($lang);
1162
-		$similarLang = $lang;
1163
-		if (strpos($similarLang, '_')) {
1164
-			// For "de_DE" we want to find "de" and the other way around
1165
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1166
-		}
1167
-
1168
-		foreach ($options as $option) {
1169
-			if (is_array($option)) {
1170
-				if ($fallback === false) {
1171
-					$fallback = $option['@value'];
1172
-				}
1173
-
1174
-				if (!isset($option['@attributes']['lang'])) {
1175
-					continue;
1176
-				}
1177
-
1178
-				$attributeLang = strtolower($option['@attributes']['lang']);
1179
-				if ($attributeLang === $lang) {
1180
-					return $option['@value'];
1181
-				}
1182
-
1183
-				if ($attributeLang === $similarLang) {
1184
-					$similarLangFallback = $option['@value'];
1185
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1186
-					if ($similarLangFallback === false) {
1187
-						$similarLangFallback =  $option['@value'];
1188
-					}
1189
-				}
1190
-			} else {
1191
-				$englishFallback = $option;
1192
-			}
1193
-		}
1194
-
1195
-		if ($similarLangFallback !== false) {
1196
-			return $similarLangFallback;
1197
-		} else if ($englishFallback !== false) {
1198
-			return $englishFallback;
1199
-		}
1200
-		return (string) $fallback;
1201
-	}
1202
-
1203
-	/**
1204
-	 * parses the app data array and enhanced the 'description' value
1205
-	 *
1206
-	 * @param array $data the app data
1207
-	 * @param string $lang
1208
-	 * @return array improved app data
1209
-	 */
1210
-	public static function parseAppInfo(array $data, $lang = null) {
1211
-
1212
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1213
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1214
-		}
1215
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1216
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1217
-		}
1218
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1219
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1220
-		} else if (isset($data['description']) && is_string($data['description'])) {
1221
-			$data['description'] = trim($data['description']);
1222
-		} else  {
1223
-			$data['description'] = '';
1224
-		}
1225
-
1226
-		return $data;
1227
-	}
1228
-
1229
-	/**
1230
-	 * @param \OCP\IConfig $config
1231
-	 * @param \OCP\IL10N $l
1232
-	 * @param array $info
1233
-	 * @throws \Exception
1234
-	 */
1235
-	public static function checkAppDependencies($config, $l, $info) {
1236
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1237
-		$missing = $dependencyAnalyzer->analyze($info);
1238
-		if (!empty($missing)) {
1239
-			$missingMsg = join(PHP_EOL, $missing);
1240
-			throw new \Exception(
1241
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1242
-					[$info['name'], $missingMsg]
1243
-				)
1244
-			);
1245
-		}
1246
-	}
63
+    static private $appVersion = [];
64
+    static private $adminForms = array();
65
+    static private $personalForms = array();
66
+    static private $appInfo = array();
67
+    static private $appTypes = array();
68
+    static private $loadedApps = array();
69
+    static private $altLogin = array();
70
+    static private $alreadyRegistered = [];
71
+    const officialApp = 200;
72
+
73
+    /**
74
+     * clean the appId
75
+     *
76
+     * @param string|boolean $app AppId that needs to be cleaned
77
+     * @return string
78
+     */
79
+    public static function cleanAppId($app) {
80
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
+    }
82
+
83
+    /**
84
+     * Check if an app is loaded
85
+     *
86
+     * @param string $app
87
+     * @return bool
88
+     */
89
+    public static function isAppLoaded($app) {
90
+        return in_array($app, self::$loadedApps, true);
91
+    }
92
+
93
+    /**
94
+     * loads all apps
95
+     *
96
+     * @param string[] | string | null $types
97
+     * @return bool
98
+     *
99
+     * This function walks through the ownCloud directory and loads all apps
100
+     * it can find. A directory contains an app if the file /appinfo/info.xml
101
+     * exists.
102
+     *
103
+     * if $types is set, only apps of those types will be loaded
104
+     */
105
+    public static function loadApps($types = null) {
106
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
+            return false;
108
+        }
109
+        // Load the enabled apps here
110
+        $apps = self::getEnabledApps();
111
+
112
+        // Add each apps' folder as allowed class path
113
+        foreach($apps as $app) {
114
+            $path = self::getAppPath($app);
115
+            if($path !== false) {
116
+                self::registerAutoloading($app, $path);
117
+            }
118
+        }
119
+
120
+        // prevent app.php from printing output
121
+        ob_start();
122
+        foreach ($apps as $app) {
123
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
+                self::loadApp($app);
125
+            }
126
+        }
127
+        ob_end_clean();
128
+
129
+        return true;
130
+    }
131
+
132
+    /**
133
+     * load a single app
134
+     *
135
+     * @param string $app
136
+     */
137
+    public static function loadApp($app) {
138
+        self::$loadedApps[] = $app;
139
+        $appPath = self::getAppPath($app);
140
+        if($appPath === false) {
141
+            return;
142
+        }
143
+
144
+        // in case someone calls loadApp() directly
145
+        self::registerAutoloading($app, $appPath);
146
+
147
+        if (is_file($appPath . '/appinfo/app.php')) {
148
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
149
+            self::requireAppFile($app);
150
+            if (self::isType($app, array('authentication'))) {
151
+                // since authentication apps affect the "is app enabled for group" check,
152
+                // the enabled apps cache needs to be cleared to make sure that the
153
+                // next time getEnableApps() is called it will also include apps that were
154
+                // enabled for groups
155
+                self::$enabledAppsCache = array();
156
+            }
157
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
158
+        }
159
+
160
+        $info = self::getAppInfo($app);
161
+        if (!empty($info['activity']['filters'])) {
162
+            foreach ($info['activity']['filters'] as $filter) {
163
+                \OC::$server->getActivityManager()->registerFilter($filter);
164
+            }
165
+        }
166
+        if (!empty($info['activity']['settings'])) {
167
+            foreach ($info['activity']['settings'] as $setting) {
168
+                \OC::$server->getActivityManager()->registerSetting($setting);
169
+            }
170
+        }
171
+        if (!empty($info['activity']['providers'])) {
172
+            foreach ($info['activity']['providers'] as $provider) {
173
+                \OC::$server->getActivityManager()->registerProvider($provider);
174
+            }
175
+        }
176
+    }
177
+
178
+    /**
179
+     * @internal
180
+     * @param string $app
181
+     * @param string $path
182
+     */
183
+    public static function registerAutoloading($app, $path) {
184
+        $key = $app . '-' . $path;
185
+        if(isset(self::$alreadyRegistered[$key])) {
186
+            return;
187
+        }
188
+        self::$alreadyRegistered[$key] = true;
189
+        // Register on PSR-4 composer autoloader
190
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
191
+        \OC::$server->registerNamespace($app, $appNamespace);
192
+        \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
193
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
194
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
195
+        }
196
+
197
+        // Register on legacy autoloader
198
+        \OC::$loader->addValidRoot($path);
199
+    }
200
+
201
+    /**
202
+     * Load app.php from the given app
203
+     *
204
+     * @param string $app app name
205
+     */
206
+    private static function requireAppFile($app) {
207
+        try {
208
+            // encapsulated here to avoid variable scope conflicts
209
+            require_once $app . '/appinfo/app.php';
210
+        } catch (Error $ex) {
211
+            \OC::$server->getLogger()->logException($ex);
212
+            $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
213
+            if (!in_array($app, $blacklist)) {
214
+                self::disable($app);
215
+            }
216
+        }
217
+    }
218
+
219
+    /**
220
+     * check if an app is of a specific type
221
+     *
222
+     * @param string $app
223
+     * @param string|array $types
224
+     * @return bool
225
+     */
226
+    public static function isType($app, $types) {
227
+        if (is_string($types)) {
228
+            $types = array($types);
229
+        }
230
+        $appTypes = self::getAppTypes($app);
231
+        foreach ($types as $type) {
232
+            if (array_search($type, $appTypes) !== false) {
233
+                return true;
234
+            }
235
+        }
236
+        return false;
237
+    }
238
+
239
+    /**
240
+     * get the types of an app
241
+     *
242
+     * @param string $app
243
+     * @return array
244
+     */
245
+    private static function getAppTypes($app) {
246
+        //load the cache
247
+        if (count(self::$appTypes) == 0) {
248
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
249
+        }
250
+
251
+        if (isset(self::$appTypes[$app])) {
252
+            return explode(',', self::$appTypes[$app]);
253
+        } else {
254
+            return array();
255
+        }
256
+    }
257
+
258
+    /**
259
+     * read app types from info.xml and cache them in the database
260
+     */
261
+    public static function setAppTypes($app) {
262
+        $appData = self::getAppInfo($app);
263
+        if(!is_array($appData)) {
264
+            return;
265
+        }
266
+
267
+        if (isset($appData['types'])) {
268
+            $appTypes = implode(',', $appData['types']);
269
+        } else {
270
+            $appTypes = '';
271
+            $appData['types'] = [];
272
+        }
273
+
274
+        \OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
275
+
276
+        if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
277
+            $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
278
+            if ($enabled !== 'yes' && $enabled !== 'no') {
279
+                \OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
280
+            }
281
+        }
282
+    }
283
+
284
+    /**
285
+     * check if app is shipped
286
+     *
287
+     * @param string $appId the id of the app to check
288
+     * @return bool
289
+     *
290
+     * Check if an app that is installed is a shipped app or installed from the appstore.
291
+     */
292
+    public static function isShipped($appId) {
293
+        return \OC::$server->getAppManager()->isShipped($appId);
294
+    }
295
+
296
+    /**
297
+     * get all enabled apps
298
+     */
299
+    protected static $enabledAppsCache = array();
300
+
301
+    /**
302
+     * Returns apps enabled for the current user.
303
+     *
304
+     * @param bool $forceRefresh whether to refresh the cache
305
+     * @param bool $all whether to return apps for all users, not only the
306
+     * currently logged in one
307
+     * @return string[]
308
+     */
309
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
310
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
311
+            return array();
312
+        }
313
+        // in incognito mode or when logged out, $user will be false,
314
+        // which is also the case during an upgrade
315
+        $appManager = \OC::$server->getAppManager();
316
+        if ($all) {
317
+            $user = null;
318
+        } else {
319
+            $user = \OC::$server->getUserSession()->getUser();
320
+        }
321
+
322
+        if (is_null($user)) {
323
+            $apps = $appManager->getInstalledApps();
324
+        } else {
325
+            $apps = $appManager->getEnabledAppsForUser($user);
326
+        }
327
+        $apps = array_filter($apps, function ($app) {
328
+            return $app !== 'files';//we add this manually
329
+        });
330
+        sort($apps);
331
+        array_unshift($apps, 'files');
332
+        return $apps;
333
+    }
334
+
335
+    /**
336
+     * checks whether or not an app is enabled
337
+     *
338
+     * @param string $app app
339
+     * @return bool
340
+     *
341
+     * This function checks whether or not an app is enabled.
342
+     */
343
+    public static function isEnabled($app) {
344
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
345
+    }
346
+
347
+    /**
348
+     * enables an app
349
+     *
350
+     * @param string $appId
351
+     * @param array $groups (optional) when set, only these groups will have access to the app
352
+     * @throws \Exception
353
+     * @return void
354
+     *
355
+     * This function set an app as enabled in appconfig.
356
+     */
357
+    public function enable($appId,
358
+                            $groups = null) {
359
+        self::$enabledAppsCache = []; // flush
360
+
361
+        // Check if app is already downloaded
362
+        $installer = new Installer(
363
+            \OC::$server->getAppFetcher(),
364
+            \OC::$server->getHTTPClientService(),
365
+            \OC::$server->getTempManager(),
366
+            \OC::$server->getLogger(),
367
+            \OC::$server->getConfig()
368
+        );
369
+        $isDownloaded = $installer->isDownloaded($appId);
370
+
371
+        if(!$isDownloaded) {
372
+            $installer->downloadApp($appId);
373
+        }
374
+
375
+        $installer->installApp($appId);
376
+
377
+        $appManager = \OC::$server->getAppManager();
378
+        if (!is_null($groups)) {
379
+            $groupManager = \OC::$server->getGroupManager();
380
+            $groupsList = [];
381
+            foreach ($groups as $group) {
382
+                $groupItem = $groupManager->get($group);
383
+                if ($groupItem instanceof \OCP\IGroup) {
384
+                    $groupsList[] = $groupManager->get($group);
385
+                }
386
+            }
387
+            $appManager->enableAppForGroups($appId, $groupsList);
388
+        } else {
389
+            $appManager->enableApp($appId);
390
+        }
391
+    }
392
+
393
+    /**
394
+     * @param string $app
395
+     * @return bool
396
+     */
397
+    public static function removeApp($app) {
398
+        if (self::isShipped($app)) {
399
+            return false;
400
+        }
401
+
402
+        $installer = new Installer(
403
+            \OC::$server->getAppFetcher(),
404
+            \OC::$server->getHTTPClientService(),
405
+            \OC::$server->getTempManager(),
406
+            \OC::$server->getLogger(),
407
+            \OC::$server->getConfig()
408
+        );
409
+        return $installer->removeApp($app);
410
+    }
411
+
412
+    /**
413
+     * This function set an app as disabled in appconfig.
414
+     *
415
+     * @param string $app app
416
+     * @throws Exception
417
+     */
418
+    public static function disable($app) {
419
+        // flush
420
+        self::$enabledAppsCache = array();
421
+
422
+        // run uninstall steps
423
+        $appData = OC_App::getAppInfo($app);
424
+        if (!is_null($appData)) {
425
+            OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
426
+        }
427
+
428
+        // emit disable hook - needed anymore ?
429
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
430
+
431
+        // finally disable it
432
+        $appManager = \OC::$server->getAppManager();
433
+        $appManager->disableApp($app);
434
+    }
435
+
436
+    // This is private as well. It simply works, so don't ask for more details
437
+    private static function proceedNavigation($list) {
438
+        usort($list, function($a, $b) {
439
+            if (isset($a['order']) && isset($b['order'])) {
440
+                return ($a['order'] < $b['order']) ? -1 : 1;
441
+            } else if (isset($a['order']) || isset($b['order'])) {
442
+                return isset($a['order']) ? -1 : 1;
443
+            } else {
444
+                return ($a['name'] < $b['name']) ? -1 : 1;
445
+            }
446
+        });
447
+
448
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
449
+        foreach ($list as $index => &$navEntry) {
450
+            if ($navEntry['id'] == $activeApp) {
451
+                $navEntry['active'] = true;
452
+            } else {
453
+                $navEntry['active'] = false;
454
+            }
455
+        }
456
+        unset($navEntry);
457
+
458
+        return $list;
459
+    }
460
+
461
+    /**
462
+     * Get the path where to install apps
463
+     *
464
+     * @return string|false
465
+     */
466
+    public static function getInstallPath() {
467
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
468
+            return false;
469
+        }
470
+
471
+        foreach (OC::$APPSROOTS as $dir) {
472
+            if (isset($dir['writable']) && $dir['writable'] === true) {
473
+                return $dir['path'];
474
+            }
475
+        }
476
+
477
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
478
+        return null;
479
+    }
480
+
481
+
482
+    /**
483
+     * search for an app in all app-directories
484
+     *
485
+     * @param string $appId
486
+     * @return false|string
487
+     */
488
+    public static function findAppInDirectories($appId) {
489
+        $sanitizedAppId = self::cleanAppId($appId);
490
+        if($sanitizedAppId !== $appId) {
491
+            return false;
492
+        }
493
+        static $app_dir = array();
494
+
495
+        if (isset($app_dir[$appId])) {
496
+            return $app_dir[$appId];
497
+        }
498
+
499
+        $possibleApps = array();
500
+        foreach (OC::$APPSROOTS as $dir) {
501
+            if (file_exists($dir['path'] . '/' . $appId)) {
502
+                $possibleApps[] = $dir;
503
+            }
504
+        }
505
+
506
+        if (empty($possibleApps)) {
507
+            return false;
508
+        } elseif (count($possibleApps) === 1) {
509
+            $dir = array_shift($possibleApps);
510
+            $app_dir[$appId] = $dir;
511
+            return $dir;
512
+        } else {
513
+            $versionToLoad = array();
514
+            foreach ($possibleApps as $possibleApp) {
515
+                $version = self::getAppVersionByPath($possibleApp['path']);
516
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
517
+                    $versionToLoad = array(
518
+                        'dir' => $possibleApp,
519
+                        'version' => $version,
520
+                    );
521
+                }
522
+            }
523
+            $app_dir[$appId] = $versionToLoad['dir'];
524
+            return $versionToLoad['dir'];
525
+            //TODO - write test
526
+        }
527
+    }
528
+
529
+    /**
530
+     * Get the directory for the given app.
531
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
532
+     *
533
+     * @param string $appId
534
+     * @return string|false
535
+     */
536
+    public static function getAppPath($appId) {
537
+        if ($appId === null || trim($appId) === '') {
538
+            return false;
539
+        }
540
+
541
+        if (($dir = self::findAppInDirectories($appId)) != false) {
542
+            return $dir['path'] . '/' . $appId;
543
+        }
544
+        return false;
545
+    }
546
+
547
+    /**
548
+     * Get the path for the given app on the access
549
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
550
+     *
551
+     * @param string $appId
552
+     * @return string|false
553
+     */
554
+    public static function getAppWebPath($appId) {
555
+        if (($dir = self::findAppInDirectories($appId)) != false) {
556
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
557
+        }
558
+        return false;
559
+    }
560
+
561
+    /**
562
+     * get the last version of the app from appinfo/info.xml
563
+     *
564
+     * @param string $appId
565
+     * @param bool $useCache
566
+     * @return string
567
+     */
568
+    public static function getAppVersion($appId, $useCache = true) {
569
+        if($useCache && isset(self::$appVersion[$appId])) {
570
+            return self::$appVersion[$appId];
571
+        }
572
+
573
+        $file = self::getAppPath($appId);
574
+        self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
575
+        return self::$appVersion[$appId];
576
+    }
577
+
578
+    /**
579
+     * get app's version based on it's path
580
+     *
581
+     * @param string $path
582
+     * @return string
583
+     */
584
+    public static function getAppVersionByPath($path) {
585
+        $infoFile = $path . '/appinfo/info.xml';
586
+        $appData = self::getAppInfo($infoFile, true);
587
+        return isset($appData['version']) ? $appData['version'] : '';
588
+    }
589
+
590
+
591
+    /**
592
+     * Read all app metadata from the info.xml file
593
+     *
594
+     * @param string $appId id of the app or the path of the info.xml file
595
+     * @param bool $path
596
+     * @param string $lang
597
+     * @return array|null
598
+     * @note all data is read from info.xml, not just pre-defined fields
599
+     */
600
+    public static function getAppInfo($appId, $path = false, $lang = null) {
601
+        if ($path) {
602
+            $file = $appId;
603
+        } else {
604
+            if ($lang === null && isset(self::$appInfo[$appId])) {
605
+                return self::$appInfo[$appId];
606
+            }
607
+            $appPath = self::getAppPath($appId);
608
+            if($appPath === false) {
609
+                return null;
610
+            }
611
+            $file = $appPath . '/appinfo/info.xml';
612
+        }
613
+
614
+        $parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
615
+        $data = $parser->parse($file);
616
+
617
+        if (is_array($data)) {
618
+            $data = OC_App::parseAppInfo($data, $lang);
619
+        }
620
+        if(isset($data['ocsid'])) {
621
+            $storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
622
+            if($storedId !== '' && $storedId !== $data['ocsid']) {
623
+                $data['ocsid'] = $storedId;
624
+            }
625
+        }
626
+
627
+        if ($lang === null) {
628
+            self::$appInfo[$appId] = $data;
629
+        }
630
+
631
+        return $data;
632
+    }
633
+
634
+    /**
635
+     * Returns the navigation
636
+     *
637
+     * @return array
638
+     *
639
+     * This function returns an array containing all entries added. The
640
+     * entries are sorted by the key 'order' ascending. Additional to the keys
641
+     * given for each app the following keys exist:
642
+     *   - active: boolean, signals if the user is on this navigation entry
643
+     */
644
+    public static function getNavigation() {
645
+        $entries = OC::$server->getNavigationManager()->getAll();
646
+        return self::proceedNavigation($entries);
647
+    }
648
+
649
+    /**
650
+     * Returns the Settings Navigation
651
+     *
652
+     * @return string[]
653
+     *
654
+     * This function returns an array containing all settings pages added. The
655
+     * entries are sorted by the key 'order' ascending.
656
+     */
657
+    public static function getSettingsNavigation() {
658
+        $entries = OC::$server->getNavigationManager()->getAll('settings');
659
+        return self::proceedNavigation($entries);
660
+    }
661
+
662
+    /**
663
+     * get the id of loaded app
664
+     *
665
+     * @return string
666
+     */
667
+    public static function getCurrentApp() {
668
+        $request = \OC::$server->getRequest();
669
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
670
+        $topFolder = substr($script, 0, strpos($script, '/'));
671
+        if (empty($topFolder)) {
672
+            $path_info = $request->getPathInfo();
673
+            if ($path_info) {
674
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
675
+            }
676
+        }
677
+        if ($topFolder == 'apps') {
678
+            $length = strlen($topFolder);
679
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
680
+        } else {
681
+            return $topFolder;
682
+        }
683
+    }
684
+
685
+    /**
686
+     * @param string $type
687
+     * @return array
688
+     */
689
+    public static function getForms($type) {
690
+        $forms = array();
691
+        switch ($type) {
692
+            case 'admin':
693
+                $source = self::$adminForms;
694
+                break;
695
+            case 'personal':
696
+                $source = self::$personalForms;
697
+                break;
698
+            default:
699
+                return array();
700
+        }
701
+        foreach ($source as $form) {
702
+            $forms[] = include $form;
703
+        }
704
+        return $forms;
705
+    }
706
+
707
+    /**
708
+     * register an admin form to be shown
709
+     *
710
+     * @param string $app
711
+     * @param string $page
712
+     */
713
+    public static function registerAdmin($app, $page) {
714
+        self::$adminForms[] = $app . '/' . $page . '.php';
715
+    }
716
+
717
+    /**
718
+     * register a personal form to be shown
719
+     * @param string $app
720
+     * @param string $page
721
+     */
722
+    public static function registerPersonal($app, $page) {
723
+        self::$personalForms[] = $app . '/' . $page . '.php';
724
+    }
725
+
726
+    /**
727
+     * @param array $entry
728
+     */
729
+    public static function registerLogIn(array $entry) {
730
+        self::$altLogin[] = $entry;
731
+    }
732
+
733
+    /**
734
+     * @return array
735
+     */
736
+    public static function getAlternativeLogIns() {
737
+        return self::$altLogin;
738
+    }
739
+
740
+    /**
741
+     * get a list of all apps in the apps folder
742
+     *
743
+     * @return array an array of app names (string IDs)
744
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
745
+     */
746
+    public static function getAllApps() {
747
+
748
+        $apps = array();
749
+
750
+        foreach (OC::$APPSROOTS as $apps_dir) {
751
+            if (!is_readable($apps_dir['path'])) {
752
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
753
+                continue;
754
+            }
755
+            $dh = opendir($apps_dir['path']);
756
+
757
+            if (is_resource($dh)) {
758
+                while (($file = readdir($dh)) !== false) {
759
+
760
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
761
+
762
+                        $apps[] = $file;
763
+                    }
764
+                }
765
+            }
766
+        }
767
+
768
+        return $apps;
769
+    }
770
+
771
+    /**
772
+     * List all apps, this is used in apps.php
773
+     *
774
+     * @return array
775
+     */
776
+    public function listAllApps() {
777
+        $installedApps = OC_App::getAllApps();
778
+
779
+        //we don't want to show configuration for these
780
+        $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
781
+        $appList = array();
782
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
783
+        $urlGenerator = \OC::$server->getURLGenerator();
784
+
785
+        foreach ($installedApps as $app) {
786
+            if (array_search($app, $blacklist) === false) {
787
+
788
+                $info = OC_App::getAppInfo($app, false, $langCode);
789
+                if (!is_array($info)) {
790
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
791
+                    continue;
792
+                }
793
+
794
+                if (!isset($info['name'])) {
795
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
796
+                    continue;
797
+                }
798
+
799
+                $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
800
+                $info['groups'] = null;
801
+                if ($enabled === 'yes') {
802
+                    $active = true;
803
+                } else if ($enabled === 'no') {
804
+                    $active = false;
805
+                } else {
806
+                    $active = true;
807
+                    $info['groups'] = $enabled;
808
+                }
809
+
810
+                $info['active'] = $active;
811
+
812
+                if (self::isShipped($app)) {
813
+                    $info['internal'] = true;
814
+                    $info['level'] = self::officialApp;
815
+                    $info['removable'] = false;
816
+                } else {
817
+                    $info['internal'] = false;
818
+                    $info['removable'] = true;
819
+                }
820
+
821
+                $appPath = self::getAppPath($app);
822
+                if($appPath !== false) {
823
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
824
+                    if (file_exists($appIcon)) {
825
+                        $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
826
+                        $info['previewAsIcon'] = true;
827
+                    } else {
828
+                        $appIcon = $appPath . '/img/app.svg';
829
+                        if (file_exists($appIcon)) {
830
+                            $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
831
+                            $info['previewAsIcon'] = true;
832
+                        }
833
+                    }
834
+                }
835
+                // fix documentation
836
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
837
+                    foreach ($info['documentation'] as $key => $url) {
838
+                        // If it is not an absolute URL we assume it is a key
839
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
840
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
841
+                            $url = $urlGenerator->linkToDocs($url);
842
+                        }
843
+
844
+                        $info['documentation'][$key] = $url;
845
+                    }
846
+                }
847
+
848
+                $info['version'] = OC_App::getAppVersion($app);
849
+                $appList[] = $info;
850
+            }
851
+        }
852
+
853
+        return $appList;
854
+    }
855
+
856
+    /**
857
+     * Returns the internal app ID or false
858
+     * @param string $ocsID
859
+     * @return string|false
860
+     */
861
+    public static function getInternalAppIdByOcs($ocsID) {
862
+        if(is_numeric($ocsID)) {
863
+            $idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
864
+            if(array_search($ocsID, $idArray)) {
865
+                return array_search($ocsID, $idArray);
866
+            }
867
+        }
868
+        return false;
869
+    }
870
+
871
+    public static function shouldUpgrade($app) {
872
+        $versions = self::getAppVersions();
873
+        $currentVersion = OC_App::getAppVersion($app);
874
+        if ($currentVersion && isset($versions[$app])) {
875
+            $installedVersion = $versions[$app];
876
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
877
+                return true;
878
+            }
879
+        }
880
+        return false;
881
+    }
882
+
883
+    /**
884
+     * Adjust the number of version parts of $version1 to match
885
+     * the number of version parts of $version2.
886
+     *
887
+     * @param string $version1 version to adjust
888
+     * @param string $version2 version to take the number of parts from
889
+     * @return string shortened $version1
890
+     */
891
+    private static function adjustVersionParts($version1, $version2) {
892
+        $version1 = explode('.', $version1);
893
+        $version2 = explode('.', $version2);
894
+        // reduce $version1 to match the number of parts in $version2
895
+        while (count($version1) > count($version2)) {
896
+            array_pop($version1);
897
+        }
898
+        // if $version1 does not have enough parts, add some
899
+        while (count($version1) < count($version2)) {
900
+            $version1[] = '0';
901
+        }
902
+        return implode('.', $version1);
903
+    }
904
+
905
+    /**
906
+     * Check whether the current ownCloud version matches the given
907
+     * application's version requirements.
908
+     *
909
+     * The comparison is made based on the number of parts that the
910
+     * app info version has. For example for ownCloud 6.0.3 if the
911
+     * app info version is expecting version 6.0, the comparison is
912
+     * made on the first two parts of the ownCloud version.
913
+     * This means that it's possible to specify "requiremin" => 6
914
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
915
+     *
916
+     * @param string $ocVersion ownCloud version to check against
917
+     * @param array $appInfo app info (from xml)
918
+     *
919
+     * @return boolean true if compatible, otherwise false
920
+     */
921
+    public static function isAppCompatible($ocVersion, $appInfo) {
922
+        $requireMin = '';
923
+        $requireMax = '';
924
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
925
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
926
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
927
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
928
+        } else if (isset($appInfo['requiremin'])) {
929
+            $requireMin = $appInfo['requiremin'];
930
+        } else if (isset($appInfo['require'])) {
931
+            $requireMin = $appInfo['require'];
932
+        }
933
+
934
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
935
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
936
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
937
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
938
+        } else if (isset($appInfo['requiremax'])) {
939
+            $requireMax = $appInfo['requiremax'];
940
+        }
941
+
942
+        if (is_array($ocVersion)) {
943
+            $ocVersion = implode('.', $ocVersion);
944
+        }
945
+
946
+        if (!empty($requireMin)
947
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
948
+        ) {
949
+
950
+            return false;
951
+        }
952
+
953
+        if (!empty($requireMax)
954
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
955
+        ) {
956
+            return false;
957
+        }
958
+
959
+        return true;
960
+    }
961
+
962
+    /**
963
+     * get the installed version of all apps
964
+     */
965
+    public static function getAppVersions() {
966
+        static $versions;
967
+
968
+        if(!$versions) {
969
+            $appConfig = \OC::$server->getAppConfig();
970
+            $versions = $appConfig->getValues(false, 'installed_version');
971
+        }
972
+        return $versions;
973
+    }
974
+
975
+    /**
976
+     * @param string $app
977
+     * @param \OCP\IConfig $config
978
+     * @param \OCP\IL10N $l
979
+     * @return bool
980
+     *
981
+     * @throws Exception if app is not compatible with this version of ownCloud
982
+     * @throws Exception if no app-name was specified
983
+     */
984
+    public function installApp($app,
985
+                                \OCP\IConfig $config,
986
+                                \OCP\IL10N $l) {
987
+        if ($app !== false) {
988
+            // check if the app is compatible with this version of ownCloud
989
+            $info = self::getAppInfo($app);
990
+            if(!is_array($info)) {
991
+                throw new \Exception(
992
+                    $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
993
+                        [$info['name']]
994
+                    )
995
+                );
996
+            }
997
+
998
+            $version = \OCP\Util::getVersion();
999
+            if (!self::isAppCompatible($version, $info)) {
1000
+                throw new \Exception(
1001
+                    $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1002
+                        array($info['name'])
1003
+                    )
1004
+                );
1005
+            }
1006
+
1007
+            // check for required dependencies
1008
+            self::checkAppDependencies($config, $l, $info);
1009
+
1010
+            $config->setAppValue($app, 'enabled', 'yes');
1011
+            if (isset($appData['id'])) {
1012
+                $config->setAppValue($app, 'ocsid', $appData['id']);
1013
+            }
1014
+
1015
+            if(isset($info['settings']) && is_array($info['settings'])) {
1016
+                $appPath = self::getAppPath($app);
1017
+                self::registerAutoloading($app, $appPath);
1018
+                \OC::$server->getSettingsManager()->setupSettings($info['settings']);
1019
+            }
1020
+
1021
+            \OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1022
+        } else {
1023
+            if(empty($appName) ) {
1024
+                throw new \Exception($l->t("No app name specified"));
1025
+            } else {
1026
+                throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1027
+            }
1028
+        }
1029
+
1030
+        return $app;
1031
+    }
1032
+
1033
+    /**
1034
+     * update the database for the app and call the update script
1035
+     *
1036
+     * @param string $appId
1037
+     * @return bool
1038
+     */
1039
+    public static function updateApp($appId) {
1040
+        $appPath = self::getAppPath($appId);
1041
+        if($appPath === false) {
1042
+            return false;
1043
+        }
1044
+        $appData = self::getAppInfo($appId);
1045
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1046
+        if (file_exists($appPath . '/appinfo/database.xml')) {
1047
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1048
+        }
1049
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1050
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1051
+        unset(self::$appVersion[$appId]);
1052
+        // run upgrade code
1053
+        if (file_exists($appPath . '/appinfo/update.php')) {
1054
+            self::loadApp($appId);
1055
+            include $appPath . '/appinfo/update.php';
1056
+        }
1057
+        self::registerAutoloading($appId, $appPath);
1058
+        self::setupBackgroundJobs($appData['background-jobs']);
1059
+        if(isset($appData['settings']) && is_array($appData['settings'])) {
1060
+            \OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1061
+        }
1062
+
1063
+        //set remote/public handlers
1064
+        if (array_key_exists('ocsid', $appData)) {
1065
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1066
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1067
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1068
+        }
1069
+        foreach ($appData['remote'] as $name => $path) {
1070
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1071
+        }
1072
+        foreach ($appData['public'] as $name => $path) {
1073
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1074
+        }
1075
+
1076
+        self::setAppTypes($appId);
1077
+
1078
+        $version = \OC_App::getAppVersion($appId);
1079
+        \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1080
+
1081
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1082
+            ManagerEvent::EVENT_APP_UPDATE, $appId
1083
+        ));
1084
+
1085
+        return true;
1086
+    }
1087
+
1088
+    /**
1089
+     * @param string $appId
1090
+     * @param string[] $steps
1091
+     * @throws \OC\NeedsUpdateException
1092
+     */
1093
+    public static function executeRepairSteps($appId, array $steps) {
1094
+        if (empty($steps)) {
1095
+            return;
1096
+        }
1097
+        // load the app
1098
+        self::loadApp($appId);
1099
+
1100
+        $dispatcher = OC::$server->getEventDispatcher();
1101
+
1102
+        // load the steps
1103
+        $r = new Repair([], $dispatcher);
1104
+        foreach ($steps as $step) {
1105
+            try {
1106
+                $r->addStep($step);
1107
+            } catch (Exception $ex) {
1108
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1109
+                \OC::$server->getLogger()->logException($ex);
1110
+            }
1111
+        }
1112
+        // run the steps
1113
+        $r->run();
1114
+    }
1115
+
1116
+    public static function setupBackgroundJobs(array $jobs) {
1117
+        $queue = \OC::$server->getJobList();
1118
+        foreach ($jobs as $job) {
1119
+            $queue->add($job);
1120
+        }
1121
+    }
1122
+
1123
+    /**
1124
+     * @param string $appId
1125
+     * @param string[] $steps
1126
+     */
1127
+    private static function setupLiveMigrations($appId, array $steps) {
1128
+        $queue = \OC::$server->getJobList();
1129
+        foreach ($steps as $step) {
1130
+            $queue->add('OC\Migration\BackgroundRepair', [
1131
+                'app' => $appId,
1132
+                'step' => $step]);
1133
+        }
1134
+    }
1135
+
1136
+    /**
1137
+     * @param string $appId
1138
+     * @return \OC\Files\View|false
1139
+     */
1140
+    public static function getStorage($appId) {
1141
+        if (OC_App::isEnabled($appId)) { //sanity check
1142
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1143
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1144
+                if (!$view->file_exists($appId)) {
1145
+                    $view->mkdir($appId);
1146
+                }
1147
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1148
+            } else {
1149
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1150
+                return false;
1151
+            }
1152
+        } else {
1153
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1154
+            return false;
1155
+        }
1156
+    }
1157
+
1158
+    protected static function findBestL10NOption($options, $lang) {
1159
+        $fallback = $similarLangFallback = $englishFallback = false;
1160
+
1161
+        $lang = strtolower($lang);
1162
+        $similarLang = $lang;
1163
+        if (strpos($similarLang, '_')) {
1164
+            // For "de_DE" we want to find "de" and the other way around
1165
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1166
+        }
1167
+
1168
+        foreach ($options as $option) {
1169
+            if (is_array($option)) {
1170
+                if ($fallback === false) {
1171
+                    $fallback = $option['@value'];
1172
+                }
1173
+
1174
+                if (!isset($option['@attributes']['lang'])) {
1175
+                    continue;
1176
+                }
1177
+
1178
+                $attributeLang = strtolower($option['@attributes']['lang']);
1179
+                if ($attributeLang === $lang) {
1180
+                    return $option['@value'];
1181
+                }
1182
+
1183
+                if ($attributeLang === $similarLang) {
1184
+                    $similarLangFallback = $option['@value'];
1185
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1186
+                    if ($similarLangFallback === false) {
1187
+                        $similarLangFallback =  $option['@value'];
1188
+                    }
1189
+                }
1190
+            } else {
1191
+                $englishFallback = $option;
1192
+            }
1193
+        }
1194
+
1195
+        if ($similarLangFallback !== false) {
1196
+            return $similarLangFallback;
1197
+        } else if ($englishFallback !== false) {
1198
+            return $englishFallback;
1199
+        }
1200
+        return (string) $fallback;
1201
+    }
1202
+
1203
+    /**
1204
+     * parses the app data array and enhanced the 'description' value
1205
+     *
1206
+     * @param array $data the app data
1207
+     * @param string $lang
1208
+     * @return array improved app data
1209
+     */
1210
+    public static function parseAppInfo(array $data, $lang = null) {
1211
+
1212
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1213
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1214
+        }
1215
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1216
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1217
+        }
1218
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1219
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1220
+        } else if (isset($data['description']) && is_string($data['description'])) {
1221
+            $data['description'] = trim($data['description']);
1222
+        } else  {
1223
+            $data['description'] = '';
1224
+        }
1225
+
1226
+        return $data;
1227
+    }
1228
+
1229
+    /**
1230
+     * @param \OCP\IConfig $config
1231
+     * @param \OCP\IL10N $l
1232
+     * @param array $info
1233
+     * @throws \Exception
1234
+     */
1235
+    public static function checkAppDependencies($config, $l, $info) {
1236
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1237
+        $missing = $dependencyAnalyzer->analyze($info);
1238
+        if (!empty($missing)) {
1239
+            $missingMsg = join(PHP_EOL, $missing);
1240
+            throw new \Exception(
1241
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1242
+                    [$info['name'], $missingMsg]
1243
+                )
1244
+            );
1245
+        }
1246
+    }
1247 1247
 }
Please login to merge, or discard this patch.
Spacing   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -110,9 +110,9 @@  discard block
 block discarded – undo
110 110
 		$apps = self::getEnabledApps();
111 111
 
112 112
 		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
113
+		foreach ($apps as $app) {
114 114
 			$path = self::getAppPath($app);
115
-			if($path !== false) {
115
+			if ($path !== false) {
116 116
 				self::registerAutoloading($app, $path);
117 117
 			}
118 118
 		}
@@ -137,15 +137,15 @@  discard block
 block discarded – undo
137 137
 	public static function loadApp($app) {
138 138
 		self::$loadedApps[] = $app;
139 139
 		$appPath = self::getAppPath($app);
140
-		if($appPath === false) {
140
+		if ($appPath === false) {
141 141
 			return;
142 142
 		}
143 143
 
144 144
 		// in case someone calls loadApp() directly
145 145
 		self::registerAutoloading($app, $appPath);
146 146
 
147
-		if (is_file($appPath . '/appinfo/app.php')) {
148
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
147
+		if (is_file($appPath.'/appinfo/app.php')) {
148
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
149 149
 			self::requireAppFile($app);
150 150
 			if (self::isType($app, array('authentication'))) {
151 151
 				// since authentication apps affect the "is app enabled for group" check,
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 				// enabled for groups
155 155
 				self::$enabledAppsCache = array();
156 156
 			}
157
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
157
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
158 158
 		}
159 159
 
160 160
 		$info = self::getAppInfo($app);
@@ -181,17 +181,17 @@  discard block
 block discarded – undo
181 181
 	 * @param string $path
182 182
 	 */
183 183
 	public static function registerAutoloading($app, $path) {
184
-		$key = $app . '-' . $path;
185
-		if(isset(self::$alreadyRegistered[$key])) {
184
+		$key = $app.'-'.$path;
185
+		if (isset(self::$alreadyRegistered[$key])) {
186 186
 			return;
187 187
 		}
188 188
 		self::$alreadyRegistered[$key] = true;
189 189
 		// Register on PSR-4 composer autoloader
190 190
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
191 191
 		\OC::$server->registerNamespace($app, $appNamespace);
192
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
192
+		\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
193 193
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
194
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
194
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
195 195
 		}
196 196
 
197 197
 		// Register on legacy autoloader
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 	private static function requireAppFile($app) {
207 207
 		try {
208 208
 			// encapsulated here to avoid variable scope conflicts
209
-			require_once $app . '/appinfo/app.php';
209
+			require_once $app.'/appinfo/app.php';
210 210
 		} catch (Error $ex) {
211 211
 			\OC::$server->getLogger()->logException($ex);
212 212
 			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
@@ -260,7 +260,7 @@  discard block
 block discarded – undo
260 260
 	 */
261 261
 	public static function setAppTypes($app) {
262 262
 		$appData = self::getAppInfo($app);
263
-		if(!is_array($appData)) {
263
+		if (!is_array($appData)) {
264 264
 			return;
265 265
 		}
266 266
 
@@ -324,8 +324,8 @@  discard block
 block discarded – undo
324 324
 		} else {
325 325
 			$apps = $appManager->getEnabledAppsForUser($user);
326 326
 		}
327
-		$apps = array_filter($apps, function ($app) {
328
-			return $app !== 'files';//we add this manually
327
+		$apps = array_filter($apps, function($app) {
328
+			return $app !== 'files'; //we add this manually
329 329
 		});
330 330
 		sort($apps);
331 331
 		array_unshift($apps, 'files');
@@ -368,7 +368,7 @@  discard block
 block discarded – undo
368 368
 		);
369 369
 		$isDownloaded = $installer->isDownloaded($appId);
370 370
 
371
-		if(!$isDownloaded) {
371
+		if (!$isDownloaded) {
372 372
 			$installer->downloadApp($appId);
373 373
 		}
374 374
 
@@ -487,7 +487,7 @@  discard block
 block discarded – undo
487 487
 	 */
488 488
 	public static function findAppInDirectories($appId) {
489 489
 		$sanitizedAppId = self::cleanAppId($appId);
490
-		if($sanitizedAppId !== $appId) {
490
+		if ($sanitizedAppId !== $appId) {
491 491
 			return false;
492 492
 		}
493 493
 		static $app_dir = array();
@@ -498,7 +498,7 @@  discard block
 block discarded – undo
498 498
 
499 499
 		$possibleApps = array();
500 500
 		foreach (OC::$APPSROOTS as $dir) {
501
-			if (file_exists($dir['path'] . '/' . $appId)) {
501
+			if (file_exists($dir['path'].'/'.$appId)) {
502 502
 				$possibleApps[] = $dir;
503 503
 			}
504 504
 		}
@@ -539,7 +539,7 @@  discard block
 block discarded – undo
539 539
 		}
540 540
 
541 541
 		if (($dir = self::findAppInDirectories($appId)) != false) {
542
-			return $dir['path'] . '/' . $appId;
542
+			return $dir['path'].'/'.$appId;
543 543
 		}
544 544
 		return false;
545 545
 	}
@@ -553,7 +553,7 @@  discard block
 block discarded – undo
553 553
 	 */
554 554
 	public static function getAppWebPath($appId) {
555 555
 		if (($dir = self::findAppInDirectories($appId)) != false) {
556
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
556
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
557 557
 		}
558 558
 		return false;
559 559
 	}
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
 	 * @return string
567 567
 	 */
568 568
 	public static function getAppVersion($appId, $useCache = true) {
569
-		if($useCache && isset(self::$appVersion[$appId])) {
569
+		if ($useCache && isset(self::$appVersion[$appId])) {
570 570
 			return self::$appVersion[$appId];
571 571
 		}
572 572
 
@@ -582,7 +582,7 @@  discard block
 block discarded – undo
582 582
 	 * @return string
583 583
 	 */
584 584
 	public static function getAppVersionByPath($path) {
585
-		$infoFile = $path . '/appinfo/info.xml';
585
+		$infoFile = $path.'/appinfo/info.xml';
586 586
 		$appData = self::getAppInfo($infoFile, true);
587 587
 		return isset($appData['version']) ? $appData['version'] : '';
588 588
 	}
@@ -605,10 +605,10 @@  discard block
 block discarded – undo
605 605
 				return self::$appInfo[$appId];
606 606
 			}
607 607
 			$appPath = self::getAppPath($appId);
608
-			if($appPath === false) {
608
+			if ($appPath === false) {
609 609
 				return null;
610 610
 			}
611
-			$file = $appPath . '/appinfo/info.xml';
611
+			$file = $appPath.'/appinfo/info.xml';
612 612
 		}
613 613
 
614 614
 		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
@@ -617,9 +617,9 @@  discard block
 block discarded – undo
617 617
 		if (is_array($data)) {
618 618
 			$data = OC_App::parseAppInfo($data, $lang);
619 619
 		}
620
-		if(isset($data['ocsid'])) {
620
+		if (isset($data['ocsid'])) {
621 621
 			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
622
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
622
+			if ($storedId !== '' && $storedId !== $data['ocsid']) {
623 623
 				$data['ocsid'] = $storedId;
624 624
 			}
625 625
 		}
@@ -711,7 +711,7 @@  discard block
 block discarded – undo
711 711
 	 * @param string $page
712 712
 	 */
713 713
 	public static function registerAdmin($app, $page) {
714
-		self::$adminForms[] = $app . '/' . $page . '.php';
714
+		self::$adminForms[] = $app.'/'.$page.'.php';
715 715
 	}
716 716
 
717 717
 	/**
@@ -720,7 +720,7 @@  discard block
 block discarded – undo
720 720
 	 * @param string $page
721 721
 	 */
722 722
 	public static function registerPersonal($app, $page) {
723
-		self::$personalForms[] = $app . '/' . $page . '.php';
723
+		self::$personalForms[] = $app.'/'.$page.'.php';
724 724
 	}
725 725
 
726 726
 	/**
@@ -749,7 +749,7 @@  discard block
 block discarded – undo
749 749
 
750 750
 		foreach (OC::$APPSROOTS as $apps_dir) {
751 751
 			if (!is_readable($apps_dir['path'])) {
752
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
752
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
753 753
 				continue;
754 754
 			}
755 755
 			$dh = opendir($apps_dir['path']);
@@ -757,7 +757,7 @@  discard block
 block discarded – undo
757 757
 			if (is_resource($dh)) {
758 758
 				while (($file = readdir($dh)) !== false) {
759 759
 
760
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
760
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
761 761
 
762 762
 						$apps[] = $file;
763 763
 					}
@@ -787,12 +787,12 @@  discard block
 block discarded – undo
787 787
 
788 788
 				$info = OC_App::getAppInfo($app, false, $langCode);
789 789
 				if (!is_array($info)) {
790
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
790
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
791 791
 					continue;
792 792
 				}
793 793
 
794 794
 				if (!isset($info['name'])) {
795
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
795
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
796 796
 					continue;
797 797
 				}
798 798
 
@@ -819,13 +819,13 @@  discard block
 block discarded – undo
819 819
 				}
820 820
 
821 821
 				$appPath = self::getAppPath($app);
822
-				if($appPath !== false) {
823
-					$appIcon = $appPath . '/img/' . $app . '.svg';
822
+				if ($appPath !== false) {
823
+					$appIcon = $appPath.'/img/'.$app.'.svg';
824 824
 					if (file_exists($appIcon)) {
825
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
825
+						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app.'.svg');
826 826
 						$info['previewAsIcon'] = true;
827 827
 					} else {
828
-						$appIcon = $appPath . '/img/app.svg';
828
+						$appIcon = $appPath.'/img/app.svg';
829 829
 						if (file_exists($appIcon)) {
830 830
 							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
831 831
 							$info['previewAsIcon'] = true;
@@ -859,9 +859,9 @@  discard block
 block discarded – undo
859 859
 	 * @return string|false
860 860
 	 */
861 861
 	public static function getInternalAppIdByOcs($ocsID) {
862
-		if(is_numeric($ocsID)) {
862
+		if (is_numeric($ocsID)) {
863 863
 			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
864
-			if(array_search($ocsID, $idArray)) {
864
+			if (array_search($ocsID, $idArray)) {
865 865
 				return array_search($ocsID, $idArray);
866 866
 			}
867 867
 		}
@@ -965,7 +965,7 @@  discard block
 block discarded – undo
965 965
 	public static function getAppVersions() {
966 966
 		static $versions;
967 967
 
968
-		if(!$versions) {
968
+		if (!$versions) {
969 969
 			$appConfig = \OC::$server->getAppConfig();
970 970
 			$versions = $appConfig->getValues(false, 'installed_version');
971 971
 		}
@@ -987,7 +987,7 @@  discard block
 block discarded – undo
987 987
 		if ($app !== false) {
988 988
 			// check if the app is compatible with this version of ownCloud
989 989
 			$info = self::getAppInfo($app);
990
-			if(!is_array($info)) {
990
+			if (!is_array($info)) {
991 991
 				throw new \Exception(
992 992
 					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
993 993
 						[$info['name']]
@@ -1012,7 +1012,7 @@  discard block
 block discarded – undo
1012 1012
 				$config->setAppValue($app, 'ocsid', $appData['id']);
1013 1013
 			}
1014 1014
 
1015
-			if(isset($info['settings']) && is_array($info['settings'])) {
1015
+			if (isset($info['settings']) && is_array($info['settings'])) {
1016 1016
 				$appPath = self::getAppPath($app);
1017 1017
 				self::registerAutoloading($app, $appPath);
1018 1018
 				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -1020,7 +1020,7 @@  discard block
 block discarded – undo
1020 1020
 
1021 1021
 			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1022 1022
 		} else {
1023
-			if(empty($appName) ) {
1023
+			if (empty($appName)) {
1024 1024
 				throw new \Exception($l->t("No app name specified"));
1025 1025
 			} else {
1026 1026
 				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
@@ -1038,39 +1038,39 @@  discard block
 block discarded – undo
1038 1038
 	 */
1039 1039
 	public static function updateApp($appId) {
1040 1040
 		$appPath = self::getAppPath($appId);
1041
-		if($appPath === false) {
1041
+		if ($appPath === false) {
1042 1042
 			return false;
1043 1043
 		}
1044 1044
 		$appData = self::getAppInfo($appId);
1045 1045
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1046
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1047
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1046
+		if (file_exists($appPath.'/appinfo/database.xml')) {
1047
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
1048 1048
 		}
1049 1049
 		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1050 1050
 		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1051 1051
 		unset(self::$appVersion[$appId]);
1052 1052
 		// run upgrade code
1053
-		if (file_exists($appPath . '/appinfo/update.php')) {
1053
+		if (file_exists($appPath.'/appinfo/update.php')) {
1054 1054
 			self::loadApp($appId);
1055
-			include $appPath . '/appinfo/update.php';
1055
+			include $appPath.'/appinfo/update.php';
1056 1056
 		}
1057 1057
 		self::registerAutoloading($appId, $appPath);
1058 1058
 		self::setupBackgroundJobs($appData['background-jobs']);
1059
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1059
+		if (isset($appData['settings']) && is_array($appData['settings'])) {
1060 1060
 			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1061 1061
 		}
1062 1062
 
1063 1063
 		//set remote/public handlers
1064 1064
 		if (array_key_exists('ocsid', $appData)) {
1065 1065
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1066
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1066
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1067 1067
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1068 1068
 		}
1069 1069
 		foreach ($appData['remote'] as $name => $path) {
1070
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1070
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
1071 1071
 		}
1072 1072
 		foreach ($appData['public'] as $name => $path) {
1073
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1073
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
1074 1074
 		}
1075 1075
 
1076 1076
 		self::setAppTypes($appId);
@@ -1140,17 +1140,17 @@  discard block
 block discarded – undo
1140 1140
 	public static function getStorage($appId) {
1141 1141
 		if (OC_App::isEnabled($appId)) { //sanity check
1142 1142
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
1143
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1143
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1144 1144
 				if (!$view->file_exists($appId)) {
1145 1145
 					$view->mkdir($appId);
1146 1146
 				}
1147
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1147
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1148 1148
 			} else {
1149
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1149
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1150 1150
 				return false;
1151 1151
 			}
1152 1152
 		} else {
1153
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1153
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1154 1154
 			return false;
1155 1155
 		}
1156 1156
 	}
@@ -1182,9 +1182,9 @@  discard block
 block discarded – undo
1182 1182
 
1183 1183
 				if ($attributeLang === $similarLang) {
1184 1184
 					$similarLangFallback = $option['@value'];
1185
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1185
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1186 1186
 					if ($similarLangFallback === false) {
1187
-						$similarLangFallback =  $option['@value'];
1187
+						$similarLangFallback = $option['@value'];
1188 1188
 					}
1189 1189
 				}
1190 1190
 			} else {
@@ -1219,7 +1219,7 @@  discard block
 block discarded – undo
1219 1219
 			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1220 1220
 		} else if (isset($data['description']) && is_string($data['description'])) {
1221 1221
 			$data['description'] = trim($data['description']);
1222
-		} else  {
1222
+		} else {
1223 1223
 			$data['description'] = '';
1224 1224
 		}
1225 1225
 
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   +395 added lines, -395 removed lines patch added patch discarded remove patch
@@ -36,399 +36,399 @@
 block discarded – undo
36 36
 use OCP\Files\Search\ISearchOperator;
37 37
 
38 38
 class Folder extends Node implements \OCP\Files\Folder {
39
-	/**
40
-	 * Creates a Folder that represents a non-existing path
41
-	 *
42
-	 * @param string $path path
43
-	 * @return string non-existing node class
44
-	 */
45
-	protected function createNonExistingNode($path) {
46
-		return new NonExistingFolder($this->root, $this->view, $path);
47
-	}
48
-
49
-	/**
50
-	 * @param string $path path relative to the folder
51
-	 * @return string
52
-	 * @throws \OCP\Files\NotPermittedException
53
-	 */
54
-	public function getFullPath($path) {
55
-		if (!$this->isValidPath($path)) {
56
-			throw new NotPermittedException('Invalid path');
57
-		}
58
-		return $this->path . $this->normalizePath($path);
59
-	}
60
-
61
-	/**
62
-	 * @param string $path
63
-	 * @return string
64
-	 */
65
-	public function getRelativePath($path) {
66
-		if ($this->path === '' or $this->path === '/') {
67
-			return $this->normalizePath($path);
68
-		}
69
-		if ($path === $this->path) {
70
-			return '/';
71
-		} else if (strpos($path, $this->path . '/') !== 0) {
72
-			return null;
73
-		} else {
74
-			$path = substr($path, strlen($this->path));
75
-			return $this->normalizePath($path);
76
-		}
77
-	}
78
-
79
-	/**
80
-	 * check if a node is a (grand-)child of the folder
81
-	 *
82
-	 * @param \OC\Files\Node\Node $node
83
-	 * @return bool
84
-	 */
85
-	public function isSubNode($node) {
86
-		return strpos($node->getPath(), $this->path . '/') === 0;
87
-	}
88
-
89
-	/**
90
-	 * get the content of this directory
91
-	 *
92
-	 * @throws \OCP\Files\NotFoundException
93
-	 * @return Node[]
94
-	 */
95
-	public function getDirectoryListing() {
96
-		$folderContent = $this->view->getDirectoryContent($this->path);
97
-
98
-		return array_map(function (FileInfo $info) {
99
-			if ($info->getMimetype() === 'httpd/unix-directory') {
100
-				return new Folder($this->root, $this->view, $info->getPath(), $info);
101
-			} else {
102
-				return new File($this->root, $this->view, $info->getPath(), $info);
103
-			}
104
-		}, $folderContent);
105
-	}
106
-
107
-	/**
108
-	 * @param string $path
109
-	 * @param FileInfo $info
110
-	 * @return File|Folder
111
-	 */
112
-	protected function createNode($path, FileInfo $info = null) {
113
-		if (is_null($info)) {
114
-			$isDir = $this->view->is_dir($path);
115
-		} else {
116
-			$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
117
-		}
118
-		if ($isDir) {
119
-			return new Folder($this->root, $this->view, $path, $info);
120
-		} else {
121
-			return new File($this->root, $this->view, $path, $info);
122
-		}
123
-	}
124
-
125
-	/**
126
-	 * Get the node at $path
127
-	 *
128
-	 * @param string $path
129
-	 * @return \OC\Files\Node\Node
130
-	 * @throws \OCP\Files\NotFoundException
131
-	 */
132
-	public function get($path) {
133
-		return $this->root->get($this->getFullPath($path));
134
-	}
135
-
136
-	/**
137
-	 * @param string $path
138
-	 * @return bool
139
-	 */
140
-	public function nodeExists($path) {
141
-		try {
142
-			$this->get($path);
143
-			return true;
144
-		} catch (NotFoundException $e) {
145
-			return false;
146
-		}
147
-	}
148
-
149
-	/**
150
-	 * @param string $path
151
-	 * @return \OC\Files\Node\Folder
152
-	 * @throws \OCP\Files\NotPermittedException
153
-	 */
154
-	public function newFolder($path) {
155
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
156
-			$fullPath = $this->getFullPath($path);
157
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
158
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
159
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
160
-			$this->view->mkdir($fullPath);
161
-			$node = new Folder($this->root, $this->view, $fullPath);
162
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
163
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
164
-			return $node;
165
-		} else {
166
-			throw new NotPermittedException('No create permission for folder');
167
-		}
168
-	}
169
-
170
-	/**
171
-	 * @param string $path
172
-	 * @return \OC\Files\Node\File
173
-	 * @throws \OCP\Files\NotPermittedException
174
-	 */
175
-	public function newFile($path) {
176
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
177
-			$fullPath = $this->getFullPath($path);
178
-			$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
179
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
180
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
181
-			$this->view->touch($fullPath);
182
-			$node = new File($this->root, $this->view, $fullPath);
183
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
184
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
185
-			return $node;
186
-		} else {
187
-			throw new NotPermittedException('No create permission for path');
188
-		}
189
-	}
190
-
191
-	/**
192
-	 * search for files with the name matching $query
193
-	 *
194
-	 * @param string|ISearchOperator $query
195
-	 * @return \OC\Files\Node\Node[]
196
-	 */
197
-	public function search($query) {
198
-		if (is_string($query)) {
199
-			return $this->searchCommon('search', array('%' . $query . '%'));
200
-		} else {
201
-			return $this->searchCommon('searchQuery', array($query));
202
-		}
203
-	}
204
-
205
-	/**
206
-	 * search for files by mimetype
207
-	 *
208
-	 * @param string $mimetype
209
-	 * @return Node[]
210
-	 */
211
-	public function searchByMime($mimetype) {
212
-		return $this->searchCommon('searchByMime', array($mimetype));
213
-	}
214
-
215
-	/**
216
-	 * search for files by tag
217
-	 *
218
-	 * @param string|int $tag name or tag id
219
-	 * @param string $userId owner of the tags
220
-	 * @return Node[]
221
-	 */
222
-	public function searchByTag($tag, $userId) {
223
-		return $this->searchCommon('searchByTag', array($tag, $userId));
224
-	}
225
-
226
-	/**
227
-	 * @param string $method cache method
228
-	 * @param array $args call args
229
-	 * @return \OC\Files\Node\Node[]
230
-	 */
231
-	private function searchCommon($method, $args) {
232
-		$files = array();
233
-		$rootLength = strlen($this->path);
234
-		$mount = $this->root->getMount($this->path);
235
-		$storage = $mount->getStorage();
236
-		$internalPath = $mount->getInternalPath($this->path);
237
-		$internalPath = rtrim($internalPath, '/');
238
-		if ($internalPath !== '') {
239
-			$internalPath = $internalPath . '/';
240
-		}
241
-		$internalRootLength = strlen($internalPath);
242
-
243
-		$cache = $storage->getCache('');
244
-
245
-		$results = call_user_func_array(array($cache, $method), $args);
246
-		foreach ($results as $result) {
247
-			if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
248
-				$result['internalPath'] = $result['path'];
249
-				$result['path'] = substr($result['path'], $internalRootLength);
250
-				$result['storage'] = $storage;
251
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
252
-			}
253
-		}
254
-
255
-		$mounts = $this->root->getMountsIn($this->path);
256
-		foreach ($mounts as $mount) {
257
-			$storage = $mount->getStorage();
258
-			if ($storage) {
259
-				$cache = $storage->getCache('');
260
-
261
-				$relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
262
-				$results = call_user_func_array(array($cache, $method), $args);
263
-				foreach ($results as $result) {
264
-					$result['internalPath'] = $result['path'];
265
-					$result['path'] = $relativeMountPoint . $result['path'];
266
-					$result['storage'] = $storage;
267
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
-				}
269
-			}
270
-		}
271
-
272
-		return array_map(function (FileInfo $file) {
273
-			return $this->createNode($file->getPath(), $file);
274
-		}, $files);
275
-	}
276
-
277
-	/**
278
-	 * @param int $id
279
-	 * @return \OC\Files\Node\Node[]
280
-	 */
281
-	public function getById($id) {
282
-		$mountCache = $this->root->getUserMountCache();
283
-		if (strpos($this->getPath(), '/', 1) > 0) {
284
-			list(, $user) = explode('/', $this->getPath());
285
-		} else {
286
-			$user = null;
287
-		}
288
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
289
-		$mounts = $this->root->getMountsIn($this->path);
290
-		$mounts[] = $this->root->getMount($this->path);
291
-		/** @var IMountPoint[] $folderMounts */
292
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
293
-			return $mountPoint->getMountPoint();
294
-		}, $mounts), $mounts);
295
-
296
-		/** @var ICachedMountInfo[] $mountsContainingFile */
297
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298
-			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299
-		}));
300
-
301
-		if (count($mountsContainingFile) === 0) {
302
-			return [];
303
-		}
304
-
305
-		// we only need to get the cache info once, since all mounts we found point to the same storage
306
-
307
-		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
309
-		if (!$cacheEntry) {
310
-			return [];
311
-		}
312
-		// cache jails will hide the "true" internal path
313
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
314
-
315
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316
-			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317
-			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318
-			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
320
-			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321
-				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322
-				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323
-			));
324
-		}, $mountsContainingFile);
325
-
326
-		return array_filter($nodes, function (Node $node) {
327
-			return $this->getRelativePath($node->getPath());
328
-		});
329
-	}
330
-
331
-	public function getFreeSpace() {
332
-		return $this->view->free_space($this->path);
333
-	}
334
-
335
-	public function delete() {
336
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
337
-			$this->sendHooks(array('preDelete'));
338
-			$fileInfo = $this->getFileInfo();
339
-			$this->view->rmdir($this->path);
340
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
341
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
342
-			$this->exists = false;
343
-		} else {
344
-			throw new NotPermittedException('No delete permission for path');
345
-		}
346
-	}
347
-
348
-	/**
349
-	 * Add a suffix to the name in case the file exists
350
-	 *
351
-	 * @param string $name
352
-	 * @return string
353
-	 * @throws NotPermittedException
354
-	 */
355
-	public function getNonExistingName($name) {
356
-		$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
357
-		return trim($this->getRelativePath($uniqueName), '/');
358
-	}
359
-
360
-	/**
361
-	 * @param int $limit
362
-	 * @param int $offset
363
-	 * @return \OCP\Files\Node[]
364
-	 */
365
-	public function getRecent($limit, $offset = 0) {
366
-		$mimetypeLoader = \OC::$server->getMimeTypeLoader();
367
-		$mounts = $this->root->getMountsIn($this->path);
368
-		$mounts[] = $this->getMountPoint();
369
-
370
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
371
-			return $mount->getStorage();
372
-		});
373
-		$storageIds = array_map(function (IMountPoint $mount) {
374
-			return $mount->getStorage()->getCache()->getNumericStorageId();
375
-		}, $mounts);
376
-		/** @var IMountPoint[] $mountMap */
377
-		$mountMap = array_combine($storageIds, $mounts);
378
-		$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
379
-
380
-		//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)
381
-
382
-		$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
383
-		$query = $builder
384
-			->select('f.*')
385
-			->from('filecache', 'f')
386
-			->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
387
-			->andWhere($builder->expr()->orX(
388
-			// handle non empty folders separate
389
-				$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
390
-				$builder->expr()->eq('f.size', new Literal(0))
391
-			))
392
-			->orderBy('f.mtime', 'DESC')
393
-			->setMaxResults($limit)
394
-			->setFirstResult($offset);
395
-
396
-		$result = $query->execute()->fetchAll();
397
-
398
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
399
-			$mount = $mountMap[$entry['storage']];
400
-			$entry['internalPath'] = $entry['path'];
401
-			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
402
-			$entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
403
-			$path = $this->getAbsolutePath($mount, $entry['path']);
404
-			if (is_null($path)) {
405
-				return null;
406
-			}
407
-			$fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
408
-			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409
-		}, $result));
410
-
411
-		return array_values(array_filter($files, function (Node $node) {
412
-			$relative = $this->getRelativePath($node->getPath());
413
-			return $relative !== null && $relative !== '/';
414
-		}));
415
-	}
416
-
417
-	private function getAbsolutePath(IMountPoint $mount, $path) {
418
-		$storage = $mount->getStorage();
419
-		if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
420
-			/** @var \OC\Files\Storage\Wrapper\Jail $storage */
421
-			$jailRoot = $storage->getUnjailedPath('');
422
-			$rootLength = strlen($jailRoot) + 1;
423
-			if ($path === $jailRoot) {
424
-				return $mount->getMountPoint();
425
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
-				return $mount->getMountPoint() . substr($path, $rootLength);
427
-			} else {
428
-				return null;
429
-			}
430
-		} else {
431
-			return $mount->getMountPoint() . $path;
432
-		}
433
-	}
39
+    /**
40
+     * Creates a Folder that represents a non-existing path
41
+     *
42
+     * @param string $path path
43
+     * @return string non-existing node class
44
+     */
45
+    protected function createNonExistingNode($path) {
46
+        return new NonExistingFolder($this->root, $this->view, $path);
47
+    }
48
+
49
+    /**
50
+     * @param string $path path relative to the folder
51
+     * @return string
52
+     * @throws \OCP\Files\NotPermittedException
53
+     */
54
+    public function getFullPath($path) {
55
+        if (!$this->isValidPath($path)) {
56
+            throw new NotPermittedException('Invalid path');
57
+        }
58
+        return $this->path . $this->normalizePath($path);
59
+    }
60
+
61
+    /**
62
+     * @param string $path
63
+     * @return string
64
+     */
65
+    public function getRelativePath($path) {
66
+        if ($this->path === '' or $this->path === '/') {
67
+            return $this->normalizePath($path);
68
+        }
69
+        if ($path === $this->path) {
70
+            return '/';
71
+        } else if (strpos($path, $this->path . '/') !== 0) {
72
+            return null;
73
+        } else {
74
+            $path = substr($path, strlen($this->path));
75
+            return $this->normalizePath($path);
76
+        }
77
+    }
78
+
79
+    /**
80
+     * check if a node is a (grand-)child of the folder
81
+     *
82
+     * @param \OC\Files\Node\Node $node
83
+     * @return bool
84
+     */
85
+    public function isSubNode($node) {
86
+        return strpos($node->getPath(), $this->path . '/') === 0;
87
+    }
88
+
89
+    /**
90
+     * get the content of this directory
91
+     *
92
+     * @throws \OCP\Files\NotFoundException
93
+     * @return Node[]
94
+     */
95
+    public function getDirectoryListing() {
96
+        $folderContent = $this->view->getDirectoryContent($this->path);
97
+
98
+        return array_map(function (FileInfo $info) {
99
+            if ($info->getMimetype() === 'httpd/unix-directory') {
100
+                return new Folder($this->root, $this->view, $info->getPath(), $info);
101
+            } else {
102
+                return new File($this->root, $this->view, $info->getPath(), $info);
103
+            }
104
+        }, $folderContent);
105
+    }
106
+
107
+    /**
108
+     * @param string $path
109
+     * @param FileInfo $info
110
+     * @return File|Folder
111
+     */
112
+    protected function createNode($path, FileInfo $info = null) {
113
+        if (is_null($info)) {
114
+            $isDir = $this->view->is_dir($path);
115
+        } else {
116
+            $isDir = $info->getType() === FileInfo::TYPE_FOLDER;
117
+        }
118
+        if ($isDir) {
119
+            return new Folder($this->root, $this->view, $path, $info);
120
+        } else {
121
+            return new File($this->root, $this->view, $path, $info);
122
+        }
123
+    }
124
+
125
+    /**
126
+     * Get the node at $path
127
+     *
128
+     * @param string $path
129
+     * @return \OC\Files\Node\Node
130
+     * @throws \OCP\Files\NotFoundException
131
+     */
132
+    public function get($path) {
133
+        return $this->root->get($this->getFullPath($path));
134
+    }
135
+
136
+    /**
137
+     * @param string $path
138
+     * @return bool
139
+     */
140
+    public function nodeExists($path) {
141
+        try {
142
+            $this->get($path);
143
+            return true;
144
+        } catch (NotFoundException $e) {
145
+            return false;
146
+        }
147
+    }
148
+
149
+    /**
150
+     * @param string $path
151
+     * @return \OC\Files\Node\Folder
152
+     * @throws \OCP\Files\NotPermittedException
153
+     */
154
+    public function newFolder($path) {
155
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
156
+            $fullPath = $this->getFullPath($path);
157
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
158
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
159
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
160
+            $this->view->mkdir($fullPath);
161
+            $node = new Folder($this->root, $this->view, $fullPath);
162
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
163
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
164
+            return $node;
165
+        } else {
166
+            throw new NotPermittedException('No create permission for folder');
167
+        }
168
+    }
169
+
170
+    /**
171
+     * @param string $path
172
+     * @return \OC\Files\Node\File
173
+     * @throws \OCP\Files\NotPermittedException
174
+     */
175
+    public function newFile($path) {
176
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
177
+            $fullPath = $this->getFullPath($path);
178
+            $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
179
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
180
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
181
+            $this->view->touch($fullPath);
182
+            $node = new File($this->root, $this->view, $fullPath);
183
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
184
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
185
+            return $node;
186
+        } else {
187
+            throw new NotPermittedException('No create permission for path');
188
+        }
189
+    }
190
+
191
+    /**
192
+     * search for files with the name matching $query
193
+     *
194
+     * @param string|ISearchOperator $query
195
+     * @return \OC\Files\Node\Node[]
196
+     */
197
+    public function search($query) {
198
+        if (is_string($query)) {
199
+            return $this->searchCommon('search', array('%' . $query . '%'));
200
+        } else {
201
+            return $this->searchCommon('searchQuery', array($query));
202
+        }
203
+    }
204
+
205
+    /**
206
+     * search for files by mimetype
207
+     *
208
+     * @param string $mimetype
209
+     * @return Node[]
210
+     */
211
+    public function searchByMime($mimetype) {
212
+        return $this->searchCommon('searchByMime', array($mimetype));
213
+    }
214
+
215
+    /**
216
+     * search for files by tag
217
+     *
218
+     * @param string|int $tag name or tag id
219
+     * @param string $userId owner of the tags
220
+     * @return Node[]
221
+     */
222
+    public function searchByTag($tag, $userId) {
223
+        return $this->searchCommon('searchByTag', array($tag, $userId));
224
+    }
225
+
226
+    /**
227
+     * @param string $method cache method
228
+     * @param array $args call args
229
+     * @return \OC\Files\Node\Node[]
230
+     */
231
+    private function searchCommon($method, $args) {
232
+        $files = array();
233
+        $rootLength = strlen($this->path);
234
+        $mount = $this->root->getMount($this->path);
235
+        $storage = $mount->getStorage();
236
+        $internalPath = $mount->getInternalPath($this->path);
237
+        $internalPath = rtrim($internalPath, '/');
238
+        if ($internalPath !== '') {
239
+            $internalPath = $internalPath . '/';
240
+        }
241
+        $internalRootLength = strlen($internalPath);
242
+
243
+        $cache = $storage->getCache('');
244
+
245
+        $results = call_user_func_array(array($cache, $method), $args);
246
+        foreach ($results as $result) {
247
+            if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
248
+                $result['internalPath'] = $result['path'];
249
+                $result['path'] = substr($result['path'], $internalRootLength);
250
+                $result['storage'] = $storage;
251
+                $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
252
+            }
253
+        }
254
+
255
+        $mounts = $this->root->getMountsIn($this->path);
256
+        foreach ($mounts as $mount) {
257
+            $storage = $mount->getStorage();
258
+            if ($storage) {
259
+                $cache = $storage->getCache('');
260
+
261
+                $relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
262
+                $results = call_user_func_array(array($cache, $method), $args);
263
+                foreach ($results as $result) {
264
+                    $result['internalPath'] = $result['path'];
265
+                    $result['path'] = $relativeMountPoint . $result['path'];
266
+                    $result['storage'] = $storage;
267
+                    $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
+                }
269
+            }
270
+        }
271
+
272
+        return array_map(function (FileInfo $file) {
273
+            return $this->createNode($file->getPath(), $file);
274
+        }, $files);
275
+    }
276
+
277
+    /**
278
+     * @param int $id
279
+     * @return \OC\Files\Node\Node[]
280
+     */
281
+    public function getById($id) {
282
+        $mountCache = $this->root->getUserMountCache();
283
+        if (strpos($this->getPath(), '/', 1) > 0) {
284
+            list(, $user) = explode('/', $this->getPath());
285
+        } else {
286
+            $user = null;
287
+        }
288
+        $mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
289
+        $mounts = $this->root->getMountsIn($this->path);
290
+        $mounts[] = $this->root->getMount($this->path);
291
+        /** @var IMountPoint[] $folderMounts */
292
+        $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
293
+            return $mountPoint->getMountPoint();
294
+        }, $mounts), $mounts);
295
+
296
+        /** @var ICachedMountInfo[] $mountsContainingFile */
297
+        $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298
+            return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299
+        }));
300
+
301
+        if (count($mountsContainingFile) === 0) {
302
+            return [];
303
+        }
304
+
305
+        // we only need to get the cache info once, since all mounts we found point to the same storage
306
+
307
+        $mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
+        $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
309
+        if (!$cacheEntry) {
310
+            return [];
311
+        }
312
+        // cache jails will hide the "true" internal path
313
+        $internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
314
+
315
+        $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316
+            $mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317
+            $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318
+            $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
+            $absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
320
+            return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321
+                $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322
+                \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323
+            ));
324
+        }, $mountsContainingFile);
325
+
326
+        return array_filter($nodes, function (Node $node) {
327
+            return $this->getRelativePath($node->getPath());
328
+        });
329
+    }
330
+
331
+    public function getFreeSpace() {
332
+        return $this->view->free_space($this->path);
333
+    }
334
+
335
+    public function delete() {
336
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
337
+            $this->sendHooks(array('preDelete'));
338
+            $fileInfo = $this->getFileInfo();
339
+            $this->view->rmdir($this->path);
340
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
341
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
342
+            $this->exists = false;
343
+        } else {
344
+            throw new NotPermittedException('No delete permission for path');
345
+        }
346
+    }
347
+
348
+    /**
349
+     * Add a suffix to the name in case the file exists
350
+     *
351
+     * @param string $name
352
+     * @return string
353
+     * @throws NotPermittedException
354
+     */
355
+    public function getNonExistingName($name) {
356
+        $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
357
+        return trim($this->getRelativePath($uniqueName), '/');
358
+    }
359
+
360
+    /**
361
+     * @param int $limit
362
+     * @param int $offset
363
+     * @return \OCP\Files\Node[]
364
+     */
365
+    public function getRecent($limit, $offset = 0) {
366
+        $mimetypeLoader = \OC::$server->getMimeTypeLoader();
367
+        $mounts = $this->root->getMountsIn($this->path);
368
+        $mounts[] = $this->getMountPoint();
369
+
370
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
371
+            return $mount->getStorage();
372
+        });
373
+        $storageIds = array_map(function (IMountPoint $mount) {
374
+            return $mount->getStorage()->getCache()->getNumericStorageId();
375
+        }, $mounts);
376
+        /** @var IMountPoint[] $mountMap */
377
+        $mountMap = array_combine($storageIds, $mounts);
378
+        $folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
379
+
380
+        //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)
381
+
382
+        $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
383
+        $query = $builder
384
+            ->select('f.*')
385
+            ->from('filecache', 'f')
386
+            ->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
387
+            ->andWhere($builder->expr()->orX(
388
+            // handle non empty folders separate
389
+                $builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
390
+                $builder->expr()->eq('f.size', new Literal(0))
391
+            ))
392
+            ->orderBy('f.mtime', 'DESC')
393
+            ->setMaxResults($limit)
394
+            ->setFirstResult($offset);
395
+
396
+        $result = $query->execute()->fetchAll();
397
+
398
+        $files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
399
+            $mount = $mountMap[$entry['storage']];
400
+            $entry['internalPath'] = $entry['path'];
401
+            $entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
402
+            $entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
403
+            $path = $this->getAbsolutePath($mount, $entry['path']);
404
+            if (is_null($path)) {
405
+                return null;
406
+            }
407
+            $fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
408
+            return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409
+        }, $result));
410
+
411
+        return array_values(array_filter($files, function (Node $node) {
412
+            $relative = $this->getRelativePath($node->getPath());
413
+            return $relative !== null && $relative !== '/';
414
+        }));
415
+    }
416
+
417
+    private function getAbsolutePath(IMountPoint $mount, $path) {
418
+        $storage = $mount->getStorage();
419
+        if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
420
+            /** @var \OC\Files\Storage\Wrapper\Jail $storage */
421
+            $jailRoot = $storage->getUnjailedPath('');
422
+            $rootLength = strlen($jailRoot) + 1;
423
+            if ($path === $jailRoot) {
424
+                return $mount->getMountPoint();
425
+            } else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
+                return $mount->getMountPoint() . substr($path, $rootLength);
427
+            } else {
428
+                return null;
429
+            }
430
+        } else {
431
+            return $mount->getMountPoint() . $path;
432
+        }
433
+    }
434 434
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
 		if (!$this->isValidPath($path)) {
56 56
 			throw new NotPermittedException('Invalid path');
57 57
 		}
58
-		return $this->path . $this->normalizePath($path);
58
+		return $this->path.$this->normalizePath($path);
59 59
 	}
60 60
 
61 61
 	/**
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
 		}
69 69
 		if ($path === $this->path) {
70 70
 			return '/';
71
-		} else if (strpos($path, $this->path . '/') !== 0) {
71
+		} else if (strpos($path, $this->path.'/') !== 0) {
72 72
 			return null;
73 73
 		} else {
74 74
 			$path = substr($path, strlen($this->path));
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 	 * @return bool
84 84
 	 */
85 85
 	public function isSubNode($node) {
86
-		return strpos($node->getPath(), $this->path . '/') === 0;
86
+		return strpos($node->getPath(), $this->path.'/') === 0;
87 87
 	}
88 88
 
89 89
 	/**
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
 	public function getDirectoryListing() {
96 96
 		$folderContent = $this->view->getDirectoryContent($this->path);
97 97
 
98
-		return array_map(function (FileInfo $info) {
98
+		return array_map(function(FileInfo $info) {
99 99
 			if ($info->getMimetype() === 'httpd/unix-directory') {
100 100
 				return new Folder($this->root, $this->view, $info->getPath(), $info);
101 101
 			} else {
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
 	 */
197 197
 	public function search($query) {
198 198
 		if (is_string($query)) {
199
-			return $this->searchCommon('search', array('%' . $query . '%'));
199
+			return $this->searchCommon('search', array('%'.$query.'%'));
200 200
 		} else {
201 201
 			return $this->searchCommon('searchQuery', array($query));
202 202
 		}
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
 		$internalPath = $mount->getInternalPath($this->path);
237 237
 		$internalPath = rtrim($internalPath, '/');
238 238
 		if ($internalPath !== '') {
239
-			$internalPath = $internalPath . '/';
239
+			$internalPath = $internalPath.'/';
240 240
 		}
241 241
 		$internalRootLength = strlen($internalPath);
242 242
 
@@ -248,7 +248,7 @@  discard block
 block discarded – undo
248 248
 				$result['internalPath'] = $result['path'];
249 249
 				$result['path'] = substr($result['path'], $internalRootLength);
250 250
 				$result['storage'] = $storage;
251
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
251
+				$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
252 252
 			}
253 253
 		}
254 254
 
@@ -262,14 +262,14 @@  discard block
 block discarded – undo
262 262
 				$results = call_user_func_array(array($cache, $method), $args);
263 263
 				foreach ($results as $result) {
264 264
 					$result['internalPath'] = $result['path'];
265
-					$result['path'] = $relativeMountPoint . $result['path'];
265
+					$result['path'] = $relativeMountPoint.$result['path'];
266 266
 					$result['storage'] = $storage;
267
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
267
+					$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
268 268
 				}
269 269
 			}
270 270
 		}
271 271
 
272
-		return array_map(function (FileInfo $file) {
272
+		return array_map(function(FileInfo $file) {
273 273
 			return $this->createNode($file->getPath(), $file);
274 274
 		}, $files);
275 275
 	}
@@ -285,16 +285,16 @@  discard block
 block discarded – undo
285 285
 		} else {
286 286
 			$user = null;
287 287
 		}
288
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
288
+		$mountsContainingFile = $mountCache->getMountsForFileId((int) $id, $user);
289 289
 		$mounts = $this->root->getMountsIn($this->path);
290 290
 		$mounts[] = $this->root->getMount($this->path);
291 291
 		/** @var IMountPoint[] $folderMounts */
292
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
292
+		$folderMounts = array_combine(array_map(function(IMountPoint $mountPoint) {
293 293
 			return $mountPoint->getMountPoint();
294 294
 		}, $mounts), $mounts);
295 295
 
296 296
 		/** @var ICachedMountInfo[] $mountsContainingFile */
297
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
297
+		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function(ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298 298
 			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299 299
 		}));
300 300
 
@@ -305,25 +305,25 @@  discard block
 block discarded – undo
305 305
 		// we only need to get the cache info once, since all mounts we found point to the same storage
306 306
 
307 307
 		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
308
+		$cacheEntry = $mount->getStorage()->getCache()->get((int) $id);
309 309
 		if (!$cacheEntry) {
310 310
 			return [];
311 311
 		}
312 312
 		// cache jails will hide the "true" internal path
313
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
313
+		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath().'/'.$cacheEntry->getPath(), '/');
314 314
 
315
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
315
+		$nodes = array_map(function(ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316 316
 			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317 317
 			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318 318
 			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
319
+			$absolutePath = $cachedMountInfo->getMountPoint().$pathRelativeToMount;
320 320
 			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321 321
 				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322 322
 				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323 323
 			));
324 324
 		}, $mountsContainingFile);
325 325
 
326
-		return array_filter($nodes, function (Node $node) {
326
+		return array_filter($nodes, function(Node $node) {
327 327
 			return $this->getRelativePath($node->getPath());
328 328
 		});
329 329
 	}
@@ -367,10 +367,10 @@  discard block
 block discarded – undo
367 367
 		$mounts = $this->root->getMountsIn($this->path);
368 368
 		$mounts[] = $this->getMountPoint();
369 369
 
370
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
370
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
371 371
 			return $mount->getStorage();
372 372
 		});
373
-		$storageIds = array_map(function (IMountPoint $mount) {
373
+		$storageIds = array_map(function(IMountPoint $mount) {
374 374
 			return $mount->getStorage()->getCache()->getNumericStorageId();
375 375
 		}, $mounts);
376 376
 		/** @var IMountPoint[] $mountMap */
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 
396 396
 		$result = $query->execute()->fetchAll();
397 397
 
398
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
398
+		$files = array_filter(array_map(function(array $entry) use ($mountMap, $mimetypeLoader) {
399 399
 			$mount = $mountMap[$entry['storage']];
400 400
 			$entry['internalPath'] = $entry['path'];
401 401
 			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
@@ -408,7 +408,7 @@  discard block
 block discarded – undo
408 408
 			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409 409
 		}, $result));
410 410
 
411
-		return array_values(array_filter($files, function (Node $node) {
411
+		return array_values(array_filter($files, function(Node $node) {
412 412
 			$relative = $this->getRelativePath($node->getPath());
413 413
 			return $relative !== null && $relative !== '/';
414 414
 		}));
@@ -422,13 +422,13 @@  discard block
 block discarded – undo
422 422
 			$rootLength = strlen($jailRoot) + 1;
423 423
 			if ($path === $jailRoot) {
424 424
 				return $mount->getMountPoint();
425
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
-				return $mount->getMountPoint() . substr($path, $rootLength);
425
+			} else if (substr($path, 0, $rootLength) === $jailRoot.'/') {
426
+				return $mount->getMountPoint().substr($path, $rootLength);
427 427
 			} else {
428 428
 				return null;
429 429
 			}
430 430
 		} else {
431
-			return $mount->getMountPoint() . $path;
431
+			return $mount->getMountPoint().$path;
432 432
 		}
433 433
 	}
434 434
 }
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.