Add moveFileOrDir method to handle cross-device file and directory moves

This commit is contained in:
crazywhalecc
2026-04-08 22:14:55 +08:00
parent 9182cf1e34
commit 2f260e4d09
2 changed files with 69 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Package\Artifact;
use StaticPHP\Attribute\Artifact\AfterSourceExtract;
use StaticPHP\Attribute\PatchDescription;
use StaticPHP\Util\SourcePatcher;
class imagick
{
#[AfterSourceExtract('ext-imagick')]
#[PatchDescription('Patch imagick for PHP 8.4 compatibility (versions < 3.8.0)')]
public function patchImagickWith84(): void
{
// match imagick version id
$file = SOURCE_PATH . '/php-src/ext/imagick/php_imagick.h';
if (!file_exists($file)) {
return;
}
$content = file_get_contents($file);
if (preg_match('/#define PHP_IMAGICK_EXTNUM\s+(\d+)/', $content, $match) === 0) {
return;
}
$extnum = intval($match[1]);
if ($extnum < 30800) {
SourcePatcher::patchFile('imagick_php84_before_30800.patch', SOURCE_PATH . '/php-src/ext/imagick');
}
}
}

View File

@@ -493,6 +493,44 @@ class FileSystem
return FileSystem::convertPath($path);
}
/**
* Move file or directory, handling cross-device scenarios
* Uses rename() if possible, falls back to copy+delete for cross-device moves
*
* @param string $source Source path
* @param string $dest Destination path
*/
public static function moveFileOrDir(string $source, string $dest): void
{
$source = FileSystem::convertPath($source);
$dest = FileSystem::convertPath($dest);
// Check if source and dest are on the same device to avoid cross-device rename errors
$source_stat = @stat($source);
$dest_parent = dirname($dest);
$dest_stat = @stat($dest_parent);
// Only use rename if on same device
if ($source_stat !== false && $dest_stat !== false && $source_stat['dev'] === $dest_stat['dev']) {
if (@rename($source, $dest)) {
return;
}
}
// Fall back to copy + delete for cross-device moves or if rename failed
if (is_dir($source)) {
FileSystem::copyDir($source, $dest);
FileSystem::removeDir($source);
} else {
if (!copy($source, $dest)) {
throw new FileSystemException("Failed to copy file from {$source} to {$dest}");
}
if (!unlink($source)) {
throw new FileSystemException("Failed to remove source file: {$source}");
}
}
}
private static function replaceFile(string $filename, int $replace_type = REPLACE_FILE_STR, mixed $callback_or_search = null, mixed $to_replace = null): false|int
{
logger()->debug('Replacing file with type[' . $replace_type . ']: ' . $filename);