Completed
Push — master ( 333060...2a9e00 )
by Morris
14:18
created

AmazonS3::getLastModified()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 12
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 12
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author André Gaul <[email protected]>
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author Christian Berendt <[email protected]>
8
 * @author Christopher T. Johnson <[email protected]>
9
 * @author Johan Björk <[email protected]>
10
 * @author Jörn Friedrich Dreyer <[email protected]>
11
 * @author Martin Mattel <[email protected]>
12
 * @author Michael Gapczynski <[email protected]>
13
 * @author Morris Jobke <[email protected]>
14
 * @author Philipp Kapfer <[email protected]>
15
 * @author Robin Appelman <[email protected]>
16
 * @author Robin McCorkell <[email protected]>
17
 * @author Thomas Müller <[email protected]>
18
 * @author Vincent Petry <[email protected]>
19
 *
20
 * @license AGPL-3.0
21
 *
22
 * This code is free software: you can redistribute it and/or modify
23
 * it under the terms of the GNU Affero General Public License, version 3,
24
 * as published by the Free Software Foundation.
25
 *
26
 * This program is distributed in the hope that it will be useful,
27
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29
 * GNU Affero General Public License for more details.
30
 *
31
 * You should have received a copy of the GNU Affero General Public License, version 3,
32
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
33
 *
34
 */
35
36
namespace OCA\Files_External\Lib\Storage;
37
38
use Aws\Result;
39
use Aws\S3\S3Client;
40
use Aws\S3\Exception\S3Exception;
41
use Icewind\Streams\CallbackWrapper;
42
use Icewind\Streams\IteratorDirectory;
43
use OC\Cache\CappedMemoryCache;
44
use OC\Files\ObjectStore\S3ConnectionTrait;
45
use OC\Files\ObjectStore\S3ObjectTrait;
46
use OCP\Constants;
47
48
class AmazonS3 extends \OC\Files\Storage\Common {
49
	use S3ConnectionTrait;
50
	use S3ObjectTrait;
51
52
	public function needsPartFile() {
53
		return false;
54
	}
55
56
	/**
57
	 * @var int in seconds
58
	 */
59
	private $rescanDelay = 10;
60
61
	/** @var CappedMemoryCache|Result[] */
62
	private $objectCache;
63
64
	/** @var CappedMemoryCache|array */
65
	private $filesCache;
66
67
	public function __construct($parameters) {
68
		parent::__construct($parameters);
69
		$this->parseParams($parameters);
70
		$this->objectCache = new CappedMemoryCache();
71
		$this->filesCache = new CappedMemoryCache();
72
	}
73
74
	/**
75
	 * @param string $path
76
	 * @return string correctly encoded path
77
	 */
78
	private function normalizePath($path) {
79
		$path = trim($path, '/');
80
81
		if (!$path) {
82
			$path = '.';
83
		}
84
85
		return $path;
86
	}
87
88
	private function isRoot($path) {
89
		return $path === '.';
90
	}
91
92
	private function cleanKey($path) {
93
		if ($this->isRoot($path)) {
94
			return '/';
95
		}
96
		return $path;
97
	}
98
99
	private function clearCache() {
100
		$this->objectCache = new CappedMemoryCache();
101
		$this->filesCache = new CappedMemoryCache();
102
	}
103
104
	private function invalidateCache($key) {
105
		unset($this->objectCache[$key]);
106
		$keys = array_keys($this->objectCache->getData());
107
		$keyLength = strlen($key);
108
		foreach ($keys as $existingKey) {
109
			if (substr($existingKey, 0, $keyLength) === $key) {
110
				unset($this->objectCache[$existingKey]);
111
			}
112
		}
113
		unset($this->filesCache[$key]);
114
	}
115
116
	/**
117
	 * @param $key
118
	 * @return Result|boolean
119
	 */
120
	private function headObject($key) {
121
		if (!isset($this->objectCache[$key])) {
122
			try {
123
				$this->objectCache[$key] = $this->getConnection()->headObject(array(
124
					'Bucket' => $this->bucket,
125
					'Key' => $key
126
				));
127
			} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
128
				if ($e->getStatusCode() >= 500) {
129
					throw $e;
130
				}
131
				$this->objectCache[$key] = false;
132
			}
133
		}
134
135
		return $this->objectCache[$key];
136
	}
137
138
	/**
139
	 * Updates old storage ids (v0.2.1 and older) that are based on key and secret to new ones based on the bucket name.
140
	 * TODO Do this in an update.php. requires iterating over all users and loading the mount.json from their home
141
	 *
142
	 * @param array $params
143
	 */
144
	public function updateLegacyId(array $params) {
145
		$oldId = 'amazon::' . $params['key'] . md5($params['secret']);
146
147
		// find by old id or bucket
148
		$stmt = \OC::$server->getDatabaseConnection()->prepare(
149
			'SELECT `numeric_id`, `id` FROM `*PREFIX*storages` WHERE `id` IN (?, ?)'
150
		);
151
		$stmt->execute(array($oldId, $this->id));
152
		while ($row = $stmt->fetch()) {
153
			$storages[$row['id']] = $row['numeric_id'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$storages was never initialized. Although not strictly required by PHP, it is generally a good practice to add $storages = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
154
		}
155
156
		if (isset($storages[$this->id]) && isset($storages[$oldId])) {
157
			// if both ids exist, delete the old storage and corresponding filecache entries
158
			\OC\Files\Cache\Storage::remove($oldId);
159
		} else if (isset($storages[$oldId])) {
160
			// if only the old id exists do an update
161
			$stmt = \OC::$server->getDatabaseConnection()->prepare(
162
				'UPDATE `*PREFIX*storages` SET `id` = ? WHERE `id` = ?'
163
			);
164
			$stmt->execute(array($this->id, $oldId));
165
		}
166
		// only the bucket based id may exist, do nothing
167
	}
168
169
	/**
170
	 * Remove a file or folder
171
	 *
172
	 * @param string $path
173
	 * @return bool
174
	 */
175
	protected function remove($path) {
176
		// remember fileType to reduce http calls
177
		$fileType = $this->filetype($path);
178
		if ($fileType === 'dir') {
179
			return $this->rmdir($path);
180
		} else if ($fileType === 'file') {
181
			return $this->unlink($path);
182
		} else {
183
			return false;
184
		}
185
	}
186
187
	public function mkdir($path) {
188
		$path = $this->normalizePath($path);
189
190
		if ($this->is_dir($path)) {
191
			return false;
192
		}
193
194
		try {
195
			$this->getConnection()->putObject(array(
196
				'Bucket' => $this->bucket,
197
				'Key' => $path . '/',
198
				'Body' => '',
199
				'ContentType' => 'httpd/unix-directory'
200
			));
201
			$this->testTimeout();
202
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
203
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
204
			return false;
205
		}
206
207
		$this->invalidateCache($path);
208
209
		return true;
210
	}
211
212
	public function file_exists($path) {
213
		return $this->filetype($path) !== false;
214
	}
215
216
217
	public function rmdir($path) {
218
		$path = $this->normalizePath($path);
219
220
		if ($this->isRoot($path)) {
221
			return $this->clearBucket();
222
		}
223
224
		if (!$this->file_exists($path)) {
225
			return false;
226
		}
227
228
		$this->invalidateCache($path);
229
		return $this->batchDelete($path);
230
	}
231
232
	protected function clearBucket() {
233
		$this->clearCache();
234
		try {
235
			$this->getConnection()->clearBucket($this->bucket);
236
			return true;
237
			// clearBucket() is not working with Ceph, so if it fails we try the slower approach
238
		} catch (\Exception $e) {
239
			return $this->batchDelete();
240
		}
241
	}
242
243
	private function batchDelete($path = null) {
244
		$params = array(
245
			'Bucket' => $this->bucket
246
		);
247
		if ($path !== null) {
248
			$params['Prefix'] = $path . '/';
249
		}
250
		try {
251
			$connection = $this->getConnection();
252
			// Since there are no real directories on S3, we need
253
			// to delete all objects prefixed with the path.
254
			do {
255
				// instead of the iterator, manually loop over the list ...
256
				$objects = $connection->listObjects($params);
257
				// ... so we can delete the files in batches
258
				if (isset($objects['Contents'])) {
259
					$connection->deleteObjects([
260
						'Bucket' => $this->bucket,
261
						'Delete' => [
262
							'Objects' => $objects['Contents']
263
						]
264
					]);
265
					$this->testTimeout();
266
				}
267
				// we reached the end when the list is no longer truncated
268
			} while ($objects['IsTruncated']);
269
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
270
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
271
			return false;
272
		}
273
		return true;
274
	}
275
276
	public function opendir($path) {
277
		$path = $this->normalizePath($path);
278
279
		if ($this->isRoot($path)) {
280
			$path = '';
281
		} else {
282
			$path .= '/';
283
		}
284
285
		try {
286
			$files = array();
287
			$results = $this->getConnection()->getPaginator('ListObjects', [
288
				'Bucket' => $this->bucket,
289
				'Delimiter' => '/',
290
				'Prefix' => $path,
291
			]);
292
293
			foreach ($results as $result) {
294
				// sub folders
295
				if (is_array($result['CommonPrefixes'])) {
296
					foreach ($result['CommonPrefixes'] as $prefix) {
297
						$files[] = substr(trim($prefix['Prefix'], '/'), strlen($path));
298
					}
299
				}
300
				if (is_array($result['Contents'])) {
301
					foreach ($result['Contents'] as $object) {
302
						if (isset($object['Key']) && $object['Key'] === $path) {
303
							// it's the directory itself, skip
304
							continue;
305
						}
306
						$file = basename(
307
							isset($object['Key']) ? $object['Key'] : $object['Prefix']
308
						);
309
						$files[] = $file;
310
311
						// store this information for later usage
312
						$this->filesCache[$file] = [
313
							'ContentLength' => $object['Size'],
314
							'LastModified' => (string)$object['LastModified'],
315
						];
316
					}
317
				}
318
			}
319
320
			return IteratorDirectory::wrap($files);
321
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
322
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
323
			return false;
324
		}
325
	}
326
327
	public function stat($path) {
328
		$path = $this->normalizePath($path);
329
330
		try {
331
			$stat = [];
332
			if ($this->is_dir($path)) {
333
				//folders don't really exist
334
				$stat['size'] = -1; //unknown
335
				$stat['mtime'] = time() - $this->rescanDelay * 1000;
336
			} else {
337
				$stat['size'] = $this->getContentLength($path);
338
				$stat['mtime'] = strtotime($this->getLastModified($path));
339
			}
340
			$stat['atime'] = time();
341
342
			return $stat;
343
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
344
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
345
			return false;
346
		}
347
	}
348
349
	/**
350
	 * Return content length for object
351
	 *
352
	 * When the information is already present (e.g. opendir has been called before)
353
	 * this value is return. Otherwise a headObject is emitted.
354
	 *
355
	 * @param $path
356
	 * @return int|mixed
357
	 */
358 View Code Duplication
	private function getContentLength($path) {
359
		if (isset($this->filesCache[$path])) {
360
			return $this->filesCache[$path]['ContentLength'];
361
		}
362
363
		$result = $this->headObject($path);
364
		if (isset($result['ContentLength'])) {
365
			return $result['ContentLength'];
366
		}
367
368
		return 0;
369
	}
370
371
	/**
372
	 * Return last modified for object
373
	 *
374
	 * When the information is already present (e.g. opendir has been called before)
375
	 * this value is return. Otherwise a headObject is emitted.
376
	 *
377
	 * @param $path
378
	 * @return mixed|string
379
	 */
380 View Code Duplication
	private function getLastModified($path) {
381
		if (isset($this->filesCache[$path])) {
382
			return $this->filesCache[$path]['LastModified'];
383
		}
384
385
		$result = $this->headObject($path);
386
		if (isset($result['LastModified'])) {
387
			return $result['LastModified'];
388
		}
389
390
		return 'now';
391
	}
392
393
	public function is_dir($path) {
394
		$path = $this->normalizePath($path);
395
		try {
396
			return $this->isRoot($path) || $this->headObject($path . '/');
397
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
398
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
399
			return false;
400
		}
401
	}
402
403
	public function filetype($path) {
404
		$path = $this->normalizePath($path);
405
406
		if ($this->isRoot($path)) {
407
			return 'dir';
408
		}
409
410
		try {
411
			if ($this->headObject($path)) {
412
				return 'file';
413
			}
414
			if ($this->headObject($path . '/')) {
415
				return 'dir';
416
			}
417
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
418
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
419
			return false;
420
		}
421
422
		return false;
423
	}
424
425
	public function getPermissions($path) {
426
		$type = $this->filetype($path);
427
		if (!$type) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false 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...
428
			return 0;
429
		}
430
		return $type === 'dir' ? Constants::PERMISSION_ALL : Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE;
431
	}
432
433
	public function unlink($path) {
434
		$path = $this->normalizePath($path);
435
436
		if ($this->is_dir($path)) {
437
			return $this->rmdir($path);
438
		}
439
440
		try {
441
			$this->deleteObject($path);
442
			$this->invalidateCache($path);
443
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
444
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
445
			return false;
446
		}
447
448
		return true;
449
	}
450
451
	public function fopen($path, $mode) {
452
		$path = $this->normalizePath($path);
453
454
		switch ($mode) {
455
			case 'r':
456 View Code Duplication
			case 'rb':
457
				try {
458
					return $this->readObject($path);
459
				} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
460
					\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
461
					return false;
462
				}
463
			case 'w':
464 View Code Duplication
			case 'wb':
465
				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile();
466
467
				$handle = fopen($tmpFile, 'w');
468
				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
469
					$this->writeBack($tmpFile, $path);
470
				});
471
			case 'a':
472
			case 'ab':
473
			case 'r+':
474
			case 'w+':
475
			case 'wb+':
476
			case 'a+':
477
			case 'x':
478
			case 'x+':
479
			case 'c':
480
			case 'c+':
481
				if (strrpos($path, '.') !== false) {
482
					$ext = substr($path, strrpos($path, '.'));
483
				} else {
484
					$ext = '';
485
				}
486
				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
487
				if ($this->file_exists($path)) {
488
					$source = $this->readObject($path);
489
					file_put_contents($tmpFile, $source);
490
				}
491
492
				$handle = fopen($tmpFile, $mode);
493
				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
494
					$this->writeBack($tmpFile, $path);
495
				});
496
		}
497
		return false;
498
	}
499
500
	public function touch($path, $mtime = null) {
501
		$path = $this->normalizePath($path);
502
503
		$metadata = array();
0 ignored issues
show
Unused Code introduced by
$metadata 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...
504
		if (is_null($mtime)) {
505
			$mtime = time();
506
		}
507
		$metadata = [
508
			'lastmodified' => gmdate(\DateTime::RFC1123, $mtime)
509
		];
510
511
		$fileType = $this->filetype($path);
512
		try {
513
			if ($fileType !== false) {
514
				if ($fileType === 'dir' && !$this->isRoot($path)) {
515
					$path .= '/';
516
				}
517
				$this->getConnection()->copyObject([
518
					'Bucket' => $this->bucket,
519
					'Key' => $this->cleanKey($path),
520
					'Metadata' => $metadata,
521
					'CopySource' => $this->bucket . '/' . $path,
522
					'MetadataDirective' => 'REPLACE',
523
				]);
524
				$this->testTimeout();
525
			} else {
526
				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
527
				$this->getConnection()->putObject([
528
					'Bucket' => $this->bucket,
529
					'Key' => $this->cleanKey($path),
530
					'Metadata' => $metadata,
531
					'Body' => '',
532
					'ContentType' => $mimeType,
533
					'MetadataDirective' => 'REPLACE',
534
				]);
535
				$this->testTimeout();
536
			}
537
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
538
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
539
			return false;
540
		}
541
542
		$this->invalidateCache($path);
543
		return true;
544
	}
545
546
	public function copy($path1, $path2) {
547
		$path1 = $this->normalizePath($path1);
548
		$path2 = $this->normalizePath($path2);
549
550
		if ($this->is_file($path1)) {
551
			try {
552
				$this->getConnection()->copyObject(array(
553
					'Bucket' => $this->bucket,
554
					'Key' => $this->cleanKey($path2),
555
					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1)
556
				));
557
				$this->testTimeout();
558
			} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
559
				\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
560
				return false;
561
			}
562
		} else {
563
			$this->remove($path2);
564
565
			try {
566
				$this->getConnection()->copyObject(array(
567
					'Bucket' => $this->bucket,
568
					'Key' => $path2 . '/',
569
					'CopySource' => S3Client::encodeKey($this->bucket . '/' . $path1 . '/')
570
				));
571
				$this->testTimeout();
572
			} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
573
				\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
574
				return false;
575
			}
576
577
			$dh = $this->opendir($path1);
578
			if (is_resource($dh)) {
579
				while (($file = readdir($dh)) !== false) {
580
					if (\OC\Files\Filesystem::isIgnoredDir($file)) {
581
						continue;
582
					}
583
584
					$source = $path1 . '/' . $file;
585
					$target = $path2 . '/' . $file;
586
					$this->copy($source, $target);
587
				}
588
			}
589
		}
590
591
		$this->invalidateCache($path2);
592
593
		return true;
594
	}
595
596
	public function rename($path1, $path2) {
597
		$path1 = $this->normalizePath($path1);
598
		$path2 = $this->normalizePath($path2);
599
600
		if ($this->is_file($path1)) {
601
602
			if ($this->copy($path1, $path2) === false) {
603
				return false;
604
			}
605
606
			if ($this->unlink($path1) === false) {
607
				$this->unlink($path2);
608
				return false;
609
			}
610
		} else {
611
612
			if ($this->copy($path1, $path2) === false) {
613
				return false;
614
			}
615
616
			if ($this->rmdir($path1) === false) {
617
				$this->rmdir($path2);
618
				return false;
619
			}
620
		}
621
622
		return true;
623
	}
624
625
	public function test() {
626
		$this->getConnection()->headBucket([
627
			'Bucket' => $this->bucket
628
		]);
629
		return true;
630
	}
631
632
	public function getId() {
633
		return $this->id;
634
	}
635
636
	public function writeBack($tmpFile, $path) {
637
		try {
638
			$source = fopen($tmpFile, 'r');
639
			$this->writeObject($path, $source);
640
			$this->invalidateCache($path);
641
			fclose($source);
642
643
			unlink($tmpFile);
644
			return true;
645
		} catch (S3Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\S3\Exception\S3Exception 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...
646
			\OC::$server->getLogger()->logException($e, ['app' => 'files_external']);
647
			return false;
648
		}
649
	}
650
651
	/**
652
	 * check if curl is installed
653
	 */
654
	public static function checkDependencies() {
655
		return true;
656
	}
657
658
}
659