aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/core_ext/file
diff options
context:
space:
mode:
authorJoshua Peek <josh@joshpeek.com>2008-08-06 14:39:13 -0500
committerJoshua Peek <josh@joshpeek.com>2008-08-06 14:54:18 -0500
commit73056500f88d569fa497d846dfe6b501a9e03739 (patch)
tree65368ccb14066781f2cf598f76ea057eca5c4569 /activesupport/lib/active_support/core_ext/file
parent080974784582e1e289c2948227b446bc56d404a1 (diff)
downloadrails-73056500f88d569fa497d846dfe6b501a9e03739.tar.gz
rails-73056500f88d569fa497d846dfe6b501a9e03739.tar.bz2
rails-73056500f88d569fa497d846dfe6b501a9e03739.zip
Make File.atomic_write copy the original permissions or use the directories default.
Diffstat (limited to 'activesupport/lib/active_support/core_ext/file')
-rw-r--r--activesupport/lib/active_support/core_ext/file/atomic.rb46
1 files changed, 46 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/core_ext/file/atomic.rb b/activesupport/lib/active_support/core_ext/file/atomic.rb
new file mode 100644
index 0000000000..4d3cf5423f
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/file/atomic.rb
@@ -0,0 +1,46 @@
+require 'tempfile'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module File #:nodoc:
+ module Atomic
+ # Write to a file atomically. Useful for situations where you don't
+ # want other processes or threads to see half-written files.
+ #
+ # File.atomic_write("important.file") do |file|
+ # file.write("hello")
+ # end
+ #
+ # If your temp directory is not on the same filesystem as the file you're
+ # trying to write, you can provide a different temporary directory.
+ #
+ # File.atomic_write("/data/something.important", "/data/tmp") do |f|
+ # file.write("hello")
+ # end
+ def atomic_write(file_name, temp_dir = Dir.tmpdir)
+ temp_file = Tempfile.new(basename(file_name), temp_dir)
+ yield temp_file
+ temp_file.close
+
+ begin
+ # Get original file permissions
+ old_stat = stat(file_name)
+ rescue Errno::ENOENT
+ # No old permissions, write a temp file to determine the defaults
+ check_name = ".permissions_check.#{Thread.current.object_id}.#{Process.pid}.#{rand(1000000)}"
+ new(check_name, "w")
+ old_stat = stat(check_name)
+ unlink(check_name)
+ end
+
+ # Overwrite original file with temp file
+ rename(temp_file.path, file_name)
+
+ # Set correct permissions on new file
+ chown(old_stat.uid, old_stat.gid, file_name)
+ chmod(old_stat.mode, file_name)
+ end
+ end
+ end
+ end
+end