r108740 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r108739‎ | r108740 | r108741 >
Date:18:44, 12 January 2012
Author:aaron
Status:ok
Tags:filebackend 
Comment:
* Added 'basePath' config param to FSFileBackend and tweaked it to behave more similarly to the backends with real containers (e.g. everything else). Resolution to absolute paths is now deferred after resolveStoragePath(), using resolveToFSPath().
* Fixed whitespace in FSFileIterator.
Modified paths:
  • /trunk/phase3/includes/filerepo/backend/FSFileBackend.php (modified) (history)
  • /trunk/phase3/tests/phpunit/includes/filerepo/FileBackendTest.php (modified) (history)
  • /trunk/phase3/tests/phpunit/includes/filerepo/StoreBatchTest.php (modified) (history)

Diff [purge]

Index: trunk/phase3/tests/phpunit/includes/filerepo/StoreBatchTest.php
@@ -1,6 +1,6 @@
22 <?php
33 /**
4 - * @group Filerepo
 4+ * @group FileRepo
55 */
66 class StoreBatchTest extends MediaWikiTestCase {
77
Index: trunk/phase3/tests/phpunit/includes/filerepo/FileBackendTest.php
@@ -1,6 +1,9 @@
22 <?php
33
4 -// @TODO: fix empty dir leakage
 4+/**
 5+ * @group FileRepo
 6+ * @TODO: fix empty dir leakage
 7+ */
58 class FileBackendTest extends MediaWikiTestCase {
69 private $backend, $multiBackend;
710 private $filesToPrune, $pathsToPrune;
Index: trunk/phase3/includes/filerepo/backend/FSFileBackend.php
@@ -6,10 +6,12 @@
77 */
88
99 /**
10 - * Class for a file system based file backend.
11 - * Containers are just directories and container sharding is not supported.
12 - * Also, for backwards-compatibility, the wiki ID prefix is not used.
13 - * Users of this class should set wiki-specific container paths as needed.
 10+ * Class for a file system (FS) based file backend.
 11+ *
 12+ * All "containers" each map to a directory under the backend's base directory.
 13+ * For backwards-compatibility, some container paths can be set to custom paths.
 14+ * The wiki ID will not be used in any custom paths, so this should be avoided.
 15+ * Sharding can be accomplished by using FileRepo-style hash paths.
1416 *
1517 * Status messages should avoid mentioning the internal FS paths.
1618 * Likewise, error suppression should be used to avoid path disclosure.
@@ -17,18 +19,28 @@
1820 * @ingroup FileBackend
1921 */
2022 class FSFileBackend extends FileBackend {
21 - /** @var Array Map of container names to paths */
22 - protected $containerPaths = array();
23 - protected $fileMode; // file permission mode
 23+ protected $basePath; // string; directory holding the container directories
 24+ /** @var Array Map of container names to root paths */
 25+ protected $containerPaths = array(); // for custom container paths
 26+ protected $fileMode; // integer; file permission mode
2427
2528 /**
2629 * @see FileBackend::__construct()
2730 * Additional $config params include:
28 - * containerPaths : Map of container names to absolute file system paths
29 - * fileMode : Octal UNIX file permissions to use on files stored
 31+ * basePath : File system directory that holds containers.
 32+ * containerPaths : Map of container names to custom file system directories.
 33+ * This should only be used for backwards-compatibility.
 34+ * fileMode : Octal UNIX file permissions to use on files stored.
3035 */
3136 public function __construct( array $config ) {
3237 parent::__construct( $config );
 38+ if ( isset( $config['basePath'] ) ) {
 39+ if ( substr( $this->basePath, -1 ) === '/' ) {
 40+ $this->basePath = substr( $this->basePath, 0, -1 ); // remove trailing slash
 41+ }
 42+ } else {
 43+ $this->basePath = null; // none; containers must have explicit paths
 44+ }
3345 $this->containerPaths = (array)$config['containerPaths'];
3446 foreach ( $this->containerPaths as &$path ) {
3547 if ( substr( $path, -1 ) === '/' ) {
@@ -44,24 +56,60 @@
4557 * @see FileBackend::resolveContainerPath()
4658 */
4759 protected function resolveContainerPath( $container, $relStoragePath ) {
48 - // Get absolute path given the container base dir
49 - if ( isset( $this->containerPaths[$container] ) ) {
50 - return $this->containerPaths[$container] . "/{$relStoragePath}";
 60+ if ( isset( $this->containerPaths[$container] ) || isset( $this->basePath ) ) {
 61+ return $relStoragePath; // container has a root directory
5162 }
5263 return null;
5364 }
5465
5566 /**
 67+ * Given the short (unresolved) and full (resolved) name of
 68+ * a container, return the file system path of the container.
 69+ *
 70+ * @param $shortCont string
 71+ * @param $fullCont string
 72+ * @return string|null
 73+ */
 74+ protected function containerFSRoot( $shortCont, $fullCont ) {
 75+ if ( isset( $this->containerPaths[$shortCont] ) ) {
 76+ return $this->containerPaths[$shortCont];
 77+ } elseif ( isset( $this->basePath ) ) {
 78+ return "{$this->basePath}/{$fullCont}";
 79+ }
 80+ return null; // no container base path defined
 81+ }
 82+
 83+ /**
 84+ * Get the absolute file system path for a storage path
 85+ *
 86+ * @param $storagePath string Storage path
 87+ * @return string|null
 88+ */
 89+ protected function resolveToFSPath( $storagePath ) {
 90+ list( $fullCont, $relPath ) = $this->resolveStoragePathReal( $storagePath );
 91+ if ( $relPath === null ) {
 92+ return null; // invalid
 93+ }
 94+ list( $b, $shortCont, $r ) = FileBackend::splitStoragePath( $storagePath );
 95+ $fsPath = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
 96+ if ( $relPath != '' ) {
 97+ $fsPath .= "/{$relPath}";
 98+ }
 99+ return $fsPath;
 100+ }
 101+
 102+ /**
56103 * @see FileBackend::doStoreInternal()
57104 */
58105 protected function doStoreInternal( array $params ) {
59106 $status = Status::newGood();
60107
61 - list( $c, $dest ) = $this->resolveStoragePathReal( $params['dst'] );
 108+ $dest = $this->resolveToFSPath( $params['dst'] );
62109 if ( $dest === null ) {
63110 $status->fatal( 'backend-fail-invalidpath', $params['dst'] );
64111 return $status;
65112 }
 113+
66114 if ( file_exists( $dest ) ) {
67115 if ( !empty( $params['overwriteDest'] ) ) {
68116 wfSuppressWarnings();
@@ -101,13 +149,13 @@
102150 protected function doCopyInternal( array $params ) {
103151 $status = Status::newGood();
104152
105 - list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] );
 153+ $source = $this->resolveToFSPath( $params['src'] );
106154 if ( $source === null ) {
107155 $status->fatal( 'backend-fail-invalidpath', $params['src'] );
108156 return $status;
109157 }
110158
111 - list( $c, $dest ) = $this->resolveStoragePathReal( $params['dst'] );
 159+ $dest = $this->resolveToFSPath( $params['dst'] );
112160 if ( $dest === null ) {
113161 $status->fatal( 'backend-fail-invalidpath', $params['dst'] );
114162 return $status;
@@ -152,12 +200,13 @@
153201 protected function doMoveInternal( array $params ) {
154202 $status = Status::newGood();
155203
156 - list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] );
 204+ $source = $this->resolveToFSPath( $params['src'] );
157205 if ( $source === null ) {
158206 $status->fatal( 'backend-fail-invalidpath', $params['src'] );
159207 return $status;
160208 }
161 - list( $c, $dest ) = $this->resolveStoragePathReal( $params['dst'] );
 209+
 210+ $dest = $this->resolveToFSPath( $params['dst'] );
162211 if ( $dest === null ) {
163212 $status->fatal( 'backend-fail-invalidpath', $params['dst'] );
164213 return $status;
@@ -204,7 +253,7 @@
205254 protected function doDeleteInternal( array $params ) {
206255 $status = Status::newGood();
207256
208 - list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] );
 257+ $source = $this->resolveToFSPath( $params['src'] );
209258 if ( $source === null ) {
210259 $status->fatal( 'backend-fail-invalidpath', $params['src'] );
211260 return $status;
@@ -234,7 +283,7 @@
235284 protected function doCreateInternal( array $params ) {
236285 $status = Status::newGood();
237286
238 - list( $c, $dest ) = $this->resolveStoragePathReal( $params['dst'] );
 287+ $dest = $this->resolveToFSPath( $params['dst'] );
239288 if ( $dest === null ) {
240289 $status->fatal( 'backend-fail-invalidpath', $params['dst'] );
241290 return $status;
@@ -276,8 +325,11 @@
277326 /**
278327 * @see FileBackend::doPrepareInternal()
279328 */
280 - protected function doPrepareInternal( $container, $dir, array $params ) {
 329+ protected function doPrepareInternal( $fullCont, $dirRel, array $params ) {
281330 $status = Status::newGood();
 331+ list( $b, $shortCont, $r ) = FileBackend::splitStoragePath( $params['dir'] );
 332+ $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
 333+ $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
282334 if ( !wfMkdirParents( $dir ) ) {
283335 $status->fatal( 'directorycreateerror', $params['dir'] );
284336 } elseif ( !is_writable( $dir ) ) {
@@ -291,8 +343,11 @@
292344 /**
293345 * @see FileBackend::doSecureInternal()
294346 */
295 - protected function doSecureInternal( $container, $dir, array $params ) {
 347+ protected function doSecureInternal( $fullCont, $dirRel, array $params ) {
296348 $status = Status::newGood();
 349+ list( $b, $shortCont, $r ) = FileBackend::splitStoragePath( $params['dir'] );
 350+ $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
 351+ $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
297352 if ( !wfMkdirParents( $dir ) ) {
298353 $status->fatal( 'directorycreateerror', $params['dir'] );
299354 return $status;
@@ -309,14 +364,13 @@
310365 }
311366 // Add a .htaccess file to the root of the container...
312367 if ( !empty( $params['noAccess'] ) ) {
313 - list( $b, $container, $r ) = FileBackend::splitStoragePath( $params['dir'] );
314 - $dirRoot = $this->containerPaths[$container]; // real path
 368+ $dirRoot = $this->resolveToFSPath( $params['dir'], '' );
315369 if ( !file_exists( "{$dirRoot}/.htaccess" ) ) {
316370 wfSuppressWarnings();
317371 $ok = file_put_contents( "{$dirRoot}/.htaccess", "Deny from all\n" );
318372 wfRestoreWarnings();
319373 if ( !$ok ) {
320 - $storeDir = "mwstore://{$this->name}/{$container}";
 374+ $storeDir = "mwstore://{$this->name}/{$shortCont}";
321375 $status->fatal( 'backend-fail-create', "$storeDir/.htaccess" );
322376 return $status;
323377 }
@@ -328,8 +382,11 @@
329383 /**
330384 * @see FileBackend::doCleanInternal()
331385 */
332 - protected function doCleanInternal( $container, $dir, array $params ) {
 386+ protected function doCleanInternal( $fullCont, $dirRel, array $params ) {
333387 $status = Status::newGood();
 388+ list( $b, $shortCont, $r ) = FileBackend::splitStoragePath( $params['dir'] );
 389+ $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
 390+ $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
334391 wfSuppressWarnings();
335392 if ( is_dir( $dir ) ) {
336393 rmdir( $dir ); // remove directory if empty
@@ -342,17 +399,13 @@
343400 * @see FileBackend::doFileExists()
344401 */
345402 protected function doGetFileStat( array $params ) {
346 - list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] );
 403+ $source = $this->resolveToFSPath( $params['src'] );
347404 if ( $source === null ) {
348405 return false; // invalid storage path
349406 }
350407
351408 wfSuppressWarnings();
352 - if ( is_file( $source ) ) { // regular file?
353 - $stat = stat( $source );
354 - } else {
355 - $stat = false;
356 - }
 409+ $stat = is_file( $source ) ? stat( $source ) : false; // regular files only
357410 wfRestoreWarnings();
358411
359412 if ( $stat ) {
@@ -368,7 +421,10 @@
369422 /**
370423 * @see FileBackend::getFileListInternal()
371424 */
372 - public function getFileListInternal( $container, $dir, array $params ) {
 425+ public function getFileListInternal( $fullCont, $dirRel, array $params ) {
 426+ list( $b, $shortCont, $r ) = FileBackend::splitStoragePath( $params['dir'] );
 427+ $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid
 428+ $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot;
373429 wfSuppressWarnings();
374430 $exists = is_dir( $dir );
375431 wfRestoreWarnings();
@@ -388,7 +444,7 @@
389445 * @see FileBackend::getLocalReference()
390446 */
391447 public function getLocalReference( array $params ) {
392 - list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] );
 448+ $source = $this->resolveToFSPath( $params['src'] );
393449 if ( $source === null ) {
394450 return null;
395451 }
@@ -399,7 +455,7 @@
400456 * @see FileBackend::getLocalCopy()
401457 */
402458 public function getLocalCopy( array $params ) {
403 - list( $c, $source ) = $this->resolveStoragePathReal( $params['src'] );
 459+ $source = $this->resolveToFSPath( $params['src'] );
404460 if ( $source === null ) {
405461 return null;
406462 }
@@ -470,7 +526,8 @@
471527 public function current() {
472528 // Return only the relative path and normalize slashes to FileBackend-style
473529 // Make sure to use the realpath since the suffix is based upon that
474 - return str_replace( '\\', '/', substr( realpath($this->iter->current()), $this->suffixStart ) );
 530+ return str_replace( '\\', '/',
 531+ substr( realpath( $this->iter->current() ), $this->suffixStart ) );
475532 }
476533
477534 public function key() {

Follow-up revisions

RevisionCommit summaryAuthorDate
r108744* Fixed a bit of bogus code left in r108740...aaron19:20, 12 January 2012

Status & tagging log