Skip to content

Commit 9365c6e

Browse files
authored
Merge pull request #325 from asgrim/use-portable-chown
Use a portable method of copying ownership to new file
2 parents 085b4ca + a104a74 commit 9365c6e

File tree

1 file changed

+36
-2
lines changed

1 file changed

+36
-2
lines changed

src/File/SudoFilePut.php

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66

77
use Php\Pie\Util\CaptureErrors;
88
use Php\Pie\Util\Process;
9+
use Symfony\Component\Process\Exception\ProcessFailedException;
910

1011
use function dirname;
1112
use function file_exists;
1213
use function file_put_contents;
1314
use function is_writable;
15+
use function preg_match;
1416
use function sys_get_temp_dir;
1517
use function tempnam;
1618

@@ -61,10 +63,42 @@ private static function writeWithSudo(string $filename, string $content): void
6163
}
6264

6365
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);
6667
}
6768

6869
Process::run([Sudo::find(), 'mv', $tempFilename, $filename]);
6970
}
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+
}
70104
}

0 commit comments

Comments
 (0)