Browse Source

Merge pull request #10104 from owncloud/s3-overwrite

Fix S3 copy and rename overwriting target directory
tags/v8.0.0alpha1
Lukas Reschke 9 years ago
parent
commit
001f223baa
2 changed files with 52 additions and 43 deletions
  1. 47
    20
      apps/files_external/lib/amazons3.php
  2. 5
    23
      apps/files_external/tests/amazons3.php

+ 47
- 20
apps/files_external/lib/amazons3.php View File

sleep($this->timeout); sleep($this->timeout);
} }
} }

private function cleanKey($path) { private function cleanKey($path) {
if ($path === '.') { if ($path === '.') {
return '/'; return '/';
$this->bucket = $params['bucket']; $this->bucket = $params['bucket'];
$scheme = ($params['use_ssl'] === 'false') ? 'http' : 'https'; $scheme = ($params['use_ssl'] === 'false') ? 'http' : 'https';
$this->test = isset($params['test']); $this->test = isset($params['test']);
$this->timeout = ( ! isset($params['timeout'])) ? 15 : $params['timeout'];
$params['region'] = ( ! isset($params['region']) || $params['region'] === '' ) ? 'eu-west-1' : $params['region'];
$params['hostname'] = ( !isset($params['hostname']) || $params['hostname'] === '' ) ? 's3.amazonaws.com' : $params['hostname'];
$this->timeout = (!isset($params['timeout'])) ? 15 : $params['timeout'];
$params['region'] = (!isset($params['region']) || $params['region'] === '') ? 'eu-west-1' : $params['region'];
$params['hostname'] = (!isset($params['hostname']) || $params['hostname'] === '') ? 's3.amazonaws.com' : $params['hostname'];
if (!isset($params['port']) || $params['port'] === '') { if (!isset($params['port']) || $params['port'] === '') {
$params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443; $params['port'] = ($params['use_ssl'] === 'false') ? 80 : 443;
} }
$base_url = $scheme.'://'.$params['hostname'].':'.$params['port'].'/';
$base_url = $scheme . '://' . $params['hostname'] . ':' . $params['port'] . '/';


$this->connection = S3Client::factory(array( $this->connection = S3Client::factory(array(
'key' => $params['key'], 'key' => $params['key'],
'waiter.interval' => 1, 'waiter.interval' => 1,
'waiter.max_attempts' => 15 'waiter.max_attempts' => 15
)); ));
$this->testTimeout();
$this->testTimeout();
} catch (S3Exception $e) { } catch (S3Exception $e) {
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
throw new \Exception("Creation of bucket failed."); throw new \Exception("Creation of bucket failed.");
if (!$this->file_exists('.')) { if (!$this->file_exists('.')) {
$result = $this->connection->putObject(array( $result = $this->connection->putObject(array(
'Bucket' => $this->bucket, 'Bucket' => $this->bucket,
'Key' => $this->cleanKey('.'),
'Body' => '',
'Key' => $this->cleanKey('.'),
'Body' => '',
'ContentType' => 'httpd/unix-directory', 'ContentType' => 'httpd/unix-directory',
'ContentLength' => 0 'ContentLength' => 0
)); ));
} }


try { try {
$result = $this->connection->putObject(array(
$this->connection->putObject(array(
'Bucket' => $this->bucket, 'Bucket' => $this->bucket,
'Key' => $path . '/',
'Body' => '',
'Key' => $path . '/',
'Body' => '',
'ContentType' => 'httpd/unix-directory', 'ContentType' => 'httpd/unix-directory',
'ContentLength' => 0 'ContentLength' => 0
)); ));
public function rmdir($path) { public function rmdir($path) {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);


if ($path === '.') {
return $this->clearBucket();
}

if (!$this->file_exists($path)) { if (!$this->file_exists($path)) {
return false; return false;
} }
)); ));


try { try {
$result = $this->connection->deleteObjects(array(
$this->connection->deleteObjects(array(
'Bucket' => $this->bucket, 'Bucket' => $this->bucket,
'Objects' => $objects['Contents'] 'Objects' => $objects['Contents']
)); ));
return true; return true;
} }


protected function clearBucket() {
try {
$this->connection->clearBucket($this->bucket);
// clearBucket() is not working with Ceph, so if it fails we try the slower approach
} catch (\Exception $e) {
try {
$iterator = $this->connection->getIterator('ListObjects', array(
'Bucket' => $this->bucket
));

foreach ($iterator as $object) {
$this->connection->deleteObject(array(
'Bucket' => $this->bucket,
'Key' => $object['Key']
));
}
} catch (S3Exception $e) {
return false;
}
}
}

public function opendir($path) { public function opendir($path) {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);


$stat['atime'] = time(); $stat['atime'] = time();


return $stat; return $stat;
} catch(S3Exception $e) {
} catch (S3Exception $e) {
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR); \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
return false; return false;
} }
public function unlink($path) { public function unlink($path) {
$path = $this->normalizePath($path); $path = $this->normalizePath($path);


if ( $this->is_dir($path) ) {
if ($this->is_dir($path)) {
return $this->rmdir($path); return $this->rmdir($path);
} }


return false; return false;
} }
} else { } else {
if ($this->file_exists($path2)) {
return false;
if ($this->is_dir($path2)) {
$this->rmdir($path2);
} else if ($this->file_exists($path2)) {
$this->unlink($path2);
} }


try { try {
} }


$dh = $this->opendir($path1); $dh = $this->opendir($path1);
if(is_resource($dh)) {
if (is_resource($dh)) {
while (($file = readdir($dh)) !== false) { while (($file = readdir($dh)) !== false) {
if ($file === '.' || $file === '..') { if ($file === '.' || $file === '..') {
continue; continue;
$path2 = $this->normalizePath($path2); $path2 = $this->normalizePath($path2);


if ($this->is_file($path1)) { if ($this->is_file($path1)) {

if ($this->copy($path1, $path2) === false) { if ($this->copy($path1, $path2) === false) {
return false; return false;
} }
return false; return false;
} }
} else { } else {
if ($this->file_exists($path2)) {
return false;
}


if ($this->copy($path1, $path2) === false) { if ($this->copy($path1, $path2) === false) {
return false; return false;
} }


try { try {
$result= $this->connection->putObject(array(
$result = $this->connection->putObject(array(
'Bucket' => $this->bucket, 'Bucket' => $this->bucket,
'Key' => $this->cleanKey(self::$tmpFiles[$tmpFile]), 'Key' => $this->cleanKey(self::$tmpFiles[$tmpFile]),
'SourceFile' => $tmpFile, 'SourceFile' => $tmpFile,

+ 5
- 23
apps/files_external/tests/amazons3.php View File



public function tearDown() { public function tearDown() {
if ($this->instance) { if ($this->instance) {
$connection = $this->instance->getConnection();

try {
// NOTE(berendt): clearBucket() is not working with Ceph
$iterator = $connection->getIterator('ListObjects', array(
'Bucket' => $this->config['amazons3']['bucket']
));

foreach ($iterator as $object) {
$connection->deleteObject(array(
'Bucket' => $this->config['amazons3']['bucket'],
'Key' => $object['Key']
));
}
} catch (S3Exception $e) {
}

$connection->deleteBucket(array(
'Bucket' => $this->config['amazons3']['bucket']
));

//wait some seconds for completing the replication
sleep(30);
$this->instance->rmdir('');
} }
} }

public function testStat() {
$this->markTestSkipped('S3 doesn\'t update the parents folder mtime');
}
} }

Loading…
Cancel
Save