<?php
-
/**
- * A repository for files accessible via the local filesystem. Does not support
- * database access or registration.
+ * A repository for files accessible via the local filesystem.
+ *
+ * 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 FileRepo
*/
+/**
+ * A repository for files accessible via the local filesystem.
+ * Does not support database access or registration.
+ *
+ * This is a mostly a legacy class. New uses should not be added.
+ *
+ * @ingroup FileRepo
+ * @deprecated since 1.19
+ */
class FSRepo extends FileRepo {
- var $directory, $url, $hashLevels;
- var $fileFactory = array( 'UnregisteredLocalFile', 'newFromTitle' );
- var $oldFileFactory = false;
-
- function __construct( $info ) {
- parent::__construct( $info );
-
- // Required settings
- $this->directory = $info['directory'];
- $this->url = $info['url'];
- $this->hashLevels = $info['hashLevels'];
- }
-
- /**
- * Get the public root directory of the repository.
- */
- function getRootDirectory() {
- return $this->directory;
- }
-
- /**
- * Get the public root URL of the repository
- */
- function getRootUrl() {
- return $this->url;
- }
-
- /**
- * Returns true if the repository uses a multi-level directory structure
- */
- function isHashed() {
- return (bool)$this->hashLevels;
- }
-
- /**
- * Get the local directory corresponding to one of the three basic zones
- */
- function getZonePath( $zone ) {
- switch ( $zone ) {
- case 'public':
- return $this->directory;
- case 'temp':
- return "{$this->directory}/temp";
- case 'deleted':
- return $GLOBALS['wgFileStore']['deleted']['directory'];
- default:
- return false;
- }
- }
-
- /**
- * Get the URL corresponding to one of the three basic zones
- */
- function getZoneUrl( $zone ) {
- switch ( $zone ) {
- case 'public':
- return $this->url;
- case 'temp':
- return "{$this->url}/temp";
- case 'deleted':
- return $GLOBALS['wgFileStore']['deleted']['url'];
- default:
- return false;
- }
- }
-
- /**
- * Get a URL referring to this repository, with the private mwrepo protocol.
- * The suffix, if supplied, is considered to be unencoded, and will be
- * URL-encoded before being returned.
- */
- function getVirtualUrl( $suffix = false ) {
- $path = 'mwrepo://' . $this->name;
- if ( $suffix !== false ) {
- $path .= '/' . rawurlencode( $suffix );
- }
- return $path;
- }
-
- /**
- * Get the local path corresponding to a virtual URL
- */
- function resolveVirtualUrl( $url ) {
- if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
- throw new MWException( __METHOD__.': unknown protoocl' );
- }
-
- $bits = explode( '/', substr( $url, 9 ), 3 );
- if ( count( $bits ) != 3 ) {
- throw new MWException( __METHOD__.": invalid mwrepo URL: $url" );
- }
- list( $repo, $zone, $rel ) = $bits;
- if ( $repo !== $this->name ) {
- throw new MWException( __METHOD__.": fetching from a foreign repo is not supported" );
- }
- $base = $this->getZonePath( $zone );
- if ( !$base ) {
- throw new MWException( __METHOD__.": invalid zone: $zone" );
- }
- return $base . '/' . rawurldecode( $rel );
- }
-
- /**
- * Store a file to a given destination.
- */
- function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
- if ( !is_writable( $this->directory ) ) {
- return new WikiErrorMsg( 'upload_directory_read_only', wfEscapeWikiText( $this->directory ) );
- }
- $root = $this->getZonePath( $dstZone );
- if ( !$root ) {
- throw new MWException( "Invalid zone: $dstZone" );
- }
- $dstPath = "$root/$dstRel";
-
- if ( !is_dir( dirname( $dstPath ) ) ) {
- wfMkdirParents( dirname( $dstPath ) );
+ function __construct( array $info ) {
+ if ( !isset( $info['backend'] ) ) {
+ // B/C settings...
+ $directory = $info['directory'];
+ $deletedDir = isset( $info['deletedDir'] )
+ ? $info['deletedDir']
+ : false;
+ $thumbDir = isset( $info['thumbDir'] )
+ ? $info['thumbDir']
+ : "{$directory}/thumb";
+ $fileMode = isset( $info['fileMode'] )
+ ? $info['fileMode']
+ : 0644;
+
+ $repoName = $info['name'];
+ // Get the FS backend configuration
+ $backend = new FSFileBackend( array(
+ 'name' => $info['name'] . '-backend',
+ 'lockManager' => 'fsLockManager',
+ 'containerPaths' => array(
+ "{$repoName}-public" => "{$directory}",
+ "{$repoName}-temp" => "{$directory}/temp",
+ "{$repoName}-thumb" => $thumbDir,
+ "{$repoName}-deleted" => $deletedDir
+ ),
+ 'fileMode' => $fileMode,
+ ) );
+ // Update repo config to use this backend
+ $info['backend'] = $backend;
}
-
- if ( self::isVirtualUrl( $srcPath ) ) {
- $srcPath = $this->resolveVirtualUrl( $srcPath );
- }
-
- if ( $flags & self::DELETE_SOURCE ) {
- if ( !rename( $srcPath, $dstPath ) ) {
- return new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ),
- wfEscapeWikiText( $dstPath ) );
- }
- } else {
- if ( !copy( $srcPath, $dstPath ) ) {
- return new WikiErrorMsg( 'filecopyerror', wfEscapeWikiText( $srcPath ),
- wfEscapeWikiText( $dstPath ) );
- }
- }
- chmod( $dstPath, 0644 );
- return true;
- }
-
- /**
- * Pick a random name in the temp zone and store a file to it.
- * Returns the URL, or a WikiError on failure.
- * @param string $originalName The base name of the file as specified
- * by the user. The file extension will be maintained.
- * @param string $srcPath The current location of the file.
- */
- function storeTemp( $originalName, $srcPath ) {
- $date = gmdate( "YmdHis" );
- $hashPath = $this->getHashPath( $originalName );
- $dstRel = "$hashPath$date!$originalName";
- $dstUrlRel = $hashPath . $date . '!' . rawurlencode( $originalName );
-
- $result = $this->store( $srcPath, 'temp', $dstRel );
- if ( WikiError::isError( $result ) ) {
- return $result;
- } else {
- return $this->getVirtualUrl( 'temp' ) . '/' . $dstUrlRel;
- }
- }
-
- /**
- * Remove a temporary file or mark it for garbage collection
- * @param string $virtualUrl The virtual URL returned by storeTemp
- * @return boolean True on success, false on failure
- */
- function freeTemp( $virtualUrl ) {
- $temp = "mwrepo://{$this->name}/temp";
- if ( substr( $virtualUrl, 0, strlen( $temp ) ) != $temp ) {
- wfDebug( __METHOD__.": Invalid virtual URL\n" );
- return false;
- }
- $path = $this->resolveVirtualUrl( $virtualUrl );
- wfSuppressWarnings();
- $success = unlink( $path );
- wfRestoreWarnings();
- return $success;
- }
-
-
- /**
- * Copy or move a file either from the local filesystem or from an mwrepo://
- * virtual URL, into this repository at the specified destination location.
- *
- * @param string $srcPath The source path or URL
- * @param string $dstRel The destination relative path
- * @param string $archiveRel The relative path where the existing file is to
- * be archived, if there is one. Relative to the public zone root.
- * @param integer $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
- * that the source file should be deleted if possible
- */
- function publish( $srcPath, $dstRel, $archiveRel, $flags = 0 ) {
- if ( !is_writable( $this->directory ) ) {
- return new WikiErrorMsg( 'upload_directory_read_only', wfEscapeWikiText( $this->directory ) );
- }
- if ( substr( $srcPath, 0, 9 ) == 'mwrepo://' ) {
- $srcPath = $this->resolveVirtualUrl( $srcPath );
- }
- if ( !$this->validateFilename( $dstRel ) ) {
- throw new MWException( 'Validation error in $dstRel' );
- }
- if ( !$this->validateFilename( $archiveRel ) ) {
- throw new MWException( 'Validation error in $archiveRel' );
- }
- $dstPath = "{$this->directory}/$dstRel";
- $archivePath = "{$this->directory}/$archiveRel";
-
- $dstDir = dirname( $dstPath );
- if ( !is_dir( $dstDir ) ) wfMkdirParents( $dstDir );
- if( is_file( $dstPath ) ) {
- $archiveDir = dirname( $archivePath );
- if ( !is_dir( $archiveDir ) ) wfMkdirParents( $archiveDir );
- wfSuppressWarnings();
- $success = rename( $dstPath, $archivePath );
- wfRestoreWarnings();
-
- if( ! $success ) {
- return new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $dstPath ),
- wfEscapeWikiText( $archivePath ) );
- }
- else wfDebug(__METHOD__.": moved file $dstPath to $archivePath\n");
- $status = 'archived';
- }
- else {
- $status = 'new';
- }
-
- $error = false;
- wfSuppressWarnings();
- if ( $flags & self::DELETE_SOURCE ) {
- if ( !rename( $srcPath, $dstPath ) ) {
- $error = new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ),
- wfEscapeWikiText( $dstPath ) );
- }
- } else {
- if ( !copy( $srcPath, $dstPath ) ) {
- $error = new WikiErrorMsg( 'filerenameerror', wfEscapeWikiText( $srcPath ),
- wfEscapeWikiText( $dstPath ) );
- }
- }
- wfRestoreWarnings();
-
- if( $error ) {
- return $error;
- } else {
- wfDebug(__METHOD__.": wrote tempfile $srcPath to $dstPath\n");
- }
-
- chmod( $dstPath, 0644 );
- return $status;
- }
-
- /**
- * Get a relative path including trailing slash, e.g. f/fa/
- * If the repo is not hashed, returns an empty string
- */
- function getHashPath( $name ) {
- return FileRepo::getHashPathForLevel( $name, $this->hashLevels );
- }
+ parent::__construct( $info );
- /**
- * Call a callback function for every file in the repository.
- * Uses the filesystem even in child classes.
- */
- function enumFilesInFS( $callback ) {
- $numDirs = 1 << ( $this->hashLevels * 4 );
- for ( $flatIndex = 0; $flatIndex < $numDirs; $flatIndex++ ) {
- $hexString = sprintf( "%0{$this->hashLevels}x", $flatIndex );
- $path = $this->directory;
- for ( $hexPos = 0; $hexPos < $this->hashLevels; $hexPos++ ) {
- $path .= '/' . substr( $hexString, 0, $hexPos + 1 );
- }
- if ( !file_exists( $path ) || !is_dir( $path ) ) {
- continue;
- }
- $dir = opendir( $path );
- while ( false !== ( $name = readdir( $dir ) ) ) {
- call_user_func( $callback, $path . '/' . $name );
- }
+ if ( !( $this->backend instanceof FSFileBackend ) ) {
+ throw new MWException( "FSRepo only supports FSFileBackend." );
}
}
-
- /**
- * Call a callback function for every file in the repository
- * May use either the database or the filesystem
- */
- function enumFiles( $callback ) {
- $this->enumFilesInFS( $callback );
- }
-
- /**
- * Get properties of a file with a given virtual URL
- * The virtual URL must refer to this repo
- */
- function getFileProps( $virtualUrl ) {
- $path = $this->resolveVirtualUrl( $virtualUrl );
- return File::getPropsFromPath( $path );
- }
}
-
-?>