https://www.mediawiki.org/wiki/Special:Code/MediaWiki/104359
Revision: 104359 Author: aaron Date: 2011-11-27 19:27:54 +0000 (Sun, 27 Nov 2011) Log Message: ----------- * Optimized getFileProps() in FSFileBackend and moved code to "default" implementation code in FileBackend * Marked public functions in FileRepo * Added FileBackend::getFileTimestamp() * Simplified TempFSFile code * Removed some LocalFile FS access * Various minor cleanups * Documentation tweaks Modified Paths: -------------- branches/FileBackend/phase3/includes/filerepo/FileRepo.php branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php branches/FileBackend/phase3/includes/filerepo/backend/FileBackendMultiWrite.php branches/FileBackend/phase3/includes/filerepo/file/FSFile.php branches/FileBackend/phase3/includes/filerepo/file/LocalFile.php branches/FileBackend/phase3/includes/filerepo/file/TempFSFile.php Modified: branches/FileBackend/phase3/includes/filerepo/FileRepo.php =================================================================== --- branches/FileBackend/phase3/includes/filerepo/FileRepo.php 2011-11-27 19:17:07 UTC (rev 104358) +++ branches/FileBackend/phase3/includes/filerepo/FileRepo.php 2011-11-27 19:27:54 UTC (rev 104359) @@ -215,7 +215,7 @@ * @param $url string * @return bool */ - static function isVirtualUrl( $url ) { + public static function isVirtualUrl( $url ) { return substr( $url, 0, 9 ) == 'mwrepo://'; } @@ -227,7 +227,7 @@ * @param $suffix string * @return string */ - function getVirtualUrl( $suffix = false ) { + public function getVirtualUrl( $suffix = false ) { $path = 'mwrepo://' . $this->name; if ( $suffix !== false ) { $path .= '/' . rawurlencode( $suffix ); @@ -241,7 +241,7 @@ * @param $zone String: one of: public, deleted, temp, thumb * @return String or false */ - function getZoneUrl( $zone ) { + public function getZoneUrl( $zone ) { switch ( $zone ) { case 'public': return $this->url; @@ -300,7 +300,7 @@ * @param $zone string * @return string|null */ - function getZonePath( $zone ) { + public function getZonePath( $zone ) { list( $container, $base ) = $this->getZoneLocation( $zone ); if ( $container === null || $base === null ) { return null; @@ -320,7 +320,7 @@ * should return false if this parameter is set. * @return File|null A File, or null if passed an invalid Title */ - function newFile( $title, $time = false ) { + public function newFile( $title, $time = false ) { $title = File::normalizeTitle( $title ); if ( !$title ) { return null; @@ -354,7 +354,7 @@ * be found. * @return File|false */ - function findFile( $title, $options = array() ) { + public function findFile( $title, $options = array() ) { $title = File::normalizeTitle( $title ); if ( !$title ) { return false; @@ -409,7 +409,7 @@ * $repo->findFiles( $findBatch ); * @return array */ - function findFiles( $items ) { + public function findFiles( $items ) { $result = array(); foreach ( $items as $item ) { if ( is_array( $item ) ) { @@ -437,7 +437,7 @@ * @param $options Option array, same as findFile(). * @return File|false */ - function findFileFromKey( $sha1, $options = array() ) { + public function findFileFromKey( $sha1, $options = array() ) { $time = isset( $options['time'] ) ? $options['time'] : false; # First try to find a matching current version of a file... @@ -468,7 +468,7 @@ * * @return string */ - function getRootUrl() { + public function getRootUrl() { return $this->url; } @@ -477,7 +477,7 @@ * * @return string */ - function isHashed() { + public function isHashed() { return (bool)$this->hashLevels; } @@ -486,7 +486,7 @@ * * @return string */ - function getThumbScriptUrl() { + public function getThumbScriptUrl() { return $this->thumbScriptUrl; } @@ -495,7 +495,7 @@ * * @return bool */ - function canTransformVia404() { + public function canTransformVia404() { return $this->transformVia404; } @@ -504,9 +504,9 @@ * * @param $title Title */ - function getNameFromTitle( Title $title ) { + public function getNameFromTitle( Title $title ) { + global $wgContLang; if ( $this->initialCapital != MWNamespace::isCapitalized( NS_FILE ) ) { - global $wgContLang; $name = $title->getUserCaseDBKey(); if ( $this->initialCapital ) { $name = $wgContLang->ucfirst( $name ); @@ -536,11 +536,11 @@ } /** - * Get the public root directory of the repository. + * Get the public zone root directory of the repository. * * @return string */ - function getRootDirectory() { + public function getRootDirectory() { return $this->getZonePath( 'public' ); } @@ -551,7 +551,7 @@ * @param $name string * @return string */ - function getHashPath( $name ) { + public function getHashPath( $name ) { return self::getHashPathForLevel( $name, $this->hashLevels ); } @@ -560,7 +560,7 @@ * * @return string */ - function getName() { + public function getName() { return $this->name; } @@ -571,7 +571,7 @@ * @param $entry string Entry point; defaults to index * @return string */ - function makeUrl( $query = '', $entry = 'index' ) { + public function makeUrl( $query = '', $entry = 'index' ) { $ext = isset( $this->scriptExtension ) ? $this->scriptExtension : '.php'; return wfAppendQuery( "{$this->scriptDirUrl}/{$entry}{$ext}", $query ); } @@ -588,7 +588,7 @@ * @param $name string * @return string */ - function getDescriptionUrl( $name ) { + public function getDescriptionUrl( $name ) { $encName = wfUrlencode( $name ); if ( !is_null( $this->descBaseUrl ) ) { # "http://example.com/wiki/Image:" @@ -623,7 +623,7 @@ * @param $lang String: language to fetch it in, if any. * @return string */ - function getDescriptionRenderUrl( $name, $lang = null ) { + public function getDescriptionRenderUrl( $name, $lang = null ) { $query = 'action=render'; if ( !is_null( $lang ) ) { $query .= '&uselang=' . $lang; @@ -645,9 +645,10 @@ /** * Get the URL of the stylesheet to apply to description pages + * * @return string */ - function getDescriptionStylesheetUrl() { + public function getDescriptionStylesheetUrl() { if ( $this->scriptDirUrl ) { return $this->makeUrl( 'title=MediaWiki:Filepage.css&' . wfArrayToCGI( Skin::getDynamicStylesheetQuery() ) ); @@ -667,7 +668,7 @@ * same contents as the source * @return FileRepoStatus */ - function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) { + public function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) { $status = $this->storeBatch( array( array( $srcPath, $dstZone, $dstRel ) ), $flags ); if ( $status->successCount == 0 ) { $status->ok = false; @@ -686,7 +687,7 @@ * same contents as the source * @return FileRepoStatus */ - function storeBatch( $triplets, $flags = 0 ) { + public function storeBatch( $triplets, $flags = 0 ) { $backend = $this->backend; // convenience // Try creating directories @@ -767,7 +768,7 @@ * @param $pairs array List of files to delete * @return void */ - function cleanupBatch( $files ) { + public function cleanupBatch( $files ) { $operations = array(); $sourceFSFilesToDelete = array(); // cleanup for disk source files foreach ( $files as $file ) { @@ -815,7 +816,7 @@ * @param $srcPath String: the current location of the file. * @return FileRepoStatus object with the URL in the value. */ - function storeTemp( $originalName, $srcPath ) { + public function storeTemp( $originalName, $srcPath ) { $date = gmdate( "YmdHis" ); $hashPath = $this->getHashPath( $originalName ); $dstRel = "{$hashPath}{$date}!{$originalName}"; @@ -831,7 +832,7 @@ * @param $virtualUrl String: the virtual URL returned by storeTemp * @return Boolean: true on success, false on failure */ - function freeTemp( $virtualUrl ) { + public function freeTemp( $virtualUrl ) { $temp = "mwrepo://{$this->name}/temp"; if ( substr( $virtualUrl, 0, strlen( $temp ) ) != $temp ) { wfDebug( __METHOD__.": Invalid temp virtual URL\n" ); @@ -857,7 +858,7 @@ * @param $flags Integer: bitfield, may be FileRepo::DELETE_SOURCE to indicate * that the source file should be deleted if possible */ - function publish( $srcPath, $dstRel, $archiveRel, $flags = 0 ) { + public function publish( $srcPath, $dstRel, $archiveRel, $flags = 0 ) { $status = $this->publishBatch( array( array( $srcPath, $dstRel, $archiveRel ) ), $flags ); if ( $status->successCount == 0 ) { $status->ok = false; @@ -878,7 +879,7 @@ * that the source files should be deleted if possible * @return FileRepoStatus */ - function publishBatch( $triplets, $flags = 0 ) { + public function publishBatch( $triplets, $flags = 0 ) { $backend = $this->backend; // convenience // Try creating directories @@ -978,7 +979,7 @@ * self::FILES_ONLY Mark file as existing only if it is a file (not directory) * @return bool */ - function fileExists( $file, $flags = 0 ) { + public function fileExists( $file, $flags = 0 ) { $result = $this->fileExistsBatch( array( $file ), $flags ); return $result[0]; } @@ -991,7 +992,7 @@ * self::FILES_ONLY Mark file as existing only if it is a file (not directory) * @return Either array of files and existence flags, or false */ - function fileExistsBatch( $files, $flags = 0 ) { + public function fileExistsBatch( $files, $flags = 0 ) { if ( !$this->initZones() ) { return false; } @@ -1024,7 +1025,7 @@ * Relative to a private archive directory. * @return FileRepoStatus object */ - function delete( $srcRel, $archiveRel ) { + public function delete( $srcRel, $archiveRel ) { return $this->deleteBatch( array( array( $srcRel, $archiveRel ) ) ); } @@ -1044,7 +1045,7 @@ * to the deleted zone root in the second element. * @return FileRepoStatus */ - function deleteBatch( $sourceDestPairs ) { + public function deleteBatch( $sourceDestPairs ) { $backend = $this->backend; // convenience if ( !isset( $this->zones['deleted'] ) ) { @@ -1111,7 +1112,7 @@ * * @return string */ - function getDeletedHashPath( $key ) { + public function getDeletedHashPath( $key ) { $path = ''; for ( $i = 0; $i < $this->deletedHashLevels; $i++ ) { $path .= $key[$i] . '/'; @@ -1122,12 +1123,12 @@ /** * Get properties of a file with a given virtual URL * The virtual URL must refer to this repo - * Properties should ultimately be obtained via File::getPropsFromPath() + * Properties should ultimately be obtained via FSFile::getProps() * * @param $virtualUrl string * @return Array */ - function getFileProps( $virtualUrl ) { + public function getFileProps( $virtualUrl ) { $path = $this->resolveVirtualUrl( $virtualUrl ); return $this->backend->getFileProps( $path ); } @@ -1139,7 +1140,7 @@ * @param $callback Array|string * @return void */ - function enumFiles( $callback ) { + public function enumFiles( $callback ) { return $this->enumFilesInStorage( $callback ); } @@ -1150,7 +1151,7 @@ * @param $callback Array|string * @return void */ - function enumFilesInStorage( $callback ) { + protected function enumFilesInStorage( $callback ) { $publicRoot = $this->getZonePath( 'public' ); $numDirs = 1 << ( $this->hashLevels * 4 ); // Use a priori assumptions about directory structure @@ -1175,7 +1176,7 @@ * @param $filename string * @return bool */ - function validateFilename( $filename ) { + public function validateFilename( $filename ) { if ( strval( $filename ) == '' ) { return false; } @@ -1284,7 +1285,7 @@ * * STUB */ - function cleanupDeletedBatch( $storageKeys ) {} + public function cleanupDeletedBatch( $storageKeys ) {} /** * Checks if there is a redirect named as $title. If there is, return the @@ -1294,7 +1295,7 @@ * @param $title Title of image * @return Bool */ - function checkRedirect( Title $title ) { + public function checkRedirect( Title $title ) { return false; } @@ -1305,7 +1306,7 @@ * STUB * @param $title Title of image */ - function invalidateImageRedirect( Title $title ) {} + public function invalidateImageRedirect( Title $title ) {} /** * Get an array or iterator of file objects for files that have a given @@ -1313,7 +1314,7 @@ * * STUB */ - function findBySha1( $hash ) { + public function findBySha1( $hash ) { return array(); } @@ -1336,7 +1337,7 @@ * * @return bool */ - function isLocal() { + public function isLocal() { return $this->getName() == 'local'; } @@ -1355,6 +1356,8 @@ * Get a key for this repo in the local cache domain. These cache keys are * not shared with remote instances of the repo. * The parameters are the parts of the key, as for wfMemcKey(). + * + * @return string */ function getLocalCacheKey( /*...*/ ) { $args = func_get_args(); @@ -1367,7 +1370,7 @@ * * @return UploadStash */ - function getUploadStash() { + public function getUploadStash() { return new UploadStash( $this ); } } Modified: branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php =================================================================== --- branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php 2011-11-27 19:17:07 UTC (rev 104358) +++ branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php 2011-11-27 19:27:54 UTC (rev 104359) @@ -2,12 +2,16 @@ /** * @file * @ingroup FileRepo + * @ingroup FileBackend */ /** * Class for a file-system based file backend. * Status messages should avoid mentioning the internal FS paths. * Likewise, error suppression should be used to path disclosure. + * + * @ingroup FileRepo + * @ingroup FileBackend */ class FSFileBackend extends FileBackend { /** @var Array Map of container names to paths */ @@ -307,12 +311,10 @@ if ( !wfMkdirParents( $dir ) ) { $status->fatal( 'directorycreateerror', $param['directory'] ); return $status; - } - if ( !is_writable( $dir ) ) { + } elseif ( !is_writable( $dir ) ) { $status->fatal( 'directoryreadonlyerror', $param['directory'] ); return $status; - } - if ( !is_readable( $dir ) ) { + } elseif ( !is_readable( $dir ) ) { $status->fatal( 'directorynotreadableerror', $param['directory'] ); return $status; } @@ -373,13 +375,22 @@ return md5_file( $source ); } + function getFileTimestamp( array $params ) { + list( $c, $source ) = $this->resolveVirtualPath( $params['source'] ); + if ( $source === null ) { + return false; // invalid storage path + } + $fsFile = new FSFile( $source ); + return $fsFile->getTimestamp(); + } + function getFileProps( array $params ) { - $tmpFile = $this->getLocalCopy( $params ); - if ( !$tmpFile ) { - return FSFile::placeholderProps(); - } else { - return $tmpFile->getProps(); + list( $c, $source ) = $this->resolveVirtualPath( $params['source'] ); + if ( $source === null ) { + return FSFile::placeholderProps(); // invalid storage path } + $fsFile = new FSFile( $source ); + return $fsFile->getProps(); } function getFileList( array $params ) { Modified: branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php =================================================================== --- branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php 2011-11-27 19:17:07 UTC (rev 104358) +++ branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php 2011-11-27 19:27:54 UTC (rev 104359) @@ -2,6 +2,7 @@ /** * @file * @ingroup FileRepo + * @ingroup FileBackend */ /** @@ -16,6 +17,9 @@ * * Methods should avoid throwing exceptions at all costs. * As a corollary, external dependencies should be kept to a minimum. + * + * @ingroup FileRepo + * @ingroup FileBackend */ abstract class FileBackendBase { protected $name; // unique backend name @@ -111,13 +115,13 @@ abstract public function fileExists( array $params ); /** - * Get a hash of the file that exists at a storage path in the backend. + * Get a hash of the file at a storage path in the backend. * Typically this will be a SHA-1 hash, MD5 hash, or something similar. * $params include: * source : source storage path * * @param Array $params - * @return string|null Gives null if the file does not exist + * @return string|false Hash string or false on failure */ abstract public function getFileHash( array $params ); @@ -129,17 +133,28 @@ abstract public function getHashType(); /** - * Get the properties of the file that exists at a storage path in the backend + * Get the last-modified timestamp of the file at a storage path. * $params include: * source : source storage path * * @param Array $params - * @return Array|null Gives null if the file does not exist + * @return string|false TS_MW timestamp or false on failure */ + abstract public function getFileTimestamp( array $params ); + + /** + * Get the properties of the file at a storage path in the backend. + * Returns FSFile::placeholderProps() on failure. + * $params include: + * source : source storage path + * + * @param Array $params + * @return Array + */ abstract public function getFileProps( array $params ); /** - * Stream the file that exists at a storage path in the backend. + * Stream the file at a storage path in the backend. * Appropriate HTTP headers (Status, Content-Type, Content-Length) * must be sent if streaming began, while none should be sent otherwise. * Implementations should flush the output buffer before sending data. @@ -202,6 +217,9 @@ /** * Base class for all single-write backends. * This class defines the methods as abstract that subclasses must implement. + * + * @ingroup FileRepo + * @ingroup FileBackend */ abstract class FileBackend extends FileBackendBase { /** @@ -308,6 +326,15 @@ return false; // not implemented } + public function getFileProps( array $params ) { + $tmpFile = $this->getLocalCopy( $params ); + if ( !$tmpFile ) { + return FSFile::placeholderProps(); + } else { + return $tmpFile->getProps(); + } + } + /** * Get the list of supported operations and their corresponding FileOp classes. * @@ -482,7 +509,7 @@ * * @param $container string * @param $relStoragePath string - * @return string|null Null if path is not valid + * @return string|null Path or null if not valid */ protected function resolveContainerPath( $container, $relStoragePath ) { return $relStoragePath; Modified: branches/FileBackend/phase3/includes/filerepo/backend/FileBackendMultiWrite.php =================================================================== --- branches/FileBackend/phase3/includes/filerepo/backend/FileBackendMultiWrite.php 2011-11-27 19:17:07 UTC (rev 104358) +++ branches/FileBackend/phase3/includes/filerepo/backend/FileBackendMultiWrite.php 2011-11-27 19:27:54 UTC (rev 104359) @@ -2,6 +2,7 @@ /** * @file * @ingroup FileRepo + * @ingroup FileBackend */ /** @@ -20,6 +21,9 @@ * * All write operations are performed on all backends. * If an operation fails on one backend it will be rolled back from the others. + * + * @ingroup FileRepo + * @ingroup FileBackend */ class FileBackendMultiWrite extends FileBackendBase { /** @var Array Prioritized list of FileBackend objects */ Modified: branches/FileBackend/phase3/includes/filerepo/file/FSFile.php =================================================================== --- branches/FileBackend/phase3/includes/filerepo/file/FSFile.php 2011-11-27 19:17:07 UTC (rev 104358) +++ branches/FileBackend/phase3/includes/filerepo/file/FSFile.php 2011-11-27 19:27:54 UTC (rev 104359) @@ -2,10 +2,14 @@ /** * @file * @ingroup FileRepo + * @ingroup FileBackend */ /** * Class representing a non-directory file on the file system + * + * @ingroup FileRepo + * @ingroup FileBackend */ class FSFile { protected $path; // path to file @@ -38,6 +42,19 @@ } /** + * Get the file's last-modified timestamp + * + * @return string|false TS_MW timestamp or false on failure + */ + public function getTimestamp() { + $timestamp = filemtime( $this->path ); + if ( $timestamp !== false ) { + $timestamp = wfTimestamp( TS_MW, $ts ); + } + return $timestamp; + } + + /** * Get an associative array containing information about * a file with the given storage path. * Modified: branches/FileBackend/phase3/includes/filerepo/file/LocalFile.php =================================================================== --- branches/FileBackend/phase3/includes/filerepo/file/LocalFile.php 2011-11-27 19:17:07 UTC (rev 104358) +++ branches/FileBackend/phase3/includes/filerepo/file/LocalFile.php 2011-11-27 19:27:54 UTC (rev 104359) @@ -234,7 +234,8 @@ * Load metadata from the file itself */ function loadFromFile() { - $this->setProps( self::getPropsFromPath( $this->getPath() ) ); + $props = $this->repo->getFileProps( $this->getVirtualUrl() ); + $this->setProps( $props ); } function getCacheFields( $prefix = 'img_' ) { @@ -748,9 +749,8 @@ # Check that the base file name is part of the thumb name # This is a basic sanity check to avoid erasing unrelated directories if ( strpos( $file, $this->getName() ) !== false ) { - wfSuppressWarnings(); - unlink( "$dir/$file" ); - wfRestoreWarnings(); + $op = array( 'operation' => 'delete', 'source' => "$dir/$file" ); + $this->repo->getBackend()->doOperations( array( $op ) ); } } } Modified: branches/FileBackend/phase3/includes/filerepo/file/TempFSFile.php =================================================================== --- branches/FileBackend/phase3/includes/filerepo/file/TempFSFile.php 2011-11-27 19:17:07 UTC (rev 104358) +++ branches/FileBackend/phase3/includes/filerepo/file/TempFSFile.php 2011-11-27 19:27:54 UTC (rev 104359) @@ -2,24 +2,26 @@ /** * @file * @ingroup FileRepo + * @ingroup FileBackend */ /** * This class is used to hold the location and do limited manipulation * of files stored temporarily (usually this will be $wgTmpDirectory) + * + * @ingroup FileRepo + * @ingroup FileBackend */ class TempFSFile extends FSFile { - protected $canDelete; // whether this object should garbage collect the temp file + protected $canDelete = true; // garbage collect the temp file /** - * Sets up the temporary file object + * Flag to not clean up after the temporary file * - * @param String $path Path to temporary file on local disk - * @param Boolean $canDelete Whether this object should garbage collect the temp file + * @return void */ - public function __construct( $path, $canDelete = true ) { - $this->path = $path; - $this->canDelete = $canDelete; + public function preserve() { + $this->canDelete = false; } /** _______________________________________________ MediaWiki-CVS mailing list MediaWiki-CVS@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs