|
6 | 6 |
|
7 | 7 | use Php\Pie\Util\CaptureErrors; |
8 | 8 | use Php\Pie\Util\Process; |
| 9 | +use Symfony\Component\Process\Exception\ProcessFailedException; |
9 | 10 |
|
10 | 11 | use function dirname; |
11 | 12 | use function file_exists; |
12 | 13 | use function file_put_contents; |
13 | 14 | use function is_writable; |
| 15 | +use function preg_match; |
14 | 16 | use function sys_get_temp_dir; |
15 | 17 | use function tempnam; |
16 | 18 |
|
@@ -61,10 +63,42 @@ private static function writeWithSudo(string $filename, string $content): void |
61 | 63 | } |
62 | 64 |
|
63 | 65 | if (file_exists($filename)) { |
64 | | - Process::run([Sudo::find(), 'chmod', '--reference=' . $filename, $tempFilename]); |
65 | | - Process::run([Sudo::find(), 'chown', '--reference=' . $filename, $tempFilename]); |
| 66 | + self::copyOwnership($filename, $tempFilename); |
66 | 67 | } |
67 | 68 |
|
68 | 69 | Process::run([Sudo::find(), 'mv', $tempFilename, $filename]); |
69 | 70 | } |
| 71 | + |
| 72 | + /** |
| 73 | + * Attempt to copy the ownership details (uid/gid) from the source to the |
| 74 | + * given target file. |
| 75 | + */ |
| 76 | + private static function copyOwnership(string $sourceFile, string $targetFile): void |
| 77 | + { |
| 78 | + try { |
| 79 | + // GNU chmod supports `--reference`, so try this first |
| 80 | + Process::run([Sudo::find(), 'chmod', '--reference=' . $sourceFile, $targetFile]); |
| 81 | + |
| 82 | + return; |
| 83 | + } catch (ProcessFailedException) { |
| 84 | + // Fall back to using `stat` to determine uid/gid |
| 85 | + try { |
| 86 | + // Try using GNU stat (-c) first |
| 87 | + $userAndGroup = Process::run(['stat', '-c', '%u:%g', $sourceFile], timeout: 2); |
| 88 | + } catch (ProcessFailedException) { |
| 89 | + try { |
| 90 | + // Fall back to using OSX stat (-f) |
| 91 | + $userAndGroup = Process::run(['stat', '-f', '%u:%g', $sourceFile], timeout: 2); |
| 92 | + } catch (ProcessFailedException) { |
| 93 | + return; |
| 94 | + } |
| 95 | + } |
| 96 | + |
| 97 | + if (empty($userAndGroup) || ! preg_match('/^\d+:\d+$/', $userAndGroup)) { |
| 98 | + return; |
| 99 | + } |
| 100 | + |
| 101 | + Process::run([Sudo::find(), 'chown', $userAndGroup, $targetFile]); |
| 102 | + } |
| 103 | + } |
70 | 104 | } |
0 commit comments