Completed
Push — master ( defc4b...3e0789 )
by Joas
14:23
created
lib/private/Files/ObjectStore/ObjectStoreStorage.php 2 patches
Indentation   +394 added lines, -394 removed lines patch added patch discarded remove patch
@@ -31,398 +31,398 @@
 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
-	private $logger;
50
-
51
-	public function __construct($params) {
52
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
53
-			$this->objectStore = $params['objectstore'];
54
-		} else {
55
-			throw new \Exception('missing IObjectStore instance');
56
-		}
57
-		if (isset($params['storageid'])) {
58
-			$this->id = 'object::store:' . $params['storageid'];
59
-		} else {
60
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
61
-		}
62
-		if (isset($params['objectPrefix'])) {
63
-			$this->objectPrefix = $params['objectPrefix'];
64
-		}
65
-		//initialize cache with root directory in cache
66
-		if (!$this->is_dir('/')) {
67
-			$this->mkdir('/');
68
-		}
69
-
70
-		$this->logger = \OC::$server->getLogger();
71
-	}
72
-
73
-	public function mkdir($path) {
74
-		$path = $this->normalizePath($path);
75
-
76
-		if ($this->file_exists($path)) {
77
-			return false;
78
-		}
79
-
80
-		$mTime = time();
81
-		$data = [
82
-			'mimetype' => 'httpd/unix-directory',
83
-			'size' => 0,
84
-			'mtime' => $mTime,
85
-			'storage_mtime' => $mTime,
86
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
87
-		];
88
-		if ($path === '') {
89
-			//create root on the fly
90
-			$data['etag'] = $this->getETag('');
91
-			$this->getCache()->put('', $data);
92
-			return true;
93
-		} else {
94
-			// if parent does not exist, create it
95
-			$parent = $this->normalizePath(dirname($path));
96
-			$parentType = $this->filetype($parent);
97
-			if ($parentType === false) {
98
-				if (!$this->mkdir($parent)) {
99
-					// something went wrong
100
-					return false;
101
-				}
102
-			} else if ($parentType === 'file') {
103
-				// parent is a file
104
-				return false;
105
-			}
106
-			// finally create the new dir
107
-			$mTime = time(); // update mtime
108
-			$data['mtime'] = $mTime;
109
-			$data['storage_mtime'] = $mTime;
110
-			$data['etag'] = $this->getETag($path);
111
-			$this->getCache()->put($path, $data);
112
-			return true;
113
-		}
114
-	}
115
-
116
-	/**
117
-	 * @param string $path
118
-	 * @return string
119
-	 */
120
-	private function normalizePath($path) {
121
-		$path = trim($path, '/');
122
-		//FIXME why do we sometimes get a path like 'files//username'?
123
-		$path = str_replace('//', '/', $path);
124
-
125
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
126
-		if (!$path || $path === '.') {
127
-			$path = '';
128
-		}
129
-
130
-		return $path;
131
-	}
132
-
133
-	/**
134
-	 * Object Stores use a NoopScanner because metadata is directly stored in
135
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
136
-	 *
137
-	 * @param string $path
138
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
139
-	 * @return \OC\Files\ObjectStore\NoopScanner
140
-	 */
141
-	public function getScanner($path = '', $storage = null) {
142
-		if (!$storage) {
143
-			$storage = $this;
144
-		}
145
-		if (!isset($this->scanner)) {
146
-			$this->scanner = new NoopScanner($storage);
147
-		}
148
-		return $this->scanner;
149
-	}
150
-
151
-	public function getId() {
152
-		return $this->id;
153
-	}
154
-
155
-	public function rmdir($path) {
156
-		$path = $this->normalizePath($path);
157
-
158
-		if (!$this->is_dir($path)) {
159
-			return false;
160
-		}
161
-
162
-		$this->rmObjects($path);
163
-
164
-		$this->getCache()->remove($path);
165
-
166
-		return true;
167
-	}
168
-
169
-	private function rmObjects($path) {
170
-		$children = $this->getCache()->getFolderContents($path);
171
-		foreach ($children as $child) {
172
-			if ($child['mimetype'] === 'httpd/unix-directory') {
173
-				$this->rmObjects($child['path']);
174
-			} else {
175
-				$this->unlink($child['path']);
176
-			}
177
-		}
178
-	}
179
-
180
-	public function unlink($path) {
181
-		$path = $this->normalizePath($path);
182
-		$stat = $this->stat($path);
183
-
184
-		if ($stat && isset($stat['fileid'])) {
185
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
186
-				return $this->rmdir($path);
187
-			}
188
-			try {
189
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
190
-			} catch (\Exception $ex) {
191
-				if ($ex->getCode() !== 404) {
192
-					$this->logger->logException($ex, [
193
-						'app' => 'objectstore',
194
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
195
-					]);
196
-					return false;
197
-				} else {
198
-					//removing from cache is ok as it does not exist in the objectstore anyway
199
-				}
200
-			}
201
-			$this->getCache()->remove($path);
202
-			return true;
203
-		}
204
-		return false;
205
-	}
206
-
207
-	public function stat($path) {
208
-		$path = $this->normalizePath($path);
209
-		$cacheEntry = $this->getCache()->get($path);
210
-		if ($cacheEntry instanceof CacheEntry) {
211
-			return $cacheEntry->getData();
212
-		} else {
213
-			return false;
214
-		}
215
-	}
216
-
217
-	/**
218
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
219
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
220
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
221
-	 *
222
-	 * @param int $fileId the fileid
223
-	 * @return null|string the unified resource name used to identify the object
224
-	 */
225
-	protected function getURN($fileId) {
226
-		if (is_numeric($fileId)) {
227
-			return $this->objectPrefix . $fileId;
228
-		}
229
-		return null;
230
-	}
231
-
232
-	public function opendir($path) {
233
-		$path = $this->normalizePath($path);
234
-
235
-		try {
236
-			$files = array();
237
-			$folderContents = $this->getCache()->getFolderContents($path);
238
-			foreach ($folderContents as $file) {
239
-				$files[] = $file['name'];
240
-			}
241
-
242
-			return IteratorDirectory::wrap($files);
243
-		} catch (\Exception $e) {
244
-			$this->logger->logException($e);
245
-			return false;
246
-		}
247
-	}
248
-
249
-	public function filetype($path) {
250
-		$path = $this->normalizePath($path);
251
-		$stat = $this->stat($path);
252
-		if ($stat) {
253
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
254
-				return 'dir';
255
-			}
256
-			return 'file';
257
-		} else {
258
-			return false;
259
-		}
260
-	}
261
-
262
-	public function fopen($path, $mode) {
263
-		$path = $this->normalizePath($path);
264
-
265
-		switch ($mode) {
266
-			case 'r':
267
-			case 'rb':
268
-				$stat = $this->stat($path);
269
-				if (is_array($stat)) {
270
-					try {
271
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
272
-					} catch (\Exception $ex) {
273
-						$this->logger->logException($ex, [
274
-							'app' => 'objectstore',
275
-							'message' => 'Count not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
276
-						]);
277
-						return false;
278
-					}
279
-				} else {
280
-					return false;
281
-				}
282
-			case 'w':
283
-			case 'wb':
284
-			case 'a':
285
-			case 'ab':
286
-			case 'r+':
287
-			case 'w+':
288
-			case 'wb+':
289
-			case 'a+':
290
-			case 'x':
291
-			case 'x+':
292
-			case 'c':
293
-			case 'c+':
294
-				if (strrpos($path, '.') !== false) {
295
-					$ext = substr($path, strrpos($path, '.'));
296
-				} else {
297
-					$ext = '';
298
-				}
299
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
300
-				if ($this->file_exists($path)) {
301
-					$source = $this->fopen($path, 'r');
302
-					file_put_contents($tmpFile, $source);
303
-				}
304
-				$handle = fopen($tmpFile, $mode);
305
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
306
-					$this->writeBack($tmpFile, $path);
307
-				});
308
-		}
309
-		return false;
310
-	}
311
-
312
-	public function file_exists($path) {
313
-		$path = $this->normalizePath($path);
314
-		return (bool)$this->stat($path);
315
-	}
316
-
317
-	public function rename($source, $target) {
318
-		$source = $this->normalizePath($source);
319
-		$target = $this->normalizePath($target);
320
-		$this->remove($target);
321
-		$this->getCache()->move($source, $target);
322
-		$this->touch(dirname($target));
323
-		return true;
324
-	}
325
-
326
-	public function getMimeType($path) {
327
-		$path = $this->normalizePath($path);
328
-		$stat = $this->stat($path);
329
-		if (is_array($stat)) {
330
-			return $stat['mimetype'];
331
-		} else {
332
-			return false;
333
-		}
334
-	}
335
-
336
-	public function touch($path, $mtime = null) {
337
-		if (is_null($mtime)) {
338
-			$mtime = time();
339
-		}
340
-
341
-		$path = $this->normalizePath($path);
342
-		$dirName = dirname($path);
343
-		$parentExists = $this->is_dir($dirName);
344
-		if (!$parentExists) {
345
-			return false;
346
-		}
347
-
348
-		$stat = $this->stat($path);
349
-		if (is_array($stat)) {
350
-			// update existing mtime in db
351
-			$stat['mtime'] = $mtime;
352
-			$this->getCache()->update($stat['fileid'], $stat);
353
-		} else {
354
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
355
-			// create new file
356
-			$stat = array(
357
-				'etag' => $this->getETag($path),
358
-				'mimetype' => $mimeType,
359
-				'size' => 0,
360
-				'mtime' => $mtime,
361
-				'storage_mtime' => $mtime,
362
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
363
-			);
364
-			$fileId = $this->getCache()->put($path, $stat);
365
-			try {
366
-				//read an empty file from memory
367
-				$this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
368
-			} catch (\Exception $ex) {
369
-				$this->getCache()->remove($path);
370
-				$this->logger->logException($ex, [
371
-					'app' => 'objectstore',
372
-					'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
373
-				]);
374
-				return false;
375
-			}
376
-		}
377
-		return true;
378
-	}
379
-
380
-	public function writeBack($tmpFile, $path) {
381
-		$stat = $this->stat($path);
382
-		if (empty($stat)) {
383
-			// create new file
384
-			$stat = array(
385
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
386
-			);
387
-		}
388
-		// update stat with new data
389
-		$mTime = time();
390
-		$stat['size'] = filesize($tmpFile);
391
-		$stat['mtime'] = $mTime;
392
-		$stat['storage_mtime'] = $mTime;
393
-
394
-		// run path based detection first, to use file extension because $tmpFile is only a random string
395
-		$mimetypeDetector =  \OC::$server->getMimeTypeDetector();
396
-		$mimetype = $mimetypeDetector->detectPath($path);
397
-		if ($mimetype === 'application/octet-stream') {
398
-			$mimetype = $mimetypeDetector->detect($tmpFile);
399
-		}
400
-
401
-		$stat['mimetype'] = $mimetype;
402
-		$stat['etag'] = $this->getETag($path);
403
-
404
-		$fileId = $this->getCache()->put($path, $stat);
405
-		try {
406
-			//upload to object storage
407
-			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
408
-		} catch (\Exception $ex) {
409
-			$this->getCache()->remove($path);
410
-			$this->logger->logException($ex, [
411
-				'app' => 'objectstore',
412
-				'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
413
-			]);
414
-			throw $ex; // make this bubble up
415
-		}
416
-	}
417
-
418
-	/**
419
-	 * external changes are not supported, exclusive access to the object storage is assumed
420
-	 *
421
-	 * @param string $path
422
-	 * @param int $time
423
-	 * @return false
424
-	 */
425
-	public function hasUpdated($path, $time) {
426
-		return false;
427
-	}
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
+    private $logger;
50
+
51
+    public function __construct($params) {
52
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
53
+            $this->objectStore = $params['objectstore'];
54
+        } else {
55
+            throw new \Exception('missing IObjectStore instance');
56
+        }
57
+        if (isset($params['storageid'])) {
58
+            $this->id = 'object::store:' . $params['storageid'];
59
+        } else {
60
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
61
+        }
62
+        if (isset($params['objectPrefix'])) {
63
+            $this->objectPrefix = $params['objectPrefix'];
64
+        }
65
+        //initialize cache with root directory in cache
66
+        if (!$this->is_dir('/')) {
67
+            $this->mkdir('/');
68
+        }
69
+
70
+        $this->logger = \OC::$server->getLogger();
71
+    }
72
+
73
+    public function mkdir($path) {
74
+        $path = $this->normalizePath($path);
75
+
76
+        if ($this->file_exists($path)) {
77
+            return false;
78
+        }
79
+
80
+        $mTime = time();
81
+        $data = [
82
+            'mimetype' => 'httpd/unix-directory',
83
+            'size' => 0,
84
+            'mtime' => $mTime,
85
+            'storage_mtime' => $mTime,
86
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
87
+        ];
88
+        if ($path === '') {
89
+            //create root on the fly
90
+            $data['etag'] = $this->getETag('');
91
+            $this->getCache()->put('', $data);
92
+            return true;
93
+        } else {
94
+            // if parent does not exist, create it
95
+            $parent = $this->normalizePath(dirname($path));
96
+            $parentType = $this->filetype($parent);
97
+            if ($parentType === false) {
98
+                if (!$this->mkdir($parent)) {
99
+                    // something went wrong
100
+                    return false;
101
+                }
102
+            } else if ($parentType === 'file') {
103
+                // parent is a file
104
+                return false;
105
+            }
106
+            // finally create the new dir
107
+            $mTime = time(); // update mtime
108
+            $data['mtime'] = $mTime;
109
+            $data['storage_mtime'] = $mTime;
110
+            $data['etag'] = $this->getETag($path);
111
+            $this->getCache()->put($path, $data);
112
+            return true;
113
+        }
114
+    }
115
+
116
+    /**
117
+     * @param string $path
118
+     * @return string
119
+     */
120
+    private function normalizePath($path) {
121
+        $path = trim($path, '/');
122
+        //FIXME why do we sometimes get a path like 'files//username'?
123
+        $path = str_replace('//', '/', $path);
124
+
125
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
126
+        if (!$path || $path === '.') {
127
+            $path = '';
128
+        }
129
+
130
+        return $path;
131
+    }
132
+
133
+    /**
134
+     * Object Stores use a NoopScanner because metadata is directly stored in
135
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
136
+     *
137
+     * @param string $path
138
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
139
+     * @return \OC\Files\ObjectStore\NoopScanner
140
+     */
141
+    public function getScanner($path = '', $storage = null) {
142
+        if (!$storage) {
143
+            $storage = $this;
144
+        }
145
+        if (!isset($this->scanner)) {
146
+            $this->scanner = new NoopScanner($storage);
147
+        }
148
+        return $this->scanner;
149
+    }
150
+
151
+    public function getId() {
152
+        return $this->id;
153
+    }
154
+
155
+    public function rmdir($path) {
156
+        $path = $this->normalizePath($path);
157
+
158
+        if (!$this->is_dir($path)) {
159
+            return false;
160
+        }
161
+
162
+        $this->rmObjects($path);
163
+
164
+        $this->getCache()->remove($path);
165
+
166
+        return true;
167
+    }
168
+
169
+    private function rmObjects($path) {
170
+        $children = $this->getCache()->getFolderContents($path);
171
+        foreach ($children as $child) {
172
+            if ($child['mimetype'] === 'httpd/unix-directory') {
173
+                $this->rmObjects($child['path']);
174
+            } else {
175
+                $this->unlink($child['path']);
176
+            }
177
+        }
178
+    }
179
+
180
+    public function unlink($path) {
181
+        $path = $this->normalizePath($path);
182
+        $stat = $this->stat($path);
183
+
184
+        if ($stat && isset($stat['fileid'])) {
185
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
186
+                return $this->rmdir($path);
187
+            }
188
+            try {
189
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
190
+            } catch (\Exception $ex) {
191
+                if ($ex->getCode() !== 404) {
192
+                    $this->logger->logException($ex, [
193
+                        'app' => 'objectstore',
194
+                        'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
195
+                    ]);
196
+                    return false;
197
+                } else {
198
+                    //removing from cache is ok as it does not exist in the objectstore anyway
199
+                }
200
+            }
201
+            $this->getCache()->remove($path);
202
+            return true;
203
+        }
204
+        return false;
205
+    }
206
+
207
+    public function stat($path) {
208
+        $path = $this->normalizePath($path);
209
+        $cacheEntry = $this->getCache()->get($path);
210
+        if ($cacheEntry instanceof CacheEntry) {
211
+            return $cacheEntry->getData();
212
+        } else {
213
+            return false;
214
+        }
215
+    }
216
+
217
+    /**
218
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
219
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
220
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
221
+     *
222
+     * @param int $fileId the fileid
223
+     * @return null|string the unified resource name used to identify the object
224
+     */
225
+    protected function getURN($fileId) {
226
+        if (is_numeric($fileId)) {
227
+            return $this->objectPrefix . $fileId;
228
+        }
229
+        return null;
230
+    }
231
+
232
+    public function opendir($path) {
233
+        $path = $this->normalizePath($path);
234
+
235
+        try {
236
+            $files = array();
237
+            $folderContents = $this->getCache()->getFolderContents($path);
238
+            foreach ($folderContents as $file) {
239
+                $files[] = $file['name'];
240
+            }
241
+
242
+            return IteratorDirectory::wrap($files);
243
+        } catch (\Exception $e) {
244
+            $this->logger->logException($e);
245
+            return false;
246
+        }
247
+    }
248
+
249
+    public function filetype($path) {
250
+        $path = $this->normalizePath($path);
251
+        $stat = $this->stat($path);
252
+        if ($stat) {
253
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
254
+                return 'dir';
255
+            }
256
+            return 'file';
257
+        } else {
258
+            return false;
259
+        }
260
+    }
261
+
262
+    public function fopen($path, $mode) {
263
+        $path = $this->normalizePath($path);
264
+
265
+        switch ($mode) {
266
+            case 'r':
267
+            case 'rb':
268
+                $stat = $this->stat($path);
269
+                if (is_array($stat)) {
270
+                    try {
271
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
272
+                    } catch (\Exception $ex) {
273
+                        $this->logger->logException($ex, [
274
+                            'app' => 'objectstore',
275
+                            'message' => 'Count not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
276
+                        ]);
277
+                        return false;
278
+                    }
279
+                } else {
280
+                    return false;
281
+                }
282
+            case 'w':
283
+            case 'wb':
284
+            case 'a':
285
+            case 'ab':
286
+            case 'r+':
287
+            case 'w+':
288
+            case 'wb+':
289
+            case 'a+':
290
+            case 'x':
291
+            case 'x+':
292
+            case 'c':
293
+            case 'c+':
294
+                if (strrpos($path, '.') !== false) {
295
+                    $ext = substr($path, strrpos($path, '.'));
296
+                } else {
297
+                    $ext = '';
298
+                }
299
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
300
+                if ($this->file_exists($path)) {
301
+                    $source = $this->fopen($path, 'r');
302
+                    file_put_contents($tmpFile, $source);
303
+                }
304
+                $handle = fopen($tmpFile, $mode);
305
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
306
+                    $this->writeBack($tmpFile, $path);
307
+                });
308
+        }
309
+        return false;
310
+    }
311
+
312
+    public function file_exists($path) {
313
+        $path = $this->normalizePath($path);
314
+        return (bool)$this->stat($path);
315
+    }
316
+
317
+    public function rename($source, $target) {
318
+        $source = $this->normalizePath($source);
319
+        $target = $this->normalizePath($target);
320
+        $this->remove($target);
321
+        $this->getCache()->move($source, $target);
322
+        $this->touch(dirname($target));
323
+        return true;
324
+    }
325
+
326
+    public function getMimeType($path) {
327
+        $path = $this->normalizePath($path);
328
+        $stat = $this->stat($path);
329
+        if (is_array($stat)) {
330
+            return $stat['mimetype'];
331
+        } else {
332
+            return false;
333
+        }
334
+    }
335
+
336
+    public function touch($path, $mtime = null) {
337
+        if (is_null($mtime)) {
338
+            $mtime = time();
339
+        }
340
+
341
+        $path = $this->normalizePath($path);
342
+        $dirName = dirname($path);
343
+        $parentExists = $this->is_dir($dirName);
344
+        if (!$parentExists) {
345
+            return false;
346
+        }
347
+
348
+        $stat = $this->stat($path);
349
+        if (is_array($stat)) {
350
+            // update existing mtime in db
351
+            $stat['mtime'] = $mtime;
352
+            $this->getCache()->update($stat['fileid'], $stat);
353
+        } else {
354
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
355
+            // create new file
356
+            $stat = array(
357
+                'etag' => $this->getETag($path),
358
+                'mimetype' => $mimeType,
359
+                'size' => 0,
360
+                'mtime' => $mtime,
361
+                'storage_mtime' => $mtime,
362
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
363
+            );
364
+            $fileId = $this->getCache()->put($path, $stat);
365
+            try {
366
+                //read an empty file from memory
367
+                $this->objectStore->writeObject($this->getURN($fileId), fopen('php://memory', 'r'));
368
+            } catch (\Exception $ex) {
369
+                $this->getCache()->remove($path);
370
+                $this->logger->logException($ex, [
371
+                    'app' => 'objectstore',
372
+                    'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
373
+                ]);
374
+                return false;
375
+            }
376
+        }
377
+        return true;
378
+    }
379
+
380
+    public function writeBack($tmpFile, $path) {
381
+        $stat = $this->stat($path);
382
+        if (empty($stat)) {
383
+            // create new file
384
+            $stat = array(
385
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
386
+            );
387
+        }
388
+        // update stat with new data
389
+        $mTime = time();
390
+        $stat['size'] = filesize($tmpFile);
391
+        $stat['mtime'] = $mTime;
392
+        $stat['storage_mtime'] = $mTime;
393
+
394
+        // run path based detection first, to use file extension because $tmpFile is only a random string
395
+        $mimetypeDetector =  \OC::$server->getMimeTypeDetector();
396
+        $mimetype = $mimetypeDetector->detectPath($path);
397
+        if ($mimetype === 'application/octet-stream') {
398
+            $mimetype = $mimetypeDetector->detect($tmpFile);
399
+        }
400
+
401
+        $stat['mimetype'] = $mimetype;
402
+        $stat['etag'] = $this->getETag($path);
403
+
404
+        $fileId = $this->getCache()->put($path, $stat);
405
+        try {
406
+            //upload to object storage
407
+            $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
408
+        } catch (\Exception $ex) {
409
+            $this->getCache()->remove($path);
410
+            $this->logger->logException($ex, [
411
+                'app' => 'objectstore',
412
+                'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
413
+            ]);
414
+            throw $ex; // make this bubble up
415
+        }
416
+    }
417
+
418
+    /**
419
+     * external changes are not supported, exclusive access to the object storage is assumed
420
+     *
421
+     * @param string $path
422
+     * @param int $time
423
+     * @return false
424
+     */
425
+    public function hasUpdated($path, $time) {
426
+        return false;
427
+    }
428 428
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -55,9 +55,9 @@  discard block
 block discarded – undo
55 55
 			throw new \Exception('missing IObjectStore instance');
56 56
 		}
57 57
 		if (isset($params['storageid'])) {
58
-			$this->id = 'object::store:' . $params['storageid'];
58
+			$this->id = 'object::store:'.$params['storageid'];
59 59
 		} else {
60
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
60
+			$this->id = 'object::store:'.$this->objectStore->getStorageId();
61 61
 		}
62 62
 		if (isset($params['objectPrefix'])) {
63 63
 			$this->objectPrefix = $params['objectPrefix'];
@@ -191,7 +191,7 @@  discard block
 block discarded – undo
191 191
 				if ($ex->getCode() !== 404) {
192 192
 					$this->logger->logException($ex, [
193 193
 						'app' => 'objectstore',
194
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
194
+						'message' => 'Could not delete object '.$this->getURN($stat['fileid']).' for '.$path,
195 195
 					]);
196 196
 					return false;
197 197
 				} else {
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 	 */
225 225
 	protected function getURN($fileId) {
226 226
 		if (is_numeric($fileId)) {
227
-			return $this->objectPrefix . $fileId;
227
+			return $this->objectPrefix.$fileId;
228 228
 		}
229 229
 		return null;
230 230
 	}
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
 					} catch (\Exception $ex) {
273 273
 						$this->logger->logException($ex, [
274 274
 							'app' => 'objectstore',
275
-							'message' => 'Count not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
275
+							'message' => 'Count not get object '.$this->getURN($stat['fileid']).' for file '.$path,
276 276
 						]);
277 277
 						return false;
278 278
 					}
@@ -302,7 +302,7 @@  discard block
 block discarded – undo
302 302
 					file_put_contents($tmpFile, $source);
303 303
 				}
304 304
 				$handle = fopen($tmpFile, $mode);
305
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
305
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
306 306
 					$this->writeBack($tmpFile, $path);
307 307
 				});
308 308
 		}
@@ -311,7 +311,7 @@  discard block
 block discarded – undo
311 311
 
312 312
 	public function file_exists($path) {
313 313
 		$path = $this->normalizePath($path);
314
-		return (bool)$this->stat($path);
314
+		return (bool) $this->stat($path);
315 315
 	}
316 316
 
317 317
 	public function rename($source, $target) {
@@ -369,7 +369,7 @@  discard block
 block discarded – undo
369 369
 				$this->getCache()->remove($path);
370 370
 				$this->logger->logException($ex, [
371 371
 					'app' => 'objectstore',
372
-					'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
372
+					'message' => 'Could not create object '.$this->getURN($fileId).' for '.$path,
373 373
 				]);
374 374
 				return false;
375 375
 			}
@@ -392,7 +392,7 @@  discard block
 block discarded – undo
392 392
 		$stat['storage_mtime'] = $mTime;
393 393
 
394 394
 		// run path based detection first, to use file extension because $tmpFile is only a random string
395
-		$mimetypeDetector =  \OC::$server->getMimeTypeDetector();
395
+		$mimetypeDetector = \OC::$server->getMimeTypeDetector();
396 396
 		$mimetype = $mimetypeDetector->detectPath($path);
397 397
 		if ($mimetype === 'application/octet-stream') {
398 398
 			$mimetype = $mimetypeDetector->detect($tmpFile);
@@ -409,7 +409,7 @@  discard block
 block discarded – undo
409 409
 			$this->getCache()->remove($path);
410 410
 			$this->logger->logException($ex, [
411 411
 				'app' => 'objectstore',
412
-				'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
412
+				'message' => 'Could not create object '.$this->getURN($fileId).' for '.$path,
413 413
 			]);
414 414
 			throw $ex; // make this bubble up
415 415
 		}
Please login to merge, or discard this patch.
lib/private/Files/Type/Detection.php 1 patch
Indentation   +287 added lines, -287 removed lines patch added patch discarded remove patch
@@ -41,291 +41,291 @@
 block discarded – undo
41 41
  * @package OC\Files\Type
42 42
  */
43 43
 class Detection implements IMimeTypeDetector {
44
-	protected $mimetypes = [];
45
-	protected $secureMimeTypes = [];
46
-
47
-	protected $mimetypeIcons = [];
48
-	/** @var string[] */
49
-	protected $mimeTypeAlias = [];
50
-
51
-	/** @var IURLGenerator */
52
-	private $urlGenerator;
53
-
54
-	/** @var string */
55
-	private $customConfigDir;
56
-
57
-	/** @var string */
58
-	private $defaultConfigDir;
59
-
60
-	/**
61
-	 * @param IURLGenerator $urlGenerator
62
-	 * @param string $customConfigDir
63
-	 * @param string $defaultConfigDir
64
-	 */
65
-	public function __construct(IURLGenerator $urlGenerator,
66
-								$customConfigDir,
67
-								$defaultConfigDir) {
68
-		$this->urlGenerator = $urlGenerator;
69
-		$this->customConfigDir = $customConfigDir;
70
-		$this->defaultConfigDir = $defaultConfigDir;
71
-	}
72
-
73
-	/**
74
-	 * Add an extension -> mimetype mapping
75
-	 *
76
-	 * $mimetype is the assumed correct mime type
77
-	 * The optional $secureMimeType is an alternative to send to send
78
-	 * to avoid potential XSS.
79
-	 *
80
-	 * @param string $extension
81
-	 * @param string $mimetype
82
-	 * @param string|null $secureMimeType
83
-	 */
84
-	public function registerType($extension,
85
-								 $mimetype,
86
-								 $secureMimeType = null) {
87
-		$this->mimetypes[$extension] = array($mimetype, $secureMimeType);
88
-		$this->secureMimeTypes[$mimetype] = $secureMimeType ?: $mimetype;
89
-	}
90
-
91
-	/**
92
-	 * Add an array of extension -> mimetype mappings
93
-	 *
94
-	 * The mimetype value is in itself an array where the first index is
95
-	 * the assumed correct mimetype and the second is either a secure alternative
96
-	 * or null if the correct is considered secure.
97
-	 *
98
-	 * @param array $types
99
-	 */
100
-	public function registerTypeArray($types) {
101
-		$this->mimetypes = array_merge($this->mimetypes, $types);
102
-
103
-		// Update the alternative mimetypes to avoid having to look them up each time.
104
-		foreach ($this->mimetypes as $mimeType) {
105
-			$this->secureMimeTypes[$mimeType[0]] = isset($mimeType[1]) ? $mimeType[1]: $mimeType[0];
106
-		}
107
-	}
108
-
109
-	/**
110
-	 * Add the mimetype aliases if they are not yet present
111
-	 */
112
-	private function loadAliases() {
113
-		if (!empty($this->mimeTypeAlias)) {
114
-			return;
115
-		}
116
-
117
-		$this->mimeTypeAlias = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypealiases.dist.json'), true);
118
-
119
-		if (file_exists($this->customConfigDir . '/mimetypealiases.json')) {
120
-			$custom = json_decode(file_get_contents($this->customConfigDir . '/mimetypealiases.json'), true);
121
-			$this->mimeTypeAlias = array_merge($this->mimeTypeAlias, $custom);
122
-		}
123
-	}
124
-
125
-	/**
126
-	 * @return string[]
127
-	 */
128
-	public function getAllAliases() {
129
-		$this->loadAliases();
130
-		return $this->mimeTypeAlias;
131
-	}
132
-
133
-	/**
134
-	 * Add mimetype mappings if they are not yet present
135
-	 */
136
-	private function loadMappings() {
137
-		if (!empty($this->mimetypes)) {
138
-			return;
139
-		}
140
-
141
-		$mimetypeMapping = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypemapping.dist.json'), true);
142
-
143
-		//Check if need to load custom mappings
144
-		if (file_exists($this->customConfigDir . '/mimetypemapping.json')) {
145
-			$custom = json_decode(file_get_contents($this->customConfigDir . '/mimetypemapping.json'), true);
146
-			$mimetypeMapping = array_merge($mimetypeMapping, $custom);
147
-		}
148
-
149
-		$this->registerTypeArray($mimetypeMapping);
150
-	}
151
-
152
-	/**
153
-	 * @return array
154
-	 */
155
-	public function getAllMappings() {
156
-		$this->loadMappings();
157
-		return $this->mimetypes;
158
-	}
159
-
160
-	/**
161
-	 * detect mimetype only based on filename, content of file is not used
162
-	 *
163
-	 * @param string $path
164
-	 * @return string
165
-	 */
166
-	public function detectPath($path) {
167
-		$this->loadMappings();
168
-
169
-		$fileName = basename($path);
170
-
171
-		// remove leading dot on hidden files with a file extension
172
-		$fileName = ltrim($fileName, '.');
173
-
174
-		// note: leading dot doesn't qualify as extension
175
-		if (strpos($fileName, '.') > 0) {
176
-
177
-			// remove versioning extension: name.v1508946057 and transfer extension: name.ocTransferId2057600214.part
178
-			$fileName = preg_replace('!((\.v\d+)|((.ocTransferId\d+)?.part))$!', '', $fileName);
179
-
180
-			//try to guess the type by the file extension
181
-			$extension = strtolower(strrchr($fileName, '.'));
182
-			$extension = substr($extension, 1); //remove leading .
183
-			return (isset($this->mimetypes[$extension]) && isset($this->mimetypes[$extension][0]))
184
-				? $this->mimetypes[$extension][0]
185
-				: 'application/octet-stream';
186
-		} else {
187
-			return 'application/octet-stream';
188
-		}
189
-	}
190
-
191
-	/**
192
-	 * detect mimetype based on both filename and content
193
-	 *
194
-	 * @param string $path
195
-	 * @return string
196
-	 */
197
-	public function detect($path) {
198
-		$this->loadMappings();
199
-
200
-		if (@is_dir($path)) {
201
-			// directories are easy
202
-			return "httpd/unix-directory";
203
-		}
204
-
205
-		$mimeType = $this->detectPath($path);
206
-
207
-		if ($mimeType === 'application/octet-stream' and function_exists('finfo_open')
208
-			and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME)
209
-		) {
210
-			$info = @strtolower(finfo_file($finfo, $path));
211
-			finfo_close($finfo);
212
-			if ($info) {
213
-				$mimeType = strpos($info, ';') !== false ? substr($info, 0, strpos($info, ';')) : $info;
214
-				return empty($mimeType) ? 'application/octet-stream' : $mimeType;
215
-			}
216
-
217
-		}
218
-		$isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://');
219
-		if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) {
220
-			// use mime magic extension if available
221
-			$mimeType = mime_content_type($path);
222
-		}
223
-		if (!$isWrapped and $mimeType === 'application/octet-stream' && \OC_Helper::canExecute("file")) {
224
-			// it looks like we have a 'file' command,
225
-			// lets see if it does have mime support
226
-			$path = escapeshellarg($path);
227
-			$fp = popen("file -b --mime-type $path 2>/dev/null", "r");
228
-			$reply = fgets($fp);
229
-			pclose($fp);
230
-
231
-			//trim the newline
232
-			$mimeType = trim($reply);
233
-
234
-			if (empty($mimeType)) {
235
-				$mimeType = 'application/octet-stream';
236
-			}
237
-
238
-		}
239
-		return $mimeType;
240
-	}
241
-
242
-	/**
243
-	 * detect mimetype based on the content of a string
244
-	 *
245
-	 * @param string $data
246
-	 * @return string
247
-	 */
248
-	public function detectString($data) {
249
-		if (function_exists('finfo_open') and function_exists('finfo_file')) {
250
-			$finfo = finfo_open(FILEINFO_MIME);
251
-			$info = finfo_buffer($finfo, $data);
252
-			return strpos($info, ';') !== false ? substr($info, 0, strpos($info, ';')) : $info;
253
-		} else {
254
-			$tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
255
-			$fh = fopen($tmpFile, 'wb');
256
-			fwrite($fh, $data, 8024);
257
-			fclose($fh);
258
-			$mime = $this->detect($tmpFile);
259
-			unset($tmpFile);
260
-			return $mime;
261
-		}
262
-	}
263
-
264
-	/**
265
-	 * Get a secure mimetype that won't expose potential XSS.
266
-	 *
267
-	 * @param string $mimeType
268
-	 * @return string
269
-	 */
270
-	public function getSecureMimeType($mimeType) {
271
-		$this->loadMappings();
272
-
273
-		return isset($this->secureMimeTypes[$mimeType])
274
-			? $this->secureMimeTypes[$mimeType]
275
-			: 'application/octet-stream';
276
-	}
277
-
278
-	/**
279
-	 * Get path to the icon of a file type
280
-	 * @param string $mimetype the MIME type
281
-	 * @return string the url
282
-	 */
283
-	public function mimeTypeIcon($mimetype) {
284
-		$this->loadAliases();
285
-
286
-		while (isset($this->mimeTypeAlias[$mimetype])) {
287
-			$mimetype = $this->mimeTypeAlias[$mimetype];
288
-		}
289
-		if (isset($this->mimetypeIcons[$mimetype])) {
290
-			return $this->mimetypeIcons[$mimetype];
291
-		}
292
-
293
-		// Replace slash and backslash with a minus
294
-		$icon = str_replace('/', '-', $mimetype);
295
-		$icon = str_replace('\\', '-', $icon);
296
-
297
-		// Is it a dir?
298
-		if ($mimetype === 'dir') {
299
-			$this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder.svg');
300
-			return $this->mimetypeIcons[$mimetype];
301
-		}
302
-		if ($mimetype === 'dir-shared') {
303
-			$this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder-shared.svg');
304
-			return $this->mimetypeIcons[$mimetype];
305
-		}
306
-		if ($mimetype === 'dir-external') {
307
-			$this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder-external.svg');
308
-			return $this->mimetypeIcons[$mimetype];
309
-		}
310
-
311
-		// Icon exists?
312
-		try {
313
-			$this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/' . $icon . '.svg');
314
-			return $this->mimetypeIcons[$mimetype];
315
-		} catch (\RuntimeException $e) {
316
-			// Specified image not found
317
-		}
318
-
319
-		// Try only the first part of the filetype
320
-		$mimePart = substr($icon, 0, strpos($icon, '-'));
321
-		try {
322
-			$this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/' . $mimePart . '.svg');
323
-			return $this->mimetypeIcons[$mimetype];
324
-		} catch (\RuntimeException $e) {
325
-			// Image for the first part of the mimetype not found
326
-		}
327
-
328
-		$this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/file.svg');
329
-		return $this->mimetypeIcons[$mimetype];
330
-	}
44
+    protected $mimetypes = [];
45
+    protected $secureMimeTypes = [];
46
+
47
+    protected $mimetypeIcons = [];
48
+    /** @var string[] */
49
+    protected $mimeTypeAlias = [];
50
+
51
+    /** @var IURLGenerator */
52
+    private $urlGenerator;
53
+
54
+    /** @var string */
55
+    private $customConfigDir;
56
+
57
+    /** @var string */
58
+    private $defaultConfigDir;
59
+
60
+    /**
61
+     * @param IURLGenerator $urlGenerator
62
+     * @param string $customConfigDir
63
+     * @param string $defaultConfigDir
64
+     */
65
+    public function __construct(IURLGenerator $urlGenerator,
66
+                                $customConfigDir,
67
+                                $defaultConfigDir) {
68
+        $this->urlGenerator = $urlGenerator;
69
+        $this->customConfigDir = $customConfigDir;
70
+        $this->defaultConfigDir = $defaultConfigDir;
71
+    }
72
+
73
+    /**
74
+     * Add an extension -> mimetype mapping
75
+     *
76
+     * $mimetype is the assumed correct mime type
77
+     * The optional $secureMimeType is an alternative to send to send
78
+     * to avoid potential XSS.
79
+     *
80
+     * @param string $extension
81
+     * @param string $mimetype
82
+     * @param string|null $secureMimeType
83
+     */
84
+    public function registerType($extension,
85
+                                    $mimetype,
86
+                                    $secureMimeType = null) {
87
+        $this->mimetypes[$extension] = array($mimetype, $secureMimeType);
88
+        $this->secureMimeTypes[$mimetype] = $secureMimeType ?: $mimetype;
89
+    }
90
+
91
+    /**
92
+     * Add an array of extension -> mimetype mappings
93
+     *
94
+     * The mimetype value is in itself an array where the first index is
95
+     * the assumed correct mimetype and the second is either a secure alternative
96
+     * or null if the correct is considered secure.
97
+     *
98
+     * @param array $types
99
+     */
100
+    public function registerTypeArray($types) {
101
+        $this->mimetypes = array_merge($this->mimetypes, $types);
102
+
103
+        // Update the alternative mimetypes to avoid having to look them up each time.
104
+        foreach ($this->mimetypes as $mimeType) {
105
+            $this->secureMimeTypes[$mimeType[0]] = isset($mimeType[1]) ? $mimeType[1]: $mimeType[0];
106
+        }
107
+    }
108
+
109
+    /**
110
+     * Add the mimetype aliases if they are not yet present
111
+     */
112
+    private function loadAliases() {
113
+        if (!empty($this->mimeTypeAlias)) {
114
+            return;
115
+        }
116
+
117
+        $this->mimeTypeAlias = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypealiases.dist.json'), true);
118
+
119
+        if (file_exists($this->customConfigDir . '/mimetypealiases.json')) {
120
+            $custom = json_decode(file_get_contents($this->customConfigDir . '/mimetypealiases.json'), true);
121
+            $this->mimeTypeAlias = array_merge($this->mimeTypeAlias, $custom);
122
+        }
123
+    }
124
+
125
+    /**
126
+     * @return string[]
127
+     */
128
+    public function getAllAliases() {
129
+        $this->loadAliases();
130
+        return $this->mimeTypeAlias;
131
+    }
132
+
133
+    /**
134
+     * Add mimetype mappings if they are not yet present
135
+     */
136
+    private function loadMappings() {
137
+        if (!empty($this->mimetypes)) {
138
+            return;
139
+        }
140
+
141
+        $mimetypeMapping = json_decode(file_get_contents($this->defaultConfigDir . '/mimetypemapping.dist.json'), true);
142
+
143
+        //Check if need to load custom mappings
144
+        if (file_exists($this->customConfigDir . '/mimetypemapping.json')) {
145
+            $custom = json_decode(file_get_contents($this->customConfigDir . '/mimetypemapping.json'), true);
146
+            $mimetypeMapping = array_merge($mimetypeMapping, $custom);
147
+        }
148
+
149
+        $this->registerTypeArray($mimetypeMapping);
150
+    }
151
+
152
+    /**
153
+     * @return array
154
+     */
155
+    public function getAllMappings() {
156
+        $this->loadMappings();
157
+        return $this->mimetypes;
158
+    }
159
+
160
+    /**
161
+     * detect mimetype only based on filename, content of file is not used
162
+     *
163
+     * @param string $path
164
+     * @return string
165
+     */
166
+    public function detectPath($path) {
167
+        $this->loadMappings();
168
+
169
+        $fileName = basename($path);
170
+
171
+        // remove leading dot on hidden files with a file extension
172
+        $fileName = ltrim($fileName, '.');
173
+
174
+        // note: leading dot doesn't qualify as extension
175
+        if (strpos($fileName, '.') > 0) {
176
+
177
+            // remove versioning extension: name.v1508946057 and transfer extension: name.ocTransferId2057600214.part
178
+            $fileName = preg_replace('!((\.v\d+)|((.ocTransferId\d+)?.part))$!', '', $fileName);
179
+
180
+            //try to guess the type by the file extension
181
+            $extension = strtolower(strrchr($fileName, '.'));
182
+            $extension = substr($extension, 1); //remove leading .
183
+            return (isset($this->mimetypes[$extension]) && isset($this->mimetypes[$extension][0]))
184
+                ? $this->mimetypes[$extension][0]
185
+                : 'application/octet-stream';
186
+        } else {
187
+            return 'application/octet-stream';
188
+        }
189
+    }
190
+
191
+    /**
192
+     * detect mimetype based on both filename and content
193
+     *
194
+     * @param string $path
195
+     * @return string
196
+     */
197
+    public function detect($path) {
198
+        $this->loadMappings();
199
+
200
+        if (@is_dir($path)) {
201
+            // directories are easy
202
+            return "httpd/unix-directory";
203
+        }
204
+
205
+        $mimeType = $this->detectPath($path);
206
+
207
+        if ($mimeType === 'application/octet-stream' and function_exists('finfo_open')
208
+            and function_exists('finfo_file') and $finfo = finfo_open(FILEINFO_MIME)
209
+        ) {
210
+            $info = @strtolower(finfo_file($finfo, $path));
211
+            finfo_close($finfo);
212
+            if ($info) {
213
+                $mimeType = strpos($info, ';') !== false ? substr($info, 0, strpos($info, ';')) : $info;
214
+                return empty($mimeType) ? 'application/octet-stream' : $mimeType;
215
+            }
216
+
217
+        }
218
+        $isWrapped = (strpos($path, '://') !== false) and (substr($path, 0, 7) === 'file://');
219
+        if (!$isWrapped and $mimeType === 'application/octet-stream' && function_exists("mime_content_type")) {
220
+            // use mime magic extension if available
221
+            $mimeType = mime_content_type($path);
222
+        }
223
+        if (!$isWrapped and $mimeType === 'application/octet-stream' && \OC_Helper::canExecute("file")) {
224
+            // it looks like we have a 'file' command,
225
+            // lets see if it does have mime support
226
+            $path = escapeshellarg($path);
227
+            $fp = popen("file -b --mime-type $path 2>/dev/null", "r");
228
+            $reply = fgets($fp);
229
+            pclose($fp);
230
+
231
+            //trim the newline
232
+            $mimeType = trim($reply);
233
+
234
+            if (empty($mimeType)) {
235
+                $mimeType = 'application/octet-stream';
236
+            }
237
+
238
+        }
239
+        return $mimeType;
240
+    }
241
+
242
+    /**
243
+     * detect mimetype based on the content of a string
244
+     *
245
+     * @param string $data
246
+     * @return string
247
+     */
248
+    public function detectString($data) {
249
+        if (function_exists('finfo_open') and function_exists('finfo_file')) {
250
+            $finfo = finfo_open(FILEINFO_MIME);
251
+            $info = finfo_buffer($finfo, $data);
252
+            return strpos($info, ';') !== false ? substr($info, 0, strpos($info, ';')) : $info;
253
+        } else {
254
+            $tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
255
+            $fh = fopen($tmpFile, 'wb');
256
+            fwrite($fh, $data, 8024);
257
+            fclose($fh);
258
+            $mime = $this->detect($tmpFile);
259
+            unset($tmpFile);
260
+            return $mime;
261
+        }
262
+    }
263
+
264
+    /**
265
+     * Get a secure mimetype that won't expose potential XSS.
266
+     *
267
+     * @param string $mimeType
268
+     * @return string
269
+     */
270
+    public function getSecureMimeType($mimeType) {
271
+        $this->loadMappings();
272
+
273
+        return isset($this->secureMimeTypes[$mimeType])
274
+            ? $this->secureMimeTypes[$mimeType]
275
+            : 'application/octet-stream';
276
+    }
277
+
278
+    /**
279
+     * Get path to the icon of a file type
280
+     * @param string $mimetype the MIME type
281
+     * @return string the url
282
+     */
283
+    public function mimeTypeIcon($mimetype) {
284
+        $this->loadAliases();
285
+
286
+        while (isset($this->mimeTypeAlias[$mimetype])) {
287
+            $mimetype = $this->mimeTypeAlias[$mimetype];
288
+        }
289
+        if (isset($this->mimetypeIcons[$mimetype])) {
290
+            return $this->mimetypeIcons[$mimetype];
291
+        }
292
+
293
+        // Replace slash and backslash with a minus
294
+        $icon = str_replace('/', '-', $mimetype);
295
+        $icon = str_replace('\\', '-', $icon);
296
+
297
+        // Is it a dir?
298
+        if ($mimetype === 'dir') {
299
+            $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder.svg');
300
+            return $this->mimetypeIcons[$mimetype];
301
+        }
302
+        if ($mimetype === 'dir-shared') {
303
+            $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder-shared.svg');
304
+            return $this->mimetypeIcons[$mimetype];
305
+        }
306
+        if ($mimetype === 'dir-external') {
307
+            $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/folder-external.svg');
308
+            return $this->mimetypeIcons[$mimetype];
309
+        }
310
+
311
+        // Icon exists?
312
+        try {
313
+            $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/' . $icon . '.svg');
314
+            return $this->mimetypeIcons[$mimetype];
315
+        } catch (\RuntimeException $e) {
316
+            // Specified image not found
317
+        }
318
+
319
+        // Try only the first part of the filetype
320
+        $mimePart = substr($icon, 0, strpos($icon, '-'));
321
+        try {
322
+            $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/' . $mimePart . '.svg');
323
+            return $this->mimetypeIcons[$mimetype];
324
+        } catch (\RuntimeException $e) {
325
+            // Image for the first part of the mimetype not found
326
+        }
327
+
328
+        $this->mimetypeIcons[$mimetype] = $this->urlGenerator->imagePath('core', 'filetypes/file.svg');
329
+        return $this->mimetypeIcons[$mimetype];
330
+    }
331 331
 }
Please login to merge, or discard this patch.