12use Wikimedia\Timestamp\ConvertibleTimestamp;
13use Wikimedia\Timestamp\TimestampFormat as TS;
43 if ( $dst ===
null ) {
44 $status->fatal(
'backend-fail-invalidpath', $params[
'dst'] );
49 $this->files[$dst] = [
50 'data' => $params[
'content'],
51 'mtime' => ConvertibleTimestamp::convert( TS::MW, time() )
62 if ( $dst ===
null ) {
63 $status->fatal(
'backend-fail-invalidpath', $params[
'dst'] );
69 $data = @file_get_contents( $params[
'src'] );
70 if ( $data ===
false ) {
71 $status->fatal(
'backend-fail-store', $params[
'src'], $params[
'dst'] );
76 $this->files[$dst] = [
78 'mtime' => ConvertibleTimestamp::convert( TS::MW, time() )
86 return $this->copyInMemory( $params,
'copy' );
91 return $this->copyInMemory( $params,
'move' );
99 private function copyInMemory( array $params,
string $action ) {
103 if ( $src ===
null ) {
104 $status->fatal(
'backend-fail-invalidpath', $params[
'src'] );
110 if ( $dst ===
null ) {
111 $status->fatal(
'backend-fail-invalidpath', $params[
'dst'] );
116 if ( !isset( $this->files[$src] ) ) {
117 if ( empty( $params[
'ignoreMissingSource'] ) ) {
119 $status->fatal(
'backend-fail-' . $action, $params[
'src'], $params[
'dst'] );
125 $this->files[$dst] = [
126 'data' => $this->files[$src][
'data'],
127 'mtime' => ConvertibleTimestamp::convert( TS::MW, time() )
130 if ( $action ===
'move' ) {
131 unset( $this->files[$src] );
141 if ( $src ===
null ) {
142 $status->fatal(
'backend-fail-invalidpath', $params[
'src'] );
147 if ( !isset( $this->files[$src] ) ) {
148 if ( empty( $params[
'ignoreMissingSource'] ) ) {
149 $status->fatal(
'backend-fail-delete', $params[
'src'] );
155 unset( $this->files[$src] );
163 if ( $src ===
null ) {
164 return self::RES_ERROR;
167 if ( isset( $this->files[$src] ) ) {
169 'mtime' => $this->files[$src][
'mtime'],
170 'size' => strlen( $this->files[$src][
'data'] ),
174 return self::RES_ABSENT;
180 foreach ( $params[
'srcs'] as $srcPath ) {
182 if ( $src ===
null ) {
183 $fsFile = self::RES_ERROR;
184 } elseif ( !isset( $this->files[$src] ) ) {
185 $fsFile = self::RES_ABSENT;
189 $fsFile = $this->tmpFileFactory->newTempFSFile(
'localcopy_', $ext );
191 $bytes = file_put_contents( $fsFile->getPath(), $this->files[$src][
'data'] );
192 if ( $bytes !== strlen( $this->files[$src][
'data'] ) ) {
193 $fsFile = self::RES_ERROR;
197 $tmpFiles[$srcPath] = $fsFile;
205 $prefix = rtrim(
"$fullCont/$dirRel",
'/' ) .
'/';
206 foreach ( $this->files as
$path => $data ) {
207 if ( str_starts_with(
$path, $prefix ) ) {
218 $prefix = rtrim(
"$fullCont/$dirRel",
'/' ) .
'/';
219 $prefixLen = strlen( $prefix );
220 foreach ( $this->files as
$path => $data ) {
221 if ( str_starts_with(
$path, $prefix ) ) {
222 $relPath = substr(
$path, $prefixLen );
223 if ( !str_contains( $relPath,
'/' ) ) {
226 $parts = array_slice( explode(
'/', $relPath ), 0, -1 );
227 if ( !empty( $params[
'topOnly'] ) ) {
228 $dirs[$parts[0]] = 1;
231 foreach ( $parts as $part ) {
232 $dirRel = ( $current ===
'' ) ? $part :
"$current/$part";
240 return array_keys( $dirs );
246 $prefix = rtrim(
"$fullCont/$dirRel",
'/' ) .
'/';
247 $prefixLen = strlen( $prefix );
248 foreach ( $this->files as
$path => $data ) {
249 if ( str_starts_with(
$path, $prefix ) ) {
250 $relPath = substr(
$path, $prefixLen );
253 ( !empty( $params[
'topOnly'] ) && str_contains( $relPath,
'/' ) )
277 if ( $relPath ===
null ) {
281 return ( $relPath !==
'' ) ?
"$fullCont/$relPath" : $fullCont;
286class_alias( MemoryFileBackend::class,
'MemoryFileBackend' );