Completed
Push — master ( 4076c0...886762 )
by Morris
122:17 queued 106:43
created

Swift::unlink()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 23
Code Lines 15

Duplication

Lines 7
Ratio 30.43 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 8
nop 1
dl 7
loc 23
rs 8.7972
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, ownCloud, Inc.
5
 *
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author Bart Visscher <[email protected]>
8
 * @author Benjamin Liles <[email protected]>
9
 * @author Christian Berendt <[email protected]>
10
 * @author Christopher Bartz <[email protected]>
11
 * @author Daniel Tosello <[email protected]>
12
 * @author Felix Moeller <[email protected]>
13
 * @author Joas Schilling <[email protected]>
14
 * @author Jörn Friedrich Dreyer <[email protected]>
15
 * @author Lukas Reschke <[email protected]>
16
 * @author Martin Mattel <[email protected]>
17
 * @author Morris Jobke <[email protected]>
18
 * @author Philipp Kapfer <[email protected]>
19
 * @author Robin Appelman <[email protected]>
20
 * @author Robin McCorkell <[email protected]>
21
 * @author Thomas Müller <[email protected]>
22
 * @author Tim Dettrick <[email protected]>
23
 * @author Vincent Petry <[email protected]>
24
 *
25
 * @license AGPL-3.0
26
 *
27
 * This code is free software: you can redistribute it and/or modify
28
 * it under the terms of the GNU Affero General Public License, version 3,
29
 * as published by the Free Software Foundation.
30
 *
31
 * This program is distributed in the hope that it will be useful,
32
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
33
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34
 * GNU Affero General Public License for more details.
35
 *
36
 * You should have received a copy of the GNU Affero General Public License, version 3,
37
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
38
 *
39
 */
40
41
namespace OCA\Files_External\Lib\Storage;
42
43
use GuzzleHttp\Psr7\Uri;
44
use Icewind\Streams\CallbackWrapper;
45
use Icewind\Streams\IteratorDirectory;
46
use OC\Files\ObjectStore\SwiftFactory;
47
use OCP\Files\StorageBadConfigException;
48
use OpenStack\Common\Error\BadResponseError;
49
use OpenStack\ObjectStore\v1\Models\StorageObject;
50
51
class Swift extends \OC\Files\Storage\Common {
52
	/** @var SwiftFactory */
53
	private $connectionFactory;
54
	/**
55
	 * @var \OpenStack\ObjectStore\v1\Models\Container
56
	 */
57
	private $container;
58
	/**
59
	 * @var string
60
	 */
61
	private $bucket;
62
	/**
63
	 * Connection parameters
64
	 *
65
	 * @var array
66
	 */
67
	private $params;
68
69
	/** @var string */
70
	private $id;
71
72
	/** @var \OC\Files\ObjectStore\Swift */
73
	private $objectStore;
74
75
	/**
76
	 * Key value cache mapping path to data object. Maps path to
77
	 * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
78
	 * paths and path to false for not existing paths.
79
	 *
80
	 * @var \OCP\ICache
81
	 */
82
	private $objectCache;
83
84
	/**
85
	 * @param string $path
86
	 * @return mixed|string
87
	 */
88 View Code Duplication
	private function normalizePath(string $path) {
89
		$path = trim($path, '/');
90
91
		if (!$path) {
92
			$path = '.';
93
		}
94
95
		$path = str_replace('#', '%23', $path);
96
97
		return $path;
98
	}
99
100
	const SUBCONTAINER_FILE = '.subcontainers';
101
102
	/**
103
	 * translate directory path to container name
104
	 *
105
	 * @param string $path
106
	 * @return string
107
	 */
108
109
	/**
110
	 * Fetches an object from the API.
111
	 * If the object is cached already or a
112
	 * failed "doesn't exist" response was cached,
113
	 * that one will be returned.
114
	 *
115
	 * @param string $path
116
	 * @return StorageObject|bool object
117
	 * or false if the object did not exist
118
	 * @throws \OCP\Files\StorageAuthException
119
	 * @throws \OCP\Files\StorageNotAvailableException
120
	 */
121
	private function fetchObject(string $path) {
122
		if ($this->objectCache->hasKey($path)) {
123
			// might be "false" if object did not exist from last check
124
			return $this->objectCache->get($path);
125
		}
126
		try {
127
			$object = $this->getContainer()->getObject($path);
128
			$object->retrieve();
129
			$this->objectCache->set($path, $object);
130
			return $object;
131
		} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
132
			// Expected response is "404 Not Found", so only log if it isn't
133 View Code Duplication
			if ($e->getResponse()->getStatusCode() !== 404) {
134
				\OC::$server->getLogger()->logException($e, [
135
					'level' => \OCP\Util::ERROR,
136
					'app' => 'files_external',
137
				]);
138
			}
139
			$this->objectCache->set($path, false);
140
			return false;
141
		}
142
	}
143
144
	/**
145
	 * Returns whether the given path exists.
146
	 *
147
	 * @param string $path
148
	 *
149
	 * @return bool true if the object exist, false otherwise
150
	 * @throws \OCP\Files\StorageAuthException
151
	 * @throws \OCP\Files\StorageNotAvailableException
152
	 */
153
	private function doesObjectExist($path) {
154
		return $this->fetchObject($path) !== false;
155
	}
156
157
	public function __construct($params) {
158
		if ((empty($params['key']) and empty($params['password']))
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
159
			or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
160
			or empty($params['region'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
161
		) {
162
			throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
163
		}
164
165
		$user = $params['user'];
166
		$this->id = 'swift::' . $user . md5($params['bucket']);
167
168
		$bucketUrl = new Uri($params['bucket']);
169
		if ($bucketUrl->getHost()) {
170
			$params['bucket'] = basename($bucketUrl->getPath());
171
			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
172
		}
173
174
		if (empty($params['url'])) {
175
			$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
176
		}
177
178
		if (empty($params['service_name'])) {
179
			$params['service_name'] = 'cloudFiles';
180
		}
181
182
		$params['autocreate'] = true;
183
184
		if (isset($params['domain'])) {
185
			$params['user'] = [
186
				'name' => $params['user'],
187
				'password' => $params['password'],
188
				'domain' => [
189
					'name' => $params['domain'],
190
				]
191
			];
192
		}
193
194
		$this->params = $params;
195
		// FIXME: private class...
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
196
		$this->objectCache = new \OC\Cache\CappedMemoryCache();
197
		$this->connectionFactory = new SwiftFactory(\OC::$server->getMemCacheFactory()->createDistributed('swift/'), $this->params);
198
		$this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
199
		$this->bucket = $params['bucket'];
200
	}
201
202
	public function mkdir($path) {
203
		$path = $this->normalizePath($path);
204
205
		if ($this->is_dir($path)) {
206
			return false;
207
		}
208
209
		if ($path !== '.') {
210
			$path .= '/';
211
		}
212
213
		try {
214
			$this->getContainer()->createObject([
215
				'name' => $path,
216
				'content' => '',
217
				'headers' => ['content-type' => 'httpd/unix-directory']
218
			]);
219
			// invalidate so that the next access gets the real object
220
			// with all properties
221
			$this->objectCache->remove($path);
222
		} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
223
			\OC::$server->getLogger()->logException($e, [
224
				'level' => \OCP\Util::ERROR,
225
				'app' => 'files_external',
226
			]);
227
			return false;
228
		}
229
230
		return true;
231
	}
232
233
	public function file_exists($path) {
234
		$path = $this->normalizePath($path);
235
236
		if ($path !== '.' && $this->is_dir($path)) {
237
			$path .= '/';
238
		}
239
240
		return $this->doesObjectExist($path);
241
	}
242
243
	public function rmdir($path) {
244
		$path = $this->normalizePath($path);
245
246
		if (!$this->is_dir($path) || !$this->isDeletable($path)) {
247
			return false;
248
		}
249
250
		$dh = $this->opendir($path);
251 View Code Duplication
		while ($file = readdir($dh)) {
252
			if (\OC\Files\Filesystem::isIgnoredDir($file)) {
253
				continue;
254
			}
255
256
			if ($this->is_dir($path . '/' . $file)) {
257
				$this->rmdir($path . '/' . $file);
258
			} else {
259
				$this->unlink($path . '/' . $file);
260
			}
261
		}
262
263
		try {
264
			$this->objectStore->deleteObject($path . '/');
265
			$this->objectCache->remove($path . '/');
266
		} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
267
			\OC::$server->getLogger()->logException($e, [
268
				'level' => \OCP\Util::ERROR,
269
				'app' => 'files_external',
270
			]);
271
			return false;
272
		}
273
274
		return true;
275
	}
276
277
	public function opendir($path) {
278
		$path = $this->normalizePath($path);
279
280
		if ($path === '.') {
281
			$path = '';
282
		} else {
283
			$path .= '/';
284
		}
285
286
//		$path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
287
288
		try {
289
			$files = [];
290
			$objects = $this->getContainer()->listObjects([
291
				'prefix' => $path,
292
				'delimiter' => '/'
293
			]);
294
295
			/** @var StorageObject $object */
296
			foreach ($objects as $object) {
297
				$file = basename($object->name);
298
				if ($file !== basename($path) && $file !== '.') {
299
					$files[] = $file;
300
				}
301
			}
302
303
			return IteratorDirectory::wrap($files);
304
		} catch (\Exception $e) {
305
			\OC::$server->getLogger()->logException($e, [
306
				'level' => \OCP\Util::ERROR,
307
				'app' => 'files_external',
308
			]);
309
			return false;
310
		}
311
312
	}
313
314
	public function stat($path) {
315
		$path = $this->normalizePath($path);
316
317
		if ($path === '.') {
318
			$path = '';
319
		} else if ($this->is_dir($path)) {
320
			$path .= '/';
321
		}
322
323
		try {
324
			$object = $this->fetchObject($path);
325
			if (!$object) {
326
				return false;
327
			}
328
		} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
329
			\OC::$server->getLogger()->logException($e, [
330
				'level' => \OCP\Util::ERROR,
331
				'app' => 'files_external',
332
			]);
333
			return false;
334
		}
335
336
		$dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
337
		$mtime = $dateTime ? $dateTime->getTimestamp() : null;
338
		$objectMetadata = $object->getMetadata();
339
		if (isset($objectMetadata['timestamp'])) {
340
			$mtime = $objectMetadata['timestamp'];
341
		}
342
343
		if (!empty($mtime)) {
344
			$mtime = floor($mtime);
345
		}
346
347
		$stat = array();
348
		$stat['size'] = (int)$object->contentLength;
349
		$stat['mtime'] = $mtime;
350
		$stat['atime'] = time();
351
		return $stat;
352
	}
353
354
	public function filetype($path) {
355
		$path = $this->normalizePath($path);
356
357
		if ($path !== '.' && $this->doesObjectExist($path)) {
358
			return 'file';
359
		}
360
361
		if ($path !== '.') {
362
			$path .= '/';
363
		}
364
365
		if ($this->doesObjectExist($path)) {
366
			return 'dir';
367
		}
368
	}
369
370
	public function unlink($path) {
371
		$path = $this->normalizePath($path);
372
373
		if ($this->is_dir($path)) {
374
			return $this->rmdir($path);
375
		}
376
377
		try {
378
			$this->objectStore->deleteObject($path);
379
			$this->objectCache->remove($path);
380
			$this->objectCache->remove($path . '/');
381
		} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
382 View Code Duplication
			if ($e->getResponse()->getStatusCode() !== 404) {
383
				\OC::$server->getLogger()->logException($e, [
384
					'level' => \OCP\Util::ERROR,
385
					'app' => 'files_external',
386
				]);
387
				throw $e;
388
			}
389
		}
390
391
		return true;
392
	}
393
394
	public function fopen($path, $mode) {
395
		$path = $this->normalizePath($path);
396
397
		switch ($mode) {
398
			case 'a':
399
			case 'ab':
400
			case 'a+':
401
				return false;
402
			case 'r':
403
			case 'rb':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
404
				try {
405
					return $this->objectStore->readObject($path);
406
				} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
407
					\OC::$server->getLogger()->logException($e, [
408
						'level' => \OCP\Util::ERROR,
409
						'app' => 'files_external',
410
					]);
411
					return false;
412
				}
413
			case 'w':
414
			case 'wb':
415
			case 'r+':
416
			case 'w+':
417
			case 'wb+':
418
			case 'x':
419
			case 'x+':
420
			case 'c':
421
			case 'c+':
422
				if (strrpos($path, '.') !== false) {
423
					$ext = substr($path, strrpos($path, '.'));
424
				} else {
425
					$ext = '';
426
				}
427
				$tmpFile = \OCP\Files::tmpFile($ext);
428
				// Fetch existing file if required
429
				if ($mode[0] !== 'w' && $this->file_exists($path)) {
430
					if ($mode[0] === 'x') {
431
						// File cannot already exist
432
						return false;
433
					}
434
					$source = $this->fopen($path, 'r');
435
					file_put_contents($tmpFile, $source);
436
				}
437
				$handle = fopen($tmpFile, $mode);
438
				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
439
					$this->writeBack($tmpFile, $path);
440
				});
441
		}
442
	}
443
444
	public function touch($path, $mtime = null) {
445
		$path = $this->normalizePath($path);
446
		if (is_null($mtime)) {
447
			$mtime = time();
448
		}
449
		$metadata = ['timestamp' => $mtime];
450
		if ($this->file_exists($path)) {
451
			if ($this->is_dir($path) && $path !== '.') {
452
				$path .= '/';
453
			}
454
455
			$object = $this->fetchObject($path);
456
			if ($object->mergeMetadata($metadata)) {
457
				// invalidate target object to force repopulation on fetch
458
				$this->objectCache->remove($path);
459
			}
460
			return true;
461
		} else {
462
			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
0 ignored issues
show
Unused Code introduced by
$mimeType is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
463
			$this->getContainer()->createObject([
464
				'name' => $path,
465
				'content' => '',
466
				'headers' => ['content-type' => 'httpd/unix-directory']
467
			]);
468
			// invalidate target object to force repopulation on fetch
469
			$this->objectCache->remove($path);
470
			return true;
471
		}
472
	}
473
474
	public function copy($path1, $path2) {
475
		$path1 = $this->normalizePath($path1);
476
		$path2 = $this->normalizePath($path2);
477
478
		$fileType = $this->filetype($path1);
479
		if ($fileType) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fileType of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
480
			// make way
481
			$this->unlink($path2);
482
		}
483
484
		if ($fileType === 'file') {
485
			try {
486
				$source = $this->fetchObject($path1);
487
				$source->copy([
488
					'destination' => $this->bucket . '/' . $path2
489
				]);
490
				// invalidate target object to force repopulation on fetch
491
				$this->objectCache->remove($path2);
492
				$this->objectCache->remove($path2 . '/');
493
			} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
494
				\OC::$server->getLogger()->logException($e, [
495
					'level' => \OCP\Util::ERROR,
496
					'app' => 'files_external',
497
				]);
498
				return false;
499
			}
500
501
		} else if ($fileType === 'dir') {
502
			try {
503
				$source = $this->fetchObject($path1 . '/');
504
				$source->copy([
505
					'destination' => $this->bucket . '/' . $path2 . '/'
506
				]);
507
				// invalidate target object to force repopulation on fetch
508
				$this->objectCache->remove($path2);
509
				$this->objectCache->remove($path2 . '/');
510
			} catch (BadResponseError $e) {
0 ignored issues
show
Bug introduced by
The class OpenStack\Common\Error\BadResponseError does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
511
				\OC::$server->getLogger()->logException($e, [
512
					'level' => \OCP\Util::ERROR,
513
					'app' => 'files_external',
514
				]);
515
				return false;
516
			}
517
518
			$dh = $this->opendir($path1);
519
			while ($file = readdir($dh)) {
520
				if (\OC\Files\Filesystem::isIgnoredDir($file)) {
521
					continue;
522
				}
523
524
				$source = $path1 . '/' . $file;
525
				$target = $path2 . '/' . $file;
526
				$this->copy($source, $target);
527
			}
528
529
		} else {
530
			//file does not exist
531
			return false;
532
		}
533
534
		return true;
535
	}
536
537
	public function rename($path1, $path2) {
538
		$path1 = $this->normalizePath($path1);
539
		$path2 = $this->normalizePath($path2);
540
541
		$fileType = $this->filetype($path1);
542
543
		if ($fileType === 'dir' || $fileType === 'file') {
544
			// copy
545
			if ($this->copy($path1, $path2) === false) {
546
				return false;
547
			}
548
549
			// cleanup
550
			if ($this->unlink($path1) === false) {
551
				throw new \Exception('failed to remove original');
552
				$this->unlink($path2);
0 ignored issues
show
Unused Code introduced by
$this->unlink($path2); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
553
				return false;
554
			}
555
556
			return true;
557
		}
558
559
		return false;
560
	}
561
562
	public function getId() {
563
		return $this->id;
564
	}
565
566
	/**
567
	 * Returns the initialized object store container.
568
	 *
569
	 * @return \OpenStack\ObjectStore\v1\Models\Container
570
	 * @throws \OCP\Files\StorageAuthException
571
	 * @throws \OCP\Files\StorageNotAvailableException
572
	 */
573
	public function getContainer() {
574
		if (is_null($this->container)) {
575
			$this->container = $this->connectionFactory->getContainer();
576
577
			if (!$this->file_exists('.')) {
578
				$this->mkdir('.');
579
			}
580
		}
581
		return $this->container;
582
	}
583
584
	public function writeBack($tmpFile, $path) {
585
		$fileData = fopen($tmpFile, 'r');
586
		$this->objectStore->writeObject($path, $fileData);
587
		// invalidate target object to force repopulation on fetch
588
		$this->objectCache->remove($path);
589
		unlink($tmpFile);
590
	}
591
592
	public function hasUpdated($path, $time) {
593
		if ($this->is_file($path)) {
594
			return parent::hasUpdated($path, $time);
595
		}
596
		$path = $this->normalizePath($path);
597
		$dh = $this->opendir($path);
598
		$content = array();
599
		while (($file = readdir($dh)) !== false) {
600
			$content[] = $file;
601
		}
602
		if ($path === '.') {
603
			$path = '';
604
		}
605
		$cachedContent = $this->getCache()->getFolderContents($path);
606
		$cachedNames = array_map(function ($content) {
607
			return $content['name'];
608
		}, $cachedContent);
609
		sort($cachedNames);
610
		sort($content);
611
		return $cachedNames !== $content;
612
	}
613
614
	/**
615
	 * check if curl is installed
616
	 */
617
	public static function checkDependencies() {
618
		return true;
619
	}
620
621
}
622