Merge "Move FileBackendStore and FileOp classes to /libs"

This commit is contained in:
jenkins-bot 2016-09-23 22:52:46 +00:00 committed by Gerrit Code Review
commit c9cf1b2763
11 changed files with 558 additions and 399 deletions

View file

@ -286,13 +286,13 @@ $wgAutoloadLocalClasses = [
'Cookie' => __DIR__ . '/includes/libs/Cookie.php',
'CookieJar' => __DIR__ . '/includes/libs/CookieJar.php',
'CopyFileBackend' => __DIR__ . '/maintenance/copyFileBackend.php',
'CopyFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'CopyFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/CopyFileOp.php',
'CopyJobQueue' => __DIR__ . '/maintenance/copyJobQueue.php',
'CoreParserFunctions' => __DIR__ . '/includes/parser/CoreParserFunctions.php',
'CoreTagHooks' => __DIR__ . '/includes/parser/CoreTagHooks.php',
'CoreVersionChecker' => __DIR__ . '/includes/registration/CoreVersionChecker.php',
'CreateAndPromote' => __DIR__ . '/maintenance/createAndPromote.php',
'CreateFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'CreateFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/CreateFileOp.php',
'CreditsAction' => __DIR__ . '/includes/actions/CreditsAction.php',
'CssContent' => __DIR__ . '/includes/content/CssContent.php',
'CssContentHandler' => __DIR__ . '/includes/content/CssContentHandler.php',
@ -343,7 +343,7 @@ $wgAutoloadLocalClasses = [
'DeleteBatch' => __DIR__ . '/maintenance/deleteBatch.php',
'DeleteDefaultMessages' => __DIR__ . '/maintenance/deleteDefaultMessages.php',
'DeleteEqualMessages' => __DIR__ . '/maintenance/deleteEqualMessages.php',
'DeleteFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'DeleteFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/DeleteFileOp.php',
'DeleteLinksJob' => __DIR__ . '/includes/jobqueue/jobs/DeleteLinksJob.php',
'DeleteLogFormatter' => __DIR__ . '/includes/logging/DeleteLogFormatter.php',
'DeleteOldRevisions' => __DIR__ . '/maintenance/deleteOldRevisions.php',
@ -358,7 +358,7 @@ $wgAutoloadLocalClasses = [
'DerivativeContext' => __DIR__ . '/includes/context/DerivativeContext.php',
'DerivativeRequest' => __DIR__ . '/includes/DerivativeRequest.php',
'DerivativeResourceLoaderContext' => __DIR__ . '/includes/resourceloader/DerivativeResourceLoaderContext.php',
'DescribeFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'DescribeFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/DescribeFileOp.php',
'Diff' => __DIR__ . '/includes/diff/DairikiDiff.php',
'DiffEngine' => __DIR__ . '/includes/diff/DiffEngine.php',
'DiffFormatter' => __DIR__ . '/includes/diff/DiffFormatter.php',
@ -459,11 +459,11 @@ $wgAutoloadLocalClasses = [
'FileBackendError' => __DIR__ . '/includes/libs/filebackend/FileBackendError.php',
'FileBackendGroup' => __DIR__ . '/includes/filebackend/FileBackendGroup.php',
'FileBackendMultiWrite' => __DIR__ . '/includes/libs/filebackend/FileBackendMultiWrite.php',
'FileBackendStore' => __DIR__ . '/includes/filebackend/FileBackendStore.php',
'FileBackendStoreOpHandle' => __DIR__ . '/includes/filebackend/FileBackendStore.php',
'FileBackendStoreShardDirIterator' => __DIR__ . '/includes/filebackend/FileBackendStore.php',
'FileBackendStoreShardFileIterator' => __DIR__ . '/includes/filebackend/FileBackendStore.php',
'FileBackendStoreShardListIterator' => __DIR__ . '/includes/filebackend/FileBackendStore.php',
'FileBackendStore' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
'FileBackendStoreOpHandle' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
'FileBackendStoreShardDirIterator' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
'FileBackendStoreShardFileIterator' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
'FileBackendStoreShardListIterator' => __DIR__ . '/includes/libs/filebackend/FileBackendStore.php',
'FileBasedSiteLookup' => __DIR__ . '/includes/site/FileBasedSiteLookup.php',
'FileCacheBase' => __DIR__ . '/includes/cache/FileCacheBase.php',
'FileContentsHasher' => __DIR__ . '/includes/utils/FileContentsHasher.php',
@ -471,8 +471,8 @@ $wgAutoloadLocalClasses = [
'FileDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
'FileDuplicateSearchPage' => __DIR__ . '/includes/specials/SpecialFileDuplicateSearch.php',
'FileJournal' => __DIR__ . '/includes/libs/filebackend/filejournal/FileJournal.php',
'FileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'FileOpBatch' => __DIR__ . '/includes/filebackend/FileOpBatch.php',
'FileOp' => __DIR__ . '/includes/libs/filebackend/fileop/FileOp.php',
'FileOpBatch' => __DIR__ . '/includes/libs/filebackend/FileOpBatch.php',
'FileRepo' => __DIR__ . '/includes/filerepo/FileRepo.php',
'FileRepoStatus' => __DIR__ . '/includes/filerepo/FileRepoStatus.php',
'FindDeprecated' => __DIR__ . '/maintenance/findDeprecated.php',
@ -947,7 +947,7 @@ $wgAutoloadLocalClasses = [
'MostlinkedTemplatesPage' => __DIR__ . '/includes/specials/SpecialMostlinkedtemplates.php',
'MostrevisionsPage' => __DIR__ . '/includes/specials/SpecialMostrevisions.php',
'MoveBatch' => __DIR__ . '/maintenance/moveBatch.php',
'MoveFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'MoveFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/MoveFileOp.php',
'MoveLogFormatter' => __DIR__ . '/includes/logging/MoveLogFormatter.php',
'MovePage' => __DIR__ . '/includes/MovePage.php',
'MovePageForm' => __DIR__ . '/includes/specials/SpecialMovepage.php',
@ -980,7 +980,7 @@ $wgAutoloadLocalClasses = [
'NukeNS' => __DIR__ . '/maintenance/nukeNS.php',
'NukePage' => __DIR__ . '/maintenance/nukePage.php',
'NullFileJournal' => __DIR__ . '/includes/libs/filebackend/filejournal/NullFileJournal.php',
'NullFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'NullFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/NullFileOp.php',
'NullIndexField' => __DIR__ . '/includes/search/NullIndexField.php',
'NullJob' => __DIR__ . '/includes/jobqueue/jobs/NullJob.php',
'NullLockManager' => __DIR__ . '/includes/libs/lockmanager/NullLockManager.php',
@ -1386,7 +1386,7 @@ $wgAutoloadLocalClasses = [
'Status' => __DIR__ . '/includes/Status.php',
'StatusValue' => __DIR__ . '/includes/libs/StatusValue.php',
'StorageTypeStats' => __DIR__ . '/maintenance/storage/storageTypeStats.php',
'StoreFileOp' => __DIR__ . '/includes/filebackend/FileOp.php',
'StoreFileOp' => __DIR__ . '/includes/libs/filebackend/fileop/StoreFileOp.php',
'StreamFile' => __DIR__ . '/includes/StreamFile.php',
'StringPrefixSearch' => __DIR__ . '/includes/PrefixSearch.php',
'StringUtils' => __DIR__ . '/includes/libs/StringUtils.php',

View file

@ -0,0 +1,97 @@
<?php
/**
* Helper class for representing operations with transaction support.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup FileBackend
* @author Aaron Schulz
*/
/**
* Copy a file from one storage path to another in the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class CopyFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'src', 'dst' ],
[ 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ],
[ 'src', 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
$this->doOperation = false; // no-op
// Update file existence predicates (cache 404s)
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // nothing to do
} else {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
}
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-copy', $this->params['src'], $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( $this->overwriteSameCase ) {
$status = StatusValue::newGood(); // nothing to do
} elseif ( $this->params['src'] === $this->params['dst'] ) {
// Just update the destination file headers
$headers = $this->getParam( 'headers' ) ?: [];
$status = $this->backend->describeInternal( $this->setFlags( [
'src' => $this->params['dst'], 'headers' => $headers
] ) );
} else {
// Copy the file to the destination
$status = $this->backend->copyInternal( $this->setFlags( $this->params ) );
}
return $status;
}
public function storagePathsRead() {
return [ $this->params['src'] ];
}
public function storagePathsChanged() {
return [ $this->params['dst'] ];
}
}

View file

@ -0,0 +1,80 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup FileBackend
* @author Aaron Schulz
*/
/**
* Create a file in the backend with the given content.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class CreateFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'content', 'dst' ],
[ 'overwrite', 'overwriteSame', 'headers' ],
[ 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source data is too big
if ( strlen( $this->getParam( 'content' ) ) > $this->backend->maxFileSizeInternal() ) {
$status->fatal( 'backend-fail-maxsize',
$this->params['dst'], $this->backend->maxFileSizeInternal() );
$status->fatal( 'backend-fail-create', $this->params['dst'] );
return $status;
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-create', $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( !$this->overwriteSameCase ) {
// Create the file at the destination
return $this->backend->createInternal( $this->setFlags( $this->params ) );
}
return StatusValue::newGood();
}
protected function getSourceSha1Base36() {
return Wikimedia\base_convert( sha1( $this->params['content'] ), 16, 36, 31 );
}
public function storagePathsChanged() {
return [ $this->params['dst'] ];
}
}

View file

@ -0,0 +1,72 @@
<?php
/**
* Helper class for representing operations with transaction support.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup FileBackend
* @author Aaron Schulz
*/
/**
* Delete a file at the given storage path from the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class DeleteFileOp extends FileOp {
protected function allowedParams() {
return [ [ 'src' ], [ 'ignoreMissingSource' ], [ 'src' ] ];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
$this->doOperation = false; // no-op
// Update file existence predicates (cache 404s)
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // nothing to do
} else {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
}
// Check if a file can be placed/changed at the source
} elseif ( !$this->backend->isPathUsableInternal( $this->params['src'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['src'] );
$status->fatal( 'backend-fail-delete', $this->params['src'] );
return $status;
}
// Update file existence predicates
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // safe to call attempt()
}
protected function doAttempt() {
// Delete the source file
return $this->backend->deleteInternal( $this->setFlags( $this->params ) );
}
public function storagePathsChanged() {
return [ $this->params['src'] ];
}
}

View file

@ -0,0 +1,65 @@
<?php
/**
* Helper class for representing operations with transaction support.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup FileBackend
* @author Aaron Schulz
*/
/**
* Change metadata for a file at the given storage path in the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class DescribeFileOp extends FileOp {
protected function allowedParams() {
return [ [ 'src' ], [ 'headers' ], [ 'src' ] ];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
// Check if a file can be placed/changed at the source
} elseif ( !$this->backend->isPathUsableInternal( $this->params['src'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['src'] );
$status->fatal( 'backend-fail-describe', $this->params['src'] );
return $status;
}
// Update file existence predicates
$predicates['exists'][$this->params['src']] =
$this->fileExists( $this->params['src'], $predicates );
$predicates['sha1'][$this->params['src']] =
$this->fileSha1( $this->params['src'], $predicates );
return $status; // safe to call attempt()
}
protected function doAttempt() {
// Update the source file's metadata
return $this->backend->describeInternal( $this->setFlags( $this->params ) );
}
public function storagePathsChanged() {
return [ $this->params['src'] ];
}
}

View file

@ -468,388 +468,3 @@ abstract class FileOp {
}
}
}
/**
* Create a file in the backend with the given content.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class CreateFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'content', 'dst' ],
[ 'overwrite', 'overwriteSame', 'headers' ],
[ 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source data is too big
if ( strlen( $this->getParam( 'content' ) ) > $this->backend->maxFileSizeInternal() ) {
$status->fatal( 'backend-fail-maxsize',
$this->params['dst'], $this->backend->maxFileSizeInternal() );
$status->fatal( 'backend-fail-create', $this->params['dst'] );
return $status;
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-create', $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( !$this->overwriteSameCase ) {
// Create the file at the destination
return $this->backend->createInternal( $this->setFlags( $this->params ) );
}
return StatusValue::newGood();
}
protected function getSourceSha1Base36() {
return Wikimedia\base_convert( sha1( $this->params['content'] ), 16, 36, 31 );
}
public function storagePathsChanged() {
return [ $this->params['dst'] ];
}
}
/**
* Store a file into the backend from a file on the file system.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class StoreFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'src', 'dst' ],
[ 'overwrite', 'overwriteSame', 'headers' ],
[ 'src', 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists on the file system
if ( !is_file( $this->params['src'] ) ) {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
// Check if the source file is too big
} elseif ( filesize( $this->params['src'] ) > $this->backend->maxFileSizeInternal() ) {
$status->fatal( 'backend-fail-maxsize',
$this->params['dst'], $this->backend->maxFileSizeInternal() );
$status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
return $status;
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( !$this->overwriteSameCase ) {
// Store the file at the destination
return $this->backend->storeInternal( $this->setFlags( $this->params ) );
}
return StatusValue::newGood();
}
protected function getSourceSha1Base36() {
MediaWiki\suppressWarnings();
$hash = sha1_file( $this->params['src'] );
MediaWiki\restoreWarnings();
if ( $hash !== false ) {
$hash = Wikimedia\base_convert( $hash, 16, 36, 31 );
}
return $hash;
}
public function storagePathsChanged() {
return [ $this->params['dst'] ];
}
}
/**
* Copy a file from one storage path to another in the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class CopyFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'src', 'dst' ],
[ 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ],
[ 'src', 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
$this->doOperation = false; // no-op
// Update file existence predicates (cache 404s)
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // nothing to do
} else {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
}
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-copy', $this->params['src'], $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( $this->overwriteSameCase ) {
$status = StatusValue::newGood(); // nothing to do
} elseif ( $this->params['src'] === $this->params['dst'] ) {
// Just update the destination file headers
$headers = $this->getParam( 'headers' ) ?: [];
$status = $this->backend->describeInternal( $this->setFlags( [
'src' => $this->params['dst'], 'headers' => $headers
] ) );
} else {
// Copy the file to the destination
$status = $this->backend->copyInternal( $this->setFlags( $this->params ) );
}
return $status;
}
public function storagePathsRead() {
return [ $this->params['src'] ];
}
public function storagePathsChanged() {
return [ $this->params['dst'] ];
}
}
/**
* Move a file from one storage path to another in the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class MoveFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'src', 'dst' ],
[ 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ],
[ 'src', 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
$this->doOperation = false; // no-op
// Update file existence predicates (cache 404s)
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // nothing to do
} else {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
}
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-move', $this->params['src'], $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( $this->overwriteSameCase ) {
if ( $this->params['src'] === $this->params['dst'] ) {
// Do nothing to the destination (which is also the source)
$status = StatusValue::newGood();
} else {
// Just delete the source as the destination file needs no changes
$status = $this->backend->deleteInternal( $this->setFlags(
[ 'src' => $this->params['src'] ]
) );
}
} elseif ( $this->params['src'] === $this->params['dst'] ) {
// Just update the destination file headers
$headers = $this->getParam( 'headers' ) ?: [];
$status = $this->backend->describeInternal( $this->setFlags(
[ 'src' => $this->params['dst'], 'headers' => $headers ]
) );
} else {
// Move the file to the destination
$status = $this->backend->moveInternal( $this->setFlags( $this->params ) );
}
return $status;
}
public function storagePathsRead() {
return [ $this->params['src'] ];
}
public function storagePathsChanged() {
return [ $this->params['src'], $this->params['dst'] ];
}
}
/**
* Delete a file at the given storage path from the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class DeleteFileOp extends FileOp {
protected function allowedParams() {
return [ [ 'src' ], [ 'ignoreMissingSource' ], [ 'src' ] ];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
$this->doOperation = false; // no-op
// Update file existence predicates (cache 404s)
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // nothing to do
} else {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
}
// Check if a file can be placed/changed at the source
} elseif ( !$this->backend->isPathUsableInternal( $this->params['src'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['src'] );
$status->fatal( 'backend-fail-delete', $this->params['src'] );
return $status;
}
// Update file existence predicates
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // safe to call attempt()
}
protected function doAttempt() {
// Delete the source file
return $this->backend->deleteInternal( $this->setFlags( $this->params ) );
}
public function storagePathsChanged() {
return [ $this->params['src'] ];
}
}
/**
* Change metadata for a file at the given storage path in the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class DescribeFileOp extends FileOp {
protected function allowedParams() {
return [ [ 'src' ], [ 'headers' ], [ 'src' ] ];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
// Check if a file can be placed/changed at the source
} elseif ( !$this->backend->isPathUsableInternal( $this->params['src'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['src'] );
$status->fatal( 'backend-fail-describe', $this->params['src'] );
return $status;
}
// Update file existence predicates
$predicates['exists'][$this->params['src']] =
$this->fileExists( $this->params['src'], $predicates );
$predicates['sha1'][$this->params['src']] =
$this->fileSha1( $this->params['src'], $predicates );
return $status; // safe to call attempt()
}
protected function doAttempt() {
// Update the source file's metadata
return $this->backend->describeInternal( $this->setFlags( $this->params ) );
}
public function storagePathsChanged() {
return [ $this->params['src'] ];
}
}
/**
* Placeholder operation that has no params and does nothing
*/
class NullFileOp extends FileOp {
}

View file

@ -0,0 +1,107 @@
<?php
/**
* Helper class for representing operations with transaction support.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup FileBackend
* @author Aaron Schulz
*/
/**
* Move a file from one storage path to another in the backend.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class MoveFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'src', 'dst' ],
[ 'overwrite', 'overwriteSame', 'ignoreMissingSource', 'headers' ],
[ 'src', 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists
if ( !$this->fileExists( $this->params['src'], $predicates ) ) {
if ( $this->getParam( 'ignoreMissingSource' ) ) {
$this->doOperation = false; // no-op
// Update file existence predicates (cache 404s)
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
return $status; // nothing to do
} else {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
}
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-move', $this->params['src'], $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['src']] = false;
$predicates['sha1'][$this->params['src']] = false;
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( $this->overwriteSameCase ) {
if ( $this->params['src'] === $this->params['dst'] ) {
// Do nothing to the destination (which is also the source)
$status = StatusValue::newGood();
} else {
// Just delete the source as the destination file needs no changes
$status = $this->backend->deleteInternal( $this->setFlags(
[ 'src' => $this->params['src'] ]
) );
}
} elseif ( $this->params['src'] === $this->params['dst'] ) {
// Just update the destination file headers
$headers = $this->getParam( 'headers' ) ?: [];
$status = $this->backend->describeInternal( $this->setFlags(
[ 'src' => $this->params['dst'], 'headers' => $headers ]
) );
} else {
// Move the file to the destination
$status = $this->backend->moveInternal( $this->setFlags( $this->params ) );
}
return $status;
}
public function storagePathsRead() {
return [ $this->params['src'] ];
}
public function storagePathsChanged() {
return [ $this->params['src'], $this->params['dst'] ];
}
}

View file

@ -0,0 +1,29 @@
<?php
/**
* Helper class for representing operations with transaction support.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup FileBackend
* @author Aaron Schulz
*/
/**
* Placeholder operation that has no params and does nothing
*/
class NullFileOp extends FileOp {
}

View file

@ -0,0 +1,94 @@
<?php
/**
* Helper class for representing operations with transaction support.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup FileBackend
* @author Aaron Schulz
*/
/**
* Store a file into the backend from a file on the file system.
* Parameters for this operation are outlined in FileBackend::doOperations().
*/
class StoreFileOp extends FileOp {
protected function allowedParams() {
return [
[ 'src', 'dst' ],
[ 'overwrite', 'overwriteSame', 'headers' ],
[ 'src', 'dst' ]
];
}
protected function doPrecheck( array &$predicates ) {
$status = StatusValue::newGood();
// Check if the source file exists on the file system
if ( !is_file( $this->params['src'] ) ) {
$status->fatal( 'backend-fail-notexists', $this->params['src'] );
return $status;
// Check if the source file is too big
} elseif ( filesize( $this->params['src'] ) > $this->backend->maxFileSizeInternal() ) {
$status->fatal( 'backend-fail-maxsize',
$this->params['dst'], $this->backend->maxFileSizeInternal() );
$status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
return $status;
// Check if a file can be placed/changed at the destination
} elseif ( !$this->backend->isPathUsableInternal( $this->params['dst'] ) ) {
$status->fatal( 'backend-fail-usable', $this->params['dst'] );
$status->fatal( 'backend-fail-store', $this->params['src'], $this->params['dst'] );
return $status;
}
// Check if destination file exists
$status->merge( $this->precheckDestExistence( $predicates ) );
$this->params['dstExists'] = $this->destExists; // see FileBackendStore::setFileCache()
if ( $status->isOK() ) {
// Update file existence predicates
$predicates['exists'][$this->params['dst']] = true;
$predicates['sha1'][$this->params['dst']] = $this->sourceSha1;
}
return $status; // safe to call attempt()
}
protected function doAttempt() {
if ( !$this->overwriteSameCase ) {
// Store the file at the destination
return $this->backend->storeInternal( $this->setFlags( $this->params ) );
}
return StatusValue::newGood();
}
protected function getSourceSha1Base36() {
MediaWiki\suppressWarnings();
$hash = sha1_file( $this->params['src'] );
MediaWiki\restoreWarnings();
if ( $hash !== false ) {
$hash = Wikimedia\base_convert( $hash, 16, 36, 31 );
}
return $hash;
}
public function storagePathsChanged() {
return [ $this->params['dst'] ];
}
}