Preserve file permissions on Windows self-update (#9733)
Windows file operations result in different file permissions depending if the file is copied or moved. A copy operation applies permissions from the destination folder (or file if it already exists and does not use inheritance), while a move operation generally preserves the source file permissions. Windows PHP `rename` uses MoveFileEx so if the user is running as an admin and the destination is in a common (non-user) location, then the permission for other users will be replaced by the admin user. Likewise for the UAC elevation feature, which uses the cmd.exe `move` command. This fix uses copy and delete operations on Windows, so that other users can continue to run composer.pharpull/9734/head
parent
e3af4ee606
commit
07f59a9162
|
@ -425,7 +425,14 @@ TAGSPUBKEY
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -534,7 +541,7 @@ TAGSPUBKEY
|
|||
/**
|
||||
* 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
|
||||
|
@ -560,13 +567,13 @@ TAGSPUBKEY
|
|||
|
||||
$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;
|
||||
|
||||
|
@ -574,11 +581,12 @@ EOT;
|
|||
exec('"'.$script.'"');
|
||||
@unlink($script);
|
||||
|
||||
// see if the file was moved
|
||||
if ($result = (hash_file('sha256', $localFilename) === $checksum)) {
|
||||
// see if the file was moved 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;
|
||||
|
|
Loading…
Reference in New Issue