Completed
Push — stable13 ( c85d6b...59b464 )
by Morris
29:22 queued 15:34
created
lib/private/Files/ObjectStore/ObjectStoreStorage.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -28,7 +28,6 @@
 block discarded – undo
28 28
 use Icewind\Streams\CallbackWrapper;
29 29
 use Icewind\Streams\IteratorDirectory;
30 30
 use OC\Files\Cache\CacheEntry;
31
-use OC\Files\Stream\CountReadStream;
32 31
 use OCP\Files\NotFoundException;
33 32
 use OCP\Files\ObjectStore\IObjectStore;
34 33
 
Please login to merge, or discard this patch.
Indentation   +403 added lines, -403 removed lines patch added patch discarded remove patch
@@ -33,407 +33,407 @@
 block discarded – undo
33 33
 use OCP\Files\ObjectStore\IObjectStore;
34 34
 
35 35
 class ObjectStoreStorage extends \OC\Files\Storage\Common {
36
-	/**
37
-	 * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
38
-	 */
39
-	protected $objectStore;
40
-	/**
41
-	 * @var string $id
42
-	 */
43
-	protected $id;
44
-	/**
45
-	 * @var \OC\User\User $user
46
-	 */
47
-	protected $user;
48
-
49
-	private $objectPrefix = 'urn:oid:';
50
-
51
-	private $logger;
52
-
53
-	public function __construct($params) {
54
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
55
-			$this->objectStore = $params['objectstore'];
56
-		} else {
57
-			throw new \Exception('missing IObjectStore instance');
58
-		}
59
-		if (isset($params['storageid'])) {
60
-			$this->id = 'object::store:' . $params['storageid'];
61
-		} else {
62
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
63
-		}
64
-		if (isset($params['objectPrefix'])) {
65
-			$this->objectPrefix = $params['objectPrefix'];
66
-		}
67
-		//initialize cache with root directory in cache
68
-		if (!$this->is_dir('/')) {
69
-			$this->mkdir('/');
70
-		}
71
-
72
-		$this->logger = \OC::$server->getLogger();
73
-	}
74
-
75
-	public function mkdir($path) {
76
-		$path = $this->normalizePath($path);
77
-
78
-		if ($this->file_exists($path)) {
79
-			return false;
80
-		}
81
-
82
-		$mTime = time();
83
-		$data = [
84
-			'mimetype' => 'httpd/unix-directory',
85
-			'size' => 0,
86
-			'mtime' => $mTime,
87
-			'storage_mtime' => $mTime,
88
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
89
-		];
90
-		if ($path === '') {
91
-			//create root on the fly
92
-			$data['etag'] = $this->getETag('');
93
-			$this->getCache()->put('', $data);
94
-			return true;
95
-		} else {
96
-			// if parent does not exist, create it
97
-			$parent = $this->normalizePath(dirname($path));
98
-			$parentType = $this->filetype($parent);
99
-			if ($parentType === false) {
100
-				if (!$this->mkdir($parent)) {
101
-					// something went wrong
102
-					return false;
103
-				}
104
-			} else if ($parentType === 'file') {
105
-				// parent is a file
106
-				return false;
107
-			}
108
-			// finally create the new dir
109
-			$mTime = time(); // update mtime
110
-			$data['mtime'] = $mTime;
111
-			$data['storage_mtime'] = $mTime;
112
-			$data['etag'] = $this->getETag($path);
113
-			$this->getCache()->put($path, $data);
114
-			return true;
115
-		}
116
-	}
117
-
118
-	/**
119
-	 * @param string $path
120
-	 * @return string
121
-	 */
122
-	private function normalizePath($path) {
123
-		$path = trim($path, '/');
124
-		//FIXME why do we sometimes get a path like 'files//username'?
125
-		$path = str_replace('//', '/', $path);
126
-
127
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
128
-		if (!$path || $path === '.') {
129
-			$path = '';
130
-		}
131
-
132
-		return $path;
133
-	}
134
-
135
-	/**
136
-	 * Object Stores use a NoopScanner because metadata is directly stored in
137
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
138
-	 *
139
-	 * @param string $path
140
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
141
-	 * @return \OC\Files\ObjectStore\NoopScanner
142
-	 */
143
-	public function getScanner($path = '', $storage = null) {
144
-		if (!$storage) {
145
-			$storage = $this;
146
-		}
147
-		if (!isset($this->scanner)) {
148
-			$this->scanner = new NoopScanner($storage);
149
-		}
150
-		return $this->scanner;
151
-	}
152
-
153
-	public function getId() {
154
-		return $this->id;
155
-	}
156
-
157
-	public function rmdir($path) {
158
-		$path = $this->normalizePath($path);
159
-
160
-		if (!$this->is_dir($path)) {
161
-			return false;
162
-		}
163
-
164
-		$this->rmObjects($path);
165
-
166
-		$this->getCache()->remove($path);
167
-
168
-		return true;
169
-	}
170
-
171
-	private function rmObjects($path) {
172
-		$children = $this->getCache()->getFolderContents($path);
173
-		foreach ($children as $child) {
174
-			if ($child['mimetype'] === 'httpd/unix-directory') {
175
-				$this->rmObjects($child['path']);
176
-			} else {
177
-				$this->unlink($child['path']);
178
-			}
179
-		}
180
-	}
181
-
182
-	public function unlink($path) {
183
-		$path = $this->normalizePath($path);
184
-		$stat = $this->stat($path);
185
-
186
-		if ($stat && isset($stat['fileid'])) {
187
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
188
-				return $this->rmdir($path);
189
-			}
190
-			try {
191
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
192
-			} catch (\Exception $ex) {
193
-				if ($ex->getCode() !== 404) {
194
-					$this->logger->logException($ex, [
195
-						'app' => 'objectstore',
196
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
197
-					]);
198
-					return false;
199
-				} else {
200
-					//removing from cache is ok as it does not exist in the objectstore anyway
201
-				}
202
-			}
203
-			$this->getCache()->remove($path);
204
-			return true;
205
-		}
206
-		return false;
207
-	}
208
-
209
-	public function stat($path) {
210
-		$path = $this->normalizePath($path);
211
-		$cacheEntry = $this->getCache()->get($path);
212
-		if ($cacheEntry instanceof CacheEntry) {
213
-			return $cacheEntry->getData();
214
-		} else {
215
-			return false;
216
-		}
217
-	}
218
-
219
-	/**
220
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
221
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
222
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
223
-	 *
224
-	 * @param int $fileId the fileid
225
-	 * @return null|string the unified resource name used to identify the object
226
-	 */
227
-	protected function getURN($fileId) {
228
-		if (is_numeric($fileId)) {
229
-			return $this->objectPrefix . $fileId;
230
-		}
231
-		return null;
232
-	}
233
-
234
-	public function opendir($path) {
235
-		$path = $this->normalizePath($path);
236
-
237
-		try {
238
-			$files = array();
239
-			$folderContents = $this->getCache()->getFolderContents($path);
240
-			foreach ($folderContents as $file) {
241
-				$files[] = $file['name'];
242
-			}
243
-
244
-			return IteratorDirectory::wrap($files);
245
-		} catch (\Exception $e) {
246
-			$this->logger->logException($e);
247
-			return false;
248
-		}
249
-	}
250
-
251
-	public function filetype($path) {
252
-		$path = $this->normalizePath($path);
253
-		$stat = $this->stat($path);
254
-		if ($stat) {
255
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
256
-				return 'dir';
257
-			}
258
-			return 'file';
259
-		} else {
260
-			return false;
261
-		}
262
-	}
263
-
264
-	public function fopen($path, $mode) {
265
-		$path = $this->normalizePath($path);
266
-
267
-		switch ($mode) {
268
-			case 'r':
269
-			case 'rb':
270
-				$stat = $this->stat($path);
271
-				if (is_array($stat)) {
272
-					try {
273
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
274
-					} catch (NotFoundException $e) {
275
-						$this->logger->logException($e, [
276
-							'app' => 'objectstore',
277
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
278
-						]);
279
-						throw $e;
280
-					} catch (\Exception $ex) {
281
-						$this->logger->logException($ex, [
282
-							'app' => 'objectstore',
283
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
284
-						]);
285
-						return false;
286
-					}
287
-				} else {
288
-					return false;
289
-				}
290
-			case 'w':
291
-			case 'wb':
292
-			case 'a':
293
-			case 'ab':
294
-			case 'r+':
295
-			case 'w+':
296
-			case 'wb+':
297
-			case 'a+':
298
-			case 'x':
299
-			case 'x+':
300
-			case 'c':
301
-			case 'c+':
302
-				if (strrpos($path, '.') !== false) {
303
-					$ext = substr($path, strrpos($path, '.'));
304
-				} else {
305
-					$ext = '';
306
-				}
307
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
308
-				if ($this->file_exists($path)) {
309
-					$source = $this->fopen($path, 'r');
310
-					file_put_contents($tmpFile, $source);
311
-				}
312
-				$handle = fopen($tmpFile, $mode);
313
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
314
-					$this->writeBack($tmpFile, $path);
315
-				});
316
-		}
317
-		return false;
318
-	}
319
-
320
-	public function file_exists($path) {
321
-		$path = $this->normalizePath($path);
322
-		return (bool)$this->stat($path);
323
-	}
324
-
325
-	public function rename($source, $target) {
326
-		$source = $this->normalizePath($source);
327
-		$target = $this->normalizePath($target);
328
-		$this->remove($target);
329
-		$this->getCache()->move($source, $target);
330
-		$this->touch(dirname($target));
331
-		return true;
332
-	}
333
-
334
-	public function getMimeType($path) {
335
-		$path = $this->normalizePath($path);
336
-		$stat = $this->stat($path);
337
-		if (is_array($stat)) {
338
-			return $stat['mimetype'];
339
-		} else {
340
-			return false;
341
-		}
342
-	}
343
-
344
-	public function touch($path, $mtime = null) {
345
-		if (is_null($mtime)) {
346
-			$mtime = time();
347
-		}
348
-
349
-		$path = $this->normalizePath($path);
350
-		$dirName = dirname($path);
351
-		$parentExists = $this->is_dir($dirName);
352
-		if (!$parentExists) {
353
-			return false;
354
-		}
355
-
356
-		$stat = $this->stat($path);
357
-		if (is_array($stat)) {
358
-			// update existing mtime in db
359
-			$stat['mtime'] = $mtime;
360
-			$this->getCache()->update($stat['fileid'], $stat);
361
-		} else {
362
-			try {
363
-				//create a empty file, need to have at least on char to make it
364
-				// work with all object storage implementations
365
-				$this->file_put_contents($path, ' ');
366
-				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
367
-				$stat = array(
368
-					'etag' => $this->getETag($path),
369
-					'mimetype' => $mimeType,
370
-					'size' => 0,
371
-					'mtime' => $mtime,
372
-					'storage_mtime' => $mtime,
373
-					'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
374
-				);
375
-				$this->getCache()->put($path, $stat);
376
-			} catch (\Exception $ex) {
377
-				$this->logger->logException($ex, [
378
-					'app' => 'objectstore',
379
-					'message' => 'Could not create object for ' . $path,
380
-				]);
381
-				return false;
382
-			}
383
-		}
384
-		return true;
385
-	}
386
-
387
-	public function writeBack($tmpFile, $path) {
388
-		$stat = $this->stat($path);
389
-		if (empty($stat)) {
390
-			// create new file
391
-			$stat = array(
392
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
393
-			);
394
-		}
395
-		// update stat with new data
396
-		$mTime = time();
397
-		$stat['size'] = filesize($tmpFile);
398
-		$stat['mtime'] = $mTime;
399
-		$stat['storage_mtime'] = $mTime;
400
-
401
-		// run path based detection first, to use file extension because $tmpFile is only a random string
402
-		$mimetypeDetector = \OC::$server->getMimeTypeDetector();
403
-		$mimetype = $mimetypeDetector->detectPath($path);
404
-		if ($mimetype === 'application/octet-stream') {
405
-			$mimetype = $mimetypeDetector->detect($tmpFile);
406
-		}
407
-
408
-		$stat['mimetype'] = $mimetype;
409
-		$stat['etag'] = $this->getETag($path);
410
-
411
-		$fileId = $this->getCache()->put($path, $stat);
412
-		try {
413
-			//upload to object storage
414
-			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
415
-		} catch (\Exception $ex) {
416
-			$this->getCache()->remove($path);
417
-			$this->logger->logException($ex, [
418
-				'app' => 'objectstore',
419
-				'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
420
-			]);
421
-			throw $ex; // make this bubble up
422
-		}
423
-	}
424
-
425
-	/**
426
-	 * external changes are not supported, exclusive access to the object storage is assumed
427
-	 *
428
-	 * @param string $path
429
-	 * @param int $time
430
-	 * @return false
431
-	 */
432
-	public function hasUpdated($path, $time) {
433
-		return false;
434
-	}
435
-
436
-	public function needsPartFile() {
437
-		return false;
438
-	}
36
+    /**
37
+     * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
38
+     */
39
+    protected $objectStore;
40
+    /**
41
+     * @var string $id
42
+     */
43
+    protected $id;
44
+    /**
45
+     * @var \OC\User\User $user
46
+     */
47
+    protected $user;
48
+
49
+    private $objectPrefix = 'urn:oid:';
50
+
51
+    private $logger;
52
+
53
+    public function __construct($params) {
54
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
55
+            $this->objectStore = $params['objectstore'];
56
+        } else {
57
+            throw new \Exception('missing IObjectStore instance');
58
+        }
59
+        if (isset($params['storageid'])) {
60
+            $this->id = 'object::store:' . $params['storageid'];
61
+        } else {
62
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
63
+        }
64
+        if (isset($params['objectPrefix'])) {
65
+            $this->objectPrefix = $params['objectPrefix'];
66
+        }
67
+        //initialize cache with root directory in cache
68
+        if (!$this->is_dir('/')) {
69
+            $this->mkdir('/');
70
+        }
71
+
72
+        $this->logger = \OC::$server->getLogger();
73
+    }
74
+
75
+    public function mkdir($path) {
76
+        $path = $this->normalizePath($path);
77
+
78
+        if ($this->file_exists($path)) {
79
+            return false;
80
+        }
81
+
82
+        $mTime = time();
83
+        $data = [
84
+            'mimetype' => 'httpd/unix-directory',
85
+            'size' => 0,
86
+            'mtime' => $mTime,
87
+            'storage_mtime' => $mTime,
88
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
89
+        ];
90
+        if ($path === '') {
91
+            //create root on the fly
92
+            $data['etag'] = $this->getETag('');
93
+            $this->getCache()->put('', $data);
94
+            return true;
95
+        } else {
96
+            // if parent does not exist, create it
97
+            $parent = $this->normalizePath(dirname($path));
98
+            $parentType = $this->filetype($parent);
99
+            if ($parentType === false) {
100
+                if (!$this->mkdir($parent)) {
101
+                    // something went wrong
102
+                    return false;
103
+                }
104
+            } else if ($parentType === 'file') {
105
+                // parent is a file
106
+                return false;
107
+            }
108
+            // finally create the new dir
109
+            $mTime = time(); // update mtime
110
+            $data['mtime'] = $mTime;
111
+            $data['storage_mtime'] = $mTime;
112
+            $data['etag'] = $this->getETag($path);
113
+            $this->getCache()->put($path, $data);
114
+            return true;
115
+        }
116
+    }
117
+
118
+    /**
119
+     * @param string $path
120
+     * @return string
121
+     */
122
+    private function normalizePath($path) {
123
+        $path = trim($path, '/');
124
+        //FIXME why do we sometimes get a path like 'files//username'?
125
+        $path = str_replace('//', '/', $path);
126
+
127
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
128
+        if (!$path || $path === '.') {
129
+            $path = '';
130
+        }
131
+
132
+        return $path;
133
+    }
134
+
135
+    /**
136
+     * Object Stores use a NoopScanner because metadata is directly stored in
137
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
138
+     *
139
+     * @param string $path
140
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
141
+     * @return \OC\Files\ObjectStore\NoopScanner
142
+     */
143
+    public function getScanner($path = '', $storage = null) {
144
+        if (!$storage) {
145
+            $storage = $this;
146
+        }
147
+        if (!isset($this->scanner)) {
148
+            $this->scanner = new NoopScanner($storage);
149
+        }
150
+        return $this->scanner;
151
+    }
152
+
153
+    public function getId() {
154
+        return $this->id;
155
+    }
156
+
157
+    public function rmdir($path) {
158
+        $path = $this->normalizePath($path);
159
+
160
+        if (!$this->is_dir($path)) {
161
+            return false;
162
+        }
163
+
164
+        $this->rmObjects($path);
165
+
166
+        $this->getCache()->remove($path);
167
+
168
+        return true;
169
+    }
170
+
171
+    private function rmObjects($path) {
172
+        $children = $this->getCache()->getFolderContents($path);
173
+        foreach ($children as $child) {
174
+            if ($child['mimetype'] === 'httpd/unix-directory') {
175
+                $this->rmObjects($child['path']);
176
+            } else {
177
+                $this->unlink($child['path']);
178
+            }
179
+        }
180
+    }
181
+
182
+    public function unlink($path) {
183
+        $path = $this->normalizePath($path);
184
+        $stat = $this->stat($path);
185
+
186
+        if ($stat && isset($stat['fileid'])) {
187
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
188
+                return $this->rmdir($path);
189
+            }
190
+            try {
191
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
192
+            } catch (\Exception $ex) {
193
+                if ($ex->getCode() !== 404) {
194
+                    $this->logger->logException($ex, [
195
+                        'app' => 'objectstore',
196
+                        'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
197
+                    ]);
198
+                    return false;
199
+                } else {
200
+                    //removing from cache is ok as it does not exist in the objectstore anyway
201
+                }
202
+            }
203
+            $this->getCache()->remove($path);
204
+            return true;
205
+        }
206
+        return false;
207
+    }
208
+
209
+    public function stat($path) {
210
+        $path = $this->normalizePath($path);
211
+        $cacheEntry = $this->getCache()->get($path);
212
+        if ($cacheEntry instanceof CacheEntry) {
213
+            return $cacheEntry->getData();
214
+        } else {
215
+            return false;
216
+        }
217
+    }
218
+
219
+    /**
220
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
221
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
222
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
223
+     *
224
+     * @param int $fileId the fileid
225
+     * @return null|string the unified resource name used to identify the object
226
+     */
227
+    protected function getURN($fileId) {
228
+        if (is_numeric($fileId)) {
229
+            return $this->objectPrefix . $fileId;
230
+        }
231
+        return null;
232
+    }
233
+
234
+    public function opendir($path) {
235
+        $path = $this->normalizePath($path);
236
+
237
+        try {
238
+            $files = array();
239
+            $folderContents = $this->getCache()->getFolderContents($path);
240
+            foreach ($folderContents as $file) {
241
+                $files[] = $file['name'];
242
+            }
243
+
244
+            return IteratorDirectory::wrap($files);
245
+        } catch (\Exception $e) {
246
+            $this->logger->logException($e);
247
+            return false;
248
+        }
249
+    }
250
+
251
+    public function filetype($path) {
252
+        $path = $this->normalizePath($path);
253
+        $stat = $this->stat($path);
254
+        if ($stat) {
255
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
256
+                return 'dir';
257
+            }
258
+            return 'file';
259
+        } else {
260
+            return false;
261
+        }
262
+    }
263
+
264
+    public function fopen($path, $mode) {
265
+        $path = $this->normalizePath($path);
266
+
267
+        switch ($mode) {
268
+            case 'r':
269
+            case 'rb':
270
+                $stat = $this->stat($path);
271
+                if (is_array($stat)) {
272
+                    try {
273
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
274
+                    } catch (NotFoundException $e) {
275
+                        $this->logger->logException($e, [
276
+                            'app' => 'objectstore',
277
+                            'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
278
+                        ]);
279
+                        throw $e;
280
+                    } catch (\Exception $ex) {
281
+                        $this->logger->logException($ex, [
282
+                            'app' => 'objectstore',
283
+                            'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
284
+                        ]);
285
+                        return false;
286
+                    }
287
+                } else {
288
+                    return false;
289
+                }
290
+            case 'w':
291
+            case 'wb':
292
+            case 'a':
293
+            case 'ab':
294
+            case 'r+':
295
+            case 'w+':
296
+            case 'wb+':
297
+            case 'a+':
298
+            case 'x':
299
+            case 'x+':
300
+            case 'c':
301
+            case 'c+':
302
+                if (strrpos($path, '.') !== false) {
303
+                    $ext = substr($path, strrpos($path, '.'));
304
+                } else {
305
+                    $ext = '';
306
+                }
307
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
308
+                if ($this->file_exists($path)) {
309
+                    $source = $this->fopen($path, 'r');
310
+                    file_put_contents($tmpFile, $source);
311
+                }
312
+                $handle = fopen($tmpFile, $mode);
313
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
314
+                    $this->writeBack($tmpFile, $path);
315
+                });
316
+        }
317
+        return false;
318
+    }
319
+
320
+    public function file_exists($path) {
321
+        $path = $this->normalizePath($path);
322
+        return (bool)$this->stat($path);
323
+    }
324
+
325
+    public function rename($source, $target) {
326
+        $source = $this->normalizePath($source);
327
+        $target = $this->normalizePath($target);
328
+        $this->remove($target);
329
+        $this->getCache()->move($source, $target);
330
+        $this->touch(dirname($target));
331
+        return true;
332
+    }
333
+
334
+    public function getMimeType($path) {
335
+        $path = $this->normalizePath($path);
336
+        $stat = $this->stat($path);
337
+        if (is_array($stat)) {
338
+            return $stat['mimetype'];
339
+        } else {
340
+            return false;
341
+        }
342
+    }
343
+
344
+    public function touch($path, $mtime = null) {
345
+        if (is_null($mtime)) {
346
+            $mtime = time();
347
+        }
348
+
349
+        $path = $this->normalizePath($path);
350
+        $dirName = dirname($path);
351
+        $parentExists = $this->is_dir($dirName);
352
+        if (!$parentExists) {
353
+            return false;
354
+        }
355
+
356
+        $stat = $this->stat($path);
357
+        if (is_array($stat)) {
358
+            // update existing mtime in db
359
+            $stat['mtime'] = $mtime;
360
+            $this->getCache()->update($stat['fileid'], $stat);
361
+        } else {
362
+            try {
363
+                //create a empty file, need to have at least on char to make it
364
+                // work with all object storage implementations
365
+                $this->file_put_contents($path, ' ');
366
+                $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
367
+                $stat = array(
368
+                    'etag' => $this->getETag($path),
369
+                    'mimetype' => $mimeType,
370
+                    'size' => 0,
371
+                    'mtime' => $mtime,
372
+                    'storage_mtime' => $mtime,
373
+                    'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
374
+                );
375
+                $this->getCache()->put($path, $stat);
376
+            } catch (\Exception $ex) {
377
+                $this->logger->logException($ex, [
378
+                    'app' => 'objectstore',
379
+                    'message' => 'Could not create object for ' . $path,
380
+                ]);
381
+                return false;
382
+            }
383
+        }
384
+        return true;
385
+    }
386
+
387
+    public function writeBack($tmpFile, $path) {
388
+        $stat = $this->stat($path);
389
+        if (empty($stat)) {
390
+            // create new file
391
+            $stat = array(
392
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
393
+            );
394
+        }
395
+        // update stat with new data
396
+        $mTime = time();
397
+        $stat['size'] = filesize($tmpFile);
398
+        $stat['mtime'] = $mTime;
399
+        $stat['storage_mtime'] = $mTime;
400
+
401
+        // run path based detection first, to use file extension because $tmpFile is only a random string
402
+        $mimetypeDetector = \OC::$server->getMimeTypeDetector();
403
+        $mimetype = $mimetypeDetector->detectPath($path);
404
+        if ($mimetype === 'application/octet-stream') {
405
+            $mimetype = $mimetypeDetector->detect($tmpFile);
406
+        }
407
+
408
+        $stat['mimetype'] = $mimetype;
409
+        $stat['etag'] = $this->getETag($path);
410
+
411
+        $fileId = $this->getCache()->put($path, $stat);
412
+        try {
413
+            //upload to object storage
414
+            $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
415
+        } catch (\Exception $ex) {
416
+            $this->getCache()->remove($path);
417
+            $this->logger->logException($ex, [
418
+                'app' => 'objectstore',
419
+                'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
420
+            ]);
421
+            throw $ex; // make this bubble up
422
+        }
423
+    }
424
+
425
+    /**
426
+     * external changes are not supported, exclusive access to the object storage is assumed
427
+     *
428
+     * @param string $path
429
+     * @param int $time
430
+     * @return false
431
+     */
432
+    public function hasUpdated($path, $time) {
433
+        return false;
434
+    }
435
+
436
+    public function needsPartFile() {
437
+        return false;
438
+    }
439 439
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -57,9 +57,9 @@  discard block
 block discarded – undo
57 57
 			throw new \Exception('missing IObjectStore instance');
58 58
 		}
59 59
 		if (isset($params['storageid'])) {
60
-			$this->id = 'object::store:' . $params['storageid'];
60
+			$this->id = 'object::store:'.$params['storageid'];
61 61
 		} else {
62
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
62
+			$this->id = 'object::store:'.$this->objectStore->getStorageId();
63 63
 		}
64 64
 		if (isset($params['objectPrefix'])) {
65 65
 			$this->objectPrefix = $params['objectPrefix'];
@@ -193,7 +193,7 @@  discard block
 block discarded – undo
193 193
 				if ($ex->getCode() !== 404) {
194 194
 					$this->logger->logException($ex, [
195 195
 						'app' => 'objectstore',
196
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
196
+						'message' => 'Could not delete object '.$this->getURN($stat['fileid']).' for '.$path,
197 197
 					]);
198 198
 					return false;
199 199
 				} else {
@@ -226,7 +226,7 @@  discard block
 block discarded – undo
226 226
 	 */
227 227
 	protected function getURN($fileId) {
228 228
 		if (is_numeric($fileId)) {
229
-			return $this->objectPrefix . $fileId;
229
+			return $this->objectPrefix.$fileId;
230 230
 		}
231 231
 		return null;
232 232
 	}
@@ -274,13 +274,13 @@  discard block
 block discarded – undo
274 274
 					} catch (NotFoundException $e) {
275 275
 						$this->logger->logException($e, [
276 276
 							'app' => 'objectstore',
277
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
277
+							'message' => 'Could not get object '.$this->getURN($stat['fileid']).' for file '.$path,
278 278
 						]);
279 279
 						throw $e;
280 280
 					} catch (\Exception $ex) {
281 281
 						$this->logger->logException($ex, [
282 282
 							'app' => 'objectstore',
283
-							'message' => 'Could not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
283
+							'message' => 'Could not get object '.$this->getURN($stat['fileid']).' for file '.$path,
284 284
 						]);
285 285
 						return false;
286 286
 					}
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
 					file_put_contents($tmpFile, $source);
311 311
 				}
312 312
 				$handle = fopen($tmpFile, $mode);
313
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
313
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
314 314
 					$this->writeBack($tmpFile, $path);
315 315
 				});
316 316
 		}
@@ -319,7 +319,7 @@  discard block
 block discarded – undo
319 319
 
320 320
 	public function file_exists($path) {
321 321
 		$path = $this->normalizePath($path);
322
-		return (bool)$this->stat($path);
322
+		return (bool) $this->stat($path);
323 323
 	}
324 324
 
325 325
 	public function rename($source, $target) {
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
 			} catch (\Exception $ex) {
377 377
 				$this->logger->logException($ex, [
378 378
 					'app' => 'objectstore',
379
-					'message' => 'Could not create object for ' . $path,
379
+					'message' => 'Could not create object for '.$path,
380 380
 				]);
381 381
 				return false;
382 382
 			}
@@ -416,7 +416,7 @@  discard block
 block discarded – undo
416 416
 			$this->getCache()->remove($path);
417 417
 			$this->logger->logException($ex, [
418 418
 				'app' => 'objectstore',
419
-				'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
419
+				'message' => 'Could not create object '.$this->getURN($fileId).' for '.$path,
420 420
 			]);
421 421
 			throw $ex; // make this bubble up
422 422
 		}
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/Swift.php 1 patch
Indentation   +248 added lines, -248 removed lines patch added patch discarded remove patch
@@ -41,253 +41,253 @@
 block discarded – undo
41 41
 
42 42
 class Swift implements IObjectStore {
43 43
 
44
-	/**
45
-	 * @var \OpenCloud\OpenStack
46
-	 */
47
-	private $client;
48
-
49
-	/**
50
-	 * @var array
51
-	 */
52
-	private $params;
53
-
54
-	/**
55
-	 * @var \OpenCloud\ObjectStore\Service
56
-	 */
57
-	private $objectStoreService;
58
-
59
-	/**
60
-	 * @var \OpenCloud\ObjectStore\Resource\Container
61
-	 */
62
-	private $container;
63
-
64
-	private $memcache;
65
-
66
-	public function __construct($params) {
67
-		if (isset($params['bucket'])) {
68
-			$params['container'] = $params['bucket'];
69
-		}
70
-		if (!isset($params['container'])) {
71
-			$params['container'] = 'owncloud';
72
-		}
73
-		if (!isset($params['autocreate'])) {
74
-			// should only be true for tests
75
-			$params['autocreate'] = false;
76
-		}
77
-
78
-		if (isset($params['apiKey'])) {
79
-			$this->client = new Rackspace($params['url'], $params);
80
-			$cacheKey = $params['username'] . '@' . $params['url'] . '/' . $params['bucket'];
81
-		} else {
82
-			$this->client = new OpenStack($params['url'], $params);
83
-			$cacheKey = $params['username'] . '@' . $params['url'] . '/' . $params['bucket'];
84
-		}
85
-
86
-		$cacheFactory = \OC::$server->getMemCacheFactory();
87
-		$this->memcache = $cacheFactory->createDistributed('swift::' . $cacheKey);
88
-
89
-		$this->params = $params;
90
-	}
91
-
92
-	protected function init() {
93
-		if ($this->container) {
94
-			return;
95
-		}
96
-
97
-		$this->importToken();
98
-
99
-		/** @var Token $token */
100
-		$token = $this->client->getTokenObject();
101
-
102
-		if (!$token || $token->hasExpired()) {
103
-			try {
104
-				$this->client->authenticate();
105
-				$this->exportToken();
106
-			} catch (ClientErrorResponseException $e) {
107
-				$statusCode = $e->getResponse()->getStatusCode();
108
-				if ($statusCode == 412) {
109
-					throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
110
-				} else if ($statusCode === 401) {
111
-					throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
112
-				} else {
113
-					throw new StorageAuthException('Unknown error', $e);
114
-				}
115
-			}
116
-		}
117
-
118
-
119
-		/** @var Catalog $catalog */
120
-		$catalog = $this->client->getCatalog();
121
-
122
-		if (isset($this->params['serviceName'])) {
123
-			$serviceName = $this->params['serviceName'];
124
-		} else {
125
-			$serviceName = Service::DEFAULT_NAME;
126
-		}
127
-
128
-		if (isset($this->params['urlType'])) {
129
-			$urlType = $this->params['urlType'];
130
-			if ($urlType !== 'internalURL' && $urlType !== 'publicURL') {
131
-				throw new StorageNotAvailableException('Invalid url type');
132
-			}
133
-		} else {
134
-			$urlType = Service::DEFAULT_URL_TYPE;
135
-		}
136
-
137
-		$catalogItem = $this->getCatalogForService($catalog, $serviceName);
138
-		if (!$catalogItem) {
139
-			$available = implode(', ', $this->getAvailableServiceNames($catalog));
140
-			throw new StorageNotAvailableException(
141
-				"Service $serviceName not found in service catalog, available services: $available"
142
-			);
143
-		} else if (isset($this->params['region'])) {
144
-			$this->validateRegion($catalogItem, $this->params['region']);
145
-		}
146
-
147
-		$this->objectStoreService = $this->client->objectStoreService($serviceName, $this->params['region'], $urlType);
148
-
149
-		try {
150
-			$this->container = $this->objectStoreService->getContainer($this->params['container']);
151
-		} catch (ClientErrorResponseException $ex) {
152
-			// if the container does not exist and autocreate is true try to create the container on the fly
153
-			if (isset($this->params['autocreate']) && $this->params['autocreate'] === true) {
154
-				$this->container = $this->objectStoreService->createContainer($this->params['container']);
155
-			} else {
156
-				throw $ex;
157
-			}
158
-		}
159
-	}
160
-
161
-	private function exportToken() {
162
-		$export = $this->client->exportCredentials();
163
-		$export['catalog'] = array_map(function (CatalogItem $item) {
164
-			return [
165
-				'name' => $item->getName(),
166
-				'endpoints' => $item->getEndpoints(),
167
-				'type' => $item->getType()
168
-			];
169
-		}, $export['catalog']->getItems());
170
-		$this->memcache->set('token', json_encode($export));
171
-	}
172
-
173
-	private function importToken() {
174
-		$cachedTokenString = $this->memcache->get('token');
175
-		if ($cachedTokenString) {
176
-			$cachedToken = json_decode($cachedTokenString, true);
177
-			$cachedToken['catalog'] = array_map(function (array $item) {
178
-				$itemClass = new \stdClass();
179
-				$itemClass->name = $item['name'];
180
-				$itemClass->endpoints = array_map(function (array $endpoint) {
181
-					return (object) $endpoint;
182
-				}, $item['endpoints']);
183
-				$itemClass->type = $item['type'];
184
-
185
-				return $itemClass;
186
-			}, $cachedToken['catalog']);
187
-			try {
188
-				$this->client->importCredentials($cachedToken);
189
-			} catch (\Exception $e) {
190
-				$this->client->setTokenObject(new Token());
191
-			}
192
-		}
193
-	}
194
-
195
-	/**
196
-	 * @param Catalog $catalog
197
-	 * @param $name
198
-	 * @return null|CatalogItem
199
-	 */
200
-	private function getCatalogForService(Catalog $catalog, $name) {
201
-		foreach ($catalog->getItems() as $item) {
202
-			/** @var CatalogItem $item */
203
-			if ($item->hasType(Service::DEFAULT_TYPE) && $item->hasName($name)) {
204
-				return $item;
205
-			}
206
-		}
207
-
208
-		return null;
209
-	}
210
-
211
-	private function validateRegion(CatalogItem $item, $region) {
212
-		$endPoints = $item->getEndpoints();
213
-		foreach ($endPoints as $endPoint) {
214
-			if ($endPoint->region === $region) {
215
-				return;
216
-			}
217
-		}
218
-
219
-		$availableRegions = implode(', ', array_map(function ($endpoint) {
220
-			return $endpoint->region;
221
-		}, $endPoints));
222
-
223
-		throw new StorageNotAvailableException("Invalid region '$region', available regions: $availableRegions");
224
-	}
225
-
226
-	private function getAvailableServiceNames(Catalog $catalog) {
227
-		return array_map(function (CatalogItem $item) {
228
-			return $item->getName();
229
-		}, array_filter($catalog->getItems(), function (CatalogItem $item) {
230
-			return $item->hasType(Service::DEFAULT_TYPE);
231
-		}));
232
-	}
233
-
234
-	/**
235
-	 * @return string the container name where objects are stored
236
-	 */
237
-	public function getStorageId() {
238
-		return $this->params['container'];
239
-	}
240
-
241
-	/**
242
-	 * @param string $urn the unified resource name used to identify the object
243
-	 * @param resource $stream stream with the data to write
244
-	 * @throws Exception from openstack lib when something goes wrong
245
-	 */
246
-	public function writeObject($urn, $stream) {
247
-		$this->init();
248
-		$this->container->uploadObject($urn, $stream);
249
-	}
250
-
251
-	/**
252
-	 * @param string $urn the unified resource name used to identify the object
253
-	 * @return resource stream with the read data
254
-	 * @throws Exception from openstack lib when something goes wrong
255
-	 */
256
-	public function readObject($urn) {
257
-		try {
258
-			$this->init();
259
-			$object = $this->container->getObject($urn);
260
-
261
-			// we need to keep a reference to objectContent or
262
-			// the stream will be closed before we can do anything with it
263
-			/** @var $objectContent \Guzzle\Http\EntityBody * */
264
-			$objectContent = $object->getContent();
265
-		} catch (ObjectNotFoundException $e) {
266
-			throw new NotFoundException("object $urn not found in object store");
267
-		}
268
-		$objectContent->rewind();
269
-
270
-		$stream = $objectContent->getStream();
271
-		// save the object content in the context of the stream to prevent it being gc'd until the stream is closed
272
-		stream_context_set_option($stream, 'swift', 'content', $objectContent);
273
-
274
-		return RetryWrapper::wrap($stream);
275
-	}
276
-
277
-	/**
278
-	 * @param string $urn Unified Resource Name
279
-	 * @return void
280
-	 * @throws Exception from openstack lib when something goes wrong
281
-	 */
282
-	public function deleteObject($urn) {
283
-		$this->init();
284
-		// see https://github.com/rackspace/php-opencloud/issues/243#issuecomment-30032242
285
-		$this->container->dataObject()->setName($urn)->delete();
286
-	}
287
-
288
-	public function deleteContainer($recursive = false) {
289
-		$this->init();
290
-		$this->container->delete($recursive);
291
-	}
44
+    /**
45
+     * @var \OpenCloud\OpenStack
46
+     */
47
+    private $client;
48
+
49
+    /**
50
+     * @var array
51
+     */
52
+    private $params;
53
+
54
+    /**
55
+     * @var \OpenCloud\ObjectStore\Service
56
+     */
57
+    private $objectStoreService;
58
+
59
+    /**
60
+     * @var \OpenCloud\ObjectStore\Resource\Container
61
+     */
62
+    private $container;
63
+
64
+    private $memcache;
65
+
66
+    public function __construct($params) {
67
+        if (isset($params['bucket'])) {
68
+            $params['container'] = $params['bucket'];
69
+        }
70
+        if (!isset($params['container'])) {
71
+            $params['container'] = 'owncloud';
72
+        }
73
+        if (!isset($params['autocreate'])) {
74
+            // should only be true for tests
75
+            $params['autocreate'] = false;
76
+        }
77
+
78
+        if (isset($params['apiKey'])) {
79
+            $this->client = new Rackspace($params['url'], $params);
80
+            $cacheKey = $params['username'] . '@' . $params['url'] . '/' . $params['bucket'];
81
+        } else {
82
+            $this->client = new OpenStack($params['url'], $params);
83
+            $cacheKey = $params['username'] . '@' . $params['url'] . '/' . $params['bucket'];
84
+        }
85
+
86
+        $cacheFactory = \OC::$server->getMemCacheFactory();
87
+        $this->memcache = $cacheFactory->createDistributed('swift::' . $cacheKey);
88
+
89
+        $this->params = $params;
90
+    }
91
+
92
+    protected function init() {
93
+        if ($this->container) {
94
+            return;
95
+        }
96
+
97
+        $this->importToken();
98
+
99
+        /** @var Token $token */
100
+        $token = $this->client->getTokenObject();
101
+
102
+        if (!$token || $token->hasExpired()) {
103
+            try {
104
+                $this->client->authenticate();
105
+                $this->exportToken();
106
+            } catch (ClientErrorResponseException $e) {
107
+                $statusCode = $e->getResponse()->getStatusCode();
108
+                if ($statusCode == 412) {
109
+                    throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
110
+                } else if ($statusCode === 401) {
111
+                    throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
112
+                } else {
113
+                    throw new StorageAuthException('Unknown error', $e);
114
+                }
115
+            }
116
+        }
117
+
118
+
119
+        /** @var Catalog $catalog */
120
+        $catalog = $this->client->getCatalog();
121
+
122
+        if (isset($this->params['serviceName'])) {
123
+            $serviceName = $this->params['serviceName'];
124
+        } else {
125
+            $serviceName = Service::DEFAULT_NAME;
126
+        }
127
+
128
+        if (isset($this->params['urlType'])) {
129
+            $urlType = $this->params['urlType'];
130
+            if ($urlType !== 'internalURL' && $urlType !== 'publicURL') {
131
+                throw new StorageNotAvailableException('Invalid url type');
132
+            }
133
+        } else {
134
+            $urlType = Service::DEFAULT_URL_TYPE;
135
+        }
136
+
137
+        $catalogItem = $this->getCatalogForService($catalog, $serviceName);
138
+        if (!$catalogItem) {
139
+            $available = implode(', ', $this->getAvailableServiceNames($catalog));
140
+            throw new StorageNotAvailableException(
141
+                "Service $serviceName not found in service catalog, available services: $available"
142
+            );
143
+        } else if (isset($this->params['region'])) {
144
+            $this->validateRegion($catalogItem, $this->params['region']);
145
+        }
146
+
147
+        $this->objectStoreService = $this->client->objectStoreService($serviceName, $this->params['region'], $urlType);
148
+
149
+        try {
150
+            $this->container = $this->objectStoreService->getContainer($this->params['container']);
151
+        } catch (ClientErrorResponseException $ex) {
152
+            // if the container does not exist and autocreate is true try to create the container on the fly
153
+            if (isset($this->params['autocreate']) && $this->params['autocreate'] === true) {
154
+                $this->container = $this->objectStoreService->createContainer($this->params['container']);
155
+            } else {
156
+                throw $ex;
157
+            }
158
+        }
159
+    }
160
+
161
+    private function exportToken() {
162
+        $export = $this->client->exportCredentials();
163
+        $export['catalog'] = array_map(function (CatalogItem $item) {
164
+            return [
165
+                'name' => $item->getName(),
166
+                'endpoints' => $item->getEndpoints(),
167
+                'type' => $item->getType()
168
+            ];
169
+        }, $export['catalog']->getItems());
170
+        $this->memcache->set('token', json_encode($export));
171
+    }
172
+
173
+    private function importToken() {
174
+        $cachedTokenString = $this->memcache->get('token');
175
+        if ($cachedTokenString) {
176
+            $cachedToken = json_decode($cachedTokenString, true);
177
+            $cachedToken['catalog'] = array_map(function (array $item) {
178
+                $itemClass = new \stdClass();
179
+                $itemClass->name = $item['name'];
180
+                $itemClass->endpoints = array_map(function (array $endpoint) {
181
+                    return (object) $endpoint;
182
+                }, $item['endpoints']);
183
+                $itemClass->type = $item['type'];
184
+
185
+                return $itemClass;
186
+            }, $cachedToken['catalog']);
187
+            try {
188
+                $this->client->importCredentials($cachedToken);
189
+            } catch (\Exception $e) {
190
+                $this->client->setTokenObject(new Token());
191
+            }
192
+        }
193
+    }
194
+
195
+    /**
196
+     * @param Catalog $catalog
197
+     * @param $name
198
+     * @return null|CatalogItem
199
+     */
200
+    private function getCatalogForService(Catalog $catalog, $name) {
201
+        foreach ($catalog->getItems() as $item) {
202
+            /** @var CatalogItem $item */
203
+            if ($item->hasType(Service::DEFAULT_TYPE) && $item->hasName($name)) {
204
+                return $item;
205
+            }
206
+        }
207
+
208
+        return null;
209
+    }
210
+
211
+    private function validateRegion(CatalogItem $item, $region) {
212
+        $endPoints = $item->getEndpoints();
213
+        foreach ($endPoints as $endPoint) {
214
+            if ($endPoint->region === $region) {
215
+                return;
216
+            }
217
+        }
218
+
219
+        $availableRegions = implode(', ', array_map(function ($endpoint) {
220
+            return $endpoint->region;
221
+        }, $endPoints));
222
+
223
+        throw new StorageNotAvailableException("Invalid region '$region', available regions: $availableRegions");
224
+    }
225
+
226
+    private function getAvailableServiceNames(Catalog $catalog) {
227
+        return array_map(function (CatalogItem $item) {
228
+            return $item->getName();
229
+        }, array_filter($catalog->getItems(), function (CatalogItem $item) {
230
+            return $item->hasType(Service::DEFAULT_TYPE);
231
+        }));
232
+    }
233
+
234
+    /**
235
+     * @return string the container name where objects are stored
236
+     */
237
+    public function getStorageId() {
238
+        return $this->params['container'];
239
+    }
240
+
241
+    /**
242
+     * @param string $urn the unified resource name used to identify the object
243
+     * @param resource $stream stream with the data to write
244
+     * @throws Exception from openstack lib when something goes wrong
245
+     */
246
+    public function writeObject($urn, $stream) {
247
+        $this->init();
248
+        $this->container->uploadObject($urn, $stream);
249
+    }
250
+
251
+    /**
252
+     * @param string $urn the unified resource name used to identify the object
253
+     * @return resource stream with the read data
254
+     * @throws Exception from openstack lib when something goes wrong
255
+     */
256
+    public function readObject($urn) {
257
+        try {
258
+            $this->init();
259
+            $object = $this->container->getObject($urn);
260
+
261
+            // we need to keep a reference to objectContent or
262
+            // the stream will be closed before we can do anything with it
263
+            /** @var $objectContent \Guzzle\Http\EntityBody * */
264
+            $objectContent = $object->getContent();
265
+        } catch (ObjectNotFoundException $e) {
266
+            throw new NotFoundException("object $urn not found in object store");
267
+        }
268
+        $objectContent->rewind();
269
+
270
+        $stream = $objectContent->getStream();
271
+        // save the object content in the context of the stream to prevent it being gc'd until the stream is closed
272
+        stream_context_set_option($stream, 'swift', 'content', $objectContent);
273
+
274
+        return RetryWrapper::wrap($stream);
275
+    }
276
+
277
+    /**
278
+     * @param string $urn Unified Resource Name
279
+     * @return void
280
+     * @throws Exception from openstack lib when something goes wrong
281
+     */
282
+    public function deleteObject($urn) {
283
+        $this->init();
284
+        // see https://github.com/rackspace/php-opencloud/issues/243#issuecomment-30032242
285
+        $this->container->dataObject()->setName($urn)->delete();
286
+    }
287
+
288
+    public function deleteContainer($recursive = false) {
289
+        $this->init();
290
+        $this->container->delete($recursive);
291
+    }
292 292
 
293 293
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/File.php 2 patches
Indentation   +542 added lines, -542 removed lines patch added patch discarded remove patch
@@ -66,547 +66,547 @@
 block discarded – undo
66 66
 
67 67
 class File extends Node implements IFile {
68 68
 
69
-	protected $request;
70
-
71
-	/**
72
-	 * Sets up the node, expects a full path name
73
-	 *
74
-	 * @param \OC\Files\View $view
75
-	 * @param \OCP\Files\FileInfo $info
76
-	 * @param \OCP\Share\IManager $shareManager
77
-	 * @param \OC\AppFramework\Http\Request $request
78
-	 */
79
-	public function __construct(View $view, FileInfo $info, IManager $shareManager = null, Request $request = null) {
80
-		parent::__construct($view, $info, $shareManager);
81
-
82
-		if (isset($request)) {
83
-			$this->request = $request;
84
-		} else {
85
-			$this->request = \OC::$server->getRequest();
86
-		}
87
-	}
88
-
89
-	/**
90
-	 * Updates the data
91
-	 *
92
-	 * The data argument is a readable stream resource.
93
-	 *
94
-	 * After a successful put operation, you may choose to return an ETag. The
95
-	 * etag must always be surrounded by double-quotes. These quotes must
96
-	 * appear in the actual string you're returning.
97
-	 *
98
-	 * Clients may use the ETag from a PUT request to later on make sure that
99
-	 * when they update the file, the contents haven't changed in the mean
100
-	 * time.
101
-	 *
102
-	 * If you don't plan to store the file byte-by-byte, and you return a
103
-	 * different object on a subsequent GET you are strongly recommended to not
104
-	 * return an ETag, and just return null.
105
-	 *
106
-	 * @param resource $data
107
-	 *
108
-	 * @throws Forbidden
109
-	 * @throws UnsupportedMediaType
110
-	 * @throws BadRequest
111
-	 * @throws Exception
112
-	 * @throws EntityTooLarge
113
-	 * @throws ServiceUnavailable
114
-	 * @throws FileLocked
115
-	 * @return string|null
116
-	 */
117
-	public function put($data) {
118
-		try {
119
-			$exists = $this->fileView->file_exists($this->path);
120
-			if ($this->info && $exists && !$this->info->isUpdateable()) {
121
-				throw new Forbidden();
122
-			}
123
-		} catch (StorageNotAvailableException $e) {
124
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
125
-		}
126
-
127
-		// verify path of the target
128
-		$this->verifyPath();
129
-
130
-		// chunked handling
131
-		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
132
-			try {
133
-				return $this->createFileChunked($data);
134
-			} catch (\Exception $e) {
135
-				$this->convertToSabreException($e);
136
-			}
137
-		}
138
-
139
-		list($partStorage) = $this->fileView->resolvePath($this->path);
140
-		$needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1);
141
-
142
-		$view = \OC\Files\Filesystem::getView();
143
-
144
-		if ($needsPartFile) {
145
-			// mark file as partial while uploading (ignored by the scanner)
146
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
147
-		} else {
148
-			// upload file directly as the final path
149
-			$partFilePath = $this->path;
150
-
151
-			if ($view && !$this->emitPreHooks($exists)) {
152
-				throw new Exception('Could not write to final file, canceled by hook');
153
-			}
154
-		}
155
-
156
-		// the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
157
-		/** @var \OC\Files\Storage\Storage $partStorage */
158
-		list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
159
-		/** @var \OC\Files\Storage\Storage $storage */
160
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
161
-		try {
162
-			if (!$needsPartFile) {
163
-				$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
164
-			}
165
-
166
-			$target = $partStorage->fopen($internalPartPath, 'wb');
167
-			if ($target === false) {
168
-				\OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR);
169
-				// because we have no clue about the cause we can only throw back a 500/Internal Server Error
170
-				throw new Exception('Could not write file contents');
171
-			}
172
-			list($count, $result) = \OC_Helper::streamCopy($data, $target);
173
-			fclose($target);
174
-
175
-			if ($result === false) {
176
-				$expected = -1;
177
-				if (isset($_SERVER['CONTENT_LENGTH'])) {
178
-					$expected = $_SERVER['CONTENT_LENGTH'];
179
-				}
180
-				throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
181
-			}
182
-
183
-			// if content length is sent by client:
184
-			// double check if the file was fully received
185
-			// compare expected and actual size
186
-			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
187
-				$expected = (int) $_SERVER['CONTENT_LENGTH'];
188
-				if ($count !== $expected) {
189
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
190
-				}
191
-			}
192
-
193
-		} catch (\Exception $e) {
194
-			if ($needsPartFile) {
195
-				$partStorage->unlink($internalPartPath);
196
-			}
197
-			$this->convertToSabreException($e);
198
-		}
199
-
200
-		try {
201
-			if ($needsPartFile) {
202
-				if ($view && !$this->emitPreHooks($exists)) {
203
-					$partStorage->unlink($internalPartPath);
204
-					throw new Exception('Could not rename part file to final file, canceled by hook');
205
-				}
206
-				try {
207
-					$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
208
-				} catch (LockedException $e) {
209
-					if ($needsPartFile) {
210
-						$partStorage->unlink($internalPartPath);
211
-					}
212
-					throw new FileLocked($e->getMessage(), $e->getCode(), $e);
213
-				}
214
-
215
-				// rename to correct path
216
-				try {
217
-					$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
218
-					$fileExists = $storage->file_exists($internalPath);
219
-					if ($renameOkay === false || $fileExists === false) {
220
-						\OC::$server->getLogger()->error('renaming part file to final file failed ($run: ' . ( $run ? 'true' : 'false' ) . ', $renameOkay: '  . ( $renameOkay ? 'true' : 'false' ) . ', $fileExists: ' . ( $fileExists ? 'true' : 'false' ) . ')', ['app' => 'webdav']);
221
-						throw new Exception('Could not rename part file to final file');
222
-					}
223
-				} catch (ForbiddenException $ex) {
224
-					throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
225
-				} catch (\Exception $e) {
226
-					$partStorage->unlink($internalPartPath);
227
-					$this->convertToSabreException($e);
228
-				}
229
-			}
230
-
231
-			// since we skipped the view we need to scan and emit the hooks ourselves
232
-			$storage->getUpdater()->update($internalPath);
233
-
234
-			try {
235
-				$this->changeLock(ILockingProvider::LOCK_SHARED);
236
-			} catch (LockedException $e) {
237
-				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
238
-			}
239
-
240
-			// allow sync clients to send the mtime along in a header
241
-			if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
242
-				$mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
243
-				if ($this->fileView->touch($this->path, $mtime)) {
244
-					$this->header('X-OC-MTime: accepted');
245
-				}
246
-			}
69
+    protected $request;
70
+
71
+    /**
72
+     * Sets up the node, expects a full path name
73
+     *
74
+     * @param \OC\Files\View $view
75
+     * @param \OCP\Files\FileInfo $info
76
+     * @param \OCP\Share\IManager $shareManager
77
+     * @param \OC\AppFramework\Http\Request $request
78
+     */
79
+    public function __construct(View $view, FileInfo $info, IManager $shareManager = null, Request $request = null) {
80
+        parent::__construct($view, $info, $shareManager);
81
+
82
+        if (isset($request)) {
83
+            $this->request = $request;
84
+        } else {
85
+            $this->request = \OC::$server->getRequest();
86
+        }
87
+    }
88
+
89
+    /**
90
+     * Updates the data
91
+     *
92
+     * The data argument is a readable stream resource.
93
+     *
94
+     * After a successful put operation, you may choose to return an ETag. The
95
+     * etag must always be surrounded by double-quotes. These quotes must
96
+     * appear in the actual string you're returning.
97
+     *
98
+     * Clients may use the ETag from a PUT request to later on make sure that
99
+     * when they update the file, the contents haven't changed in the mean
100
+     * time.
101
+     *
102
+     * If you don't plan to store the file byte-by-byte, and you return a
103
+     * different object on a subsequent GET you are strongly recommended to not
104
+     * return an ETag, and just return null.
105
+     *
106
+     * @param resource $data
107
+     *
108
+     * @throws Forbidden
109
+     * @throws UnsupportedMediaType
110
+     * @throws BadRequest
111
+     * @throws Exception
112
+     * @throws EntityTooLarge
113
+     * @throws ServiceUnavailable
114
+     * @throws FileLocked
115
+     * @return string|null
116
+     */
117
+    public function put($data) {
118
+        try {
119
+            $exists = $this->fileView->file_exists($this->path);
120
+            if ($this->info && $exists && !$this->info->isUpdateable()) {
121
+                throw new Forbidden();
122
+            }
123
+        } catch (StorageNotAvailableException $e) {
124
+            throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
125
+        }
126
+
127
+        // verify path of the target
128
+        $this->verifyPath();
129
+
130
+        // chunked handling
131
+        if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
132
+            try {
133
+                return $this->createFileChunked($data);
134
+            } catch (\Exception $e) {
135
+                $this->convertToSabreException($e);
136
+            }
137
+        }
138
+
139
+        list($partStorage) = $this->fileView->resolvePath($this->path);
140
+        $needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1);
141
+
142
+        $view = \OC\Files\Filesystem::getView();
143
+
144
+        if ($needsPartFile) {
145
+            // mark file as partial while uploading (ignored by the scanner)
146
+            $partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
147
+        } else {
148
+            // upload file directly as the final path
149
+            $partFilePath = $this->path;
150
+
151
+            if ($view && !$this->emitPreHooks($exists)) {
152
+                throw new Exception('Could not write to final file, canceled by hook');
153
+            }
154
+        }
155
+
156
+        // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
157
+        /** @var \OC\Files\Storage\Storage $partStorage */
158
+        list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
159
+        /** @var \OC\Files\Storage\Storage $storage */
160
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
161
+        try {
162
+            if (!$needsPartFile) {
163
+                $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
164
+            }
165
+
166
+            $target = $partStorage->fopen($internalPartPath, 'wb');
167
+            if ($target === false) {
168
+                \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR);
169
+                // because we have no clue about the cause we can only throw back a 500/Internal Server Error
170
+                throw new Exception('Could not write file contents');
171
+            }
172
+            list($count, $result) = \OC_Helper::streamCopy($data, $target);
173
+            fclose($target);
174
+
175
+            if ($result === false) {
176
+                $expected = -1;
177
+                if (isset($_SERVER['CONTENT_LENGTH'])) {
178
+                    $expected = $_SERVER['CONTENT_LENGTH'];
179
+                }
180
+                throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
181
+            }
182
+
183
+            // if content length is sent by client:
184
+            // double check if the file was fully received
185
+            // compare expected and actual size
186
+            if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
187
+                $expected = (int) $_SERVER['CONTENT_LENGTH'];
188
+                if ($count !== $expected) {
189
+                    throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
190
+                }
191
+            }
192
+
193
+        } catch (\Exception $e) {
194
+            if ($needsPartFile) {
195
+                $partStorage->unlink($internalPartPath);
196
+            }
197
+            $this->convertToSabreException($e);
198
+        }
199
+
200
+        try {
201
+            if ($needsPartFile) {
202
+                if ($view && !$this->emitPreHooks($exists)) {
203
+                    $partStorage->unlink($internalPartPath);
204
+                    throw new Exception('Could not rename part file to final file, canceled by hook');
205
+                }
206
+                try {
207
+                    $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
208
+                } catch (LockedException $e) {
209
+                    if ($needsPartFile) {
210
+                        $partStorage->unlink($internalPartPath);
211
+                    }
212
+                    throw new FileLocked($e->getMessage(), $e->getCode(), $e);
213
+                }
214
+
215
+                // rename to correct path
216
+                try {
217
+                    $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
218
+                    $fileExists = $storage->file_exists($internalPath);
219
+                    if ($renameOkay === false || $fileExists === false) {
220
+                        \OC::$server->getLogger()->error('renaming part file to final file failed ($run: ' . ( $run ? 'true' : 'false' ) . ', $renameOkay: '  . ( $renameOkay ? 'true' : 'false' ) . ', $fileExists: ' . ( $fileExists ? 'true' : 'false' ) . ')', ['app' => 'webdav']);
221
+                        throw new Exception('Could not rename part file to final file');
222
+                    }
223
+                } catch (ForbiddenException $ex) {
224
+                    throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
225
+                } catch (\Exception $e) {
226
+                    $partStorage->unlink($internalPartPath);
227
+                    $this->convertToSabreException($e);
228
+                }
229
+            }
230
+
231
+            // since we skipped the view we need to scan and emit the hooks ourselves
232
+            $storage->getUpdater()->update($internalPath);
233
+
234
+            try {
235
+                $this->changeLock(ILockingProvider::LOCK_SHARED);
236
+            } catch (LockedException $e) {
237
+                throw new FileLocked($e->getMessage(), $e->getCode(), $e);
238
+            }
239
+
240
+            // allow sync clients to send the mtime along in a header
241
+            if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
242
+                $mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
243
+                if ($this->fileView->touch($this->path, $mtime)) {
244
+                    $this->header('X-OC-MTime: accepted');
245
+                }
246
+            }
247 247
 					
248
-			if ($view) {
249
-				$this->emitPostHooks($exists);
250
-			}
251
-
252
-			$this->refreshInfo();
253
-
254
-			if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
255
-				$checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
256
-				$this->fileView->putFileInfo($this->path, ['checksum' => $checksum]);
257
-				$this->refreshInfo();
258
-			} else if ($this->getChecksum() !== null && $this->getChecksum() !== '') {
259
-				$this->fileView->putFileInfo($this->path, ['checksum' => '']);
260
-				$this->refreshInfo();
261
-			}
262
-
263
-		} catch (StorageNotAvailableException $e) {
264
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
265
-		}
266
-
267
-		return '"' . $this->info->getEtag() . '"';
268
-	}
269
-
270
-	private function getPartFileBasePath($path) {
271
-		$partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
272
-		if ($partFileInStorage) {
273
-			return $path;
274
-		} else {
275
-			return md5($path); // will place it in the root of the view with a unique name
276
-		}
277
-	}
278
-
279
-	/**
280
-	 * @param string $path
281
-	 */
282
-	private function emitPreHooks($exists, $path = null) {
283
-		if (is_null($path)) {
284
-			$path = $this->path;
285
-		}
286
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
287
-		$run = true;
288
-
289
-		if (!$exists) {
290
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
291
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
292
-				\OC\Files\Filesystem::signal_param_run => &$run,
293
-			));
294
-		} else {
295
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
296
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
297
-				\OC\Files\Filesystem::signal_param_run => &$run,
298
-			));
299
-		}
300
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
301
-			\OC\Files\Filesystem::signal_param_path => $hookPath,
302
-			\OC\Files\Filesystem::signal_param_run => &$run,
303
-		));
304
-		return $run;
305
-	}
306
-
307
-	/**
308
-	 * @param string $path
309
-	 */
310
-	private function emitPostHooks($exists, $path = null) {
311
-		if (is_null($path)) {
312
-			$path = $this->path;
313
-		}
314
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
315
-		if (!$exists) {
316
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
317
-				\OC\Files\Filesystem::signal_param_path => $hookPath
318
-			));
319
-		} else {
320
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
321
-				\OC\Files\Filesystem::signal_param_path => $hookPath
322
-			));
323
-		}
324
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
325
-			\OC\Files\Filesystem::signal_param_path => $hookPath
326
-		));
327
-	}
328
-
329
-	/**
330
-	 * Returns the data
331
-	 *
332
-	 * @return resource
333
-	 * @throws Forbidden
334
-	 * @throws ServiceUnavailable
335
-	 */
336
-	public function get() {
337
-		//throw exception if encryption is disabled but files are still encrypted
338
-		try {
339
-			if (!$this->info->isReadable()) {
340
-				// do a if the file did not exist
341
-				throw new NotFound();
342
-			}
343
-			$res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
344
-			if ($res === false) {
345
-				throw new ServiceUnavailable("Could not open file");
346
-			}
347
-			return $res;
348
-		} catch (GenericEncryptionException $e) {
349
-			// returning 503 will allow retry of the operation at a later point in time
350
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
351
-		} catch (StorageNotAvailableException $e) {
352
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
353
-		} catch (ForbiddenException $ex) {
354
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
355
-		} catch (LockedException $e) {
356
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
357
-		} catch (NotFoundException $e) {
358
-			throw new NotFound('File not found: ' . $e->getMessage(), $e->getCode(), $e);
359
-		}
360
-	}
361
-
362
-	/**
363
-	 * Delete the current file
364
-	 *
365
-	 * @throws Forbidden
366
-	 * @throws ServiceUnavailable
367
-	 */
368
-	public function delete() {
369
-		if (!$this->info->isDeletable()) {
370
-			throw new Forbidden();
371
-		}
372
-
373
-		try {
374
-			if (!$this->fileView->unlink($this->path)) {
375
-				// assume it wasn't possible to delete due to permissions
376
-				throw new Forbidden();
377
-			}
378
-		} catch (StorageNotAvailableException $e) {
379
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
380
-		} catch (ForbiddenException $ex) {
381
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
382
-		} catch (LockedException $e) {
383
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
384
-		}
385
-	}
386
-
387
-	/**
388
-	 * Returns the mime-type for a file
389
-	 *
390
-	 * If null is returned, we'll assume application/octet-stream
391
-	 *
392
-	 * @return string
393
-	 */
394
-	public function getContentType() {
395
-		$mimeType = $this->info->getMimetype();
396
-
397
-		// PROPFIND needs to return the correct mime type, for consistency with the web UI
398
-		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
399
-			return $mimeType;
400
-		}
401
-		return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
402
-	}
403
-
404
-	/**
405
-	 * @return array|false
406
-	 */
407
-	public function getDirectDownload() {
408
-		if (\OCP\App::isEnabled('encryption')) {
409
-			return [];
410
-		}
411
-		/** @var \OCP\Files\Storage $storage */
412
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
413
-		if (is_null($storage)) {
414
-			return [];
415
-		}
416
-
417
-		return $storage->getDirectDownload($internalPath);
418
-	}
419
-
420
-	/**
421
-	 * @param resource $data
422
-	 * @return null|string
423
-	 * @throws Exception
424
-	 * @throws BadRequest
425
-	 * @throws NotImplemented
426
-	 * @throws ServiceUnavailable
427
-	 */
428
-	private function createFileChunked($data) {
429
-		list($path, $name) = \Sabre\Uri\split($this->path);
430
-
431
-		$info = \OC_FileChunking::decodeName($name);
432
-		if (empty($info)) {
433
-			throw new NotImplemented('Invalid chunk name');
434
-		}
435
-
436
-		$chunk_handler = new \OC_FileChunking($info);
437
-		$bytesWritten = $chunk_handler->store($info['index'], $data);
438
-
439
-		//detect aborted upload
440
-		if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
441
-			if (isset($_SERVER['CONTENT_LENGTH'])) {
442
-				$expected = (int) $_SERVER['CONTENT_LENGTH'];
443
-				if ($bytesWritten !== $expected) {
444
-					$chunk_handler->remove($info['index']);
445
-					throw new BadRequest(
446
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
447
-				}
448
-			}
449
-		}
450
-
451
-		if ($chunk_handler->isComplete()) {
452
-			list($storage,) = $this->fileView->resolvePath($path);
453
-			$needsPartFile = $this->needsPartFile($storage);
454
-			$partFile = null;
455
-
456
-			$targetPath = $path . '/' . $info['name'];
457
-			/** @var \OC\Files\Storage\Storage $targetStorage */
458
-			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
459
-
460
-			$exists = $this->fileView->file_exists($targetPath);
461
-
462
-			try {
463
-				$this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
464
-
465
-				$this->emitPreHooks($exists, $targetPath);
466
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
467
-				/** @var \OC\Files\Storage\Storage $targetStorage */
468
-				list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
469
-
470
-				if ($needsPartFile) {
471
-					// we first assembly the target file as a part file
472
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
473
-					/** @var \OC\Files\Storage\Storage $targetStorage */
474
-					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
475
-
476
-
477
-					$chunk_handler->file_assemble($partStorage, $partInternalPath);
478
-
479
-					// here is the final atomic rename
480
-					$renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
481
-					$fileExists = $targetStorage->file_exists($targetInternalPath);
482
-					if ($renameOkay === false || $fileExists === false) {
483
-						\OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::rename() failed', \OCP\Util::ERROR);
484
-						// only delete if an error occurred and the target file was already created
485
-						if ($fileExists) {
486
-							// set to null to avoid double-deletion when handling exception
487
-							// stray part file
488
-							$partFile = null;
489
-							$targetStorage->unlink($targetInternalPath);
490
-						}
491
-						$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
492
-						throw new Exception('Could not rename part file assembled from chunks');
493
-					}
494
-				} else {
495
-					// assemble directly into the final file
496
-					$chunk_handler->file_assemble($targetStorage, $targetInternalPath);
497
-				}
498
-
499
-				// allow sync clients to send the mtime along in a header
500
-				if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
501
-					$mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
502
-					if ($targetStorage->touch($targetInternalPath, $mtime)) {
503
-						$this->header('X-OC-MTime: accepted');
504
-					}
505
-				}
506
-
507
-				// since we skipped the view we need to scan and emit the hooks ourselves
508
-				$targetStorage->getUpdater()->update($targetInternalPath);
509
-
510
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
511
-
512
-				$this->emitPostHooks($exists, $targetPath);
513
-
514
-				// FIXME: should call refreshInfo but can't because $this->path is not the of the final file
515
-				$info = $this->fileView->getFileInfo($targetPath);
516
-
517
-				if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
518
-					$checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
519
-					$this->fileView->putFileInfo($targetPath, ['checksum' => $checksum]);
520
-				} else if ($info->getChecksum() !== null && $info->getChecksum() !== '') {
521
-					$this->fileView->putFileInfo($this->path, ['checksum' => '']);
522
-				}
523
-
524
-				$this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
525
-
526
-				return $info->getEtag();
527
-			} catch (\Exception $e) {
528
-				if ($partFile !== null) {
529
-					$targetStorage->unlink($targetInternalPath);
530
-				}
531
-				$this->convertToSabreException($e);
532
-			}
533
-		}
534
-
535
-		return null;
536
-	}
537
-
538
-	/**
539
-	 * Returns whether a part file is needed for the given storage
540
-	 * or whether the file can be assembled/uploaded directly on the
541
-	 * target storage.
542
-	 *
543
-	 * @param \OCP\Files\Storage $storage
544
-	 * @return bool true if the storage needs part file handling
545
-	 */
546
-	private function needsPartFile($storage) {
547
-		// TODO: in the future use ChunkHandler provided by storage
548
-		return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') &&
549
-			!$storage->instanceOfStorage('OC\Files\Storage\OwnCloud') &&
550
-			$storage->needsPartFile();
551
-	}
552
-
553
-	/**
554
-	 * Convert the given exception to a SabreException instance
555
-	 *
556
-	 * @param \Exception $e
557
-	 *
558
-	 * @throws \Sabre\DAV\Exception
559
-	 */
560
-	private function convertToSabreException(\Exception $e) {
561
-		if ($e instanceof \Sabre\DAV\Exception) {
562
-			throw $e;
563
-		}
564
-		if ($e instanceof NotPermittedException) {
565
-			// a more general case - due to whatever reason the content could not be written
566
-			throw new Forbidden($e->getMessage(), 0, $e);
567
-		}
568
-		if ($e instanceof ForbiddenException) {
569
-			// the path for the file was forbidden
570
-			throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
571
-		}
572
-		if ($e instanceof EntityTooLargeException) {
573
-			// the file is too big to be stored
574
-			throw new EntityTooLarge($e->getMessage(), 0, $e);
575
-		}
576
-		if ($e instanceof InvalidContentException) {
577
-			// the file content is not permitted
578
-			throw new UnsupportedMediaType($e->getMessage(), 0, $e);
579
-		}
580
-		if ($e instanceof InvalidPathException) {
581
-			// the path for the file was not valid
582
-			// TODO: find proper http status code for this case
583
-			throw new Forbidden($e->getMessage(), 0, $e);
584
-		}
585
-		if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
586
-			// the file is currently being written to by another process
587
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
588
-		}
589
-		if ($e instanceof GenericEncryptionException) {
590
-			// returning 503 will allow retry of the operation at a later point in time
591
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
592
-		}
593
-		if ($e instanceof StorageNotAvailableException) {
594
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
595
-		}
596
-
597
-		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
598
-	}
599
-
600
-	/**
601
-	 * Get the checksum for this file
602
-	 *
603
-	 * @return string
604
-	 */
605
-	public function getChecksum() {
606
-		return $this->info->getChecksum();
607
-	}
608
-
609
-	protected function header($string) {
610
-		\header($string);
611
-	}
248
+            if ($view) {
249
+                $this->emitPostHooks($exists);
250
+            }
251
+
252
+            $this->refreshInfo();
253
+
254
+            if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
255
+                $checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
256
+                $this->fileView->putFileInfo($this->path, ['checksum' => $checksum]);
257
+                $this->refreshInfo();
258
+            } else if ($this->getChecksum() !== null && $this->getChecksum() !== '') {
259
+                $this->fileView->putFileInfo($this->path, ['checksum' => '']);
260
+                $this->refreshInfo();
261
+            }
262
+
263
+        } catch (StorageNotAvailableException $e) {
264
+            throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
265
+        }
266
+
267
+        return '"' . $this->info->getEtag() . '"';
268
+    }
269
+
270
+    private function getPartFileBasePath($path) {
271
+        $partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
272
+        if ($partFileInStorage) {
273
+            return $path;
274
+        } else {
275
+            return md5($path); // will place it in the root of the view with a unique name
276
+        }
277
+    }
278
+
279
+    /**
280
+     * @param string $path
281
+     */
282
+    private function emitPreHooks($exists, $path = null) {
283
+        if (is_null($path)) {
284
+            $path = $this->path;
285
+        }
286
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
287
+        $run = true;
288
+
289
+        if (!$exists) {
290
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
291
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
292
+                \OC\Files\Filesystem::signal_param_run => &$run,
293
+            ));
294
+        } else {
295
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
296
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
297
+                \OC\Files\Filesystem::signal_param_run => &$run,
298
+            ));
299
+        }
300
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
301
+            \OC\Files\Filesystem::signal_param_path => $hookPath,
302
+            \OC\Files\Filesystem::signal_param_run => &$run,
303
+        ));
304
+        return $run;
305
+    }
306
+
307
+    /**
308
+     * @param string $path
309
+     */
310
+    private function emitPostHooks($exists, $path = null) {
311
+        if (is_null($path)) {
312
+            $path = $this->path;
313
+        }
314
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
315
+        if (!$exists) {
316
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
317
+                \OC\Files\Filesystem::signal_param_path => $hookPath
318
+            ));
319
+        } else {
320
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
321
+                \OC\Files\Filesystem::signal_param_path => $hookPath
322
+            ));
323
+        }
324
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
325
+            \OC\Files\Filesystem::signal_param_path => $hookPath
326
+        ));
327
+    }
328
+
329
+    /**
330
+     * Returns the data
331
+     *
332
+     * @return resource
333
+     * @throws Forbidden
334
+     * @throws ServiceUnavailable
335
+     */
336
+    public function get() {
337
+        //throw exception if encryption is disabled but files are still encrypted
338
+        try {
339
+            if (!$this->info->isReadable()) {
340
+                // do a if the file did not exist
341
+                throw new NotFound();
342
+            }
343
+            $res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
344
+            if ($res === false) {
345
+                throw new ServiceUnavailable("Could not open file");
346
+            }
347
+            return $res;
348
+        } catch (GenericEncryptionException $e) {
349
+            // returning 503 will allow retry of the operation at a later point in time
350
+            throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
351
+        } catch (StorageNotAvailableException $e) {
352
+            throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
353
+        } catch (ForbiddenException $ex) {
354
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
355
+        } catch (LockedException $e) {
356
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
357
+        } catch (NotFoundException $e) {
358
+            throw new NotFound('File not found: ' . $e->getMessage(), $e->getCode(), $e);
359
+        }
360
+    }
361
+
362
+    /**
363
+     * Delete the current file
364
+     *
365
+     * @throws Forbidden
366
+     * @throws ServiceUnavailable
367
+     */
368
+    public function delete() {
369
+        if (!$this->info->isDeletable()) {
370
+            throw new Forbidden();
371
+        }
372
+
373
+        try {
374
+            if (!$this->fileView->unlink($this->path)) {
375
+                // assume it wasn't possible to delete due to permissions
376
+                throw new Forbidden();
377
+            }
378
+        } catch (StorageNotAvailableException $e) {
379
+            throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
380
+        } catch (ForbiddenException $ex) {
381
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
382
+        } catch (LockedException $e) {
383
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
384
+        }
385
+    }
386
+
387
+    /**
388
+     * Returns the mime-type for a file
389
+     *
390
+     * If null is returned, we'll assume application/octet-stream
391
+     *
392
+     * @return string
393
+     */
394
+    public function getContentType() {
395
+        $mimeType = $this->info->getMimetype();
396
+
397
+        // PROPFIND needs to return the correct mime type, for consistency with the web UI
398
+        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
399
+            return $mimeType;
400
+        }
401
+        return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
402
+    }
403
+
404
+    /**
405
+     * @return array|false
406
+     */
407
+    public function getDirectDownload() {
408
+        if (\OCP\App::isEnabled('encryption')) {
409
+            return [];
410
+        }
411
+        /** @var \OCP\Files\Storage $storage */
412
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
413
+        if (is_null($storage)) {
414
+            return [];
415
+        }
416
+
417
+        return $storage->getDirectDownload($internalPath);
418
+    }
419
+
420
+    /**
421
+     * @param resource $data
422
+     * @return null|string
423
+     * @throws Exception
424
+     * @throws BadRequest
425
+     * @throws NotImplemented
426
+     * @throws ServiceUnavailable
427
+     */
428
+    private function createFileChunked($data) {
429
+        list($path, $name) = \Sabre\Uri\split($this->path);
430
+
431
+        $info = \OC_FileChunking::decodeName($name);
432
+        if (empty($info)) {
433
+            throw new NotImplemented('Invalid chunk name');
434
+        }
435
+
436
+        $chunk_handler = new \OC_FileChunking($info);
437
+        $bytesWritten = $chunk_handler->store($info['index'], $data);
438
+
439
+        //detect aborted upload
440
+        if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
441
+            if (isset($_SERVER['CONTENT_LENGTH'])) {
442
+                $expected = (int) $_SERVER['CONTENT_LENGTH'];
443
+                if ($bytesWritten !== $expected) {
444
+                    $chunk_handler->remove($info['index']);
445
+                    throw new BadRequest(
446
+                        'expected filesize ' . $expected . ' got ' . $bytesWritten);
447
+                }
448
+            }
449
+        }
450
+
451
+        if ($chunk_handler->isComplete()) {
452
+            list($storage,) = $this->fileView->resolvePath($path);
453
+            $needsPartFile = $this->needsPartFile($storage);
454
+            $partFile = null;
455
+
456
+            $targetPath = $path . '/' . $info['name'];
457
+            /** @var \OC\Files\Storage\Storage $targetStorage */
458
+            list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
459
+
460
+            $exists = $this->fileView->file_exists($targetPath);
461
+
462
+            try {
463
+                $this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
464
+
465
+                $this->emitPreHooks($exists, $targetPath);
466
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
467
+                /** @var \OC\Files\Storage\Storage $targetStorage */
468
+                list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
469
+
470
+                if ($needsPartFile) {
471
+                    // we first assembly the target file as a part file
472
+                    $partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
473
+                    /** @var \OC\Files\Storage\Storage $targetStorage */
474
+                    list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
475
+
476
+
477
+                    $chunk_handler->file_assemble($partStorage, $partInternalPath);
478
+
479
+                    // here is the final atomic rename
480
+                    $renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
481
+                    $fileExists = $targetStorage->file_exists($targetInternalPath);
482
+                    if ($renameOkay === false || $fileExists === false) {
483
+                        \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::rename() failed', \OCP\Util::ERROR);
484
+                        // only delete if an error occurred and the target file was already created
485
+                        if ($fileExists) {
486
+                            // set to null to avoid double-deletion when handling exception
487
+                            // stray part file
488
+                            $partFile = null;
489
+                            $targetStorage->unlink($targetInternalPath);
490
+                        }
491
+                        $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
492
+                        throw new Exception('Could not rename part file assembled from chunks');
493
+                    }
494
+                } else {
495
+                    // assemble directly into the final file
496
+                    $chunk_handler->file_assemble($targetStorage, $targetInternalPath);
497
+                }
498
+
499
+                // allow sync clients to send the mtime along in a header
500
+                if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
501
+                    $mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
502
+                    if ($targetStorage->touch($targetInternalPath, $mtime)) {
503
+                        $this->header('X-OC-MTime: accepted');
504
+                    }
505
+                }
506
+
507
+                // since we skipped the view we need to scan and emit the hooks ourselves
508
+                $targetStorage->getUpdater()->update($targetInternalPath);
509
+
510
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
511
+
512
+                $this->emitPostHooks($exists, $targetPath);
513
+
514
+                // FIXME: should call refreshInfo but can't because $this->path is not the of the final file
515
+                $info = $this->fileView->getFileInfo($targetPath);
516
+
517
+                if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
518
+                    $checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
519
+                    $this->fileView->putFileInfo($targetPath, ['checksum' => $checksum]);
520
+                } else if ($info->getChecksum() !== null && $info->getChecksum() !== '') {
521
+                    $this->fileView->putFileInfo($this->path, ['checksum' => '']);
522
+                }
523
+
524
+                $this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
525
+
526
+                return $info->getEtag();
527
+            } catch (\Exception $e) {
528
+                if ($partFile !== null) {
529
+                    $targetStorage->unlink($targetInternalPath);
530
+                }
531
+                $this->convertToSabreException($e);
532
+            }
533
+        }
534
+
535
+        return null;
536
+    }
537
+
538
+    /**
539
+     * Returns whether a part file is needed for the given storage
540
+     * or whether the file can be assembled/uploaded directly on the
541
+     * target storage.
542
+     *
543
+     * @param \OCP\Files\Storage $storage
544
+     * @return bool true if the storage needs part file handling
545
+     */
546
+    private function needsPartFile($storage) {
547
+        // TODO: in the future use ChunkHandler provided by storage
548
+        return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') &&
549
+            !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud') &&
550
+            $storage->needsPartFile();
551
+    }
552
+
553
+    /**
554
+     * Convert the given exception to a SabreException instance
555
+     *
556
+     * @param \Exception $e
557
+     *
558
+     * @throws \Sabre\DAV\Exception
559
+     */
560
+    private function convertToSabreException(\Exception $e) {
561
+        if ($e instanceof \Sabre\DAV\Exception) {
562
+            throw $e;
563
+        }
564
+        if ($e instanceof NotPermittedException) {
565
+            // a more general case - due to whatever reason the content could not be written
566
+            throw new Forbidden($e->getMessage(), 0, $e);
567
+        }
568
+        if ($e instanceof ForbiddenException) {
569
+            // the path for the file was forbidden
570
+            throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
571
+        }
572
+        if ($e instanceof EntityTooLargeException) {
573
+            // the file is too big to be stored
574
+            throw new EntityTooLarge($e->getMessage(), 0, $e);
575
+        }
576
+        if ($e instanceof InvalidContentException) {
577
+            // the file content is not permitted
578
+            throw new UnsupportedMediaType($e->getMessage(), 0, $e);
579
+        }
580
+        if ($e instanceof InvalidPathException) {
581
+            // the path for the file was not valid
582
+            // TODO: find proper http status code for this case
583
+            throw new Forbidden($e->getMessage(), 0, $e);
584
+        }
585
+        if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
586
+            // the file is currently being written to by another process
587
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
588
+        }
589
+        if ($e instanceof GenericEncryptionException) {
590
+            // returning 503 will allow retry of the operation at a later point in time
591
+            throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
592
+        }
593
+        if ($e instanceof StorageNotAvailableException) {
594
+            throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
595
+        }
596
+
597
+        throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
598
+    }
599
+
600
+    /**
601
+     * Get the checksum for this file
602
+     *
603
+     * @return string
604
+     */
605
+    public function getChecksum() {
606
+        return $this->info->getChecksum();
607
+    }
608
+
609
+    protected function header($string) {
610
+        \header($string);
611
+    }
612 612
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
 				throw new Forbidden();
122 122
 			}
123 123
 		} catch (StorageNotAvailableException $e) {
124
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
124
+			throw new ServiceUnavailable("File is not updatable: ".$e->getMessage());
125 125
 		}
126 126
 
127 127
 		// verify path of the target
@@ -143,7 +143,7 @@  discard block
 block discarded – undo
143 143
 
144 144
 		if ($needsPartFile) {
145 145
 			// mark file as partial while uploading (ignored by the scanner)
146
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
146
+			$partFilePath = $this->getPartFileBasePath($this->path).'.ocTransferId'.rand().'.part';
147 147
 		} else {
148 148
 			// upload file directly as the final path
149 149
 			$partFilePath = $this->path;
@@ -177,7 +177,7 @@  discard block
 block discarded – undo
177 177
 				if (isset($_SERVER['CONTENT_LENGTH'])) {
178 178
 					$expected = $_SERVER['CONTENT_LENGTH'];
179 179
 				}
180
-				throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
180
+				throw new Exception('Error while copying file to target location (copied bytes: '.$count.', expected filesize: '.$expected.' )');
181 181
 			}
182 182
 
183 183
 			// if content length is sent by client:
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
 			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
187 187
 				$expected = (int) $_SERVER['CONTENT_LENGTH'];
188 188
 				if ($count !== $expected) {
189
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
189
+					throw new BadRequest('expected filesize '.$expected.' got '.$count);
190 190
 				}
191 191
 			}
192 192
 
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
 					$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
218 218
 					$fileExists = $storage->file_exists($internalPath);
219 219
 					if ($renameOkay === false || $fileExists === false) {
220
-						\OC::$server->getLogger()->error('renaming part file to final file failed ($run: ' . ( $run ? 'true' : 'false' ) . ', $renameOkay: '  . ( $renameOkay ? 'true' : 'false' ) . ', $fileExists: ' . ( $fileExists ? 'true' : 'false' ) . ')', ['app' => 'webdav']);
220
+						\OC::$server->getLogger()->error('renaming part file to final file failed ($run: '.($run ? 'true' : 'false').', $renameOkay: '.($renameOkay ? 'true' : 'false').', $fileExists: '.($fileExists ? 'true' : 'false').')', ['app' => 'webdav']);
221 221
 						throw new Exception('Could not rename part file to final file');
222 222
 					}
223 223
 				} catch (ForbiddenException $ex) {
@@ -261,10 +261,10 @@  discard block
 block discarded – undo
261 261
 			}
262 262
 
263 263
 		} catch (StorageNotAvailableException $e) {
264
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
264
+			throw new ServiceUnavailable("Failed to check file size: ".$e->getMessage());
265 265
 		}
266 266
 
267
-		return '"' . $this->info->getEtag() . '"';
267
+		return '"'.$this->info->getEtag().'"';
268 268
 	}
269 269
 
270 270
 	private function getPartFileBasePath($path) {
@@ -347,15 +347,15 @@  discard block
 block discarded – undo
347 347
 			return $res;
348 348
 		} catch (GenericEncryptionException $e) {
349 349
 			// returning 503 will allow retry of the operation at a later point in time
350
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
350
+			throw new ServiceUnavailable("Encryption not ready: ".$e->getMessage());
351 351
 		} catch (StorageNotAvailableException $e) {
352
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
352
+			throw new ServiceUnavailable("Failed to open file: ".$e->getMessage());
353 353
 		} catch (ForbiddenException $ex) {
354 354
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
355 355
 		} catch (LockedException $e) {
356 356
 			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
357 357
 		} catch (NotFoundException $e) {
358
-			throw new NotFound('File not found: ' . $e->getMessage(), $e->getCode(), $e);
358
+			throw new NotFound('File not found: '.$e->getMessage(), $e->getCode(), $e);
359 359
 		}
360 360
 	}
361 361
 
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
 				throw new Forbidden();
377 377
 			}
378 378
 		} catch (StorageNotAvailableException $e) {
379
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
379
+			throw new ServiceUnavailable("Failed to unlink: ".$e->getMessage());
380 380
 		} catch (ForbiddenException $ex) {
381 381
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
382 382
 		} catch (LockedException $e) {
@@ -443,7 +443,7 @@  discard block
 block discarded – undo
443 443
 				if ($bytesWritten !== $expected) {
444 444
 					$chunk_handler->remove($info['index']);
445 445
 					throw new BadRequest(
446
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
446
+						'expected filesize '.$expected.' got '.$bytesWritten);
447 447
 				}
448 448
 			}
449 449
 		}
@@ -453,7 +453,7 @@  discard block
 block discarded – undo
453 453
 			$needsPartFile = $this->needsPartFile($storage);
454 454
 			$partFile = null;
455 455
 
456
-			$targetPath = $path . '/' . $info['name'];
456
+			$targetPath = $path.'/'.$info['name'];
457 457
 			/** @var \OC\Files\Storage\Storage $targetStorage */
458 458
 			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
459 459
 
@@ -469,7 +469,7 @@  discard block
 block discarded – undo
469 469
 
470 470
 				if ($needsPartFile) {
471 471
 					// we first assembly the target file as a part file
472
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
472
+					$partFile = $this->getPartFileBasePath($path.'/'.$info['name']).'.ocTransferId'.$info['transferid'].'.part';
473 473
 					/** @var \OC\Files\Storage\Storage $targetStorage */
474 474
 					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
475 475
 
@@ -588,10 +588,10 @@  discard block
 block discarded – undo
588 588
 		}
589 589
 		if ($e instanceof GenericEncryptionException) {
590 590
 			// returning 503 will allow retry of the operation at a later point in time
591
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
591
+			throw new ServiceUnavailable('Encryption not ready: '.$e->getMessage(), 0, $e);
592 592
 		}
593 593
 		if ($e instanceof StorageNotAvailableException) {
594
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
594
+			throw new ServiceUnavailable('Failed to write file contents: '.$e->getMessage(), 0, $e);
595 595
 		}
596 596
 
597 597
 		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
Please login to merge, or discard this patch.