/** @var WANObjectCache */
protected $wanCache;
+ /**
+ * @var string
+ * @protected Use $this->getName(). Public for back-compat only
+ */
+ public $name;
+
/**
* @param array|null $info
* @throws MWException
/**
* Store a file to a given destination.
*
- * @param string $srcPath Source file system path, storage path, or virtual URL
+ * Using FSFile/TempFSFile can improve performance via caching.
+ * Using TempFSFile can further improve performance by signalling that it is safe
+ * to touch the source file or write extended attribute metadata to it directly.
+ *
+ * @param string|FSFile $srcPath Source file system path, storage path, or virtual URL
* @param string $dstZone Destination zone
* @param string $dstRel Destination relative path
* @param int $flags Bitwise combination of the following flags:
/**
* Store a batch of files
*
+ * @see FileRepo::store()
+ *
* @param array $triplets (src, dest zone, dest rel) triplets as per store()
* @param int $flags Bitwise combination of the following flags:
* self::OVERWRITE Overwrite an existing destination file instead of failing
$operations = [];
// Validate each triplet and get the store operation...
foreach ( $triplets as $triplet ) {
- list( $srcPath, $dstZone, $dstRel ) = $triplet;
+ list( $src, $dstZone, $dstRel ) = $triplet;
+ $srcPath = ( $src instanceof FSFile ) ? $src->getPath() : $src;
wfDebug( __METHOD__
. "( \$src='$srcPath', \$dstZone='$dstZone', \$dstRel='$dstRel' )\n"
);
-
+ // Resolve source path
+ if ( $src instanceof FSFile ) {
+ $op = 'store';
+ } else {
+ $src = $this->resolveToStoragePathIfVirtual( $src );
+ $op = FileBackend::isStoragePath( $src ) ? 'copy' : 'store';
+ }
// Resolve destination path
$root = $this->getZonePath( $dstZone );
if ( !$root ) {
return $this->newFatal( 'directorycreateerror', $dstDir );
}
- // Resolve source to a storage path if virtual
- $srcPath = $this->resolveToStoragePath( $srcPath );
-
- // Get the appropriate file operation
- if ( FileBackend::isStoragePath( $srcPath ) ) {
- $opName = 'copy';
- } else {
- $opName = 'store';
- }
+ // Copy the source file to the destination
$operations[] = [
- 'op' => $opName,
- 'src' => $srcPath,
+ 'op' => $op,
+ 'src' => $src, // storage path (copy) or local file path (store)
'dst' => $dstPath,
- 'overwrite' => $flags & self::OVERWRITE,
- 'overwriteSame' => $flags & self::OVERWRITE_SAME,
+ 'overwrite' => ( $flags & self::OVERWRITE ) ? true : false,
+ 'overwriteSame' => ( $flags & self::OVERWRITE_SAME ) ? true : false,
];
}
$path = $this->getZonePath( $zone ) . "/$rel";
} else {
// Resolve source to a storage path if virtual
- $path = $this->resolveToStoragePath( $path );
+ $path = $this->resolveToStoragePathIfVirtual( $path );
}
$operations[] = [ 'op' => 'delete', 'src' => $path ];
}
* This function can be used to write to otherwise read-only foreign repos.
* This is intended for copying generated thumbnails into the repo.
*
+ * Using FSFile/TempFSFile can improve performance via caching.
+ * Using TempFSFile can further improve performance by signalling that it is safe
+ * to touch the source file or write extended attribute metadata to it directly.
+ *
* @param string|FSFile $src Source file system path, storage path, or virtual URL
* @param string $dst Virtual URL or storage path
* @param array|string|null $options An array consisting of a key named headers
return $this->quickImportBatch( [ [ $src, $dst, $options ] ] );
}
- /**
- * Purge a file from the repo. This does no locking nor journaling.
- * This function can be used to write to otherwise read-only foreign repos.
- * This is intended for purging thumbnails.
- *
- * @param string $path Virtual URL or storage path
- * @return Status
- */
- final public function quickPurge( $path ) {
- return $this->quickPurgeBatch( [ $path ] );
- }
-
- /**
- * Deletes a directory if empty.
- * This function can be used to write to otherwise read-only foreign repos.
- *
- * @param string $dir Virtual URL (or storage path) of directory to clean
- * @return Status
- */
- public function quickCleanDir( $dir ) {
- $status = $this->newGood();
- $status->merge( $this->backend->clean(
- [ 'dir' => $this->resolveToStoragePath( $dir ) ] ) );
-
- return $status;
- }
-
/**
* Import a batch of files from the local file system into the repo.
* This does no locking nor journaling and overrides existing files.
* This function can be used to write to otherwise read-only foreign repos.
* This is intended for copying generated thumbnails into the repo.
*
+ * @see FileRepo::quickImport()
+ *
* All path parameters may be a file system path, storage path, or virtual URL.
* When "headers" are given they are used as HTTP headers if supported.
*
if ( $src instanceof FSFile ) {
$op = 'store';
} else {
- $src = $this->resolveToStoragePath( $src );
+ $src = $this->resolveToStoragePathIfVirtual( $src );
$op = FileBackend::isStoragePath( $src ) ? 'copy' : 'store';
}
- $dst = $this->resolveToStoragePath( $dst );
+ $dst = $this->resolveToStoragePathIfVirtual( $dst );
if ( !isset( $triple[2] ) ) {
$headers = [];
$operations[] = [
'op' => $op,
- 'src' => $src,
+ 'src' => $src, // storage path (copy) or local path/FSFile (store)
'dst' => $dst,
'headers' => $headers
];
return $status;
}
+ /**
+ * Purge a file from the repo. This does no locking nor journaling.
+ * This function can be used to write to otherwise read-only foreign repos.
+ * This is intended for purging thumbnails.
+ *
+ * @param string $path Virtual URL or storage path
+ * @return Status
+ */
+ final public function quickPurge( $path ) {
+ return $this->quickPurgeBatch( [ $path ] );
+ }
+
+ /**
+ * Deletes a directory if empty.
+ * This function can be used to write to otherwise read-only foreign repos.
+ *
+ * @param string $dir Virtual URL (or storage path) of directory to clean
+ * @return Status
+ */
+ public function quickCleanDir( $dir ) {
+ $status = $this->newGood();
+ $status->merge( $this->backend->clean(
+ [ 'dir' => $this->resolveToStoragePathIfVirtual( $dir ) ] ) );
+
+ return $status;
+ }
+
/**
* Purge a batch of files from the repo.
* This function can be used to write to otherwise read-only foreign repos.
foreach ( $paths as $path ) {
$operations[] = [
'op' => 'delete',
- 'src' => $this->resolveToStoragePath( $path ),
+ 'src' => $this->resolveToStoragePathIfVirtual( $path ),
'ignoreMissingSource' => true
];
}
$sources = [];
foreach ( $srcPaths as $srcPath ) {
// Resolve source to a storage path if virtual
- $source = $this->resolveToStoragePath( $srcPath );
+ $source = $this->resolveToStoragePathIfVirtual( $srcPath );
$sources[] = $source; // chunk to merge
}
* Returns a Status object. On success, the value contains "new" or
* "archived", to indicate whether the file was new with that name.
*
+ * Using FSFile/TempFSFile can improve performance via caching.
+ * Using TempFSFile can further improve performance by signalling that it is safe
+ * to touch the source file or write extended attribute metadata to it directly.
+ *
* Options to $options include:
* - headers : name/value map of HTTP headers to use in response to GET/HEAD requests
*
/**
* Publish a batch of files
*
+ * @see FileRepo::publish()
+ *
* @param array $ntuples (source, dest, archive) triplets or
* (source, dest, archive, options) 4-tuples as per publish().
* @param int $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
$options = $ntuple[3] ?? [];
// Resolve source to a storage path if virtual
- $srcPath = $this->resolveToStoragePath( $srcPath );
+ $srcPath = $this->resolveToStoragePathIfVirtual( $srcPath );
if ( !$this->validateFilename( $dstRel ) ) {
throw new MWException( 'Validation error in $dstRel' );
}
// Copy (or move) the source file to the destination
if ( FileBackend::isStoragePath( $srcPath ) ) {
- if ( $flags & self::DELETE_SOURCE ) {
- $operations[] = [
- 'op' => 'move',
- 'src' => $srcPath,
- 'dst' => $dstPath,
- 'overwrite' => true, // replace current
- 'headers' => $headers
- ];
- } else {
- $operations[] = [
- 'op' => 'copy',
- 'src' => $srcPath,
- 'dst' => $dstPath,
- 'overwrite' => true, // replace current
- 'headers' => $headers
- ];
- }
- } else { // FS source path
+ $operations[] = [
+ 'op' => ( $flags & self::DELETE_SOURCE ) ? 'move' : 'copy',
+ 'src' => $srcPath,
+ 'dst' => $dstPath,
+ 'overwrite' => true, // replace current
+ 'headers' => $headers
+ ];
+ } else {
$operations[] = [
'op' => 'store',
- 'src' => $src, // prefer FSFile objects
+ 'src' => $src, // storage path (copy) or local path/FSFile (store)
'dst' => $dstPath,
'overwrite' => true, // replace current
'headers' => $headers
* @return Status
*/
protected function initDirectory( $dir ) {
- $path = $this->resolveToStoragePath( $dir );
+ $path = $this->resolveToStoragePathIfVirtual( $dir );
list( , $container, ) = FileBackend::splitStoragePath( $path );
$params = [ 'dir' => $path ];
$status = $this->newGood();
$status->merge( $this->backend->clean(
- [ 'dir' => $this->resolveToStoragePath( $dir ) ] ) );
+ [ 'dir' => $this->resolveToStoragePathIfVirtual( $dir ) ] ) );
return $status;
}
* @return array Map of files and existence flags, or false
*/
public function fileExistsBatch( array $files ) {
- $paths = array_map( [ $this, 'resolveToStoragePath' ], $files );
+ $paths = array_map( [ $this, 'resolveToStoragePathIfVirtual' ], $files );
$this->backend->preloadFileStat( [ 'srcs' => $paths ] );
$result = [];
foreach ( $files as $key => $file ) {
- $path = $this->resolveToStoragePath( $file );
+ $path = $this->resolveToStoragePathIfVirtual( $file );
$result[$key] = $this->backend->fileExists( [ 'src' => $path ] );
}
* @return string
* @throws MWException
*/
- protected function resolveToStoragePath( $path ) {
+ protected function resolveToStoragePathIfVirtual( $path ) {
if ( self::isVirtualUrl( $path ) ) {
return $this->resolveVirtualUrl( $path );
}
* @return TempFSFile|null Returns null on failure
*/
public function getLocalCopy( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getLocalCopy( [ 'src' => $path ] );
}
* @return FSFile|null Returns null on failure.
*/
public function getLocalReference( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getLocalReference( [ 'src' => $path ] );
}
* @return string|bool False on failure
*/
public function getFileTimestamp( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getFileTimestamp( [ 'src' => $path ] );
}
* @return int|bool False on failure
*/
public function getFileSize( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getFileSize( [ 'src' => $path ] );
}
* @return string|bool
*/
public function getFileSha1( $virtualUrl ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
return $this->backend->getFileSha1Base36( [ 'src' => $path ] );
}
* @since 1.27
*/
public function streamFileWithStatus( $virtualUrl, $headers = [], $optHeaders = [] ) {
- $path = $this->resolveToStoragePath( $virtualUrl );
+ $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
$params = [ 'src' => $path, 'headers' => $headers, 'options' => $optHeaders ];
// T172851: HHVM does not flush the output properly, causing OOM