MediaWiki  1.27.1
FileBackend.php
Go to the documentation of this file.
1 <?php
85 abstract class FileBackend {
87  protected $name;
88 
90  protected $wikiId;
91 
93  protected $readOnly;
94 
96  protected $parallelize;
97 
99  protected $concurrency;
100 
102  protected $lockManager;
103 
105  protected $fileJournal;
106 
108  const ATTR_HEADERS = 1; // files can be tagged with standard HTTP headers
109  const ATTR_METADATA = 2; // files can be stored with metadata key/values
110  const ATTR_UNICODE_PATHS = 4; // files can have Unicode paths (not just ASCII)
111 
136  public function __construct( array $config ) {
137  $this->name = $config['name'];
138  $this->wikiId = $config['wikiId']; // e.g. "my_wiki-en_"
139  if ( !preg_match( '!^[a-zA-Z0-9-_]{1,255}$!', $this->name ) ) {
140  throw new FileBackendException( "Backend name '{$this->name}' is invalid." );
141  } elseif ( !is_string( $this->wikiId ) ) {
142  throw new FileBackendException( "Backend wiki ID not provided for '{$this->name}'." );
143  }
144  $this->lockManager = isset( $config['lockManager'] )
145  ? $config['lockManager']
146  : new NullLockManager( [] );
147  $this->fileJournal = isset( $config['fileJournal'] )
148  ? $config['fileJournal']
149  : FileJournal::factory( [ 'class' => 'NullFileJournal' ], $this->name );
150  $this->readOnly = isset( $config['readOnly'] )
151  ? (string)$config['readOnly']
152  : '';
153  $this->parallelize = isset( $config['parallelize'] )
154  ? (string)$config['parallelize']
155  : 'off';
156  $this->concurrency = isset( $config['concurrency'] )
157  ? (int)$config['concurrency']
158  : 50;
159  }
160 
168  final public function getName() {
169  return $this->name;
170  }
171 
179  final public function getWikiId() {
180  return $this->wikiId;
181  }
182 
188  final public function isReadOnly() {
189  return ( $this->readOnly != '' );
190  }
191 
197  final public function getReadOnlyReason() {
198  return ( $this->readOnly != '' ) ? $this->readOnly : false;
199  }
200 
207  public function getFeatures() {
208  return self::ATTR_UNICODE_PATHS;
209  }
210 
218  final public function hasFeatures( $bitfield ) {
219  return ( $this->getFeatures() & $bitfield ) === $bitfield;
220  }
221 
370  final public function doOperations( array $ops, array $opts = [] ) {
371  if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
372  return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
373  }
374  if ( !count( $ops ) ) {
375  return Status::newGood(); // nothing to do
376  }
377 
378  $ops = $this->resolveFSFileObjects( $ops );
379  if ( empty( $opts['force'] ) ) { // sanity
380  unset( $opts['nonLocking'] );
381  }
382 
384  $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
385 
386  return $this->doOperationsInternal( $ops, $opts );
387  }
388 
394  abstract protected function doOperationsInternal( array $ops, array $opts );
395 
407  final public function doOperation( array $op, array $opts = [] ) {
408  return $this->doOperations( [ $op ], $opts );
409  }
410 
421  final public function create( array $params, array $opts = [] ) {
422  return $this->doOperation( [ 'op' => 'create' ] + $params, $opts );
423  }
424 
435  final public function store( array $params, array $opts = [] ) {
436  return $this->doOperation( [ 'op' => 'store' ] + $params, $opts );
437  }
438 
449  final public function copy( array $params, array $opts = [] ) {
450  return $this->doOperation( [ 'op' => 'copy' ] + $params, $opts );
451  }
452 
463  final public function move( array $params, array $opts = [] ) {
464  return $this->doOperation( [ 'op' => 'move' ] + $params, $opts );
465  }
466 
477  final public function delete( array $params, array $opts = [] ) {
478  return $this->doOperation( [ 'op' => 'delete' ] + $params, $opts );
479  }
480 
492  final public function describe( array $params, array $opts = [] ) {
493  return $this->doOperation( [ 'op' => 'describe' ] + $params, $opts );
494  }
495 
608  final public function doQuickOperations( array $ops, array $opts = [] ) {
609  if ( empty( $opts['bypassReadOnly'] ) && $this->isReadOnly() ) {
610  return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
611  }
612  if ( !count( $ops ) ) {
613  return Status::newGood(); // nothing to do
614  }
615 
616  $ops = $this->resolveFSFileObjects( $ops );
617  foreach ( $ops as &$op ) {
618  $op['overwrite'] = true; // avoids RTTs in key/value stores
619  }
620 
622  $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
623 
624  return $this->doQuickOperationsInternal( $ops );
625  }
626 
632  abstract protected function doQuickOperationsInternal( array $ops );
633 
644  final public function doQuickOperation( array $op ) {
645  return $this->doQuickOperations( [ $op ] );
646  }
647 
658  final public function quickCreate( array $params ) {
659  return $this->doQuickOperation( [ 'op' => 'create' ] + $params );
660  }
661 
672  final public function quickStore( array $params ) {
673  return $this->doQuickOperation( [ 'op' => 'store' ] + $params );
674  }
675 
686  final public function quickCopy( array $params ) {
687  return $this->doQuickOperation( [ 'op' => 'copy' ] + $params );
688  }
689 
700  final public function quickMove( array $params ) {
701  return $this->doQuickOperation( [ 'op' => 'move' ] + $params );
702  }
703 
714  final public function quickDelete( array $params ) {
715  return $this->doQuickOperation( [ 'op' => 'delete' ] + $params );
716  }
717 
728  final public function quickDescribe( array $params ) {
729  return $this->doQuickOperation( [ 'op' => 'describe' ] + $params );
730  }
731 
744  abstract public function concatenate( array $params );
745 
764  final public function prepare( array $params ) {
765  if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
766  return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
767  }
769  $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
770  return $this->doPrepare( $params );
771  }
772 
777  abstract protected function doPrepare( array $params );
778 
795  final public function secure( array $params ) {
796  if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
797  return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
798  }
800  $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
801  return $this->doSecure( $params );
802  }
803 
808  abstract protected function doSecure( array $params );
809 
828  final public function publish( array $params ) {
829  if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
830  return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
831  }
833  $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
834  return $this->doPublish( $params );
835  }
836 
841  abstract protected function doPublish( array $params );
842 
854  final public function clean( array $params ) {
855  if ( empty( $params['bypassReadOnly'] ) && $this->isReadOnly() ) {
856  return Status::newFatal( 'backend-fail-readonly', $this->name, $this->readOnly );
857  }
859  $scope = $this->getScopedPHPBehaviorForOps(); // try to ignore client aborts
860  return $this->doClean( $params );
861  }
862 
867  abstract protected function doClean( array $params );
868 
876  final protected function getScopedPHPBehaviorForOps() {
877  if ( PHP_SAPI != 'cli' ) { // http://bugs.php.net/bug.php?id=47540
878  $old = ignore_user_abort( true ); // avoid half-finished operations
879  return new ScopedCallback( function () use ( $old ) {
880  ignore_user_abort( $old );
881  } );
882  }
883 
884  return null;
885  }
886 
896  abstract public function fileExists( array $params );
897 
906  abstract public function getFileTimestamp( array $params );
907 
917  final public function getFileContents( array $params ) {
918  $contents = $this->getFileContentsMulti(
919  [ 'srcs' => [ $params['src'] ] ] + $params );
920 
921  return $contents[$params['src']];
922  }
923 
938  abstract public function getFileContentsMulti( array $params );
939 
958  abstract public function getFileXAttributes( array $params );
959 
968  abstract public function getFileSize( array $params );
969 
983  abstract public function getFileStat( array $params );
984 
993  abstract public function getFileSha1Base36( array $params );
994 
1004  abstract public function getFileProps( array $params );
1005 
1019  abstract public function streamFile( array $params );
1020 
1039  final public function getLocalReference( array $params ) {
1040  $fsFiles = $this->getLocalReferenceMulti(
1041  [ 'srcs' => [ $params['src'] ] ] + $params );
1042 
1043  return $fsFiles[$params['src']];
1044  }
1045 
1060  abstract public function getLocalReferenceMulti( array $params );
1061 
1072  final public function getLocalCopy( array $params ) {
1073  $tmpFiles = $this->getLocalCopyMulti(
1074  [ 'srcs' => [ $params['src'] ] ] + $params );
1075 
1076  return $tmpFiles[$params['src']];
1077  }
1078 
1093  abstract public function getLocalCopyMulti( array $params );
1094 
1111  abstract public function getFileHttpUrl( array $params );
1112 
1125  abstract public function directoryExists( array $params );
1126 
1145  abstract public function getDirectoryList( array $params );
1146 
1160  final public function getTopDirectoryList( array $params ) {
1161  return $this->getDirectoryList( [ 'topOnly' => true ] + $params );
1162  }
1163 
1182  abstract public function getFileList( array $params );
1183 
1198  final public function getTopFileList( array $params ) {
1199  return $this->getFileList( [ 'topOnly' => true ] + $params );
1200  }
1201 
1210  abstract public function preloadCache( array $paths );
1211 
1220  abstract public function clearCache( array $paths = null );
1221 
1236  abstract public function preloadFileStat( array $params );
1237 
1249  final public function lockFiles( array $paths, $type, $timeout = 0 ) {
1250  $paths = array_map( 'FileBackend::normalizeStoragePath', $paths );
1251 
1252  return $this->lockManager->lock( $paths, $type, $timeout );
1253  }
1254 
1262  final public function unlockFiles( array $paths, $type ) {
1263  $paths = array_map( 'FileBackend::normalizeStoragePath', $paths );
1264 
1265  return $this->lockManager->unlock( $paths, $type );
1266  }
1267 
1284  final public function getScopedFileLocks( array $paths, $type, Status $status, $timeout = 0 ) {
1285  if ( $type === 'mixed' ) {
1286  foreach ( $paths as &$typePaths ) {
1287  $typePaths = array_map( 'FileBackend::normalizeStoragePath', $typePaths );
1288  }
1289  } else {
1290  $paths = array_map( 'FileBackend::normalizeStoragePath', $paths );
1291  }
1292 
1293  return ScopedLock::factory( $this->lockManager, $paths, $type, $status, $timeout );
1294  }
1295 
1312  abstract public function getScopedLocksForOps( array $ops, Status $status );
1313 
1321  final public function getRootStoragePath() {
1322  return "mwstore://{$this->name}";
1323  }
1324 
1332  final public function getContainerStoragePath( $container ) {
1333  return $this->getRootStoragePath() . "/{$container}";
1334  }
1335 
1341  final public function getJournal() {
1342  return $this->fileJournal;
1343  }
1344 
1354  protected function resolveFSFileObjects( array $ops ) {
1355  foreach ( $ops as &$op ) {
1356  $src = isset( $op['src'] ) ? $op['src'] : null;
1357  if ( $src instanceof FSFile ) {
1358  $op['srcRef'] = $src;
1359  $op['src'] = $src->getPath();
1360  }
1361  }
1362  unset( $op );
1363 
1364  return $ops;
1365  }
1366 
1374  final public static function isStoragePath( $path ) {
1375  return ( strpos( $path, 'mwstore://' ) === 0 );
1376  }
1377 
1386  final public static function splitStoragePath( $storagePath ) {
1387  if ( self::isStoragePath( $storagePath ) ) {
1388  // Remove the "mwstore://" prefix and split the path
1389  $parts = explode( '/', substr( $storagePath, 10 ), 3 );
1390  if ( count( $parts ) >= 2 && $parts[0] != '' && $parts[1] != '' ) {
1391  if ( count( $parts ) == 3 ) {
1392  return $parts; // e.g. "backend/container/path"
1393  } else {
1394  return [ $parts[0], $parts[1], '' ]; // e.g. "backend/container"
1395  }
1396  }
1397  }
1398 
1399  return [ null, null, null ];
1400  }
1401 
1409  final public static function normalizeStoragePath( $storagePath ) {
1410  list( $backend, $container, $relPath ) = self::splitStoragePath( $storagePath );
1411  if ( $relPath !== null ) { // must be for this backend
1412  $relPath = self::normalizeContainerPath( $relPath );
1413  if ( $relPath !== null ) {
1414  return ( $relPath != '' )
1415  ? "mwstore://{$backend}/{$container}/{$relPath}"
1416  : "mwstore://{$backend}/{$container}";
1417  }
1418  }
1419 
1420  return null;
1421  }
1422 
1431  final public static function parentStoragePath( $storagePath ) {
1432  $storagePath = dirname( $storagePath );
1433  list( , , $rel ) = self::splitStoragePath( $storagePath );
1434 
1435  return ( $rel === null ) ? null : $storagePath;
1436  }
1437 
1445  final public static function extensionFromPath( $path, $case = 'lowercase' ) {
1446  $i = strrpos( $path, '.' );
1447  $ext = $i ? substr( $path, $i + 1 ) : '';
1448 
1449  if ( $case === 'lowercase' ) {
1450  $ext = strtolower( $ext );
1451  } elseif ( $case === 'uppercase' ) {
1452  $ext = strtoupper( $ext );
1453  }
1454 
1455  return $ext;
1456  }
1457 
1465  final public static function isPathTraversalFree( $path ) {
1466  return ( self::normalizeContainerPath( $path ) !== null );
1467  }
1468 
1478  final public static function makeContentDisposition( $type, $filename = '' ) {
1479  $parts = [];
1480 
1481  $type = strtolower( $type );
1482  if ( !in_array( $type, [ 'inline', 'attachment' ] ) ) {
1483  throw new FileBackendError( "Invalid Content-Disposition type '$type'." );
1484  }
1485  $parts[] = $type;
1486 
1487  if ( strlen( $filename ) ) {
1488  $parts[] = "filename*=UTF-8''" . rawurlencode( basename( $filename ) );
1489  }
1490 
1491  return implode( ';', $parts );
1492  }
1493 
1504  final protected static function normalizeContainerPath( $path ) {
1505  // Normalize directory separators
1506  $path = strtr( $path, '\\', '/' );
1507  // Collapse any consecutive directory separators
1508  $path = preg_replace( '![/]{2,}!', '/', $path );
1509  // Remove any leading directory separator
1510  $path = ltrim( $path, '/' );
1511  // Use the same traversal protection as Title::secureAndSplit()
1512  if ( strpos( $path, '.' ) !== false ) {
1513  if (
1514  $path === '.' ||
1515  $path === '..' ||
1516  strpos( $path, './' ) === 0 ||
1517  strpos( $path, '../' ) === 0 ||
1518  strpos( $path, '/./' ) !== false ||
1519  strpos( $path, '/../' ) !== false
1520  ) {
1521  return null;
1522  }
1523  }
1524 
1525  return $path;
1526  }
1527 }
1528 
1536 }
1537 
1545 }
doQuickOperationsInternal(array $ops)
FileJournal $fileJournal
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
Definition: deferred.txt:11
describe(array $params, array $opts=[])
Performs a single describe operation.
the array() calling protocol came about after MediaWiki 1.4rc1.
unlockFiles(array $paths, $type)
Unlock the files at the given storage paths in the backend.
doOperations(array $ops, array $opts=[])
This is the main entry point into the backend for write operations.
doPrepare(array $params)
getFileStat(array $params)
Get quick information about a file at a storage path in the backend.
getWikiId()
Get the wiki identifier used for this backend (possibly empty).
publish(array $params)
Remove measures to block web access to a storage directory and the container it belongs to...
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
secure(array $params)
Take measures to block web access to a storage directory and the container it belongs to...
Simple version of LockManager that does nothing.
const ATTR_HEADERS
Bitfield flags for supported features.
quickMove(array $params)
Performs a single quick move operation.
getFileHttpUrl(array $params)
Return an HTTP URL to a given file that requires no authentication to use.
quickDelete(array $params)
Performs a single quick delete operation.
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:177
getFileXAttributes(array $params)
Get metadata about a file at a storage path in the backend.
getScopedPHPBehaviorForOps()
Enter file operation scope.
getName()
Get the unique backend name.
getFileContentsMulti(array $params)
Like getFileContents() except it takes an array of storage paths and returns a map of storage paths t...
getDirectoryList(array $params)
Get an iterator to list all directories under a storage directory.
doOperation(array $op, array $opts=[])
Same as doOperations() except it takes a single operation.
doClean(array $params)
getFileTimestamp(array $params)
Get the last-modified timestamp of the file at a storage path.
int $concurrency
How many operations can be done in parallel.
Definition: FileBackend.php:99
static newFatal($message)
Factory function for fatal errors.
Definition: Status.php:89
getLocalReferenceMulti(array $params)
Like getLocalReference() except it takes an array of storage paths and returns a map of storage paths...
static extensionFromPath($path, $case= 'lowercase')
Get the final extension from a storage or FS path.
directoryExists(array $params)
Check if a directory exists at a given storage path.
hasFeatures($bitfield)
Check if the backend medium supports a field of extra features.
resolveFSFileObjects(array $ops)
Convert FSFile 'src' paths to string paths (with an 'srcRef' field set to the FSFile) ...
Generic file backend exception for checked and unexpected (e.g.
string $readOnly
Read-only explanation message.
Definition: FileBackend.php:93
Class for asserting that a callback happens when an dummy object leaves scope.
create(array $params, array $opts=[])
Performs a single create operation.
move(array $params, array $opts=[])
Performs a single move operation.
quickStore(array $params)
Performs a single quick store operation.
getContainerStoragePath($container)
Get the storage path for the given container for this backend.
getReadOnlyReason()
Get an explanatory message if this backend is read-only.
static normalizeContainerPath($path)
Validate and normalize a relative storage path.
quickCreate(array $params)
Performs a single quick create operation.
getTopFileList(array $params)
Same as FileBackend::getFileList() except only lists files that are immediately under the given direc...
File backend exception for checked exceptions (e.g.
lockFiles(array $paths, $type, $timeout=0)
Lock the files at the given storage paths in the backend.
__construct(array $config)
Create a new backend instance from configuration.
static isStoragePath($path)
Check if a given path is a "mwstore://" path.
quickCopy(array $params)
Performs a single quick copy operation.
fileExists(array $params)
Check if a file exists at a storage path in the backend.
getFileSha1Base36(array $params)
Get a SHA-1 hash of the file at a storage path in the backend.
$params
store(array $params, array $opts=[])
Performs a single store operation.
const ATTR_UNICODE_PATHS
doSecure(array $params)
const ATTR_METADATA
getFileSize(array $params)
Get the size (bytes) of a file at a storage path in the backend.
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
Definition: distributors.txt:9
doQuickOperations(array $ops, array $opts=[])
Perform a set of independent file operations on some files.
prepare(array $params)
Prepare a storage directory for usage.
string $name
Unique backend name.
Definition: FileBackend.php:87
getLocalCopy(array $params)
Get a local copy on disk of the file at a storage path in the backend.
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
Definition: injection.txt:35
getJournal()
Get the file journal object for this backend.
concatenate(array $params)
Concatenate a list of storage files into a single file system file.
static factory(LockManager $manager, array $paths, $type, Status $status, $timeout=0)
Get a ScopedLock object representing a lock on resource paths.
Definition: ScopedLock.php:69
getRootStoragePath()
Get the root storage path of this backend.
Class representing a non-directory file on the file system.
Definition: FSFile.php:29
preloadCache(array $paths)
Preload persistent file stat cache and property cache into in-process cache.
copy(array $params, array $opts=[])
Performs a single copy operation.
doOperationsInternal(array $ops, array $opts)
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
Definition: design.txt:12
Base class for all file backend classes (including multi-write backends).
Definition: FileBackend.php:85
getFileList(array $params)
Get an iterator to list all stored files under a storage directory.
static isPathTraversalFree($path)
Check if a relative path has no directory traversals.
getTopDirectoryList(array $params)
Same as FileBackend::getDirectoryList() except only lists directories that are immediately under the ...
getLocalCopyMulti(array $params)
Like getLocalCopy() except it takes an array of storage paths and returns a map of storage paths to T...
static makeContentDisposition($type, $filename= '')
Build a Content-Disposition header value per RFC 6266.
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
Definition: hooks.txt:1004
quickDescribe(array $params)
Performs a single quick describe operation.
string $parallelize
When to do operations in parallel.
Definition: FileBackend.php:96
streamFile(array $params)
Stream the file at a storage path in the backend.
getScopedLocksForOps(array $ops, Status $status)
Get an array of scoped locks needed for a batch of file operations.
clean(array $params)
Delete a storage directory if it is empty.
getFileProps(array $params)
Get the properties of the file at a storage path in the backend.
static splitStoragePath($storagePath)
Split a storage path into a backend name, a container name, and a relative file path.
clearCache(array $paths=null)
Invalidate any in-process file stat and property cache.
LockManager $lockManager
doQuickOperation(array $op)
Same as doQuickOperations() except it takes a single operation.
string $wikiId
Unique wiki name.
Definition: FileBackend.php:90
isReadOnly()
Check if this backend is read-only.
preloadFileStat(array $params)
Preload file stat information (concurrently if possible) into in-process cache.
getLocalReference(array $params)
Returns a file system file, identical to the file at a storage path.
getFeatures()
Get the a bitfield of extra features supported by the backend medium.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition: hooks.txt:2338
static factory(array $config, $backend)
Create an appropriate FileJournal object from config.
Definition: FileJournal.php:63
static newGood($value=null)
Factory function for good results.
Definition: Status.php:101
doPublish(array $params)
getFileContents(array $params)
Get the contents of a file at a storage path in the backend.
getScopedFileLocks(array $paths, $type, Status $status, $timeout=0)
Lock the files at the given storage paths in the backend.
static parentStoragePath($storagePath)
Get the parent storage directory of a storage path.