Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use copy in selfupdate to fix Windows PHP-8.1 regression #10446

Merged
merged 1 commit into from Jan 21, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 20 additions & 9 deletions src/Composer/Command/SelfUpdateCommand.php
Expand Up @@ -104,7 +104,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
$localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];

if ($input->getOption('update-keys')) {
return $this->fetchKeys($io, $config);
$this->fetchKeys($io, $config);

return 0;
}

// ensure composer.phar location is accessible
Expand Down Expand Up @@ -417,7 +419,14 @@ protected function setLocalPhar($localFilename, $newFilename, $backupTarget = nu
}

try {
rename($newFilename, $localFilename);
if (Platform::isWindows()) {
// use copy to apply permissions from the destination directory
// as rename uses source permissions and may block other users
copy($newFilename, $localFilename);
@unlink($newFilename);
} else {
rename($newFilename, $localFilename);
}

return true;
} catch (\Exception $e) {
Expand All @@ -428,6 +437,7 @@ protected function setLocalPhar($localFilename, $newFilename, $backupTarget = nu
return $this->tryAsWindowsAdmin($localFilename, $newFilename);
}

@unlink($newFilename);
$action = 'Composer '.($backupTarget ? 'update' : 'rollback');
throw new FilesystemException($action.' failed: "'.$localFilename.'" could not be written.'.PHP_EOL.$e->getMessage());
}
Expand Down Expand Up @@ -528,7 +538,7 @@ protected function isWindowsNonAdminUser()
/**
* Invokes a UAC prompt to update composer.phar as an admin
*
* Uses a .vbs script to elevate and run the cmd.exe move command.
* Uses a .vbs script to elevate and run the cmd.exe copy command.
*
* @param string $localFilename The composer.phar location
* @param string $newFilename The downloaded or backup phar
Expand All @@ -554,26 +564,27 @@ protected function tryAsWindowsAdmin($localFilename, $newFilename)

$checksum = hash_file('sha256', $newFilename);

// cmd's internal move is fussy about backslashes
// cmd's internal copy is fussy about backslashes
$source = str_replace('/', '\\', $newFilename);
$destination = str_replace('/', '\\', $localFilename);

$vbs = <<<EOT
Set UAC = CreateObject("Shell.Application")
UAC.ShellExecute "cmd.exe", "/c move /y ""$source"" ""$destination""", "", "runas", 0
UAC.ShellExecute "cmd.exe", "/c copy /b /y ""$source"" ""$destination""", "", "runas", 0
Wscript.Sleep(300)
EOT;

file_put_contents($script, $vbs);
exec('"'.$script.'"');
@unlink($script);

// see if the file was moved
if ($result = (hash_file('sha256', $localFilename) === $checksum)) {
// see if the file was copied and is still accessible
if ($result = is_readable($localFilename) && (hash_file('sha256', $localFilename) === $checksum)) {
$io->writeError('<info>Operation succeeded.</info>');
@unlink($newFilename);
} else {
$io->writeError('<error>Operation failed (file not written). '.$helpMessage.'</error>');
};
$io->writeError('<error>Operation failed.'.$helpMessage.'</error>');
}

return $result;
}
Expand Down