Index: trunk/phase3/tests/phpunit/includes/filerepo/FileBackendTest.php |
— | — | @@ -72,6 +72,8 @@ |
73 | 73 | function doTestStore( $op, $source, $dest ) { |
74 | 74 | $backendName = $this->backendClass(); |
75 | 75 | |
| 76 | + $this->backend->prepare( array( 'dir' => dirname( $dest ) ) ); |
| 77 | + |
76 | 78 | file_put_contents( $source, "Unit test file" ); |
77 | 79 | $status = $this->backend->doOperation( $op ); |
78 | 80 | |
— | — | @@ -137,6 +139,9 @@ |
138 | 140 | function doTestCopy( $op, $source, $dest ) { |
139 | 141 | $backendName = $this->backendClass(); |
140 | 142 | |
| 143 | + $this->backend->prepare( array( 'dir' => dirname( $source ) ) ); |
| 144 | + $this->backend->prepare( array( 'dir' => dirname( $dest ) ) ); |
| 145 | + |
141 | 146 | $status = $this->backend->doOperation( |
142 | 147 | array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); |
143 | 148 | $this->assertEquals( true, $status->isOK(), |
— | — | @@ -207,6 +212,9 @@ |
208 | 213 | public function doTestMove( $op, $source, $dest ) { |
209 | 214 | $backendName = $this->backendClass(); |
210 | 215 | |
| 216 | + $this->backend->prepare( array( 'dir' => dirname( $source ) ) ); |
| 217 | + $this->backend->prepare( array( 'dir' => dirname( $dest ) ) ); |
| 218 | + |
211 | 219 | $status = $this->backend->doOperation( |
212 | 220 | array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); |
213 | 221 | $this->assertEquals( true, $status->isOK(), |
— | — | @@ -278,6 +286,8 @@ |
279 | 287 | public function doTestDelete( $op, $source, $withSource, $okStatus ) { |
280 | 288 | $backendName = $this->backendClass(); |
281 | 289 | |
| 290 | + $this->backend->prepare( array( 'dir' => dirname( $source ) ) ); |
| 291 | + |
282 | 292 | if ( $withSource ) { |
283 | 293 | $status = $this->backend->doOperation( |
284 | 294 | array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) ); |
— | — | @@ -359,6 +369,8 @@ |
360 | 370 | public function doTestCreate( $op, $dest, $alreadyExists, $okStatus, $newSize ) { |
361 | 371 | $backendName = $this->backendClass(); |
362 | 372 | |
| 373 | + $this->backend->prepare( array( 'dir' => dirname( $dest ) ) ); |
| 374 | + |
363 | 375 | $oldText = 'blah...blah...waahwaah'; |
364 | 376 | if ( $alreadyExists ) { |
365 | 377 | $status = $this->backend->doOperation( |
— | — | @@ -462,6 +474,7 @@ |
463 | 475 | // Create sources |
464 | 476 | $ops = array(); |
465 | 477 | foreach ( $srcs as $i => $source ) { |
| 478 | + $this->backend->prepare( array( 'dir' => dirname( $source ) ) ); |
466 | 479 | $ops[] = array( |
467 | 480 | 'op' => 'create', // operation |
468 | 481 | 'dst' => $source, // source |
— | — | @@ -585,20 +598,22 @@ |
586 | 599 | /** |
587 | 600 | * @dataProvider provider_testGetFileContents |
588 | 601 | */ |
589 | | - public function doTestGetFileContents( $src, $content ) { |
| 602 | + public function doTestGetFileContents( $source, $content ) { |
590 | 603 | $backendName = $this->backendClass(); |
591 | 604 | |
| 605 | + $this->backend->prepare( array( 'dir' => dirname( $source ) ) ); |
| 606 | + |
592 | 607 | $status = $this->backend->doOperation( |
593 | | - array( 'op' => 'create', 'content' => $content, 'dst' => $src ) ); |
| 608 | + array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); |
594 | 609 | $this->assertEquals( true, $status->isOK(), |
595 | | - "Creation of file at $src succeeded ($backendName)." ); |
| 610 | + "Creation of file at $source succeeded ($backendName)." ); |
596 | 611 | |
597 | | - $newContents = $this->backend->getFileContents( array( 'src' => $src ) ); |
| 612 | + $newContents = $this->backend->getFileContents( array( 'src' => $source ) ); |
598 | 613 | $this->assertNotEquals( false, $newContents, |
599 | | - "Read of file at $src succeeded ($backendName)." ); |
| 614 | + "Read of file at $source succeeded ($backendName)." ); |
600 | 615 | |
601 | 616 | $this->assertEquals( $content, $newContents, |
602 | | - "Contents read match data at $src ($backendName)." ); |
| 617 | + "Contents read match data at $source ($backendName)." ); |
603 | 618 | } |
604 | 619 | |
605 | 620 | function provider_testGetFileContents() { |
— | — | @@ -626,20 +641,22 @@ |
627 | 642 | $this->tearDownFiles(); |
628 | 643 | } |
629 | 644 | |
630 | | - public function doTestGetLocalCopy( $src, $content ) { |
| 645 | + public function doTestGetLocalCopy( $source, $content ) { |
631 | 646 | $backendName = $this->backendClass(); |
632 | 647 | |
| 648 | + $this->backend->prepare( array( 'dir' => dirname( $source ) ) ); |
| 649 | + |
633 | 650 | $status = $this->backend->doOperation( |
634 | | - array( 'op' => 'create', 'content' => $content, 'dst' => $src ) ); |
| 651 | + array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); |
635 | 652 | $this->assertEquals( true, $status->isOK(), |
636 | | - "Creation of file at $src succeeded ($backendName)." ); |
| 653 | + "Creation of file at $source succeeded ($backendName)." ); |
637 | 654 | |
638 | | - $tmpFile = $this->backend->getLocalCopy( array( 'src' => $src ) ); |
| 655 | + $tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) ); |
639 | 656 | $this->assertNotNull( $tmpFile, |
640 | | - "Creation of local copy of $src succeeded ($backendName)." ); |
| 657 | + "Creation of local copy of $source succeeded ($backendName)." ); |
641 | 658 | |
642 | 659 | $contents = file_get_contents( $tmpFile->getPath() ); |
643 | | - $this->assertNotEquals( false, $contents, "Local copy of $src exists ($backendName)." ); |
| 660 | + $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." ); |
644 | 661 | } |
645 | 662 | |
646 | 663 | function provider_testGetLocalCopy() { |
— | — | @@ -667,20 +684,22 @@ |
668 | 685 | $this->tearDownFiles(); |
669 | 686 | } |
670 | 687 | |
671 | | - public function doTestGetLocalReference( $src, $content ) { |
| 688 | + public function doTestGetLocalReference( $source, $content ) { |
672 | 689 | $backendName = $this->backendClass(); |
673 | 690 | |
| 691 | + $this->backend->prepare( array( 'dir' => dirname( $source ) ) ); |
| 692 | + |
674 | 693 | $status = $this->backend->doOperation( |
675 | | - array( 'op' => 'create', 'content' => $content, 'dst' => $src ) ); |
| 694 | + array( 'op' => 'create', 'content' => $content, 'dst' => $source ) ); |
676 | 695 | $this->assertEquals( true, $status->isOK(), |
677 | | - "Creation of file at $src succeeded ($backendName)." ); |
| 696 | + "Creation of file at $source succeeded ($backendName)." ); |
678 | 697 | |
679 | | - $tmpFile = $this->backend->getLocalReference( array( 'src' => $src ) ); |
| 698 | + $tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) ); |
680 | 699 | $this->assertNotNull( $tmpFile, |
681 | | - "Creation of local copy of $src succeeded ($backendName)." ); |
| 700 | + "Creation of local copy of $source succeeded ($backendName)." ); |
682 | 701 | |
683 | 702 | $contents = file_get_contents( $tmpFile->getPath() ); |
684 | | - $this->assertNotEquals( false, $contents, "Local copy of $src exists ($backendName)." ); |
| 703 | + $this->assertNotEquals( false, $contents, "Local copy of $source exists ($backendName)." ); |
685 | 704 | } |
686 | 705 | |
687 | 706 | function provider_testGetLocalReference() { |
— | — | @@ -779,6 +798,7 @@ |
780 | 799 | $ops = array(); |
781 | 800 | foreach ( $files as $file ) { |
782 | 801 | $ops[] = array( 'op' => 'create', 'content' => 'xxy', 'dst' => $file ); |
| 802 | + $this->backend->prepare( array( 'dir' => dirname( $file ) ) ); |
783 | 803 | } |
784 | 804 | $status = $this->backend->doOperations( $ops ); |
785 | 805 | $this->assertEquals( true, $status->isOK(), |
Index: trunk/phase3/includes/filerepo/backend/FileBackendMultiWrite.php |
— | — | @@ -18,6 +18,7 @@ |
19 | 19 | * If an operation fails on one backend it will be rolled back from the others. |
20 | 20 | * |
21 | 21 | * @ingroup FileBackend |
| 22 | + * @since 1.19 |
22 | 23 | */ |
23 | 24 | class FileBackendMultiWrite extends FileBackendBase { |
24 | 25 | /** @var Array Prioritized list of FileBackend objects */ |
Index: trunk/phase3/includes/filerepo/backend/lockmanager/LockManagerGroup.php |
— | — | @@ -4,6 +4,7 @@ |
5 | 5 | * |
6 | 6 | * @ingroup LockManager |
7 | 7 | * @author Aaron Schulz |
| 8 | + * @since 1.19 |
8 | 9 | */ |
9 | 10 | class LockManagerGroup { |
10 | 11 | protected static $instance = null; |
Index: trunk/phase3/includes/filerepo/backend/lockmanager/LSLockManager.php |
— | — | @@ -11,6 +11,7 @@ |
12 | 12 | * A majority of peers must agree for a lock to be acquired. |
13 | 13 | * |
14 | 14 | * @ingroup LockManager |
| 15 | + * @since 1.19 |
15 | 16 | */ |
16 | 17 | class LSLockManager extends LockManager { |
17 | 18 | /** @var Array Mapping of lock types to the type actually used */ |
Index: trunk/phase3/includes/filerepo/backend/lockmanager/LockManager.php |
— | — | @@ -161,6 +161,7 @@ |
162 | 162 | |
163 | 163 | /** |
164 | 164 | * Simple version of LockManager that does nothing |
| 165 | + * @since 1.19 |
165 | 166 | */ |
166 | 167 | class NullLockManager extends LockManager { |
167 | 168 | protected function doLock( array $paths, $type ) { |
Index: trunk/phase3/includes/filerepo/backend/lockmanager/DBLockManager.php |
— | — | @@ -14,6 +14,7 @@ |
15 | 15 | * Caching is used to avoid hitting servers that are down. |
16 | 16 | * |
17 | 17 | * @ingroup LockManager |
| 18 | + * @since 1.19 |
18 | 19 | */ |
19 | 20 | class DBLockManager extends LockManager { |
20 | 21 | /** @var Array Map of DB names to server config */ |
Index: trunk/phase3/includes/filerepo/backend/lockmanager/FSLockManager.php |
— | — | @@ -10,6 +10,7 @@ |
11 | 11 | * locks will be ignored; see http://nfs.sourceforge.net/#section_d. |
12 | 12 | * |
13 | 13 | * @ingroup LockManager |
| 14 | + * @since 1.19 |
14 | 15 | */ |
15 | 16 | class FSLockManager extends LockManager { |
16 | 17 | /** @var Array Mapping of lock types to the type actually used */ |
Index: trunk/phase3/includes/filerepo/backend/FileOp.php |
— | — | @@ -8,8 +8,9 @@ |
9 | 9 | /** |
10 | 10 | * Helper class for representing operations with transaction support. |
11 | 11 | * FileBackend::doOperations() will require these classes for supported operations. |
| 12 | + * Do not use this class from places outside FileBackend. |
12 | 13 | * |
13 | | - * Use of large fields should be avoided as we want to be able to support |
| 14 | + * Use of large fields should be avoided as we want to support |
14 | 15 | * potentially many FileOp classes in large arrays in memory. |
15 | 16 | * |
16 | 17 | * @ingroup FileBackend |
Index: trunk/phase3/includes/filerepo/backend/FSFileBackend.php |
— | — | @@ -19,6 +19,7 @@ |
20 | 20 | * Likewise, error suppression should be used to avoid path disclosure. |
21 | 21 | * |
22 | 22 | * @ingroup FileBackend |
| 23 | + * @since 1.19 |
23 | 24 | */ |
24 | 25 | class FSFileBackend extends FileBackend { |
25 | 26 | protected $basePath; // string; directory holding the container directories |
— | — | @@ -125,18 +126,13 @@ |
126 | 127 | $status->fatal( 'backend-fail-alreadyexists', $params['dst'] ); |
127 | 128 | return $status; |
128 | 129 | } |
129 | | - } else { |
130 | | - if ( !wfMkdirParents( dirname( $dest ) ) ) { |
131 | | - $status->fatal( 'directorycreateerror', $params['dst'] ); |
132 | | - return $status; |
133 | | - } |
134 | 130 | } |
135 | 131 | |
136 | 132 | wfSuppressWarnings(); |
137 | 133 | $ok = copy( $params['src'], $dest ); |
138 | 134 | wfRestoreWarnings(); |
139 | 135 | if ( !$ok ) { |
140 | | - $status->fatal( 'backend-fail-copy', $params['src'], $params['dst'] ); |
| 136 | + $status->fatal( 'backend-fail-store', $params['src'], $params['dst'] ); |
141 | 137 | return $status; |
142 | 138 | } |
143 | 139 | |
— | — | @@ -176,11 +172,6 @@ |
177 | 173 | $status->fatal( 'backend-fail-alreadyexists', $params['dst'] ); |
178 | 174 | return $status; |
179 | 175 | } |
180 | | - } else { |
181 | | - if ( !wfMkdirParents( dirname( $dest ) ) ) { |
182 | | - $status->fatal( 'directorycreateerror', $params['dst'] ); |
183 | | - return $status; |
184 | | - } |
185 | 176 | } |
186 | 177 | |
187 | 178 | wfSuppressWarnings(); |
— | — | @@ -230,11 +221,6 @@ |
231 | 222 | $status->fatal( 'backend-fail-alreadyexists', $params['dst'] ); |
232 | 223 | return $status; |
233 | 224 | } |
234 | | - } else { |
235 | | - if ( !wfMkdirParents( dirname( $dest ) ) ) { |
236 | | - $status->fatal( 'directorycreateerror', $params['dst'] ); |
237 | | - return $status; |
238 | | - } |
239 | 225 | } |
240 | 226 | |
241 | 227 | wfSuppressWarnings(); |
— | — | @@ -304,11 +290,6 @@ |
305 | 291 | $status->fatal( 'backend-fail-alreadyexists', $params['dst'] ); |
306 | 292 | return $status; |
307 | 293 | } |
308 | | - } else { |
309 | | - if ( !wfMkdirParents( dirname( $dest ) ) ) { |
310 | | - $status->fatal( 'directorycreateerror', $params['dst'] ); |
311 | | - return $status; |
312 | | - } |
313 | 294 | } |
314 | 295 | |
315 | 296 | wfSuppressWarnings(); |
— | — | @@ -332,7 +313,7 @@ |
333 | 314 | list( $b, $shortCont, $r ) = FileBackend::splitStoragePath( $params['dir'] ); |
334 | 315 | $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid |
335 | 316 | $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot; |
336 | | - if ( !wfMkdirParents( $dir ) ) { |
| 317 | + if ( !wfMkdirParents( $dir ) ) { // make directory and its parents |
337 | 318 | $status->fatal( 'directorycreateerror', $params['dir'] ); |
338 | 319 | } elseif ( !is_writable( $dir ) ) { |
339 | 320 | $status->fatal( 'directoryreadonlyerror', $params['dir'] ); |
— | — | @@ -350,10 +331,6 @@ |
351 | 332 | list( $b, $shortCont, $r ) = FileBackend::splitStoragePath( $params['dir'] ); |
352 | 333 | $contRoot = $this->containerFSRoot( $shortCont, $fullCont ); // must be valid |
353 | 334 | $dir = ( $dirRel != '' ) ? "{$contRoot}/{$dirRel}" : $contRoot; |
354 | | - if ( !wfMkdirParents( $dir ) ) { |
355 | | - $status->fatal( 'directorycreateerror', $params['dir'] ); |
356 | | - return $status; |
357 | | - } |
358 | 335 | // Seed new directories with a blank index.html, to prevent crawling... |
359 | 336 | if ( !empty( $params['noListing'] ) && !file_exists( "{$dir}/index.html" ) ) { |
360 | 337 | wfSuppressWarnings(); |
— | — | @@ -527,6 +504,7 @@ |
528 | 505 | /** |
529 | 506 | * Wrapper around RecursiveDirectoryIterator that catches |
530 | 507 | * exception or does any custom behavoir that we may want. |
| 508 | + * Do not use this class from places outside FSFileBackend. |
531 | 509 | * |
532 | 510 | * @ingroup FileBackend |
533 | 511 | */ |
Index: trunk/phase3/includes/filerepo/backend/FileBackendGroup.php |
— | — | @@ -9,6 +9,7 @@ |
10 | 10 | * Class to handle file backend registration |
11 | 11 | * |
12 | 12 | * @ingroup FileBackend |
| 13 | + * @since 1.19 |
13 | 14 | */ |
14 | 15 | class FileBackendGroup { |
15 | 16 | protected static $instance = null; |
Index: trunk/phase3/includes/filerepo/backend/FileBackend.php |
— | — | @@ -323,7 +323,11 @@ |
324 | 324 | if ( $this->readOnly != '' ) { |
325 | 325 | return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly ); |
326 | 326 | } |
327 | | - return $this->doSecure( $params ); |
| 327 | + $status = $this->doPrepare( $params ); // dir must exist to restrict it |
| 328 | + if ( $status->isOK() ) { |
| 329 | + $status->merge( $this->doSecure( $params ) ); |
| 330 | + } |
| 331 | + return $status; |
328 | 332 | } |
329 | 333 | |
330 | 334 | /** |