Index: branches/FileBackend/phase3/includes/upload/UploadStash.php |
— | — | @@ -233,7 +233,7 @@ |
234 | 234 | 'us_user' => $this->userId, |
235 | 235 | 'us_key' => $key, |
236 | 236 | 'us_orig_path' => $path, |
237 | | - 'us_path' => $stashPath, |
| 237 | + 'us_path' => $stashPath, // virtual URL |
238 | 238 | 'us_size' => $fileProps['size'], |
239 | 239 | 'us_sha1' => $fileProps['sha1'], |
240 | 240 | 'us_mime' => $fileProps['mime'], |
Index: branches/FileBackend/phase3/includes/GlobalFunctions.php |
— | — | @@ -2387,6 +2387,11 @@ |
2388 | 2388 | wfDebug( "$caller: called wfMkdirParents($dir)\n" ); |
2389 | 2389 | } |
2390 | 2390 | |
| 2391 | + if ( FileBackend::isStoragePath( $dir ) ) { |
| 2392 | + throw new MWException( "Given virtual path `$dir`." ); |
| 2393 | + return false; |
| 2394 | + } |
| 2395 | + |
2391 | 2396 | if( strval( $dir ) === '' || file_exists( $dir ) ) { |
2392 | 2397 | return true; |
2393 | 2398 | } |
Index: branches/FileBackend/phase3/includes/filerepo/file/LocalFile.php |
— | — | @@ -881,7 +881,7 @@ |
882 | 882 | |
883 | 883 | /** |
884 | 884 | * Upload a file and record it in the DB |
885 | | - * @param $srcPath String: source path or virtual URL |
| 885 | + * @param $srcPath String: source storage path or virtual URL |
886 | 886 | * @param $comment String: upload description |
887 | 887 | * @param $pageText String: text to use for the new description page, |
888 | 888 | * if a new description page is created |
— | — | @@ -1003,6 +1003,7 @@ |
1004 | 1004 | if ( $dbw->affectedRows() == 0 ) { |
1005 | 1005 | $reupload = true; |
1006 | 1006 | |
| 1007 | + #if ( !$oldver ) wfDebugDieBacktrace(); |
1007 | 1008 | # Collision, this is an update of a file |
1008 | 1009 | # Insert previous contents into oldimage |
1009 | 1010 | $dbw->insertSelect( 'oldimage', 'image', |
Index: branches/FileBackend/phase3/includes/filerepo/file/UnregisteredLocalFile.php |
— | — | @@ -27,8 +27,8 @@ |
28 | 28 | var $handler; |
29 | 29 | |
30 | 30 | /** |
31 | | - * @param $path |
32 | | - * @param $mime |
| 31 | + * @param $path string Storage path |
| 32 | + * @param $mime string |
33 | 33 | * @return UnregisteredLocalFile |
34 | 34 | */ |
35 | 35 | static function newFromPath( $path, $mime ) { |
— | — | @@ -135,10 +135,11 @@ |
136 | 136 | } |
137 | 137 | |
138 | 138 | function getSize() { |
139 | | - if ( file_exists( $this->path ) ) { |
140 | | - return filesize( $this->path ); |
141 | | - } else { |
142 | | - return false; |
| 139 | + $this->assertRepoDefined(); |
| 140 | + $props = $this->repo->getFileProps( $this->path ); |
| 141 | + if ( isset( $props['size'] ) ) { |
| 142 | + return $props['size']; |
143 | 143 | } |
| 144 | + return false; // doesn't exist |
144 | 145 | } |
145 | 146 | } |
Index: branches/FileBackend/phase3/includes/filerepo/file/TempFSFile.php |
— | — | @@ -15,6 +15,9 @@ |
16 | 16 | class TempFSFile extends FSFile { |
17 | 17 | protected $canDelete = true; // garbage collect the temp file |
18 | 18 | |
| 19 | + /** @var Array of active temp files to purge on shutdown */ |
| 20 | + protected static $instances = array(); |
| 21 | + |
19 | 22 | /** |
20 | 23 | * Make a new temporary file on the file system |
21 | 24 | * |
— | — | @@ -35,7 +38,10 @@ |
36 | 39 | } else { |
37 | 40 | $path = $tmpDest; |
38 | 41 | } |
39 | | - return new self( $path ); |
| 42 | + $tmpFile = new self( $path ); |
| 43 | + self::$instances[] = $tmpFile; |
| 44 | + |
| 45 | + return $tmpFile; |
40 | 46 | } |
41 | 47 | |
42 | 48 | /** |
— | — | @@ -48,8 +54,8 @@ |
49 | 55 | } |
50 | 56 | |
51 | 57 | /** |
52 | | - * Cleans up after the temporary file. |
53 | | - * Currently this means removing it from the local disk. |
| 58 | + * Cleans up after the temporary file by deleting it. |
| 59 | + * This is done on shutdown after PHP kills self::$instances. |
54 | 60 | */ |
55 | 61 | function __destruct() { |
56 | 62 | if ( $this->canDelete ) { |
Index: branches/FileBackend/phase3/includes/filerepo/file/File.php |
— | — | @@ -118,6 +118,7 @@ |
119 | 119 | /** |
120 | 120 | * Given a string or Title object return either a |
121 | 121 | * valid Title object with namespace NS_FILE or null |
| 122 | + * |
122 | 123 | * @param $title Title|string |
123 | 124 | * @param $exception string|false Use 'exception' to throw an error on bad titles |
124 | 125 | * @return Title|null |
— | — | @@ -243,6 +244,7 @@ |
244 | 245 | |
245 | 246 | /** |
246 | 247 | * Return the associated title object |
| 248 | + * |
247 | 249 | * @return Title|false |
248 | 250 | */ |
249 | 251 | public function getTitle() { |
— | — | @@ -850,6 +852,7 @@ |
851 | 853 | |
852 | 854 | /** |
853 | 855 | * Get a MediaHandler instance for this file |
| 856 | + * |
854 | 857 | * @return MediaHandler |
855 | 858 | */ |
856 | 859 | function getHandler() { |
— | — | @@ -861,6 +864,7 @@ |
862 | 865 | |
863 | 866 | /** |
864 | 867 | * Get a ThumbnailImage representing a file type icon |
| 868 | + * |
865 | 869 | * @return ThumbnailImage |
866 | 870 | */ |
867 | 871 | function iconThumb() { |
Index: branches/FileBackend/phase3/includes/filerepo/file/FSFile.php |
— | — | @@ -113,8 +113,14 @@ |
114 | 114 | return $info; |
115 | 115 | } |
116 | 116 | |
| 117 | + /** |
| 118 | + * Placeholder file properties to use for files that don't exist |
| 119 | + * |
| 120 | + * @return Array |
| 121 | + */ |
117 | 122 | public static function placeholderProps() { |
118 | 123 | $info = array(); |
| 124 | + $info['fileExists'] = false; |
119 | 125 | $info['mime'] = null; |
120 | 126 | $info['media_type'] = MEDIATYPE_UNKNOWN; |
121 | 127 | $info['metadata'] = ''; |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FileBackendMultiWrite.php |
— | — | @@ -6,15 +6,15 @@ |
7 | 7 | */ |
8 | 8 | |
9 | 9 | /** |
10 | | - * This class defines a multi-write backend. Multiple backends can |
11 | | - * be registered to this proxy backend it will act as a single backend. |
12 | | - * Use this when all access to the backends is through this proxy backend. |
| 10 | + * This class defines a multi-write backend. Multiple backends can be |
| 11 | + * registered to this proxy backend and it will act as a single backend. |
| 12 | + * Use this when all access to those backends is through this proxy backend. |
13 | 13 | * At least one of the backends must be declared the "master" backend. |
14 | 14 | * |
15 | 15 | * The order that the backends are defined sets the priority of which |
16 | 16 | * backend is read from or written to first. Functions like fileExists() |
17 | 17 | * and getFileProps() will return information based on the first backend |
18 | | - * that has the file (normally both should have it anyway). Special cases: |
| 18 | + * that has the file. Special cases are listed below: |
19 | 19 | * a) getFileList() will return results from the first backend that is |
20 | 20 | * not declared as non-persistent cache. This is for correctness. |
21 | 21 | * b) getFileTimestamp() will always check only the master backend to |
— | — | @@ -25,6 +25,8 @@ |
26 | 26 | * All write operations are performed on all backends. |
27 | 27 | * If an operation fails on one backend it will be rolled back from the others. |
28 | 28 | * |
| 29 | + * Non-persistent backends used for caching must be declared. |
| 30 | + * |
29 | 31 | * @ingroup FileRepo |
30 | 32 | * @ingroup FileBackend |
31 | 33 | */ |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FileOp.php |
— | — | @@ -16,6 +16,8 @@ |
17 | 17 | protected $params; |
18 | 18 | /** $var FileBackendBase */ |
19 | 19 | protected $backend; |
| 20 | + /** @var TempLocalFile|null */ |
| 21 | + protected $tmpSourceFile, $tmpDestFile; |
20 | 22 | |
21 | 23 | protected $state; |
22 | 24 | protected $failed; |
— | — | @@ -145,6 +147,31 @@ |
146 | 148 | * @return Status |
147 | 149 | */ |
148 | 150 | abstract protected function doFinish(); |
| 151 | + |
| 152 | + /** |
| 153 | + * Backup any file at the source to a temporary file |
| 154 | + * |
| 155 | + * @return Status |
| 156 | + */ |
| 157 | + protected function backupSource() { |
| 158 | + $status = Status::newGood(); |
| 159 | + // Check if a file already exists at the source... |
| 160 | + $params = array( 'source' => $this->params['source'] ); |
| 161 | + if ( $this->backend->fileExists( $params ) ) { |
| 162 | + // Create a temporary backup copy... |
| 163 | + $this->tmpSourcePath = $this->backend->getLocalCopy( $params ); |
| 164 | + if ( $this->tmpSourcePath === null ) { |
| 165 | + $status->fatal( 'backend-fail-backup', $this->params['source'] ); |
| 166 | + return $status; |
| 167 | + } |
| 168 | + } else { |
| 169 | + if ( empty( $this->params['ignoreMissingSource'] ) ) { |
| 170 | + $status->fatal( 'backend-fail-notexists', $this->params['source'] ); |
| 171 | + return $status; |
| 172 | + } |
| 173 | + } |
| 174 | + return $status; |
| 175 | + } |
149 | 176 | |
150 | 177 | /** |
151 | 178 | * Backup any file at the destination to a temporary file. |
— | — | @@ -164,7 +191,7 @@ |
165 | 192 | |
166 | 193 | if ( !empty( $this->params['overwriteDest'] ) ) { |
167 | 194 | // Create a temporary backup copy... |
168 | | - $this->tmpDestFile = $this->getLocalCopy( $this->params['dest'] ); |
| 195 | + $this->tmpDestFile = $this->backend->getLocalCopy( $params ); |
169 | 196 | if ( !$this->tmpDestFile ) { |
170 | 197 | $status->fatal( 'backend-fail-backup', $this->params['dest'] ); |
171 | 198 | return $status; |
— | — | @@ -217,7 +244,7 @@ |
218 | 245 | if ( $this->backend->getHashType() === 'md5' ) { |
219 | 246 | $hash = $this->backend->getFileHash( $path ); |
220 | 247 | } else { |
221 | | - $tmp = $this->getLocalCopy( $path ); |
| 248 | + $tmp = $this->backend->getLocalCopy( array( 'source' => $path ) ); |
222 | 249 | if ( !$tmp ) { |
223 | 250 | return false; // error |
224 | 251 | } |
— | — | @@ -231,6 +258,27 @@ |
232 | 259 | } |
233 | 260 | |
234 | 261 | /** |
| 262 | + * Restore any temporary source backup file |
| 263 | + * |
| 264 | + * @return Status |
| 265 | + */ |
| 266 | + protected function restoreSource() { |
| 267 | + $status = Status::newGood(); |
| 268 | + // Restore any file that was at the destination |
| 269 | + if ( $this->tmpSourcePath !== null ) { |
| 270 | + $params = array( |
| 271 | + 'source' => $this->tmpSourcePath, |
| 272 | + 'dest' => $this->params['source'] |
| 273 | + ); |
| 274 | + $status = $this->backend->store( $params ); |
| 275 | + if ( !$status->isOK() ) { |
| 276 | + return $status; |
| 277 | + } |
| 278 | + } |
| 279 | + return $status; |
| 280 | + } |
| 281 | + |
| 282 | + /** |
235 | 283 | * Restore any temporary destination backup file |
236 | 284 | * |
237 | 285 | * @return Status |
— | — | @@ -261,9 +309,6 @@ |
262 | 310 | * overwriteSame : override any existing file at destination |
263 | 311 | */ |
264 | 312 | class StoreFileOp extends FileOp { |
265 | | - /** @var TempLocalFile|null */ |
266 | | - protected $tmpDestFile; // temp copy of existing destination file |
267 | | - |
268 | 313 | protected function doPrecheck() { |
269 | 314 | $status = Status::newGood(); |
270 | 315 | // Check if the source files exists on disk (FS) |
— | — | @@ -278,8 +323,7 @@ |
279 | 324 | |
280 | 325 | protected function doAttempt() { |
281 | 326 | // Store the file at the destination |
282 | | - $status = $this->backend->store( $this->params ); |
283 | | - return $status; |
| 327 | + return $this->backend->store( $this->params ); |
284 | 328 | } |
285 | 329 | |
286 | 330 | protected function doRevert() { |
— | — | @@ -290,7 +334,7 @@ |
291 | 335 | return $status; // also can't restore any dest file |
292 | 336 | } |
293 | 337 | // Restore any file that was at the destination |
294 | | - $status = $this->restoreDest(); |
| 338 | + $status->merge( $this->restoreDest() ); |
295 | 339 | return $status; |
296 | 340 | } |
297 | 341 | |
— | — | @@ -318,14 +362,12 @@ |
319 | 363 | class CreateFileOp extends FileOp { |
320 | 364 | protected function doPrecheck() { |
321 | 365 | // Create a destination backup copy as needed |
322 | | - $status = $this->checkAndBackupDest(); |
323 | | - return $status; |
| 366 | + return $this->checkAndBackupDest(); |
324 | 367 | } |
325 | 368 | |
326 | 369 | protected function doAttempt() { |
327 | 370 | // Create the file at the destination |
328 | | - $status = $this->backend->create( $this->params ); |
329 | | - return $status; |
| 371 | + return $this->backend->create( $this->params ); |
330 | 372 | } |
331 | 373 | |
332 | 374 | protected function doRevert() { |
— | — | @@ -336,7 +378,7 @@ |
337 | 379 | return $status; // also can't restore any dest file |
338 | 380 | } |
339 | 381 | // Restore any file that was at the destination |
340 | | - $status = $this->restoreDest(); |
| 382 | + $status->merge( $this->restoreDest() ); |
341 | 383 | return $status; |
342 | 384 | } |
343 | 385 | |
— | — | @@ -377,8 +419,7 @@ |
378 | 420 | |
379 | 421 | protected function doAttempt() { |
380 | 422 | // Copy the file into the destination |
381 | | - $status = $this->backend->copy( $this->params ); |
382 | | - return $status; |
| 423 | + return $this->backend->copy( $this->params ); |
383 | 424 | } |
384 | 425 | |
385 | 426 | protected function doRevert() { |
— | — | @@ -389,7 +430,7 @@ |
390 | 431 | return $status; // also can't restore any dest file |
391 | 432 | } |
392 | 433 | // Restore any file that was at the destination |
393 | | - $status = $this->restoreDest(); |
| 434 | + $status->merge( $this->restoreDest() ); |
394 | 435 | return $status; |
395 | 436 | } |
396 | 437 | |
— | — | @@ -432,6 +473,9 @@ |
433 | 474 | } |
434 | 475 | // Create a destination backup copy as needed |
435 | 476 | $status->merge( $this->checkAndBackupDest() ); |
| 477 | + if ( !$status->isOK() ) { |
| 478 | + return $status; |
| 479 | + } |
436 | 480 | return $status; |
437 | 481 | } |
438 | 482 | |
— | — | @@ -439,9 +483,19 @@ |
440 | 484 | // Native moves: move the file into the destination |
441 | 485 | if ( $this->usingMove ) { |
442 | 486 | $status = $this->backend->move( $this->params ); |
443 | | - // Non-native moves: copy the file into the destination |
| 487 | + // Non-native moves: copy the file into the destination & delete source |
444 | 488 | } else { |
| 489 | + // Copy source to dest |
445 | 490 | $status = $this->backend->copy( $this->params ); |
| 491 | + if ( !$status->isOK() ) { |
| 492 | + return $status; |
| 493 | + } |
| 494 | + // Delete source |
| 495 | + $params = array( 'source' => $this->params['source'] ); |
| 496 | + $status = $this->backend->delete( $params ); |
| 497 | + if ( !$status->isOK() ) { |
| 498 | + return $status; |
| 499 | + } |
446 | 500 | } |
447 | 501 | return $status; |
448 | 502 | } |
— | — | @@ -459,6 +513,13 @@ |
460 | 514 | } |
461 | 515 | // Non-native moves: remove the file saved to the destination |
462 | 516 | } else { |
| 517 | + // Copy destination back to source |
| 518 | + $params = array( 'source' => $this->params['dest'], 'dest' => $this->params['source'] ); |
| 519 | + $status = $this->backend->copy( $params ); |
| 520 | + if ( !$status->isOK() ) { |
| 521 | + return $status; // also can't restore any dest file |
| 522 | + } |
| 523 | + // Delete destination |
463 | 524 | $params = array( 'source' => $this->params['dest'] ); |
464 | 525 | $status = $this->backend->delete( $params ); |
465 | 526 | if ( !$status->isOK() ) { |
— | — | @@ -466,20 +527,12 @@ |
467 | 528 | } |
468 | 529 | } |
469 | 530 | // Restore any file that was at the destination |
470 | | - $status = $this->restoreDest(); |
| 531 | + $status->merge( $this->restoreDest() ); |
471 | 532 | return $status; |
472 | 533 | } |
473 | 534 | |
474 | 535 | protected function doFinish() { |
475 | | - // Native moves: nothing is at the source anymore |
476 | | - if ( $this->usingMove ) { |
477 | | - $status = Status::newGood(); |
478 | | - // Non-native moves: delete the source file |
479 | | - } else { |
480 | | - $params = array( 'source' => $this->params['source'] ); |
481 | | - $status = $this->backend->delete( $params ); |
482 | | - } |
483 | | - return $status; |
| 536 | + return Status::newGood(); |
484 | 537 | } |
485 | 538 | |
486 | 539 | protected function getSourceMD5() { |
— | — | @@ -502,14 +555,12 @@ |
503 | 556 | class ConcatenateFileOp extends FileOp { |
504 | 557 | protected function doPrecheck() { |
505 | 558 | // Create a destination backup copy as needed |
506 | | - $status = $this->checkAndBackupDest(); |
507 | | - return $status; |
| 559 | + return $this->checkAndBackupDest(); |
508 | 560 | } |
509 | 561 | |
510 | 562 | protected function doAttempt() { |
511 | 563 | // Concatenate the file at the destination |
512 | | - $status = $this->backend->concatenate( $this->params ); |
513 | | - return $status; |
| 564 | + return $this->backend->concatenate( $this->params ); |
514 | 565 | } |
515 | 566 | |
516 | 567 | protected function doRevert() { |
— | — | @@ -520,7 +571,7 @@ |
521 | 572 | return $status; // also can't restore any dest file |
522 | 573 | } |
523 | 574 | // Restore any file that was at the destination |
524 | | - $status = $this->restoreDest(); |
| 575 | + $status->merge( $this->restoreDest() ); |
525 | 576 | return $status; |
526 | 577 | } |
527 | 578 | |
— | — | @@ -546,28 +597,28 @@ |
547 | 598 | class DeleteFileOp extends FileOp { |
548 | 599 | protected function doPrecheck() { |
549 | 600 | $status = Status::newGood(); |
550 | | - if ( empty( $this->params['ignoreMissingSource'] ) ) { |
551 | | - $params = array( 'source' => $this->params['source'] ); |
552 | | - if ( !$this->backend->fileExists( $params ) ) { |
553 | | - $status->fatal( 'backend-fail-notexists', $this->params['source'] ); |
554 | | - return $status; |
555 | | - } |
| 601 | + $params = array( 'source' => $this->params['source'] ); |
| 602 | + if ( $this->backend->fileExists( $params ) ) { |
| 603 | + // Create a source backup copy as needed |
| 604 | + $status->merge( $this->backupSource() ); |
| 605 | + } elseif ( empty( $this->params['ignoreMissingSource'] ) ) { |
| 606 | + $status->fatal( 'backend-fail-notexists', $this->params['source'] ); |
556 | 607 | } |
557 | 608 | return $status; |
558 | 609 | } |
559 | 610 | |
560 | 611 | protected function doAttempt() { |
561 | | - return Status::newGood(); |
| 612 | + // Delete the source file |
| 613 | + return $this->backend->delete( $this->params ); |
562 | 614 | } |
563 | 615 | |
564 | 616 | protected function doRevert() { |
565 | | - return Status::newGood(); |
| 617 | + // Restore any source file |
| 618 | + return $this->restoreSource(); |
566 | 619 | } |
567 | 620 | |
568 | 621 | protected function doFinish() { |
569 | | - // Delete the source file |
570 | | - $status = $this->backend->delete( $this->params ); |
571 | | - return $status; |
| 622 | + return Status::newGood(); |
572 | 623 | } |
573 | 624 | |
574 | 625 | function storagePathsUsed() { |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FSFileBackend.php |
— | — | @@ -76,6 +76,15 @@ |
77 | 77 | } |
78 | 78 | |
79 | 79 | function copy( array $params ) { |
| 80 | + $status = Status::newGood(); |
| 81 | + |
| 82 | + list( $c, $source ) = $this->resolveStoragePath( $params['source'] ); |
| 83 | + if ( $source === null ) { |
| 84 | + $status->fatal( 'backend-fail-invalidpath', $params['source'] ); |
| 85 | + return $status; |
| 86 | + } |
| 87 | + $params['source'] = $source; // resolve source to FS path |
| 88 | + |
80 | 89 | return $this->store( $params ); // both source and dest are on FS |
81 | 90 | } |
82 | 91 | |
Index: branches/FileBackend/phase3/includes/filerepo/backend/LockManager.php |
— | — | @@ -287,7 +287,7 @@ |
288 | 288 | * |
289 | 289 | * @param Array $config |
290 | 290 | */ |
291 | | - function __construct( array $config ) { |
| 291 | + public function __construct( array $config ) { |
292 | 292 | // Sanitize dbsByBucket config to prevent PHP errors |
293 | 293 | $this->dbsByBucket = array_filter( $config['dbsByBucket'], 'is_array' ); |
294 | 294 | $this->dbsByBucket = array_values( $this->dbsByBucket ); // consecutive |
— | — | @@ -671,8 +671,6 @@ |
672 | 672 | * Simple version of LockManager that does nothing |
673 | 673 | */ |
674 | 674 | class NullLockManager extends LockManager { |
675 | | - function __construct( array $config ) {} |
676 | | - |
677 | 675 | protected function doLock( array $keys, $type ) { |
678 | 676 | return Status::newGood(); |
679 | 677 | } |
Index: branches/FileBackend/phase3/includes/filerepo/backend/FileBackend.php |
— | — | @@ -521,7 +521,9 @@ |
522 | 522 | // Note: strlen( 'mwstore://' ) = 10 |
523 | 523 | $parts = explode( '/', substr( $storagePath, 10 ), 3 ); |
524 | 524 | if ( count( $parts ) == 3 ) { |
525 | | - return $parts; |
| 525 | + return $parts; // e.g. "backend/container/path" |
| 526 | + } elseif ( count( $parts ) == 2 ) { |
| 527 | + return array( $parts[0], $parts[1], '' ); // e.g. "backend/container" |
526 | 528 | } |
527 | 529 | } |
528 | 530 | return array( null, null, null ); |
Index: branches/FileBackend/phase3/includes/filerepo/FileRepo.php |
— | — | @@ -786,8 +786,8 @@ |
787 | 787 | } |
788 | 788 | |
789 | 789 | /** |
790 | | - * Copy or move a file either from a storage path or from a mwrepo:// |
791 | | - * virtual URL, into this repository at the specified destination location. |
| 790 | + * Copy or move a file either from a storage path, virtual URL, |
| 791 | + * or FS path, into this repository at the specified destination location. |
792 | 792 | * |
793 | 793 | * Returns a FileRepoStatus object. On success, the value contains "new" or |
794 | 794 | * "archived", to indicate whether the file was new with that name. |
— | — | @@ -883,20 +883,33 @@ |
884 | 884 | } else { |
885 | 885 | $status->value[$i] = 'new'; |
886 | 886 | } |
887 | | - if ( $flags & self::DELETE_SOURCE ) { |
| 887 | + // Copy (or move) the source file to the destination |
| 888 | + if ( FileBackend::isStoragePath( $srcPath ) ) { |
| 889 | + if ( $flags & self::DELETE_SOURCE ) { |
| 890 | + $operations[] = array( |
| 891 | + 'op' => 'move', |
| 892 | + 'source' => $srcPath, |
| 893 | + 'dest' => $dstPath, |
| 894 | + 'ignoreErrors' => true |
| 895 | + ); |
| 896 | + } else { |
| 897 | + $operations[] = array( |
| 898 | + 'op' => 'copy', |
| 899 | + 'source' => $srcPath, |
| 900 | + 'dest' => $dstPath, |
| 901 | + 'ignoreErrors' => true |
| 902 | + ); |
| 903 | + } |
| 904 | + } else { // FS source path |
888 | 905 | $operations[] = array( |
889 | | - 'op' => 'move', |
| 906 | + 'op' => 'store', |
890 | 907 | 'source' => $srcPath, |
891 | 908 | 'dest' => $dstPath, |
892 | 909 | 'ignoreErrors' => true |
893 | 910 | ); |
894 | | - } else { |
895 | | - $operations[] = array( |
896 | | - 'op' => 'copy', |
897 | | - 'source' => $srcPath, |
898 | | - 'dest' => $dstPath, |
899 | | - 'ignoreErrors' => true |
900 | | - ); |
| 911 | + if ( $flags & self::DELETE_SOURCE ) { |
| 912 | + $sourceFSFilesToDelete[] = $srcPath; |
| 913 | + } |
901 | 914 | } |
902 | 915 | } |
903 | 916 | |
— | — | @@ -1229,14 +1242,9 @@ |
1230 | 1243 | if ( !isset( $this->simpleCleanPairs ) ) { |
1231 | 1244 | global $IP; |
1232 | 1245 | $this->simpleCleanPairs = array( |
1233 | | - $this->directory => 'public', |
1234 | | - "{$this->directory}/temp" => 'temp', |
1235 | 1246 | $IP => '$IP', |
1236 | 1247 | dirname( __FILE__ ) => '$IP/extensions/WebStore', // WTF |
1237 | 1248 | ); |
1238 | | - if ( $this->deletedDir ) { |
1239 | | - $this->simpleCleanPairs[$this->deletedDir] = 'deleted'; |
1240 | | - } |
1241 | 1249 | } |
1242 | 1250 | return strtr( $param, $this->simpleCleanPairs ); |
1243 | 1251 | } |
Index: branches/FileBackend/phase3/includes/media/Generic.php |
— | — | @@ -211,12 +211,12 @@ |
212 | 212 | return new MediaTransformError( 'thumbnail_error', |
213 | 213 | $params['width'], 0, wfMsg( 'thumbnail-temp-create' ) ); |
214 | 214 | } |
215 | | - $tmpDest = $tmpFile->getPath(); |
| 215 | + $tmpDest = $tmpFile->getPath(); // path of 0-byte temp file |
216 | 216 | // Create the output thumbnail on the FS |
217 | 217 | $out = $this->doFSTransform( $image, $tmpDest, $dstUrl, $params, $flags ); |
218 | 218 | // Copy any thumbnail from FS into storage at $dstpath |
219 | 219 | // Note: no file is created if it's to be rendered client-side. |
220 | | - if ( !$out->isError() && is_file( $tmpDest ) ) { |
| 220 | + if ( !$out->isError() && filesize( $tmpDest ) ) { |
221 | 221 | $op = array( 'op' => 'store', |
222 | 222 | 'source' => $tmpDest, 'dest' => $dstPath, 'overwriteDest' => true ); |
223 | 223 | if ( !$image->getRepo()->getBackend()->doOperation( $op )->isOK() ) { |