Passed
Push — master ( 2398d1...ba155a )
by Roeland
16:02 queued 06:20
created
apps/files_external/lib/Lib/Storage/Swift.php 2 patches
Indentation   +569 added lines, -569 removed lines patch added patch discarded remove patch
@@ -50,577 +50,577 @@
 block discarded – undo
50 50
 use OpenStack\ObjectStore\v1\Models\StorageObject;
51 51
 
52 52
 class Swift extends \OC\Files\Storage\Common {
53
-	/** @var SwiftFactory */
54
-	private $connectionFactory;
55
-	/**
56
-	 * @var \OpenStack\ObjectStore\v1\Models\Container
57
-	 */
58
-	private $container;
59
-	/**
60
-	 * @var string
61
-	 */
62
-	private $bucket;
63
-	/**
64
-	 * Connection parameters
65
-	 *
66
-	 * @var array
67
-	 */
68
-	private $params;
69
-
70
-	/** @var string */
71
-	private $id;
72
-
73
-	/** @var \OC\Files\ObjectStore\Swift */
74
-	private $objectStore;
75
-
76
-	/**
77
-	 * Key value cache mapping path to data object. Maps path to
78
-	 * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
79
-	 * paths and path to false for not existing paths.
80
-	 *
81
-	 * @var \OCP\ICache
82
-	 */
83
-	private $objectCache;
84
-
85
-	/**
86
-	 * @param string $path
87
-	 * @return mixed|string
88
-	 */
89
-	private function normalizePath(string $path) {
90
-		$path = trim($path, '/');
91
-
92
-		if (!$path) {
93
-			$path = '.';
94
-		}
95
-
96
-		$path = str_replace('#', '%23', $path);
97
-
98
-		return $path;
99
-	}
100
-
101
-	const SUBCONTAINER_FILE = '.subcontainers';
102
-
103
-	/**
104
-	 * translate directory path to container name
105
-	 *
106
-	 * @param string $path
107
-	 * @return string
108
-	 */
109
-
110
-	/**
111
-	 * Fetches an object from the API.
112
-	 * If the object is cached already or a
113
-	 * failed "doesn't exist" response was cached,
114
-	 * that one will be returned.
115
-	 *
116
-	 * @param string $path
117
-	 * @return StorageObject|bool object
118
-	 * or false if the object did not exist
119
-	 * @throws \OCP\Files\StorageAuthException
120
-	 * @throws \OCP\Files\StorageNotAvailableException
121
-	 */
122
-	private function fetchObject(string $path) {
123
-		if ($this->objectCache->hasKey($path)) {
124
-			// might be "false" if object did not exist from last check
125
-			return $this->objectCache->get($path);
126
-		}
127
-		try {
128
-			$object = $this->getContainer()->getObject($path);
129
-			$object->retrieve();
130
-			$this->objectCache->set($path, $object);
131
-			return $object;
132
-		} catch (BadResponseError $e) {
133
-			// Expected response is "404 Not Found", so only log if it isn't
134
-			if ($e->getResponse()->getStatusCode() !== 404) {
135
-				\OC::$server->getLogger()->logException($e, [
136
-					'level' => ILogger::ERROR,
137
-					'app' => 'files_external',
138
-				]);
139
-			}
140
-			$this->objectCache->set($path, false);
141
-			return false;
142
-		}
143
-	}
144
-
145
-	/**
146
-	 * Returns whether the given path exists.
147
-	 *
148
-	 * @param string $path
149
-	 *
150
-	 * @return bool true if the object exist, false otherwise
151
-	 * @throws \OCP\Files\StorageAuthException
152
-	 * @throws \OCP\Files\StorageNotAvailableException
153
-	 */
154
-	private function doesObjectExist($path) {
155
-		return $this->fetchObject($path) !== false;
156
-	}
157
-
158
-	public function __construct($params) {
159
-		if ((empty($params['key']) and empty($params['password']))
160
-			or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
161
-			or empty($params['region'])
162
-		) {
163
-			throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
164
-		}
165
-
166
-		$user = $params['user'];
167
-		$this->id = 'swift::' . $user . md5($params['bucket']);
168
-
169
-		$bucketUrl = new Uri($params['bucket']);
170
-		if ($bucketUrl->getHost()) {
171
-			$params['bucket'] = basename($bucketUrl->getPath());
172
-			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
173
-		}
174
-
175
-		if (empty($params['url'])) {
176
-			$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
177
-		}
178
-
179
-		if (empty($params['service_name'])) {
180
-			$params['service_name'] = 'cloudFiles';
181
-		}
182
-
183
-		$params['autocreate'] = true;
184
-
185
-		if (isset($params['domain'])) {
186
-			$params['user'] = [
187
-				'name' => $params['user'],
188
-				'password' => $params['password'],
189
-				'domain' => [
190
-					'name' => $params['domain'],
191
-				]
192
-			];
193
-		}
194
-
195
-		$this->params = $params;
196
-		// FIXME: private class...
197
-		$this->objectCache = new \OC\Cache\CappedMemoryCache();
198
-		$this->connectionFactory = new SwiftFactory(
199
-			\OC::$server->getMemCacheFactory()->createDistributed('swift/'),
200
-			$this->params,
201
-			\OC::$server->getLogger()
202
-		);
203
-		$this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
204
-		$this->bucket = $params['bucket'];
205
-	}
206
-
207
-	public function mkdir($path) {
208
-		$path = $this->normalizePath($path);
209
-
210
-		if ($this->is_dir($path)) {
211
-			return false;
212
-		}
213
-
214
-		if ($path !== '.') {
215
-			$path .= '/';
216
-		}
217
-
218
-		try {
219
-			$this->getContainer()->createObject([
220
-				'name' => $path,
221
-				'content' => '',
222
-				'headers' => ['content-type' => 'httpd/unix-directory']
223
-			]);
224
-			// invalidate so that the next access gets the real object
225
-			// with all properties
226
-			$this->objectCache->remove($path);
227
-		} catch (BadResponseError $e) {
228
-			\OC::$server->getLogger()->logException($e, [
229
-				'level' => ILogger::ERROR,
230
-				'app' => 'files_external',
231
-			]);
232
-			return false;
233
-		}
234
-
235
-		return true;
236
-	}
237
-
238
-	public function file_exists($path) {
239
-		$path = $this->normalizePath($path);
240
-
241
-		if ($path !== '.' && $this->is_dir($path)) {
242
-			$path .= '/';
243
-		}
244
-
245
-		return $this->doesObjectExist($path);
246
-	}
247
-
248
-	public function rmdir($path) {
249
-		$path = $this->normalizePath($path);
250
-
251
-		if (!$this->is_dir($path) || !$this->isDeletable($path)) {
252
-			return false;
253
-		}
254
-
255
-		$dh = $this->opendir($path);
256
-		while ($file = readdir($dh)) {
257
-			if (\OC\Files\Filesystem::isIgnoredDir($file)) {
258
-				continue;
259
-			}
260
-
261
-			if ($this->is_dir($path . '/' . $file)) {
262
-				$this->rmdir($path . '/' . $file);
263
-			} else {
264
-				$this->unlink($path . '/' . $file);
265
-			}
266
-		}
267
-
268
-		try {
269
-			$this->objectStore->deleteObject($path . '/');
270
-			$this->objectCache->remove($path . '/');
271
-		} catch (BadResponseError $e) {
272
-			\OC::$server->getLogger()->logException($e, [
273
-				'level' => ILogger::ERROR,
274
-				'app' => 'files_external',
275
-			]);
276
-			return false;
277
-		}
278
-
279
-		return true;
280
-	}
281
-
282
-	public function opendir($path) {
283
-		$path = $this->normalizePath($path);
284
-
285
-		if ($path === '.') {
286
-			$path = '';
287
-		} else {
288
-			$path .= '/';
289
-		}
53
+    /** @var SwiftFactory */
54
+    private $connectionFactory;
55
+    /**
56
+     * @var \OpenStack\ObjectStore\v1\Models\Container
57
+     */
58
+    private $container;
59
+    /**
60
+     * @var string
61
+     */
62
+    private $bucket;
63
+    /**
64
+     * Connection parameters
65
+     *
66
+     * @var array
67
+     */
68
+    private $params;
69
+
70
+    /** @var string */
71
+    private $id;
72
+
73
+    /** @var \OC\Files\ObjectStore\Swift */
74
+    private $objectStore;
75
+
76
+    /**
77
+     * Key value cache mapping path to data object. Maps path to
78
+     * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
79
+     * paths and path to false for not existing paths.
80
+     *
81
+     * @var \OCP\ICache
82
+     */
83
+    private $objectCache;
84
+
85
+    /**
86
+     * @param string $path
87
+     * @return mixed|string
88
+     */
89
+    private function normalizePath(string $path) {
90
+        $path = trim($path, '/');
91
+
92
+        if (!$path) {
93
+            $path = '.';
94
+        }
95
+
96
+        $path = str_replace('#', '%23', $path);
97
+
98
+        return $path;
99
+    }
100
+
101
+    const SUBCONTAINER_FILE = '.subcontainers';
102
+
103
+    /**
104
+     * translate directory path to container name
105
+     *
106
+     * @param string $path
107
+     * @return string
108
+     */
109
+
110
+    /**
111
+     * Fetches an object from the API.
112
+     * If the object is cached already or a
113
+     * failed "doesn't exist" response was cached,
114
+     * that one will be returned.
115
+     *
116
+     * @param string $path
117
+     * @return StorageObject|bool object
118
+     * or false if the object did not exist
119
+     * @throws \OCP\Files\StorageAuthException
120
+     * @throws \OCP\Files\StorageNotAvailableException
121
+     */
122
+    private function fetchObject(string $path) {
123
+        if ($this->objectCache->hasKey($path)) {
124
+            // might be "false" if object did not exist from last check
125
+            return $this->objectCache->get($path);
126
+        }
127
+        try {
128
+            $object = $this->getContainer()->getObject($path);
129
+            $object->retrieve();
130
+            $this->objectCache->set($path, $object);
131
+            return $object;
132
+        } catch (BadResponseError $e) {
133
+            // Expected response is "404 Not Found", so only log if it isn't
134
+            if ($e->getResponse()->getStatusCode() !== 404) {
135
+                \OC::$server->getLogger()->logException($e, [
136
+                    'level' => ILogger::ERROR,
137
+                    'app' => 'files_external',
138
+                ]);
139
+            }
140
+            $this->objectCache->set($path, false);
141
+            return false;
142
+        }
143
+    }
144
+
145
+    /**
146
+     * Returns whether the given path exists.
147
+     *
148
+     * @param string $path
149
+     *
150
+     * @return bool true if the object exist, false otherwise
151
+     * @throws \OCP\Files\StorageAuthException
152
+     * @throws \OCP\Files\StorageNotAvailableException
153
+     */
154
+    private function doesObjectExist($path) {
155
+        return $this->fetchObject($path) !== false;
156
+    }
157
+
158
+    public function __construct($params) {
159
+        if ((empty($params['key']) and empty($params['password']))
160
+            or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
161
+            or empty($params['region'])
162
+        ) {
163
+            throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
164
+        }
165
+
166
+        $user = $params['user'];
167
+        $this->id = 'swift::' . $user . md5($params['bucket']);
168
+
169
+        $bucketUrl = new Uri($params['bucket']);
170
+        if ($bucketUrl->getHost()) {
171
+            $params['bucket'] = basename($bucketUrl->getPath());
172
+            $params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
173
+        }
174
+
175
+        if (empty($params['url'])) {
176
+            $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
177
+        }
178
+
179
+        if (empty($params['service_name'])) {
180
+            $params['service_name'] = 'cloudFiles';
181
+        }
182
+
183
+        $params['autocreate'] = true;
184
+
185
+        if (isset($params['domain'])) {
186
+            $params['user'] = [
187
+                'name' => $params['user'],
188
+                'password' => $params['password'],
189
+                'domain' => [
190
+                    'name' => $params['domain'],
191
+                ]
192
+            ];
193
+        }
194
+
195
+        $this->params = $params;
196
+        // FIXME: private class...
197
+        $this->objectCache = new \OC\Cache\CappedMemoryCache();
198
+        $this->connectionFactory = new SwiftFactory(
199
+            \OC::$server->getMemCacheFactory()->createDistributed('swift/'),
200
+            $this->params,
201
+            \OC::$server->getLogger()
202
+        );
203
+        $this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
204
+        $this->bucket = $params['bucket'];
205
+    }
206
+
207
+    public function mkdir($path) {
208
+        $path = $this->normalizePath($path);
209
+
210
+        if ($this->is_dir($path)) {
211
+            return false;
212
+        }
213
+
214
+        if ($path !== '.') {
215
+            $path .= '/';
216
+        }
217
+
218
+        try {
219
+            $this->getContainer()->createObject([
220
+                'name' => $path,
221
+                'content' => '',
222
+                'headers' => ['content-type' => 'httpd/unix-directory']
223
+            ]);
224
+            // invalidate so that the next access gets the real object
225
+            // with all properties
226
+            $this->objectCache->remove($path);
227
+        } catch (BadResponseError $e) {
228
+            \OC::$server->getLogger()->logException($e, [
229
+                'level' => ILogger::ERROR,
230
+                'app' => 'files_external',
231
+            ]);
232
+            return false;
233
+        }
234
+
235
+        return true;
236
+    }
237
+
238
+    public function file_exists($path) {
239
+        $path = $this->normalizePath($path);
240
+
241
+        if ($path !== '.' && $this->is_dir($path)) {
242
+            $path .= '/';
243
+        }
244
+
245
+        return $this->doesObjectExist($path);
246
+    }
247
+
248
+    public function rmdir($path) {
249
+        $path = $this->normalizePath($path);
250
+
251
+        if (!$this->is_dir($path) || !$this->isDeletable($path)) {
252
+            return false;
253
+        }
254
+
255
+        $dh = $this->opendir($path);
256
+        while ($file = readdir($dh)) {
257
+            if (\OC\Files\Filesystem::isIgnoredDir($file)) {
258
+                continue;
259
+            }
260
+
261
+            if ($this->is_dir($path . '/' . $file)) {
262
+                $this->rmdir($path . '/' . $file);
263
+            } else {
264
+                $this->unlink($path . '/' . $file);
265
+            }
266
+        }
267
+
268
+        try {
269
+            $this->objectStore->deleteObject($path . '/');
270
+            $this->objectCache->remove($path . '/');
271
+        } catch (BadResponseError $e) {
272
+            \OC::$server->getLogger()->logException($e, [
273
+                'level' => ILogger::ERROR,
274
+                'app' => 'files_external',
275
+            ]);
276
+            return false;
277
+        }
278
+
279
+        return true;
280
+    }
281
+
282
+    public function opendir($path) {
283
+        $path = $this->normalizePath($path);
284
+
285
+        if ($path === '.') {
286
+            $path = '';
287
+        } else {
288
+            $path .= '/';
289
+        }
290 290
 
291 291
 //		$path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
292 292
 
293
-		try {
294
-			$files = [];
295
-			$objects = $this->getContainer()->listObjects([
296
-				'prefix' => $path,
297
-				'delimiter' => '/'
298
-			]);
299
-
300
-			/** @var StorageObject $object */
301
-			foreach ($objects as $object) {
302
-				$file = basename($object->name);
303
-				if ($file !== basename($path) && $file !== '.') {
304
-					$files[] = $file;
305
-				}
306
-			}
307
-
308
-			return IteratorDirectory::wrap($files);
309
-		} catch (\Exception $e) {
310
-			\OC::$server->getLogger()->logException($e, [
311
-				'level' => ILogger::ERROR,
312
-				'app' => 'files_external',
313
-			]);
314
-			return false;
315
-		}
316
-
317
-	}
318
-
319
-	public function stat($path) {
320
-		$path = $this->normalizePath($path);
321
-
322
-		if ($path === '.') {
323
-			$path = '';
324
-		} else if ($this->is_dir($path)) {
325
-			$path .= '/';
326
-		}
327
-
328
-		try {
329
-			$object = $this->fetchObject($path);
330
-			if (!$object) {
331
-				return false;
332
-			}
333
-		} catch (BadResponseError $e) {
334
-			\OC::$server->getLogger()->logException($e, [
335
-				'level' => ILogger::ERROR,
336
-				'app' => 'files_external',
337
-			]);
338
-			return false;
339
-		}
340
-
341
-		$dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
342
-		$mtime = $dateTime ? $dateTime->getTimestamp() : null;
343
-		$objectMetadata = $object->getMetadata();
344
-		if (isset($objectMetadata['timestamp'])) {
345
-			$mtime = $objectMetadata['timestamp'];
346
-		}
347
-
348
-		if (!empty($mtime)) {
349
-			$mtime = floor($mtime);
350
-		}
351
-
352
-		$stat = array();
353
-		$stat['size'] = (int)$object->contentLength;
354
-		$stat['mtime'] = $mtime;
355
-		$stat['atime'] = time();
356
-		return $stat;
357
-	}
358
-
359
-	public function filetype($path) {
360
-		$path = $this->normalizePath($path);
361
-
362
-		if ($path !== '.' && $this->doesObjectExist($path)) {
363
-			return 'file';
364
-		}
365
-
366
-		if ($path !== '.') {
367
-			$path .= '/';
368
-		}
369
-
370
-		if ($this->doesObjectExist($path)) {
371
-			return 'dir';
372
-		}
373
-	}
374
-
375
-	public function unlink($path) {
376
-		$path = $this->normalizePath($path);
377
-
378
-		if ($this->is_dir($path)) {
379
-			return $this->rmdir($path);
380
-		}
381
-
382
-		try {
383
-			$this->objectStore->deleteObject($path);
384
-			$this->objectCache->remove($path);
385
-			$this->objectCache->remove($path . '/');
386
-		} catch (BadResponseError $e) {
387
-			if ($e->getResponse()->getStatusCode() !== 404) {
388
-				\OC::$server->getLogger()->logException($e, [
389
-					'level' => ILogger::ERROR,
390
-					'app' => 'files_external',
391
-				]);
392
-				throw $e;
393
-			}
394
-		}
395
-
396
-		return true;
397
-	}
398
-
399
-	public function fopen($path, $mode) {
400
-		$path = $this->normalizePath($path);
401
-
402
-		switch ($mode) {
403
-			case 'a':
404
-			case 'ab':
405
-			case 'a+':
406
-				return false;
407
-			case 'r':
408
-			case 'rb':
409
-				try {
410
-					return $this->objectStore->readObject($path);
411
-				} catch (BadResponseError $e) {
412
-					\OC::$server->getLogger()->logException($e, [
413
-						'level' => ILogger::ERROR,
414
-						'app' => 'files_external',
415
-					]);
416
-					return false;
417
-				}
418
-			case 'w':
419
-			case 'wb':
420
-			case 'r+':
421
-			case 'w+':
422
-			case 'wb+':
423
-			case 'x':
424
-			case 'x+':
425
-			case 'c':
426
-			case 'c+':
427
-				if (strrpos($path, '.') !== false) {
428
-					$ext = substr($path, strrpos($path, '.'));
429
-				} else {
430
-					$ext = '';
431
-				}
432
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
433
-				// Fetch existing file if required
434
-				if ($mode[0] !== 'w' && $this->file_exists($path)) {
435
-					if ($mode[0] === 'x') {
436
-						// File cannot already exist
437
-						return false;
438
-					}
439
-					$source = $this->fopen($path, 'r');
440
-					file_put_contents($tmpFile, $source);
441
-				}
442
-				$handle = fopen($tmpFile, $mode);
443
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
444
-					$this->writeBack($tmpFile, $path);
445
-				});
446
-		}
447
-	}
448
-
449
-	public function touch($path, $mtime = null) {
450
-		$path = $this->normalizePath($path);
451
-		if (is_null($mtime)) {
452
-			$mtime = time();
453
-		}
454
-		$metadata = ['timestamp' => (string)$mtime];
455
-		if ($this->file_exists($path)) {
456
-			if ($this->is_dir($path) && $path !== '.') {
457
-				$path .= '/';
458
-			}
459
-
460
-			$object = $this->fetchObject($path);
461
-			if ($object->mergeMetadata($metadata)) {
462
-				// invalidate target object to force repopulation on fetch
463
-				$this->objectCache->remove($path);
464
-			}
465
-			return true;
466
-		} else {
467
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
468
-			$this->getContainer()->createObject([
469
-				'name' => $path,
470
-				'content' => '',
471
-				'headers' => ['content-type' => 'httpd/unix-directory']
472
-			]);
473
-			// invalidate target object to force repopulation on fetch
474
-			$this->objectCache->remove($path);
475
-			return true;
476
-		}
477
-	}
478
-
479
-	public function copy($path1, $path2) {
480
-		$path1 = $this->normalizePath($path1);
481
-		$path2 = $this->normalizePath($path2);
482
-
483
-		$fileType = $this->filetype($path1);
484
-		if ($fileType) {
485
-			// make way
486
-			$this->unlink($path2);
487
-		}
488
-
489
-		if ($fileType === 'file') {
490
-			try {
491
-				$source = $this->fetchObject($path1);
492
-				$source->copy([
493
-					'destination' => $this->bucket . '/' . $path2
494
-				]);
495
-				// invalidate target object to force repopulation on fetch
496
-				$this->objectCache->remove($path2);
497
-				$this->objectCache->remove($path2 . '/');
498
-			} catch (BadResponseError $e) {
499
-				\OC::$server->getLogger()->logException($e, [
500
-					'level' => ILogger::ERROR,
501
-					'app' => 'files_external',
502
-				]);
503
-				return false;
504
-			}
505
-
506
-		} else if ($fileType === 'dir') {
507
-			try {
508
-				$source = $this->fetchObject($path1 . '/');
509
-				$source->copy([
510
-					'destination' => $this->bucket . '/' . $path2 . '/'
511
-				]);
512
-				// invalidate target object to force repopulation on fetch
513
-				$this->objectCache->remove($path2);
514
-				$this->objectCache->remove($path2 . '/');
515
-			} catch (BadResponseError $e) {
516
-				\OC::$server->getLogger()->logException($e, [
517
-					'level' => ILogger::ERROR,
518
-					'app' => 'files_external',
519
-				]);
520
-				return false;
521
-			}
522
-
523
-			$dh = $this->opendir($path1);
524
-			while ($file = readdir($dh)) {
525
-				if (\OC\Files\Filesystem::isIgnoredDir($file)) {
526
-					continue;
527
-				}
528
-
529
-				$source = $path1 . '/' . $file;
530
-				$target = $path2 . '/' . $file;
531
-				$this->copy($source, $target);
532
-			}
533
-
534
-		} else {
535
-			//file does not exist
536
-			return false;
537
-		}
538
-
539
-		return true;
540
-	}
541
-
542
-	public function rename($path1, $path2) {
543
-		$path1 = $this->normalizePath($path1);
544
-		$path2 = $this->normalizePath($path2);
545
-
546
-		$fileType = $this->filetype($path1);
547
-
548
-		if ($fileType === 'dir' || $fileType === 'file') {
549
-			// copy
550
-			if ($this->copy($path1, $path2) === false) {
551
-				return false;
552
-			}
553
-
554
-			// cleanup
555
-			if ($this->unlink($path1) === false) {
556
-				throw new \Exception('failed to remove original');
557
-				$this->unlink($path2);
558
-				return false;
559
-			}
560
-
561
-			return true;
562
-		}
563
-
564
-		return false;
565
-	}
566
-
567
-	public function getId() {
568
-		return $this->id;
569
-	}
570
-
571
-	/**
572
-	 * Returns the initialized object store container.
573
-	 *
574
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
575
-	 * @throws \OCP\Files\StorageAuthException
576
-	 * @throws \OCP\Files\StorageNotAvailableException
577
-	 */
578
-	public function getContainer() {
579
-		if (is_null($this->container)) {
580
-			$this->container = $this->connectionFactory->getContainer();
581
-
582
-			if (!$this->file_exists('.')) {
583
-				$this->mkdir('.');
584
-			}
585
-		}
586
-		return $this->container;
587
-	}
588
-
589
-	public function writeBack($tmpFile, $path) {
590
-		$fileData = fopen($tmpFile, 'r');
591
-		$this->objectStore->writeObject($path, $fileData);
592
-		// invalidate target object to force repopulation on fetch
593
-		$this->objectCache->remove($path);
594
-		unlink($tmpFile);
595
-	}
596
-
597
-	public function hasUpdated($path, $time) {
598
-		if ($this->is_file($path)) {
599
-			return parent::hasUpdated($path, $time);
600
-		}
601
-		$path = $this->normalizePath($path);
602
-		$dh = $this->opendir($path);
603
-		$content = array();
604
-		while (($file = readdir($dh)) !== false) {
605
-			$content[] = $file;
606
-		}
607
-		if ($path === '.') {
608
-			$path = '';
609
-		}
610
-		$cachedContent = $this->getCache()->getFolderContents($path);
611
-		$cachedNames = array_map(function ($content) {
612
-			return $content['name'];
613
-		}, $cachedContent);
614
-		sort($cachedNames);
615
-		sort($content);
616
-		return $cachedNames !== $content;
617
-	}
618
-
619
-	/**
620
-	 * check if curl is installed
621
-	 */
622
-	public static function checkDependencies() {
623
-		return true;
624
-	}
293
+        try {
294
+            $files = [];
295
+            $objects = $this->getContainer()->listObjects([
296
+                'prefix' => $path,
297
+                'delimiter' => '/'
298
+            ]);
299
+
300
+            /** @var StorageObject $object */
301
+            foreach ($objects as $object) {
302
+                $file = basename($object->name);
303
+                if ($file !== basename($path) && $file !== '.') {
304
+                    $files[] = $file;
305
+                }
306
+            }
307
+
308
+            return IteratorDirectory::wrap($files);
309
+        } catch (\Exception $e) {
310
+            \OC::$server->getLogger()->logException($e, [
311
+                'level' => ILogger::ERROR,
312
+                'app' => 'files_external',
313
+            ]);
314
+            return false;
315
+        }
316
+
317
+    }
318
+
319
+    public function stat($path) {
320
+        $path = $this->normalizePath($path);
321
+
322
+        if ($path === '.') {
323
+            $path = '';
324
+        } else if ($this->is_dir($path)) {
325
+            $path .= '/';
326
+        }
327
+
328
+        try {
329
+            $object = $this->fetchObject($path);
330
+            if (!$object) {
331
+                return false;
332
+            }
333
+        } catch (BadResponseError $e) {
334
+            \OC::$server->getLogger()->logException($e, [
335
+                'level' => ILogger::ERROR,
336
+                'app' => 'files_external',
337
+            ]);
338
+            return false;
339
+        }
340
+
341
+        $dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
342
+        $mtime = $dateTime ? $dateTime->getTimestamp() : null;
343
+        $objectMetadata = $object->getMetadata();
344
+        if (isset($objectMetadata['timestamp'])) {
345
+            $mtime = $objectMetadata['timestamp'];
346
+        }
347
+
348
+        if (!empty($mtime)) {
349
+            $mtime = floor($mtime);
350
+        }
351
+
352
+        $stat = array();
353
+        $stat['size'] = (int)$object->contentLength;
354
+        $stat['mtime'] = $mtime;
355
+        $stat['atime'] = time();
356
+        return $stat;
357
+    }
358
+
359
+    public function filetype($path) {
360
+        $path = $this->normalizePath($path);
361
+
362
+        if ($path !== '.' && $this->doesObjectExist($path)) {
363
+            return 'file';
364
+        }
365
+
366
+        if ($path !== '.') {
367
+            $path .= '/';
368
+        }
369
+
370
+        if ($this->doesObjectExist($path)) {
371
+            return 'dir';
372
+        }
373
+    }
374
+
375
+    public function unlink($path) {
376
+        $path = $this->normalizePath($path);
377
+
378
+        if ($this->is_dir($path)) {
379
+            return $this->rmdir($path);
380
+        }
381
+
382
+        try {
383
+            $this->objectStore->deleteObject($path);
384
+            $this->objectCache->remove($path);
385
+            $this->objectCache->remove($path . '/');
386
+        } catch (BadResponseError $e) {
387
+            if ($e->getResponse()->getStatusCode() !== 404) {
388
+                \OC::$server->getLogger()->logException($e, [
389
+                    'level' => ILogger::ERROR,
390
+                    'app' => 'files_external',
391
+                ]);
392
+                throw $e;
393
+            }
394
+        }
395
+
396
+        return true;
397
+    }
398
+
399
+    public function fopen($path, $mode) {
400
+        $path = $this->normalizePath($path);
401
+
402
+        switch ($mode) {
403
+            case 'a':
404
+            case 'ab':
405
+            case 'a+':
406
+                return false;
407
+            case 'r':
408
+            case 'rb':
409
+                try {
410
+                    return $this->objectStore->readObject($path);
411
+                } catch (BadResponseError $e) {
412
+                    \OC::$server->getLogger()->logException($e, [
413
+                        'level' => ILogger::ERROR,
414
+                        'app' => 'files_external',
415
+                    ]);
416
+                    return false;
417
+                }
418
+            case 'w':
419
+            case 'wb':
420
+            case 'r+':
421
+            case 'w+':
422
+            case 'wb+':
423
+            case 'x':
424
+            case 'x+':
425
+            case 'c':
426
+            case 'c+':
427
+                if (strrpos($path, '.') !== false) {
428
+                    $ext = substr($path, strrpos($path, '.'));
429
+                } else {
430
+                    $ext = '';
431
+                }
432
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
433
+                // Fetch existing file if required
434
+                if ($mode[0] !== 'w' && $this->file_exists($path)) {
435
+                    if ($mode[0] === 'x') {
436
+                        // File cannot already exist
437
+                        return false;
438
+                    }
439
+                    $source = $this->fopen($path, 'r');
440
+                    file_put_contents($tmpFile, $source);
441
+                }
442
+                $handle = fopen($tmpFile, $mode);
443
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
444
+                    $this->writeBack($tmpFile, $path);
445
+                });
446
+        }
447
+    }
448
+
449
+    public function touch($path, $mtime = null) {
450
+        $path = $this->normalizePath($path);
451
+        if (is_null($mtime)) {
452
+            $mtime = time();
453
+        }
454
+        $metadata = ['timestamp' => (string)$mtime];
455
+        if ($this->file_exists($path)) {
456
+            if ($this->is_dir($path) && $path !== '.') {
457
+                $path .= '/';
458
+            }
459
+
460
+            $object = $this->fetchObject($path);
461
+            if ($object->mergeMetadata($metadata)) {
462
+                // invalidate target object to force repopulation on fetch
463
+                $this->objectCache->remove($path);
464
+            }
465
+            return true;
466
+        } else {
467
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
468
+            $this->getContainer()->createObject([
469
+                'name' => $path,
470
+                'content' => '',
471
+                'headers' => ['content-type' => 'httpd/unix-directory']
472
+            ]);
473
+            // invalidate target object to force repopulation on fetch
474
+            $this->objectCache->remove($path);
475
+            return true;
476
+        }
477
+    }
478
+
479
+    public function copy($path1, $path2) {
480
+        $path1 = $this->normalizePath($path1);
481
+        $path2 = $this->normalizePath($path2);
482
+
483
+        $fileType = $this->filetype($path1);
484
+        if ($fileType) {
485
+            // make way
486
+            $this->unlink($path2);
487
+        }
488
+
489
+        if ($fileType === 'file') {
490
+            try {
491
+                $source = $this->fetchObject($path1);
492
+                $source->copy([
493
+                    'destination' => $this->bucket . '/' . $path2
494
+                ]);
495
+                // invalidate target object to force repopulation on fetch
496
+                $this->objectCache->remove($path2);
497
+                $this->objectCache->remove($path2 . '/');
498
+            } catch (BadResponseError $e) {
499
+                \OC::$server->getLogger()->logException($e, [
500
+                    'level' => ILogger::ERROR,
501
+                    'app' => 'files_external',
502
+                ]);
503
+                return false;
504
+            }
505
+
506
+        } else if ($fileType === 'dir') {
507
+            try {
508
+                $source = $this->fetchObject($path1 . '/');
509
+                $source->copy([
510
+                    'destination' => $this->bucket . '/' . $path2 . '/'
511
+                ]);
512
+                // invalidate target object to force repopulation on fetch
513
+                $this->objectCache->remove($path2);
514
+                $this->objectCache->remove($path2 . '/');
515
+            } catch (BadResponseError $e) {
516
+                \OC::$server->getLogger()->logException($e, [
517
+                    'level' => ILogger::ERROR,
518
+                    'app' => 'files_external',
519
+                ]);
520
+                return false;
521
+            }
522
+
523
+            $dh = $this->opendir($path1);
524
+            while ($file = readdir($dh)) {
525
+                if (\OC\Files\Filesystem::isIgnoredDir($file)) {
526
+                    continue;
527
+                }
528
+
529
+                $source = $path1 . '/' . $file;
530
+                $target = $path2 . '/' . $file;
531
+                $this->copy($source, $target);
532
+            }
533
+
534
+        } else {
535
+            //file does not exist
536
+            return false;
537
+        }
538
+
539
+        return true;
540
+    }
541
+
542
+    public function rename($path1, $path2) {
543
+        $path1 = $this->normalizePath($path1);
544
+        $path2 = $this->normalizePath($path2);
545
+
546
+        $fileType = $this->filetype($path1);
547
+
548
+        if ($fileType === 'dir' || $fileType === 'file') {
549
+            // copy
550
+            if ($this->copy($path1, $path2) === false) {
551
+                return false;
552
+            }
553
+
554
+            // cleanup
555
+            if ($this->unlink($path1) === false) {
556
+                throw new \Exception('failed to remove original');
557
+                $this->unlink($path2);
558
+                return false;
559
+            }
560
+
561
+            return true;
562
+        }
563
+
564
+        return false;
565
+    }
566
+
567
+    public function getId() {
568
+        return $this->id;
569
+    }
570
+
571
+    /**
572
+     * Returns the initialized object store container.
573
+     *
574
+     * @return \OpenStack\ObjectStore\v1\Models\Container
575
+     * @throws \OCP\Files\StorageAuthException
576
+     * @throws \OCP\Files\StorageNotAvailableException
577
+     */
578
+    public function getContainer() {
579
+        if (is_null($this->container)) {
580
+            $this->container = $this->connectionFactory->getContainer();
581
+
582
+            if (!$this->file_exists('.')) {
583
+                $this->mkdir('.');
584
+            }
585
+        }
586
+        return $this->container;
587
+    }
588
+
589
+    public function writeBack($tmpFile, $path) {
590
+        $fileData = fopen($tmpFile, 'r');
591
+        $this->objectStore->writeObject($path, $fileData);
592
+        // invalidate target object to force repopulation on fetch
593
+        $this->objectCache->remove($path);
594
+        unlink($tmpFile);
595
+    }
596
+
597
+    public function hasUpdated($path, $time) {
598
+        if ($this->is_file($path)) {
599
+            return parent::hasUpdated($path, $time);
600
+        }
601
+        $path = $this->normalizePath($path);
602
+        $dh = $this->opendir($path);
603
+        $content = array();
604
+        while (($file = readdir($dh)) !== false) {
605
+            $content[] = $file;
606
+        }
607
+        if ($path === '.') {
608
+            $path = '';
609
+        }
610
+        $cachedContent = $this->getCache()->getFolderContents($path);
611
+        $cachedNames = array_map(function ($content) {
612
+            return $content['name'];
613
+        }, $cachedContent);
614
+        sort($cachedNames);
615
+        sort($content);
616
+        return $cachedNames !== $content;
617
+    }
618
+
619
+    /**
620
+     * check if curl is installed
621
+     */
622
+    public static function checkDependencies() {
623
+        return true;
624
+    }
625 625
 
626 626
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -164,12 +164,12 @@  discard block
 block discarded – undo
164 164
 		}
165 165
 
166 166
 		$user = $params['user'];
167
-		$this->id = 'swift::' . $user . md5($params['bucket']);
167
+		$this->id = 'swift::'.$user.md5($params['bucket']);
168 168
 
169 169
 		$bucketUrl = new Uri($params['bucket']);
170 170
 		if ($bucketUrl->getHost()) {
171 171
 			$params['bucket'] = basename($bucketUrl->getPath());
172
-			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
172
+			$params['endpoint_url'] = (string) $bucketUrl->withPath(dirname($bucketUrl->getPath()));
173 173
 		}
174 174
 
175 175
 		if (empty($params['url'])) {
@@ -258,16 +258,16 @@  discard block
 block discarded – undo
258 258
 				continue;
259 259
 			}
260 260
 
261
-			if ($this->is_dir($path . '/' . $file)) {
262
-				$this->rmdir($path . '/' . $file);
261
+			if ($this->is_dir($path.'/'.$file)) {
262
+				$this->rmdir($path.'/'.$file);
263 263
 			} else {
264
-				$this->unlink($path . '/' . $file);
264
+				$this->unlink($path.'/'.$file);
265 265
 			}
266 266
 		}
267 267
 
268 268
 		try {
269
-			$this->objectStore->deleteObject($path . '/');
270
-			$this->objectCache->remove($path . '/');
269
+			$this->objectStore->deleteObject($path.'/');
270
+			$this->objectCache->remove($path.'/');
271 271
 		} catch (BadResponseError $e) {
272 272
 			\OC::$server->getLogger()->logException($e, [
273 273
 				'level' => ILogger::ERROR,
@@ -350,7 +350,7 @@  discard block
 block discarded – undo
350 350
 		}
351 351
 
352 352
 		$stat = array();
353
-		$stat['size'] = (int)$object->contentLength;
353
+		$stat['size'] = (int) $object->contentLength;
354 354
 		$stat['mtime'] = $mtime;
355 355
 		$stat['atime'] = time();
356 356
 		return $stat;
@@ -382,7 +382,7 @@  discard block
 block discarded – undo
382 382
 		try {
383 383
 			$this->objectStore->deleteObject($path);
384 384
 			$this->objectCache->remove($path);
385
-			$this->objectCache->remove($path . '/');
385
+			$this->objectCache->remove($path.'/');
386 386
 		} catch (BadResponseError $e) {
387 387
 			if ($e->getResponse()->getStatusCode() !== 404) {
388 388
 				\OC::$server->getLogger()->logException($e, [
@@ -440,7 +440,7 @@  discard block
 block discarded – undo
440 440
 					file_put_contents($tmpFile, $source);
441 441
 				}
442 442
 				$handle = fopen($tmpFile, $mode);
443
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
443
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
444 444
 					$this->writeBack($tmpFile, $path);
445 445
 				});
446 446
 		}
@@ -451,7 +451,7 @@  discard block
 block discarded – undo
451 451
 		if (is_null($mtime)) {
452 452
 			$mtime = time();
453 453
 		}
454
-		$metadata = ['timestamp' => (string)$mtime];
454
+		$metadata = ['timestamp' => (string) $mtime];
455 455
 		if ($this->file_exists($path)) {
456 456
 			if ($this->is_dir($path) && $path !== '.') {
457 457
 				$path .= '/';
@@ -490,11 +490,11 @@  discard block
 block discarded – undo
490 490
 			try {
491 491
 				$source = $this->fetchObject($path1);
492 492
 				$source->copy([
493
-					'destination' => $this->bucket . '/' . $path2
493
+					'destination' => $this->bucket.'/'.$path2
494 494
 				]);
495 495
 				// invalidate target object to force repopulation on fetch
496 496
 				$this->objectCache->remove($path2);
497
-				$this->objectCache->remove($path2 . '/');
497
+				$this->objectCache->remove($path2.'/');
498 498
 			} catch (BadResponseError $e) {
499 499
 				\OC::$server->getLogger()->logException($e, [
500 500
 					'level' => ILogger::ERROR,
@@ -505,13 +505,13 @@  discard block
 block discarded – undo
505 505
 
506 506
 		} else if ($fileType === 'dir') {
507 507
 			try {
508
-				$source = $this->fetchObject($path1 . '/');
508
+				$source = $this->fetchObject($path1.'/');
509 509
 				$source->copy([
510
-					'destination' => $this->bucket . '/' . $path2 . '/'
510
+					'destination' => $this->bucket.'/'.$path2.'/'
511 511
 				]);
512 512
 				// invalidate target object to force repopulation on fetch
513 513
 				$this->objectCache->remove($path2);
514
-				$this->objectCache->remove($path2 . '/');
514
+				$this->objectCache->remove($path2.'/');
515 515
 			} catch (BadResponseError $e) {
516 516
 				\OC::$server->getLogger()->logException($e, [
517 517
 					'level' => ILogger::ERROR,
@@ -526,8 +526,8 @@  discard block
 block discarded – undo
526 526
 					continue;
527 527
 				}
528 528
 
529
-				$source = $path1 . '/' . $file;
530
-				$target = $path2 . '/' . $file;
529
+				$source = $path1.'/'.$file;
530
+				$target = $path2.'/'.$file;
531 531
 				$this->copy($source, $target);
532 532
 			}
533 533
 
@@ -608,7 +608,7 @@  discard block
 block discarded – undo
608 608
 			$path = '';
609 609
 		}
610 610
 		$cachedContent = $this->getCache()->getFolderContents($path);
611
-		$cachedNames = array_map(function ($content) {
611
+		$cachedNames = array_map(function($content) {
612 612
 			return $content['name'];
613 613
 		}, $cachedContent);
614 614
 		sort($cachedNames);
Please login to merge, or discard this patch.