Passed
Push — master ( 0485e6...d8dea5 )
by Morris
14:45 queued 13s
created
lib/private/Files/ObjectStore/ObjectStoreStorage.php 1 patch
Indentation   +478 added lines, -478 removed lines patch added patch discarded remove patch
@@ -37,485 +37,485 @@
 block discarded – undo
37 37
 use OCP\Files\ObjectStore\IObjectStore;
38 38
 
39 39
 class ObjectStoreStorage extends \OC\Files\Storage\Common {
40
-	/**
41
-	 * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
42
-	 */
43
-	protected $objectStore;
44
-	/**
45
-	 * @var string $id
46
-	 */
47
-	protected $id;
48
-	/**
49
-	 * @var \OC\User\User $user
50
-	 */
51
-	protected $user;
52
-
53
-	private $objectPrefix = 'urn:oid:';
54
-
55
-	private $logger;
56
-
57
-	public function __construct($params) {
58
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
59
-			$this->objectStore = $params['objectstore'];
60
-		} else {
61
-			throw new \Exception('missing IObjectStore instance');
62
-		}
63
-		if (isset($params['storageid'])) {
64
-			$this->id = 'object::store:' . $params['storageid'];
65
-		} else {
66
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
67
-		}
68
-		if (isset($params['objectPrefix'])) {
69
-			$this->objectPrefix = $params['objectPrefix'];
70
-		}
71
-		//initialize cache with root directory in cache
72
-		if (!$this->is_dir('/')) {
73
-			$this->mkdir('/');
74
-		}
75
-
76
-		$this->logger = \OC::$server->getLogger();
77
-	}
78
-
79
-	public function mkdir($path) {
80
-		$path = $this->normalizePath($path);
81
-
82
-		if ($this->file_exists($path)) {
83
-			return false;
84
-		}
85
-
86
-		$mTime = time();
87
-		$data = [
88
-			'mimetype' => 'httpd/unix-directory',
89
-			'size' => 0,
90
-			'mtime' => $mTime,
91
-			'storage_mtime' => $mTime,
92
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
93
-		];
94
-		if ($path === '') {
95
-			//create root on the fly
96
-			$data['etag'] = $this->getETag('');
97
-			$this->getCache()->put('', $data);
98
-			return true;
99
-		} else {
100
-			// if parent does not exist, create it
101
-			$parent = $this->normalizePath(dirname($path));
102
-			$parentType = $this->filetype($parent);
103
-			if ($parentType === false) {
104
-				if (!$this->mkdir($parent)) {
105
-					// something went wrong
106
-					return false;
107
-				}
108
-			} elseif ($parentType === 'file') {
109
-				// parent is a file
110
-				return false;
111
-			}
112
-			// finally create the new dir
113
-			$mTime = time(); // update mtime
114
-			$data['mtime'] = $mTime;
115
-			$data['storage_mtime'] = $mTime;
116
-			$data['etag'] = $this->getETag($path);
117
-			$this->getCache()->put($path, $data);
118
-			return true;
119
-		}
120
-	}
121
-
122
-	/**
123
-	 * @param string $path
124
-	 * @return string
125
-	 */
126
-	private function normalizePath($path) {
127
-		$path = trim($path, '/');
128
-		//FIXME why do we sometimes get a path like 'files//username'?
129
-		$path = str_replace('//', '/', $path);
130
-
131
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
132
-		if (!$path || $path === '.') {
133
-			$path = '';
134
-		}
135
-
136
-		return $path;
137
-	}
138
-
139
-	/**
140
-	 * Object Stores use a NoopScanner because metadata is directly stored in
141
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
142
-	 *
143
-	 * @param string $path
144
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
145
-	 * @return \OC\Files\ObjectStore\NoopScanner
146
-	 */
147
-	public function getScanner($path = '', $storage = null) {
148
-		if (!$storage) {
149
-			$storage = $this;
150
-		}
151
-		if (!isset($this->scanner)) {
152
-			$this->scanner = new NoopScanner($storage);
153
-		}
154
-		return $this->scanner;
155
-	}
156
-
157
-	public function getId() {
158
-		return $this->id;
159
-	}
160
-
161
-	public function rmdir($path) {
162
-		$path = $this->normalizePath($path);
163
-
164
-		if (!$this->is_dir($path)) {
165
-			return false;
166
-		}
167
-
168
-		if (!$this->rmObjects($path)) {
169
-			return false;
170
-		}
171
-
172
-		$this->getCache()->remove($path);
173
-
174
-		return true;
175
-	}
176
-
177
-	private function rmObjects($path) {
178
-		$children = $this->getCache()->getFolderContents($path);
179
-		foreach ($children as $child) {
180
-			if ($child['mimetype'] === 'httpd/unix-directory') {
181
-				if (!$this->rmObjects($child['path'])) {
182
-					return false;
183
-				}
184
-			} else {
185
-				if (!$this->unlink($child['path'])) {
186
-					return false;
187
-				}
188
-			}
189
-		}
190
-
191
-		return true;
192
-	}
193
-
194
-	public function unlink($path) {
195
-		$path = $this->normalizePath($path);
196
-		$stat = $this->stat($path);
197
-
198
-		if ($stat && isset($stat['fileid'])) {
199
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
200
-				return $this->rmdir($path);
201
-			}
202
-			try {
203
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
204
-			} catch (\Exception $ex) {
205
-				if ($ex->getCode() !== 404) {
206
-					$this->logger->logException($ex, [
207
-						'app' => 'objectstore',
208
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
209
-					]);
210
-					return false;
211
-				}
212
-				//removing from cache is ok as it does not exist in the objectstore anyway
213
-			}
214
-			$this->getCache()->remove($path);
215
-			return true;
216
-		}
217
-		return false;
218
-	}
219
-
220
-	public function stat($path) {
221
-		$path = $this->normalizePath($path);
222
-		$cacheEntry = $this->getCache()->get($path);
223
-		if ($cacheEntry instanceof CacheEntry) {
224
-			return $cacheEntry->getData();
225
-		} else {
226
-			return false;
227
-		}
228
-	}
229
-
230
-	public function getPermissions($path) {
231
-		$stat = $this->stat($path);
232
-
233
-		if (is_array($stat) && isset($stat['permissions'])) {
234
-			return $stat['permissions'];
235
-		}
236
-
237
-		return parent::getPermissions($path);
238
-	}
239
-
240
-	/**
241
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
242
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
243
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
244
-	 *
245
-	 * @param int $fileId the fileid
246
-	 * @return null|string the unified resource name used to identify the object
247
-	 */
248
-	public function getURN($fileId) {
249
-		if (is_numeric($fileId)) {
250
-			return $this->objectPrefix . $fileId;
251
-		}
252
-		return null;
253
-	}
254
-
255
-	public function opendir($path) {
256
-		$path = $this->normalizePath($path);
257
-
258
-		try {
259
-			$files = [];
260
-			$folderContents = $this->getCache()->getFolderContents($path);
261
-			foreach ($folderContents as $file) {
262
-				$files[] = $file['name'];
263
-			}
264
-
265
-			return IteratorDirectory::wrap($files);
266
-		} catch (\Exception $e) {
267
-			$this->logger->logException($e);
268
-			return false;
269
-		}
270
-	}
271
-
272
-	public function filetype($path) {
273
-		$path = $this->normalizePath($path);
274
-		$stat = $this->stat($path);
275
-		if ($stat) {
276
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
277
-				return 'dir';
278
-			}
279
-			return 'file';
280
-		} else {
281
-			return false;
282
-		}
283
-	}
284
-
285
-	public function fopen($path, $mode) {
286
-		$path = $this->normalizePath($path);
287
-
288
-		if (strrpos($path, '.') !== false) {
289
-			$ext = substr($path, strrpos($path, '.'));
290
-		} else {
291
-			$ext = '';
292
-		}
293
-
294
-		switch ($mode) {
295
-			case 'r':
296
-			case 'rb':
297
-				$stat = $this->stat($path);
298
-				if (is_array($stat)) {
299
-					try {
300
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
301
-					} catch (NotFoundException $e) {
302
-						$this->logger->logException($e, [
303
-							'app' => 'objectstore',
304
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
305
-						]);
306
-						throw $e;
307
-					} catch (\Exception $ex) {
308
-						$this->logger->logException($ex, [
309
-							'app' => 'objectstore',
310
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
311
-						]);
312
-						return false;
313
-					}
314
-				} else {
315
-					return false;
316
-				}
317
-				// no break
318
-			case 'w':
319
-			case 'wb':
320
-			case 'w+':
321
-			case 'wb+':
322
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
323
-				$handle = fopen($tmpFile, $mode);
324
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
325
-					$this->writeBack($tmpFile, $path);
326
-				});
327
-			case 'a':
328
-			case 'ab':
329
-			case 'r+':
330
-			case 'a+':
331
-			case 'x':
332
-			case 'x+':
333
-			case 'c':
334
-			case 'c+':
335
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
336
-				if ($this->file_exists($path)) {
337
-					$source = $this->fopen($path, 'r');
338
-					file_put_contents($tmpFile, $source);
339
-				}
340
-				$handle = fopen($tmpFile, $mode);
341
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
342
-					$this->writeBack($tmpFile, $path);
343
-				});
344
-		}
345
-		return false;
346
-	}
347
-
348
-	public function file_exists($path) {
349
-		$path = $this->normalizePath($path);
350
-		return (bool)$this->stat($path);
351
-	}
352
-
353
-	public function rename($source, $target) {
354
-		$source = $this->normalizePath($source);
355
-		$target = $this->normalizePath($target);
356
-		$this->remove($target);
357
-		$this->getCache()->move($source, $target);
358
-		$this->touch(dirname($target));
359
-		return true;
360
-	}
361
-
362
-	public function getMimeType($path) {
363
-		$path = $this->normalizePath($path);
364
-		return parent::getMimeType($path);
365
-	}
366
-
367
-	public function touch($path, $mtime = null) {
368
-		if (is_null($mtime)) {
369
-			$mtime = time();
370
-		}
371
-
372
-		$path = $this->normalizePath($path);
373
-		$dirName = dirname($path);
374
-		$parentExists = $this->is_dir($dirName);
375
-		if (!$parentExists) {
376
-			return false;
377
-		}
378
-
379
-		$stat = $this->stat($path);
380
-		if (is_array($stat)) {
381
-			// update existing mtime in db
382
-			$stat['mtime'] = $mtime;
383
-			$this->getCache()->update($stat['fileid'], $stat);
384
-		} else {
385
-			try {
386
-				//create a empty file, need to have at least on char to make it
387
-				// work with all object storage implementations
388
-				$this->file_put_contents($path, ' ');
389
-				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
390
-				$stat = [
391
-					'etag' => $this->getETag($path),
392
-					'mimetype' => $mimeType,
393
-					'size' => 0,
394
-					'mtime' => $mtime,
395
-					'storage_mtime' => $mtime,
396
-					'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
397
-				];
398
-				$this->getCache()->put($path, $stat);
399
-			} catch (\Exception $ex) {
400
-				$this->logger->logException($ex, [
401
-					'app' => 'objectstore',
402
-					'message' => 'Could not create object for ' . $path,
403
-				]);
404
-				throw $ex;
405
-			}
406
-		}
407
-		return true;
408
-	}
409
-
410
-	public function writeBack($tmpFile, $path) {
411
-		$size = filesize($tmpFile);
412
-		$this->writeStream($path, fopen($tmpFile, 'r'), $size);
413
-	}
414
-
415
-	/**
416
-	 * external changes are not supported, exclusive access to the object storage is assumed
417
-	 *
418
-	 * @param string $path
419
-	 * @param int $time
420
-	 * @return false
421
-	 */
422
-	public function hasUpdated($path, $time) {
423
-		return false;
424
-	}
425
-
426
-	public function needsPartFile() {
427
-		return false;
428
-	}
429
-
430
-	public function file_put_contents($path, $data) {
431
-		$handle = $this->fopen($path, 'w+');
432
-		fwrite($handle, $data);
433
-		fclose($handle);
434
-		return true;
435
-	}
436
-
437
-	public function writeStream(string $path, $stream, int $size = null): int {
438
-		$stat = $this->stat($path);
439
-		if (empty($stat)) {
440
-			// create new file
441
-			$stat = [
442
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
443
-			];
444
-		}
445
-		// update stat with new data
446
-		$mTime = time();
447
-		$stat['size'] = (int)$size;
448
-		$stat['mtime'] = $mTime;
449
-		$stat['storage_mtime'] = $mTime;
450
-
451
-		$mimetypeDetector = \OC::$server->getMimeTypeDetector();
452
-		$mimetype = $mimetypeDetector->detectPath($path);
453
-
454
-		$stat['mimetype'] = $mimetype;
455
-		$stat['etag'] = $this->getETag($path);
456
-
457
-		$exists = $this->getCache()->inCache($path);
458
-		$uploadPath = $exists ? $path : $path . '.part';
459
-
460
-		if ($exists) {
461
-			$fileId = $stat['fileid'];
462
-		} else {
463
-			$fileId = $this->getCache()->put($uploadPath, $stat);
464
-		}
465
-
466
-		$urn = $this->getURN($fileId);
467
-		try {
468
-			//upload to object storage
469
-			if ($size === null) {
470
-				$countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, &$size) {
471
-					$this->getCache()->update($fileId, [
472
-						'size' => $writtenSize
473
-					]);
474
-					$size = $writtenSize;
475
-				});
476
-				$this->objectStore->writeObject($urn, $countStream);
477
-				if (is_resource($countStream)) {
478
-					fclose($countStream);
479
-				}
480
-				$stat['size'] = $size;
481
-			} else {
482
-				$this->objectStore->writeObject($urn, $stream);
483
-			}
484
-		} catch (\Exception $ex) {
485
-			if (!$exists) {
486
-				/*
40
+    /**
41
+     * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
42
+     */
43
+    protected $objectStore;
44
+    /**
45
+     * @var string $id
46
+     */
47
+    protected $id;
48
+    /**
49
+     * @var \OC\User\User $user
50
+     */
51
+    protected $user;
52
+
53
+    private $objectPrefix = 'urn:oid:';
54
+
55
+    private $logger;
56
+
57
+    public function __construct($params) {
58
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
59
+            $this->objectStore = $params['objectstore'];
60
+        } else {
61
+            throw new \Exception('missing IObjectStore instance');
62
+        }
63
+        if (isset($params['storageid'])) {
64
+            $this->id = 'object::store:' . $params['storageid'];
65
+        } else {
66
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
67
+        }
68
+        if (isset($params['objectPrefix'])) {
69
+            $this->objectPrefix = $params['objectPrefix'];
70
+        }
71
+        //initialize cache with root directory in cache
72
+        if (!$this->is_dir('/')) {
73
+            $this->mkdir('/');
74
+        }
75
+
76
+        $this->logger = \OC::$server->getLogger();
77
+    }
78
+
79
+    public function mkdir($path) {
80
+        $path = $this->normalizePath($path);
81
+
82
+        if ($this->file_exists($path)) {
83
+            return false;
84
+        }
85
+
86
+        $mTime = time();
87
+        $data = [
88
+            'mimetype' => 'httpd/unix-directory',
89
+            'size' => 0,
90
+            'mtime' => $mTime,
91
+            'storage_mtime' => $mTime,
92
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
93
+        ];
94
+        if ($path === '') {
95
+            //create root on the fly
96
+            $data['etag'] = $this->getETag('');
97
+            $this->getCache()->put('', $data);
98
+            return true;
99
+        } else {
100
+            // if parent does not exist, create it
101
+            $parent = $this->normalizePath(dirname($path));
102
+            $parentType = $this->filetype($parent);
103
+            if ($parentType === false) {
104
+                if (!$this->mkdir($parent)) {
105
+                    // something went wrong
106
+                    return false;
107
+                }
108
+            } elseif ($parentType === 'file') {
109
+                // parent is a file
110
+                return false;
111
+            }
112
+            // finally create the new dir
113
+            $mTime = time(); // update mtime
114
+            $data['mtime'] = $mTime;
115
+            $data['storage_mtime'] = $mTime;
116
+            $data['etag'] = $this->getETag($path);
117
+            $this->getCache()->put($path, $data);
118
+            return true;
119
+        }
120
+    }
121
+
122
+    /**
123
+     * @param string $path
124
+     * @return string
125
+     */
126
+    private function normalizePath($path) {
127
+        $path = trim($path, '/');
128
+        //FIXME why do we sometimes get a path like 'files//username'?
129
+        $path = str_replace('//', '/', $path);
130
+
131
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
132
+        if (!$path || $path === '.') {
133
+            $path = '';
134
+        }
135
+
136
+        return $path;
137
+    }
138
+
139
+    /**
140
+     * Object Stores use a NoopScanner because metadata is directly stored in
141
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
142
+     *
143
+     * @param string $path
144
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
145
+     * @return \OC\Files\ObjectStore\NoopScanner
146
+     */
147
+    public function getScanner($path = '', $storage = null) {
148
+        if (!$storage) {
149
+            $storage = $this;
150
+        }
151
+        if (!isset($this->scanner)) {
152
+            $this->scanner = new NoopScanner($storage);
153
+        }
154
+        return $this->scanner;
155
+    }
156
+
157
+    public function getId() {
158
+        return $this->id;
159
+    }
160
+
161
+    public function rmdir($path) {
162
+        $path = $this->normalizePath($path);
163
+
164
+        if (!$this->is_dir($path)) {
165
+            return false;
166
+        }
167
+
168
+        if (!$this->rmObjects($path)) {
169
+            return false;
170
+        }
171
+
172
+        $this->getCache()->remove($path);
173
+
174
+        return true;
175
+    }
176
+
177
+    private function rmObjects($path) {
178
+        $children = $this->getCache()->getFolderContents($path);
179
+        foreach ($children as $child) {
180
+            if ($child['mimetype'] === 'httpd/unix-directory') {
181
+                if (!$this->rmObjects($child['path'])) {
182
+                    return false;
183
+                }
184
+            } else {
185
+                if (!$this->unlink($child['path'])) {
186
+                    return false;
187
+                }
188
+            }
189
+        }
190
+
191
+        return true;
192
+    }
193
+
194
+    public function unlink($path) {
195
+        $path = $this->normalizePath($path);
196
+        $stat = $this->stat($path);
197
+
198
+        if ($stat && isset($stat['fileid'])) {
199
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
200
+                return $this->rmdir($path);
201
+            }
202
+            try {
203
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
204
+            } catch (\Exception $ex) {
205
+                if ($ex->getCode() !== 404) {
206
+                    $this->logger->logException($ex, [
207
+                        'app' => 'objectstore',
208
+                        'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
209
+                    ]);
210
+                    return false;
211
+                }
212
+                //removing from cache is ok as it does not exist in the objectstore anyway
213
+            }
214
+            $this->getCache()->remove($path);
215
+            return true;
216
+        }
217
+        return false;
218
+    }
219
+
220
+    public function stat($path) {
221
+        $path = $this->normalizePath($path);
222
+        $cacheEntry = $this->getCache()->get($path);
223
+        if ($cacheEntry instanceof CacheEntry) {
224
+            return $cacheEntry->getData();
225
+        } else {
226
+            return false;
227
+        }
228
+    }
229
+
230
+    public function getPermissions($path) {
231
+        $stat = $this->stat($path);
232
+
233
+        if (is_array($stat) && isset($stat['permissions'])) {
234
+            return $stat['permissions'];
235
+        }
236
+
237
+        return parent::getPermissions($path);
238
+    }
239
+
240
+    /**
241
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
242
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
243
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
244
+     *
245
+     * @param int $fileId the fileid
246
+     * @return null|string the unified resource name used to identify the object
247
+     */
248
+    public function getURN($fileId) {
249
+        if (is_numeric($fileId)) {
250
+            return $this->objectPrefix . $fileId;
251
+        }
252
+        return null;
253
+    }
254
+
255
+    public function opendir($path) {
256
+        $path = $this->normalizePath($path);
257
+
258
+        try {
259
+            $files = [];
260
+            $folderContents = $this->getCache()->getFolderContents($path);
261
+            foreach ($folderContents as $file) {
262
+                $files[] = $file['name'];
263
+            }
264
+
265
+            return IteratorDirectory::wrap($files);
266
+        } catch (\Exception $e) {
267
+            $this->logger->logException($e);
268
+            return false;
269
+        }
270
+    }
271
+
272
+    public function filetype($path) {
273
+        $path = $this->normalizePath($path);
274
+        $stat = $this->stat($path);
275
+        if ($stat) {
276
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
277
+                return 'dir';
278
+            }
279
+            return 'file';
280
+        } else {
281
+            return false;
282
+        }
283
+    }
284
+
285
+    public function fopen($path, $mode) {
286
+        $path = $this->normalizePath($path);
287
+
288
+        if (strrpos($path, '.') !== false) {
289
+            $ext = substr($path, strrpos($path, '.'));
290
+        } else {
291
+            $ext = '';
292
+        }
293
+
294
+        switch ($mode) {
295
+            case 'r':
296
+            case 'rb':
297
+                $stat = $this->stat($path);
298
+                if (is_array($stat)) {
299
+                    try {
300
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
301
+                    } catch (NotFoundException $e) {
302
+                        $this->logger->logException($e, [
303
+                            'app' => 'objectstore',
304
+                            'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
305
+                        ]);
306
+                        throw $e;
307
+                    } catch (\Exception $ex) {
308
+                        $this->logger->logException($ex, [
309
+                            'app' => 'objectstore',
310
+                            'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
311
+                        ]);
312
+                        return false;
313
+                    }
314
+                } else {
315
+                    return false;
316
+                }
317
+                // no break
318
+            case 'w':
319
+            case 'wb':
320
+            case 'w+':
321
+            case 'wb+':
322
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
323
+                $handle = fopen($tmpFile, $mode);
324
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
325
+                    $this->writeBack($tmpFile, $path);
326
+                });
327
+            case 'a':
328
+            case 'ab':
329
+            case 'r+':
330
+            case 'a+':
331
+            case 'x':
332
+            case 'x+':
333
+            case 'c':
334
+            case 'c+':
335
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
336
+                if ($this->file_exists($path)) {
337
+                    $source = $this->fopen($path, 'r');
338
+                    file_put_contents($tmpFile, $source);
339
+                }
340
+                $handle = fopen($tmpFile, $mode);
341
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
342
+                    $this->writeBack($tmpFile, $path);
343
+                });
344
+        }
345
+        return false;
346
+    }
347
+
348
+    public function file_exists($path) {
349
+        $path = $this->normalizePath($path);
350
+        return (bool)$this->stat($path);
351
+    }
352
+
353
+    public function rename($source, $target) {
354
+        $source = $this->normalizePath($source);
355
+        $target = $this->normalizePath($target);
356
+        $this->remove($target);
357
+        $this->getCache()->move($source, $target);
358
+        $this->touch(dirname($target));
359
+        return true;
360
+    }
361
+
362
+    public function getMimeType($path) {
363
+        $path = $this->normalizePath($path);
364
+        return parent::getMimeType($path);
365
+    }
366
+
367
+    public function touch($path, $mtime = null) {
368
+        if (is_null($mtime)) {
369
+            $mtime = time();
370
+        }
371
+
372
+        $path = $this->normalizePath($path);
373
+        $dirName = dirname($path);
374
+        $parentExists = $this->is_dir($dirName);
375
+        if (!$parentExists) {
376
+            return false;
377
+        }
378
+
379
+        $stat = $this->stat($path);
380
+        if (is_array($stat)) {
381
+            // update existing mtime in db
382
+            $stat['mtime'] = $mtime;
383
+            $this->getCache()->update($stat['fileid'], $stat);
384
+        } else {
385
+            try {
386
+                //create a empty file, need to have at least on char to make it
387
+                // work with all object storage implementations
388
+                $this->file_put_contents($path, ' ');
389
+                $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
390
+                $stat = [
391
+                    'etag' => $this->getETag($path),
392
+                    'mimetype' => $mimeType,
393
+                    'size' => 0,
394
+                    'mtime' => $mtime,
395
+                    'storage_mtime' => $mtime,
396
+                    'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
397
+                ];
398
+                $this->getCache()->put($path, $stat);
399
+            } catch (\Exception $ex) {
400
+                $this->logger->logException($ex, [
401
+                    'app' => 'objectstore',
402
+                    'message' => 'Could not create object for ' . $path,
403
+                ]);
404
+                throw $ex;
405
+            }
406
+        }
407
+        return true;
408
+    }
409
+
410
+    public function writeBack($tmpFile, $path) {
411
+        $size = filesize($tmpFile);
412
+        $this->writeStream($path, fopen($tmpFile, 'r'), $size);
413
+    }
414
+
415
+    /**
416
+     * external changes are not supported, exclusive access to the object storage is assumed
417
+     *
418
+     * @param string $path
419
+     * @param int $time
420
+     * @return false
421
+     */
422
+    public function hasUpdated($path, $time) {
423
+        return false;
424
+    }
425
+
426
+    public function needsPartFile() {
427
+        return false;
428
+    }
429
+
430
+    public function file_put_contents($path, $data) {
431
+        $handle = $this->fopen($path, 'w+');
432
+        fwrite($handle, $data);
433
+        fclose($handle);
434
+        return true;
435
+    }
436
+
437
+    public function writeStream(string $path, $stream, int $size = null): int {
438
+        $stat = $this->stat($path);
439
+        if (empty($stat)) {
440
+            // create new file
441
+            $stat = [
442
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
443
+            ];
444
+        }
445
+        // update stat with new data
446
+        $mTime = time();
447
+        $stat['size'] = (int)$size;
448
+        $stat['mtime'] = $mTime;
449
+        $stat['storage_mtime'] = $mTime;
450
+
451
+        $mimetypeDetector = \OC::$server->getMimeTypeDetector();
452
+        $mimetype = $mimetypeDetector->detectPath($path);
453
+
454
+        $stat['mimetype'] = $mimetype;
455
+        $stat['etag'] = $this->getETag($path);
456
+
457
+        $exists = $this->getCache()->inCache($path);
458
+        $uploadPath = $exists ? $path : $path . '.part';
459
+
460
+        if ($exists) {
461
+            $fileId = $stat['fileid'];
462
+        } else {
463
+            $fileId = $this->getCache()->put($uploadPath, $stat);
464
+        }
465
+
466
+        $urn = $this->getURN($fileId);
467
+        try {
468
+            //upload to object storage
469
+            if ($size === null) {
470
+                $countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, &$size) {
471
+                    $this->getCache()->update($fileId, [
472
+                        'size' => $writtenSize
473
+                    ]);
474
+                    $size = $writtenSize;
475
+                });
476
+                $this->objectStore->writeObject($urn, $countStream);
477
+                if (is_resource($countStream)) {
478
+                    fclose($countStream);
479
+                }
480
+                $stat['size'] = $size;
481
+            } else {
482
+                $this->objectStore->writeObject($urn, $stream);
483
+            }
484
+        } catch (\Exception $ex) {
485
+            if (!$exists) {
486
+                /*
487 487
 				 * Only remove the entry if we are dealing with a new file.
488 488
 				 * Else people lose access to existing files
489 489
 				 */
490
-				$this->getCache()->remove($uploadPath);
491
-				$this->logger->logException($ex, [
492
-					'app' => 'objectstore',
493
-					'message' => 'Could not create object ' . $urn . ' for ' . $path,
494
-				]);
495
-			} else {
496
-				$this->logger->logException($ex, [
497
-					'app' => 'objectstore',
498
-					'message' => 'Could not update object ' . $urn . ' for ' . $path,
499
-				]);
500
-			}
501
-			throw $ex; // make this bubble up
502
-		}
503
-
504
-		if ($exists) {
505
-			$this->getCache()->update($fileId, $stat);
506
-		} else {
507
-			if ($this->objectStore->objectExists($urn)) {
508
-				$this->getCache()->move($uploadPath, $path);
509
-			} else {
510
-				$this->getCache()->remove($uploadPath);
511
-				throw new \Exception("Object not found after writing (urn: $urn, path: $path)", 404);
512
-			}
513
-		}
514
-
515
-		return $size;
516
-	}
517
-
518
-	public function getObjectStore(): IObjectStore {
519
-		return $this->objectStore;
520
-	}
490
+                $this->getCache()->remove($uploadPath);
491
+                $this->logger->logException($ex, [
492
+                    'app' => 'objectstore',
493
+                    'message' => 'Could not create object ' . $urn . ' for ' . $path,
494
+                ]);
495
+            } else {
496
+                $this->logger->logException($ex, [
497
+                    'app' => 'objectstore',
498
+                    'message' => 'Could not update object ' . $urn . ' for ' . $path,
499
+                ]);
500
+            }
501
+            throw $ex; // make this bubble up
502
+        }
503
+
504
+        if ($exists) {
505
+            $this->getCache()->update($fileId, $stat);
506
+        } else {
507
+            if ($this->objectStore->objectExists($urn)) {
508
+                $this->getCache()->move($uploadPath, $path);
509
+            } else {
510
+                $this->getCache()->remove($uploadPath);
511
+                throw new \Exception("Object not found after writing (urn: $urn, path: $path)", 404);
512
+            }
513
+        }
514
+
515
+        return $size;
516
+    }
517
+
518
+    public function getObjectStore(): IObjectStore {
519
+        return $this->objectStore;
520
+    }
521 521
 }
Please login to merge, or discard this patch.