From 6e5329cd8ef03e304270584509df4d88f1534667 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Sun, 18 Sep 2016 16:25:41 -0700 Subject: [PATCH] Move FileBackendStore and FileOp classes to /libs Change-Id: If490f64bec282e5dfcdaf7feb1cbf46d3dce1064 --- autoload.php | 28 +- .../filebackend/FileBackendStore.php | 0 .../{ => libs}/filebackend/FileOpBatch.php | 0 .../libs/filebackend/fileop/CopyFileOp.php | 97 +++++ .../libs/filebackend/fileop/CreateFileOp.php | 80 ++++ .../libs/filebackend/fileop/DeleteFileOp.php | 72 ++++ .../filebackend/fileop/DescribeFileOp.php | 65 +++ .../filebackend/fileop}/FileOp.php | 385 ------------------ .../libs/filebackend/fileop/MoveFileOp.php | 107 +++++ .../libs/filebackend/fileop/NullFileOp.php | 29 ++ .../libs/filebackend/fileop/StoreFileOp.php | 94 +++++ 11 files changed, 558 insertions(+), 399 deletions(-) rename includes/{ => libs}/filebackend/FileBackendStore.php (100%) rename includes/{ => libs}/filebackend/FileOpBatch.php (100%) create mode 100644 includes/libs/filebackend/fileop/CopyFileOp.php create mode 100644 includes/libs/filebackend/fileop/CreateFileOp.php create mode 100644 includes/libs/filebackend/fileop/DeleteFileOp.php create mode 100644 includes/libs/filebackend/fileop/DescribeFileOp.php rename includes/{filebackend => libs/filebackend/fileop}/FileOp.php (50%) create mode 100644 includes/libs/filebackend/fileop/MoveFileOp.php create mode 100644 includes/libs/filebackend/fileop/NullFileOp.php create mode 100644 includes/libs/filebackend/fileop/StoreFileOp.php diff --git a/autoload.php b/autoload.php index 9bd6c26bd0..0c59b4ae62 100644 --- a/autoload.php +++ b/autoload.php @@ -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', diff --git a/includes/filebackend/FileBackendStore.php b/includes/libs/filebackend/FileBackendStore.php similarity index 100% rename from includes/filebackend/FileBackendStore.php rename to includes/libs/filebackend/FileBackendStore.php diff --git a/includes/filebackend/FileOpBatch.php b/includes/libs/filebackend/FileOpBatch.php similarity index 100% rename from includes/filebackend/FileOpBatch.php rename to includes/libs/filebackend/FileOpBatch.php diff --git a/includes/libs/filebackend/fileop/CopyFileOp.php b/includes/libs/filebackend/fileop/CopyFileOp.php new file mode 100644 index 0000000000..e3b8c51719 --- /dev/null +++ b/includes/libs/filebackend/fileop/CopyFileOp.php @@ -0,0 +1,97 @@ +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'] ]; + } +} diff --git a/includes/libs/filebackend/fileop/CreateFileOp.php b/includes/libs/filebackend/fileop/CreateFileOp.php new file mode 100644 index 0000000000..120ca2b7de --- /dev/null +++ b/includes/libs/filebackend/fileop/CreateFileOp.php @@ -0,0 +1,80 @@ +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'] ]; + } +} diff --git a/includes/libs/filebackend/fileop/DeleteFileOp.php b/includes/libs/filebackend/fileop/DeleteFileOp.php new file mode 100644 index 0000000000..0ccb1e3d7f --- /dev/null +++ b/includes/libs/filebackend/fileop/DeleteFileOp.php @@ -0,0 +1,72 @@ +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'] ]; + } +} diff --git a/includes/libs/filebackend/fileop/DescribeFileOp.php b/includes/libs/filebackend/fileop/DescribeFileOp.php new file mode 100644 index 0000000000..9b53222433 --- /dev/null +++ b/includes/libs/filebackend/fileop/DescribeFileOp.php @@ -0,0 +1,65 @@ +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'] ]; + } +} diff --git a/includes/filebackend/FileOp.php b/includes/libs/filebackend/fileop/FileOp.php similarity index 50% rename from includes/filebackend/FileOp.php rename to includes/libs/filebackend/fileop/FileOp.php index 8207b124b2..fab5a3743c 100644 --- a/includes/filebackend/FileOp.php +++ b/includes/libs/filebackend/fileop/FileOp.php @@ -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 { -} diff --git a/includes/libs/filebackend/fileop/MoveFileOp.php b/includes/libs/filebackend/fileop/MoveFileOp.php new file mode 100644 index 0000000000..fee3f4a0f0 --- /dev/null +++ b/includes/libs/filebackend/fileop/MoveFileOp.php @@ -0,0 +1,107 @@ +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'] ]; + } +} diff --git a/includes/libs/filebackend/fileop/NullFileOp.php b/includes/libs/filebackend/fileop/NullFileOp.php new file mode 100644 index 0000000000..ed23e810d3 --- /dev/null +++ b/includes/libs/filebackend/fileop/NullFileOp.php @@ -0,0 +1,29 @@ +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'] ]; + } +} -- 2.20.1