diff options
| author | Jack Nagel | 2014-09-20 17:11:16 -0500 |
|---|---|---|
| committer | Jack Nagel | 2014-09-20 17:11:16 -0500 |
| commit | 2d16f8c202dc080056262bade9417f249a4ba827 (patch) | |
| tree | 24c9f86cc1a4ab4ad163d3ce3177c7d21e0d8a6e /Library | |
| parent | 6ad82e65da50b3ebd86dffa3e27e31b0f6dac318 (diff) | |
| download | brew-2d16f8c202dc080056262bade9417f249a4ba827.tar.bz2 | |
Make Pathname#atomic_write truly atomic
As we know, files cannot be moved across filesystems atomically. In that
case, FileUtils.mv will make a copy. But if we create the temp file in
the same directory as the target, we can avoid this and use File.rename
directly.
Additionally, the rename should be the absolute last step, so that the
original file is preserved if altering ownership and permissions fails.
Diffstat (limited to 'Library')
| -rw-r--r-- | Library/Homebrew/extend/pathname.rb | 13 |
1 files changed, 7 insertions, 6 deletions
diff --git a/Library/Homebrew/extend/pathname.rb b/Library/Homebrew/extend/pathname.rb index ca1d167c1..e65dc25ef 100644 --- a/Library/Homebrew/extend/pathname.rb +++ b/Library/Homebrew/extend/pathname.rb @@ -105,10 +105,9 @@ class Pathname # NOTE always overwrites def atomic_write content require "tempfile" - tf = Tempfile.new(basename.to_s) + tf = Tempfile.new(basename.to_s, dirname) tf.binmode tf.write(content) - tf.close begin old_stat = stat @@ -116,16 +115,18 @@ class Pathname old_stat = default_stat end - FileUtils.mv tf.path, self - uid = Process.uid gid = Process.groups.delete(old_stat.gid) { Process.gid } begin - chown(uid, gid) - chmod(old_stat.mode) + tf.chown(uid, gid) + tf.chmod(old_stat.mode) rescue Errno::EPERM end + + File.rename(tf.path, self) + ensure + tf.close! end def default_stat |
