69 parent::__construct( $config );
70 $this->mimeCallback = isset( $config[
'mimeCallback'] )
71 ? $config[
'mimeCallback']
75 $this->expensiveCache =
new ProcessCacheLRU( self::CACHE_EXPENSIVE_SIZE );
126 if ( !isset( $params[
'dstExists'] ) || $params[
'dstExists'] ) {
167 if ( !isset( $params[
'dstExists'] ) || $params[
'dstExists'] ) {
205 if ( !isset( $params[
'dstExists'] ) || $params[
'dstExists'] ) {
270 $this->
clearCache( [ $params[
'src'], $params[
'dst'] ] );
272 if ( !isset( $params[
'dstExists'] ) || $params[
'dstExists'] ) {
285 unset( $params[
'async'] );
290 if ( $nsrc !== $ndst &&
$status->isOK() ) {
315 if ( count( $params[
'headers'] ) ) {
354 $start_time = microtime(
true );
356 $sec = microtime(
true ) - $start_time;
358 wfDebugLog(
'FileOperation', get_class( $this ) .
"-{$this->name}" .
359 " failed to concatenate " . count( $params[
'srcs'] ) .
" file(s) [$sec sec]" );
373 $tmpPath = $params[
'dst'];
374 unset( $params[
'latest'] );
377 MediaWiki\suppressWarnings();
378 $ok = ( is_file( $tmpPath ) && filesize( $tmpPath ) == 0 );
379 MediaWiki\restoreWarnings();
381 $status->fatal(
'backend-fail-opentemp', $tmpPath );
388 foreach ( $fsFiles
as $path => &$fsFile ) {
401 $tmpHandle = fopen( $tmpPath,
'ab' );
402 if ( $tmpHandle ===
false ) {
403 $status->fatal(
'backend-fail-opentemp', $tmpPath );
409 foreach ( $fsFiles
as $virtualSource => $fsFile ) {
411 $sourceHandle = fopen( $fsFile->getPath(),
'rb' );
412 if ( $sourceHandle ===
false ) {
413 fclose( $tmpHandle );
414 $status->fatal(
'backend-fail-read', $virtualSource );
419 if ( !stream_copy_to_stream( $sourceHandle, $tmpHandle ) ) {
420 fclose( $sourceHandle );
421 fclose( $tmpHandle );
422 $status->fatal(
'backend-fail-writetemp', $tmpPath );
426 fclose( $sourceHandle );
428 if ( !fclose( $tmpHandle ) ) {
429 $status->fatal(
'backend-fail-closetemp', $tmpPath );
444 if (
$dir === null ) {
445 $status->fatal(
'backend-fail-invalidpath', $params[
'dir'] );
450 if ( $shard !== null ) {
453 wfDebug( __METHOD__ .
": iterating over all container shards.\n" );
454 list( , $shortCont, ) = self::splitStoragePath( $params[
'dir'] );
479 if (
$dir === null ) {
480 $status->fatal(
'backend-fail-invalidpath', $params[
'dir'] );
485 if ( $shard !== null ) {
488 wfDebug( __METHOD__ .
": iterating over all container shards.\n" );
489 list( , $shortCont, ) = self::splitStoragePath( $params[
'dir'] );
514 if (
$dir === null ) {
515 $status->fatal(
'backend-fail-invalidpath', $params[
'dir'] );
520 if ( $shard !== null ) {
523 wfDebug( __METHOD__ .
": iterating over all container shards.\n" );
524 list( , $shortCont, ) = self::splitStoragePath( $params[
'dir'] );
551 if ( $subDirsRel !== null ) {
552 foreach ( $subDirsRel
as $subDirRel ) {
553 $subDir = $params[
'dir'] .
"/{$subDirRel}";
554 $status->merge( $this->
doClean( [
'dir' => $subDir ] + $params ) );
556 unset( $subDirsRel );
561 if (
$dir === null ) {
562 $status->fatal(
'backend-fail-invalidpath', $params[
'dir'] );
568 $filesLockEx = [ $params[
'dir'] ];
574 if ( $shard !== null ) {
578 wfDebug( __METHOD__ .
": iterating over all container shards.\n" );
579 list( , $shortCont, ) = self::splitStoragePath( $params[
'dir'] );
604 return ( $stat === null ) ? null : (bool)$stat;
611 return $stat ? $stat[
'mtime'] :
false;
618 return $stat ? $stat[
'size'] :
false;
622 $path = self::normalizeStoragePath( $params[
'src'] );
623 if (
$path === null ) {
627 $latest = !empty( $params[
'latest'] );
628 if ( !$latest && !$this->cheapCache->has(
$path,
'stat', self::CACHE_TTL ) ) {
631 if ( $this->cheapCache->has(
$path,
'stat', self::CACHE_TTL ) ) {
632 $stat = $this->cheapCache->get(
$path,
'stat' );
635 if ( is_array( $stat ) ) {
636 if ( !$latest || $stat[
'latest'] ) {
639 } elseif ( in_array( $stat, [
'NOT_EXIST',
'NOT_EXIST_LATEST' ] ) ) {
640 if ( !$latest || $stat ===
'NOT_EXIST_LATEST' ) {
646 if ( is_array( $stat ) ) {
648 $stat[
'latest'] = isset( $stat[
'latest'] ) ? $stat[
'latest'] : $latest;
649 $this->cheapCache->set(
$path,
'stat', $stat );
651 if ( isset( $stat[
'sha1'] ) ) {
652 $this->cheapCache->set(
$path,
'sha1',
653 [
'hash' => $stat[
'sha1'],
'latest' => $latest ] );
655 if ( isset( $stat[
'xattr'] ) ) {
656 $stat[
'xattr'] = self::normalizeXAttributes( $stat[
'xattr'] );
657 $this->cheapCache->set(
$path,
'xattr',
658 [
'map' => $stat[
'xattr'],
'latest' => $latest ] );
660 } elseif ( $stat ===
false ) {
661 $this->cheapCache->set(
$path,
'stat', $latest ?
'NOT_EXIST_LATEST' :
'NOT_EXIST' );
662 $this->cheapCache->set(
$path,
'xattr', [
'map' =>
false,
'latest' => $latest ] );
663 $this->cheapCache->set(
$path,
'sha1', [
'hash' =>
false,
'latest' => $latest ] );
664 wfDebug( __METHOD__ .
": File $path does not exist.\n" );
666 wfDebug( __METHOD__ .
": Could not stat file $path.\n" );
694 MediaWiki\suppressWarnings();
695 $contents[
$path] = $fsFile ? file_get_contents( $fsFile->getPath() ) :
false;
696 MediaWiki\restoreWarnings();
703 $path = self::normalizeStoragePath( $params[
'src'] );
704 if (
$path === null ) {
708 $latest = !empty( $params[
'latest'] );
709 if ( $this->cheapCache->has(
$path,
'xattr', self::CACHE_TTL ) ) {
710 $stat = $this->cheapCache->get(
$path,
'xattr' );
713 if ( !$latest || $stat[
'latest'] ) {
718 $fields = is_array( $fields ) ? self::normalizeXAttributes( $fields ) :
false;
719 $this->cheapCache->set(
$path,
'xattr', [
'map' => $fields,
'latest' => $latest ] );
729 return [
'headers' => [],
'metadata' => [] ];
733 $path = self::normalizeStoragePath( $params[
'src'] );
734 if (
$path === null ) {
738 $latest = !empty( $params[
'latest'] );
739 if ( $this->cheapCache->has(
$path,
'sha1', self::CACHE_TTL ) ) {
740 $stat = $this->cheapCache->get(
$path,
'sha1' );
743 if ( !$latest || $stat[
'latest'] ) {
744 return $stat[
'hash'];
748 $this->cheapCache->set(
$path,
'sha1', [
'hash' => $hash,
'latest' => $latest ] );
763 return $fsFile->getSha1Base36();
781 $latest = !empty( $params[
'latest'] );
783 foreach ( $params[
'srcs']
as $src ) {
784 $path = self::normalizeStoragePath( $src );
785 if (
$path === null ) {
786 $fsFiles[$src] = null;
787 } elseif ( $this->expensiveCache->has(
$path,
'localRef' ) ) {
788 $val = $this->expensiveCache->get(
$path,
'localRef' );
791 if ( !$latest || $val[
'latest'] ) {
792 $fsFiles[$src] = $val[
'object'];
797 $params[
'srcs'] = array_diff( $params[
'srcs'], array_keys( $fsFiles ) );
799 $fsFiles[
$path] = $fsFile;
801 $this->expensiveCache->set(
$path,
'localRef',
802 [
'object' => $fsFile,
'latest' => $latest ] );
848 $params[
'options'] = isset( $params[
'options'] ) ? $params[
'options'] : [];
849 $params[
'headers'] = isset( $params[
'headers'] ) ? $params[
'headers'] : [];
852 if ( ( empty( $params[
'headless'] ) || $params[
'headers'] ) && headers_sent() ) {
853 print "Headers already sent, terminating.\n";
854 $status->fatal(
'backend-fail-stream', $params[
'src'] );
879 $params[
'headers'],
true, $params[
'options'],
$flags );
886 $status->fatal(
'backend-fail-stream', $params[
'src'] );
894 if (
$dir === null ) {
897 if ( $shard !== null ) {
900 wfDebug( __METHOD__ .
": iterating over all container shards.\n" );
901 list( , $shortCont, ) = self::splitStoragePath( $params[
'dir'] );
908 } elseif ( $exists === null ) {
929 if (
$dir === null ) {
932 if ( $shard !== null ) {
936 wfDebug( __METHOD__ .
": iterating over all container shards.\n" );
938 list( , $shortCont, ) = self::splitStoragePath( $params[
'dir'] );
959 if (
$dir === null ) {
962 if ( $shard !== null ) {
966 wfDebug( __METHOD__ .
": iterating over all container shards.\n" );
968 list( , $shortCont, ) = self::splitStoragePath( $params[
'dir'] );
1000 'store' =>
'StoreFileOp',
1001 'copy' =>
'CopyFileOp',
1002 'move' =>
'MoveFileOp',
1003 'delete' =>
'DeleteFileOp',
1004 'create' =>
'CreateFileOp',
1005 'describe' =>
'DescribeFileOp',
1006 'null' =>
'NullFileOp'
1011 foreach ( $ops
as $operation ) {
1012 $opName = $operation[
'op'];
1013 if ( isset( $supportedOps[$opName] ) ) {
1014 $class = $supportedOps[$opName];
1018 $performOps[] =
new $class( $this,
$params );
1039 $paths = [
'sh' => [],
'ex' => [] ];
1040 foreach ( $performOps
as $fileOp ) {
1041 $paths[
'sh'] = array_merge( $paths[
'sh'], $fileOp->storagePathsRead() );
1042 $paths[
'ex'] = array_merge( $paths[
'ex'], $fileOp->storagePathsChanged() );
1045 $paths[
'sh'] = array_diff( $paths[
'sh'], $paths[
'ex'] );
1047 $paths[
'sh'] = array_merge( $paths[
'sh'], array_map(
'dirname', $paths[
'ex'] ) );
1066 $ops = array_map( [ $this,
'sanitizeOpHeaders' ], $ops );
1072 if ( empty( $opts[
'nonLocking'] ) ) {
1084 if ( empty( $opts[
'preserveCache'] ) ) {
1090 foreach ( $performOps
as $op ) {
1091 $paths = array_merge( $paths, $op->storagePathsRead() );
1092 $paths = array_merge( $paths, $op->storagePathsChanged() );
1096 $this->cheapCache->resize( max( 2 * count( $paths ), self::CACHE_CHEAP_SIZE ) );
1101 $ok = $this->
preloadFileStat( [
'srcs' => $paths,
'latest' =>
true ] );
1110 foreach ( $ops
as $i => $op ) {
1111 $subStatus->success[$i] =
false;
1112 ++$subStatus->failCount;
1114 wfDebugLog(
'FileOperation', get_class( $this ) .
"-{$this->name} " .
1120 $status->success = $subStatus->success;
1123 $this->cheapCache->resize( self::CACHE_CHEAP_SIZE );
1133 $ops = array_map( [ $this,
'sanitizeOpHeaders' ], $ops );
1138 $supportedOps = [
'create',
'store',
'copy',
'move',
'delete',
'describe',
'null' ];
1140 $async = ( $this->parallelize ===
'implicit' && count( $ops ) > 1 );
1144 $fileOpHandles = [];
1145 $curFileOpHandles = [];
1148 if ( !in_array(
$params[
'op'], $supportedOps ) ) {
1149 throw new FileBackendError(
"Operation '{$params['op']}' is not supported." );
1151 $method =
$params[
'op'] .
'Internal';
1152 $subStatus = $this->$method( [
'async' => $async ] +
$params );
1154 if ( count( $curFileOpHandles ) >= $maxConcurrency ) {
1155 $fileOpHandles[] = $curFileOpHandles;
1156 $curFileOpHandles = [];
1158 $curFileOpHandles[$index] = $subStatus->value;
1160 $statuses[$index] = $subStatus;
1163 if ( count( $curFileOpHandles ) ) {
1164 $fileOpHandles[] = $curFileOpHandles;
1167 foreach ( $fileOpHandles
as $fileHandleBatch ) {
1171 foreach ( $statuses
as $index => $subStatus ) {
1173 if ( $subStatus->isOK() ) {
1174 $status->success[$index] =
true;
1177 $status->success[$index] =
false;
1198 foreach ( $fileOpHandles
as $fileOpHandle ) {
1200 throw new FileBackendError(
"Given a non-FileBackendStoreOpHandle object." );
1201 } elseif ( $fileOpHandle->backend->getName() !== $this->
getName() ) {
1202 throw new FileBackendError(
"Given a FileBackendStoreOpHandle for the wrong backend." );
1206 foreach ( $fileOpHandles
as $fileOpHandle ) {
1207 $fileOpHandle->closeResources();
1222 if ( count( $fileOpHandles ) ) {
1223 throw new FileBackendError(
"This backend supports no asynchronous operations." );
1241 static $longs = [
'content-disposition' ];
1243 if ( isset( $op[
'headers'] ) ) {
1247 $maxHVLen = in_array(
$name, $longs ) ? INF : 255;
1248 if ( strlen(
$name ) > 255 || strlen(
$value ) > $maxHVLen ) {
1249 trigger_error(
"Header '$name: $value' is too long." );
1254 $op[
'headers'] = $newHeaders;
1264 $fullConts[] = $fullCont;
1272 if ( is_array( $paths ) ) {
1273 $paths = array_map(
'FileBackend::normalizeStoragePath', $paths );
1274 $paths = array_filter( $paths,
'strlen' );
1276 if ( $paths === null ) {
1277 $this->cheapCache->clear();
1278 $this->expensiveCache->clear();
1281 $this->cheapCache->clear( $path );
1282 $this->expensiveCache->clear( $path );
1302 $params[
'concurrency'] = ( $this->parallelize !==
'off' ) ? $this->concurrency : 1;
1304 if ( $stats === null ) {
1308 $latest = !empty( $params[
'latest'] );
1309 foreach ( $stats
as $path => $stat ) {
1311 if (
$path === null ) {
1314 if ( is_array( $stat ) ) {
1316 $stat[
'latest'] = isset( $stat[
'latest'] ) ? $stat[
'latest'] : $latest;
1317 $this->cheapCache->set(
$path,
'stat', $stat );
1319 if ( isset( $stat[
'sha1'] ) ) {
1320 $this->cheapCache->set(
$path,
'sha1',
1321 [
'hash' => $stat[
'sha1'],
'latest' => $latest ] );
1323 if ( isset( $stat[
'xattr'] ) ) {
1324 $stat[
'xattr'] = self::normalizeXAttributes( $stat[
'xattr'] );
1325 $this->cheapCache->set(
$path,
'xattr',
1326 [
'map' => $stat[
'xattr'],
'latest' => $latest ] );
1328 } elseif ( $stat ===
false ) {
1329 $this->cheapCache->set(
$path,
'stat',
1330 $latest ?
'NOT_EXIST_LATEST' :
'NOT_EXIST' );
1331 $this->cheapCache->set(
$path,
'xattr',
1332 [
'map' =>
false,
'latest' => $latest ] );
1333 $this->cheapCache->set(
$path,
'sha1',
1334 [
'hash' =>
false,
'latest' => $latest ] );
1335 wfDebug( __METHOD__ .
": File $path does not exist.\n" );
1338 wfDebug( __METHOD__ .
": Could not stat file $path.\n" );
1384 return self::isValidContainerName( $container ) && !preg_match(
'/[.]/', $container );
1401 return (
bool)preg_match(
'/^[a-z0-9][a-z0-9-_.]{0,199}$/i', $container );
1418 list( $backend, $shortCont, $relPath ) = self::splitStoragePath( $storagePath );
1419 if ( $backend === $this->
name ) {
1420 $relPath = self::normalizeContainerPath( $relPath );
1421 if ( $relPath !== null && self::isValidShortContainerName( $shortCont ) ) {
1426 if ( $relPath !== null ) {
1429 if ( self::isValidContainerName( $container ) ) {
1432 if ( $container !== null ) {
1433 return [ $container, $relPath, $cShard ];
1440 return [ null, null, null ];
1460 if ( $cShard !== null && substr( $relPath, -1 ) !==
'/' ) {
1461 return [ $container, $relPath ];
1464 return [ null, null ];
1477 if ( $levels == 1 || $levels == 2 ) {
1479 $char = (
$base == 36 ) ?
'[0-9a-z]' :
'[0-9a-f]';
1482 if ( $levels === 1 ) {
1483 $hashDirRegex =
'(' . $char .
')';
1486 $hashDirRegex = $char .
'/(' . $char .
'{2})';
1488 $hashDirRegex =
'(' . $char .
')/(' . $char .
')';
1495 if ( preg_match(
"!^(?:[^/]{2,}/)*$hashDirRegex(?:/|$)!", $relPath, $m ) ) {
1496 return '.' . implode(
'', array_slice( $m, 1 ) );
1516 return ( $shard !== null );
1528 if ( isset( $this->shardViaHashLevels[$container] ) ) {
1529 $config = $this->shardViaHashLevels[$container];
1530 $hashLevels = (int)$config[
'levels'];
1531 if ( $hashLevels == 1 || $hashLevels == 2 ) {
1532 $hashBase = (int)$config[
'base'];
1533 if ( $hashBase == 16 || $hashBase == 36 ) {
1534 return [ $hashLevels, $hashBase, $config[
'repeat'] ];
1539 return [ 0, 0,
false ];
1551 if ( $digits > 0 ) {
1552 $numShards = pow(
$base, $digits );
1553 for ( $index = 0; $index < $numShards; $index++ ) {
1554 $shards[] =
'.' . Wikimedia\base_convert( $index, 10,
$base, $digits );
1568 if ( $this->wikiId !=
'' ) {
1569 return "{$this->wikiId}-$container";
1598 return $relStoragePath;
1608 return "filebackend:{$this->name}:{$this->wikiId}:container:{$container}";
1618 $this->memCache->set( $this->
containerCacheKey( $container ), $val, 14 * 86400 );
1628 if ( !$this->memCache->delete( $this->containerCacheKey( $container ), 300 ) ) {
1629 trigger_error(
"Unable to delete stat cache for container $container." );
1646 foreach ( $items
as $item ) {
1647 if ( self::isStoragePath( $item ) ) {
1649 } elseif ( is_string( $item ) ) {
1656 if ( $fullCont !== null ) {
1663 $values = $this->memCache->getMulti( array_keys( $contNames ) );
1664 foreach ( $values
as $cacheKey => $val ) {
1665 $contInfo[$contNames[$cacheKey]] = $val;
1689 return "filebackend:{$this->name}:{$this->wikiId}:file:" . sha1(
$path );
1702 if (
$path === null ) {
1706 $ttl = min( 7 * 86400, max( 300, floor( .1 * $age ) ) );
1709 $this->memCache->set( $key, $val, $ttl );
1722 if (
$path === null ) {
1725 if ( !$this->memCache->delete( $this->fileCacheKey(
$path ), 300 ) ) {
1726 trigger_error(
"Unable to delete stat cache for file $path." );
1743 foreach ( $items
as $item ) {
1744 if ( self::isStoragePath( $item ) ) {
1749 $paths = array_filter( $paths,
'strlen' );
1753 if ( $rel !== null ) {
1758 $values = $this->memCache->getMulti( array_keys( $pathNames ) );
1759 foreach ( $values
as $cacheKey => $val ) {
1760 $path = $pathNames[$cacheKey];
1761 if ( is_array( $val ) ) {
1762 $val[
'latest'] =
false;
1763 $this->cheapCache->set( $path,
'stat', $val );
1764 if ( isset( $val[
'sha1'] ) ) {
1765 $this->cheapCache->set( $path,
'sha1',
1766 [
'hash' => $val[
'sha1'],
'latest' =>
false ] );
1768 if ( isset( $val[
'xattr'] ) ) {
1769 $val[
'xattr'] = self::normalizeXAttributes( $val[
'xattr'] );
1770 $this->cheapCache->set( $path,
'xattr',
1771 [
'map' => $val[
'xattr'],
'latest' =>
false ] );
1785 $newXAttr = [
'headers' => [],
'metadata' => [] ];
1788 $newXAttr[
'headers'][strtolower(
$name )] =
$value;
1792 $newXAttr[
'metadata'][strtolower(
$name )] =
$value;
1805 $opts[
'concurrency'] = 1;
1806 if ( $this->parallelize ===
'implicit' ) {
1807 if ( !isset( $opts[
'parallelize'] ) || $opts[
'parallelize'] ) {
1810 } elseif ( $this->parallelize ===
'explicit' ) {
1811 if ( !empty( $opts[
'parallelize'] ) ) {
1828 if ( $this->mimeCallback ) {
1829 return call_user_func_array( $this->mimeCallback, func_get_args() );
1833 if ( $fsPath !== null && function_exists(
'finfo_file' ) ) {
1834 $finfo = finfo_open( FILEINFO_MIME_TYPE );
1835 $mime = finfo_file( $finfo, $fsPath );
1836 finfo_close( $finfo );
1839 return is_string(
$mime ) ?
$mime :
'unknown/unknown';
1865 array_map(
'fclose', $this->resourcesToClose );
1906 $iter =
new AppendIterator();
1907 foreach ( $suffixes
as $suffix ) {
1908 $iter->append( $this->
listFromShard( $this->container . $suffix ) );
1911 parent::__construct( $iter );
1915 $rel = $this->getInnerIterator()->current();
1916 $path = $this->params[
'dir'] .
"/{$rel}";
1917 if ( $this->backend->isSingleShardPathInternal(
$path ) ) {
1919 } elseif ( isset( $this->multiShardPaths[$rel] ) ) {
1923 $this->multiShardPaths[$rel] = 1;
1931 $this->multiShardPaths = [];
1948 $list = $this->backend->getDirectoryListInternal(
1950 if ( $list === null ) {
1951 return new ArrayIterator( [] );
1953 return is_array( $list ) ?
new ArrayIterator( $list ) : $list;
1963 $list = $this->backend->getFileListInternal(
1965 if ( $list === null ) {
1966 return new ArrayIterator( [] );
1968 return is_array( $list ) ?
new ArrayIterator( $list ) : $list;
primeContainerCache(array $items)
Do a batch lookup from cache for container stats for all containers used in a list of container names...
doPublishInternal($container, $dir, array $params)
getFileHttpUrl(array $params)
const CACHE_EXPENSIVE_SIZE
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
doOperationsInternal(array $ops, array $opts)
setConcurrencyFlags(array $opts)
Set the 'concurrency' option from a list of operation options.
the array() calling protocol came about after MediaWiki 1.4rc1.
getScopedLocksForOps(array $ops, Status $status)
setFileCache($path, array $val)
Set the cached stat info for a file path.
Iterator for listing regular files.
moveInternal(array $params)
Move a file from one storage path to another in the backend.
processing should stop and the error should be shown to the user * false
concatenate(array $params)
doPrepareInternal($container, $dir, array $params)
doGetLocalReferenceMulti(array $params)
resolveContainerName($container)
Resolve a container name, checking if it's allowed by the backend.
getPathsToLockForOpsInternal(array $performOps)
Get a list of storage paths to lock for a list of operations Returns an array with LockManager::LOCK_...
static instance()
Singleton.
static normalizeXAttributes(array $xattr)
Normalize file headers/metadata to the FileBackend::getFileXAttributes() format.
listFromShard($container)
Get the list for a given container shard.
doGetFileXAttributes(array $params)
getFileStat(array $params)
getContainerSuffixes($container)
Get a list of full container shard suffixes for a container.
Generic operation result class Has warning/error list, boolean status and arbitrary value...
listFromShard($container)
The most up to date schema for the tables in the database will always be tables sql in the maintenance directory
__construct(array $config)
if($ext== 'php'||$ext== 'php5') $mime
getName()
Get the unique backend name.
string $directory
Resolved relative path.
it s the revision text itself In either if gzip is the revision text is gzipped $flags
string $container
Full container name.
ProcessCacheLRU $expensiveCache
Map of paths to large (RAM/disk) cache items.
fileCacheKey($path)
Get the cache key for a file path.
static send404Message($fname, $flags=0)
Send out a standard 404 message for a file.
FileBackendStore helper function to handle listings that span container shards.
static isValidContainerName($container)
Check if a full container name is valid.
int $concurrency
How many operations can be done in parallel.
static newFatal($message)
Factory function for fatal errors.
storeInternal(array $params)
Store a file into the backend from a file on disk.
array $shardViaHashLevels
Map of container names to sharding config.
doSecureInternal($container, $dir, array $params)
wfDebug($text, $dest= 'all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestamp($outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
doCreateInternal(array $params)
static newEmpty()
Get an instance that wraps EmptyBagOStuff.
wfDebugLog($logGroup, $text, $dest= 'all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
streamFile(array $params)
getFileSha1Base36(array $params)
executeOpHandlesInternal(array $fileOpHandles)
Execute a list of FileBackendStoreOpHandle handles in parallel.
getFileSize(array $params)
doQuickOperationsInternal(array $ops)
File backend exception for checked exceptions (e.g.
isPathUsableInternal($storagePath)
Check if a file can be created or changed at a given storage path.
ProcessCacheLRU $cheapCache
Map of paths to small (RAM/disk) cache items.
createInternal(array $params)
Create a file in the backend with the given contents.
fileExists(array $params)
directoryExists(array $params)
doStreamFile(array $params)
getFileXAttributes(array $params)
nullInternal(array $params)
No-op file operation that does nothing.
deleteInternal(array $params)
Delete a file at the storage path.
preloadCache(array $paths)
doGetLocalCopyMulti(array $params)
getFileContentsMulti(array $params)
getFileTimestamp(array $params)
maxFileSizeInternal()
Get the maximum allowable file size given backend medium restrictions and basic performance constrain...
FileBackendStore $backend
static placeholderProps()
Placeholder file properties to use for files that don't exist.
getOperationsInternal(array $ops)
Return a list of FileOp objects from a list of operations.
clearCache(array $paths=null)
callable $mimeCallback
Method to get the MIME type of files.
resolveStoragePathReal($storagePath)
Like resolveStoragePath() except null values are returned if the container is sharded and the shard c...
listFromShard($container)
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
doGetFileStatMulti(array $params)
Get file stat information (concurrently if possible) for several files.
getContentType($storagePath, $content, $fsPath)
Get the content type to use in HEAD/GET requests for a file.
copyInternal(array $params)
Copy a file from one storage path to another in the backend.
doGetFileStat(array $params)
string $name
Unique backend name.
doGetFileContentsMulti(array $params)
Base class for all backends using particular storage medium.
preloadFileStat(array $params)
fullContainerName($container)
Get the full container name, including the wiki ID prefix.
directoriesAreVirtual()
Is this a key/value store where directories are just virtual? Virtual directories exists in so much a...
getFileList(array $params)
closeResources()
Close all open file handles.
__construct(FileBackendStore $backend, $container, $dir, array $suffixes, array $params)
containerCacheKey($container)
Get the cache key for a container.
static stream($fname, $headers=[], $sendErrors=true, $optHeaders=[], $flags=0)
Stream a file to the browser, adding all the headings and fun stuff.
Iterator for listing directories.
getContainerHashLevels($container)
Get the sharding config for a container.
static normalizeStoragePath($storagePath)
Normalize a storage path by cleaning up directory separators.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
static attempt(array $performOps, array $opts, FileJournal $journal)
Attempt to perform a series of file operations.
resolveContainerPath($container, $relStoragePath)
Resolve a relative storage path, checking if it's allowed by the backend.
setContainerCache($container, array $val)
Set the cached info for a container.
doConcatenate(array $params)
getContainerShard($container, $relPath)
Get the container name shard suffix for a given path.
FileBackendStore $backend
getDirectoryListInternal($container, $dir, array $params)
Do not call this function from places outside FileBackend.
doPrimeContainerCache(array $containerInfo)
Fill the backend-specific process cache given an array of resolved container names and their correspo...
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content $content
doClearCache(array $paths=null)
Clears any additional stat caches for storage paths.
describeInternal(array $params)
Alter metadata for a file at the storage path.
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
doStoreInternal(array $params)
isSingleShardPathInternal($storagePath)
Check if a storage path maps to a single shard.
Base class for all file backend classes (including multi-write backends).
doDeleteInternal(array $params)
getTopDirectoryList(array $params)
Same as FileBackend::getDirectoryList() except only lists directories that are immediately under the ...
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
deleteFileCache($path)
Delete the cached stat info for a file path.
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
doMoveInternal(array $params)
sanitizeOpHeaders(array $op)
Normalize and filter HTTP headers from a file operation.
doDescribeInternal(array $params)
static isValidShortContainerName($container)
Check if a short container name is valid.
doCleanInternal($container, $dir, array $params)
getLocalReferenceMulti(array $params)
FileBackendStore helper class for performing asynchronous file operations.
doGetFileSha1Base36(array $params)
deleteContainerCache($container)
Delete the cached info for a container.
primeFileCache(array $items)
Do a batch lookup from cache for file stats for all paths used in a list of storage paths or FileOp o...
getFileListInternal($container, $dir, array $params)
Do not call this function from places outside FileBackend.
doCopyInternal(array $params)
getLocalReference(array $params)
Returns a file system file, identical to the file at a storage path.
getDirectoryList(array $params)
Handles per process caching of items.
getLocalCopyMulti(array $params)
static newGood($value=null)
Factory function for good results.
getFileProps(array $params)
doDirectoryExists($container, $dir, array $params)
getScopedFileLocks(array $paths, $type, Status $status, $timeout=0)
Lock the files at the given storage paths in the backend.
resolveStoragePath($storagePath)
Splits a storage path into an internal container name, an internal relative file name, and a container shard suffix.
doExecuteOpHandlesInternal(array $fileOpHandles)