/**#@+
* @private
*/
- var $fileExists, # does the file file exist on disk? (loadFromXxx)
- $historyLine, # Number of line to return by nextHistoryLine() (constructor)
- $historyRes, # result of the query for the file's history (nextHistoryLine)
+ var
+ $fileExists, # does the file file exist on disk? (loadFromXxx)
+ $historyLine, # Number of line to return by nextHistoryLine() (constructor)
+ $historyRes, # result of the query for the file's history (nextHistoryLine)
$width, # \
$height, # |
$bits, # --- returned by getimagesize (loadFromXxx)
$upgraded, # Whether the row was upgraded on load
$locked, # True if the image row is locked
$missing, # True if file is not present in file system. Not to be cached in memcached
- $deleted; # Bitfield akin to rev_deleted
+ $deleted; # Bitfield akin to rev_deleted
/**#@-*/
/**
* Create a LocalFile from a SHA-1 key
* Do not call this except from inside a repo class.
+ * @param $sha1
+ * @param $repo LocalRepo
+ * @param $timestamp
*/
static function newFromKey( $sha1, $repo, $timestamp = false ) {
$conds = array( 'img_sha1' => $sha1 );
* Delete cached transformed files
*/
function purgeThumbnails() {
- global $wgUseSquid;
+ global $wgUseSquid, $wgExcludeFromThumbnailPurge;
// Delete thumbnails
$files = $this->getThumbnails();
$urls = array();
foreach ( $files as $file ) {
+ // Only remove files not in the $wgExcludeFromThumbnailPurge configuration variable
+ $ext = pathinfo( "$dir/$file", PATHINFO_EXTENSION );
+ if ( in_array( $ext, $wgExcludeFromThumbnailPurge ) ) {
+ continue;
+ }
+
# 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 ) {
$res = $dbr->select( $tables, $fields, $conds, __METHOD__, $opts, $join_conds );
$r = array();
- while ( $row = $dbr->fetchObject( $res ) ) {
+ foreach ( $res as $row ) {
if ( $this->repo->oldFileFromRowFactory ) {
$r[] = call_user_func( $this->repo->oldFileFromRowFactory, $row, $this->repo );
} else {
$result = $dbw->select( 'oldimage',
array( 'oi_archive_name' ),
array( 'oi_name' => $this->getName() ) );
- while ( $row = $dbw->fetchObject( $result ) ) {
+ foreach ( $result as $row ) {
$batch->addOld( $row->oi_archive_name );
}
$status = $batch->execute();
$status = $batch->execute();
- if ( !$status->ok ) {
+ if ( !$status->isGood() ) {
return $status;
}
/** scaleHeight inherited */
/** getImageSize inherited */
- /** getDescriptionUrl inherited */
- /** getDescriptionText inherited */
+ /**
+ * Get the URL of the file description page.
+ */
+ function getDescriptionUrl() {
+ return $this->title->getLocalUrl();
+ }
+
+ /**
+ * Get the HTML text of the description page
+ * This is not used by ImagePage for local files, since (among other things)
+ * it skips the parser cache.
+ */
+ function getDescriptionText() {
+ global $wgParser;
+ $revision = Revision::newFromTitle( $this->title );
+ if ( !$revision ) return false;
+ $text = $revision->getText();
+ if ( !$text ) return false;
+ $pout = $wgParser->parse( $text, $this->title, new ParserOptions() );
+ return $pout->getText();
+ }
function getDescription() {
$this->load();
* @ingroup FileRepo
*/
class LocalFileDeleteBatch {
- var $file, $reason, $srcRels = array(), $archiveUrls = array(), $deletionBatch, $suppress;
+
+ /**
+ * @var LocalFile
+ */
+ var $file;
+
+ var $reason, $srcRels = array(), $archiveUrls = array(), $deletionBatch, $suppress;
var $status;
function __construct( File $file, $reason = '', $suppress = false ) {
__METHOD__
);
- while ( $row = $dbw->fetchObject( $res ) ) {
+ foreach ( $res as $row ) {
if ( rtrim( $row->oi_sha1, "\0" ) === '' ) {
// Get the hash from the file
$oldUrl = $this->file->getArchiveVirtualUrl( $row->oi_archive_name );
$dbw->bitAnd( 'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE ),
__METHOD__ );
- while ( $row = $dbw->fetchObject( $res ) ) {
+ foreach ( $res as $row ) {
$privateFiles[$row->oi_archive_name] = 1;
}
}
* @ingroup FileRepo
*/
class LocalFileRestoreBatch {
- var $file, $cleanupBatch, $ids, $all, $unsuppress = false;
+ /**
+ * @var LocalFile
+ */
+ var $file;
+
+ var $cleanupBatch, $ids, $all, $unsuppress = false;
function __construct( File $file, $unsuppress = false ) {
$this->file = $file;
$first = true;
$archiveNames = array();
- while ( $row = $dbw->fetchObject( $result ) ) {
+ foreach ( $result as $row ) {
$idsPresent[] = $row->fa_id;
if ( $row->fa_name != $this->file->getName() ) {
$storeStatus = $this->file->repo->storeBatch( $storeBatch, FileRepo::OVERWRITE_SAME );
$status->merge( $storeStatus );
- if ( !$status->ok ) {
- // Store batch returned a critical error -- this usually means nothing was stored
- // Stop now and return an error
+ if ( !$status->isGood() ) {
+ // Even if some files could be copied, fail entirely as that is the
+ // easiest thing to do without data loss
+ $this->cleanupFailedBatch( $storeStatus, $storeBatch );
+ $status->ok = false;
$this->file->unlock();
return $status;
return $status;
}
+
+ function cleanupFailedBatch( $storeStatus, $storeBatch ) {
+ $cleanupBatch = array();
+
+ foreach ( $storeStatus->success as $i => $success ) {
+ if ( $success ) {
+ $cleanupBatch[] = array( $storeBatch[$i][1], $storeBatch[$i][1] );
+ }
+ }
+ $this->file->repo->cleanupBatch( $cleanupBatch );
+ }
}
# ------------------------------------------------------------------------------
__METHOD__
);
- while ( $row = $this->db->fetchObject( $result ) ) {
+ foreach ( $result as $row ) {
$oldName = $row->oi_archive_name;
$bits = explode( '!', $oldName, 2 );
$triplets = $this->getMoveTriplets();
$triplets = $this->removeNonexistentFiles( $triplets );
- $statusDb = $this->doDBUpdates();
- wfDebugLog( 'imagemove', "Renamed {$this->file->name} in database: {$statusDb->successCount} successes, {$statusDb->failCount} failures" );
- $statusMove = $repo->storeBatch( $triplets, FSRepo::DELETE_SOURCE );
+
+ // Copy the files into their new location
+ $statusMove = $repo->storeBatch( $triplets );
wfDebugLog( 'imagemove', "Moved files for {$this->file->name}: {$statusMove->successCount} successes, {$statusMove->failCount} failures" );
-
- if ( !$statusMove->isOk() ) {
+ if ( !$statusMove->isGood() ) {
wfDebugLog( 'imagemove', "Error in moving files: " . $statusMove->getWikiText() );
- $this->db->rollback();
+ $this->cleanupTarget( $triplets );
+ $statusMove->ok = false;
+ return $statusMove;
}
+ $this->db->begin();
+ $statusDb = $this->doDBUpdates();
+ wfDebugLog( 'imagemove', "Renamed {$this->file->name} in database: {$statusDb->successCount} successes, {$statusDb->failCount} failures" );
+ if ( !$statusDb->isGood() ) {
+ $this->db->rollback();
+ // Something went wrong with the DB updates, so remove the target files
+ $this->cleanupTarget( $triplets );
+ $statusDb->ok = false;
+ return $statusDb;
+ }
+ $this->db->commit();
+
+ // Everything went ok, remove the source files
+ $this->cleanupSource( $triplets );
+
$status->merge( $statusDb );
$status->merge( $statusMove );
$status->successCount++;
} else {
$status->failCount++;
+ $status->fatal( 'imageinvalidfilename' );
+ return $status;
}
// Update old images
$total = $this->oldCount;
$status->successCount += $affected;
$status->failCount += $total - $affected;
+ if ( $status->failCount ) {
+ $status->error( 'imageinvalidfilename' );
+ }
return $status;
}
return $filteredTriplets;
}
+
+ /**
+ * Cleanup a partially moved array of triplets by deleting the target
+ * files. Called if something went wrong half way.
+ */
+ function cleanupTarget( $triplets ) {
+ // Create dest pairs from the triplets
+ $pairs = array();
+ foreach ( $triplets as $triplet ) {
+ $pairs[] = array( $triplet[1], $triplet[2] );
+ }
+
+ $this->file->repo->cleanupBatch( $pairs );
+ }
+
+ /**
+ * Cleanup a fully moved array of triplets by deleting the source files.
+ * Called at the end of the move process if everything else went ok.
+ */
+ function cleanupSource( $triplets ) {
+ // Create source file names from the triplets
+ $files = array();
+ foreach ( $triplets as $triplet ) {
+ $files[] = $triplet[0];
+ }
+
+ $this->file->repo->cleanupBatch( $files );
+ }
}