summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-09-08 13:38:01 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-09-08 13:38:01 +0000
commit032a314c5025d2d87e5ea11c58162e698fff0168 (patch)
tree7afb2017f336e7db02e11d9205de911d9cfcf40b /lib
parente6dd856d73d084371c0b916cdfabf5775c1d0375 (diff)
* lib/tempfile.rb, lib/tmpdir.rb (Tmpname): extracted new module.
[ruby-dev:39197] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24795 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rwxr-xr-xlib/tempfile.rb82
-rw-r--r--lib/tmpdir.rb89
2 files changed, 79 insertions, 92 deletions
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
index 46164e8b99..4ebeea28a1 100755
--- a/lib/tempfile.rb
+++ b/lib/tempfile.rb
@@ -80,8 +80,7 @@ require 'thread'
# mutex.
class Tempfile < DelegateClass(File)
MAX_TRY = 10 # :nodoc:
- @@cleanlist = []
- @@lock = Mutex.new
+ include Dir::Tmpname
# call-seq:
# new(basename, [tmpdir = Dir.tmpdir], [options])
@@ -128,70 +127,24 @@ class Tempfile < DelegateClass(File)
# If Tempfile.new cannot find a unique filename within a limited
# number of tries, then it will raise an exception.
def initialize(basename, *rest)
- # I wish keyword argument settled soon.
- if opts = Hash.try_convert(rest[-1])
- rest.pop
- end
- tmpdir = rest[0] || Dir::tmpdir
- if $SAFE > 0 and tmpdir.tainted?
- tmpdir = '/tmp'
- end
+ @data = []
+ @clean_proc = self.class.callback(@data)
+ ObjectSpace.define_finalizer(self, @clean_proc)
- lock = tmpname = nil
- n = failure = 0
- @@lock.synchronize {
+ create(basename, *rest) do |tmpname, n, opts|
+ lock = tmpname + '.lock'
+ self.class.mkdir(lock)
begin
- begin
- tmpname = File.join(tmpdir, make_tmpname(basename, n))
- lock = tmpname + '.lock'
- n += 1
- end while @@cleanlist.include?(tmpname) or
- File.exist?(lock) or File.exist?(tmpname)
- Dir.mkdir(lock)
- rescue
- failure += 1
- retry if failure < MAX_TRY
- raise "cannot generate tempfile `#{tmpname}'"
+ @data[1] = @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600, *opts)
+ @data[0] = @tmpname = tmpname
+ ensure
+ self.class.rmdir(lock)
end
- }
-
- @data = [tmpname]
- @clean_proc = Tempfile.callback(@data)
- ObjectSpace.define_finalizer(self, @clean_proc)
-
- if opts.nil?
- opts = []
- else
- opts = [opts]
end
- @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600, *opts)
- @tmpname = tmpname
- @@cleanlist << @tmpname
- @data[1] = @tmpfile
- @data[2] = @@cleanlist
super(@tmpfile)
-
- # Now we have all the File/IO methods defined, you must not
- # carelessly put bare puts(), etc. after this.
-
- Dir.rmdir(lock)
end
- def make_tmpname(basename, n)
- case basename
- when Array
- prefix, suffix = *basename
- else
- prefix, suffix = basename, ''
- end
-
- t = Time.now.strftime("%Y%m%d")
- th = Thread.current.object_id
- path = "#{prefix}#{t}-#{$$}-#{th.to_s(36)}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}"
- end
- private :make_tmpname
-
# Opens or reopens the file with mode "r+".
def open
@tmpfile.close if @tmpfile
@@ -269,8 +222,7 @@ class Tempfile < DelegateClass(File)
if File.exist?(@tmpname)
File.unlink(@tmpname)
end
- @@cleanlist.delete(@tmpname)
- # remove tmpname and cleanlist from callback
+ # remove tmpname from callback
@data[0] = @data[2] = nil
@data = @tmpname = nil
rescue Errno::EACCES
@@ -302,7 +254,7 @@ class Tempfile < DelegateClass(File)
pid = $$
Proc.new {
if pid == $$
- path, tmpfile, cleanlist = *data
+ path, tmpfile = *data
STDERR.print "removing ", path, "..." if $DEBUG
@@ -311,7 +263,6 @@ class Tempfile < DelegateClass(File)
# keep this order for thread safeness
if path
File.unlink(path) if File.exist?(path)
- cleanlist.delete(path) if cleanlist
end
STDERR.print "done\n" if $DEBUG
@@ -354,6 +305,13 @@ class Tempfile < DelegateClass(File)
tempfile
end
end
+
+ def mkdir(*args)
+ Dir.mkdir(*args)
+ end
+ def rmdir(*args)
+ Dir.rmdir(*args)
+ end
end
end
diff --git a/lib/tmpdir.rb b/lib/tmpdir.rb
index 0d247bdd54..0aa9cf5e3b 100644
--- a/lib/tmpdir.rb
+++ b/lib/tmpdir.rb
@@ -10,8 +10,12 @@ class Dir
@@systmpdir = '/tmp'
- begin
- require 'Win32API'
+ if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and
+ begin
+ require 'Win32API'
+ true
+ rescue LoadError
+ end
CSIDL_LOCAL_APPDATA = 0x001c
max_pathlen = 260
windir = "\0"*(max_pathlen+1)
@@ -30,7 +34,6 @@ class Dir
windir.force_encoding(Dir.pwd.encoding)
temp = File.expand_path('temp', windir.untaint)
@@systmpdir = temp if File.directory?(temp) and File.writable?(temp)
- rescue LoadError
end
##
@@ -95,41 +98,67 @@ class Dir
# FileUtils.remove_entry_secure dir
# end
#
- def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil)
- case prefix_suffix
- when nil
- prefix = "d"
- suffix = ""
- when String
- prefix = prefix_suffix
- suffix = ""
- when Array
- prefix = prefix_suffix[0]
- suffix = prefix_suffix[1]
+ def Dir.mktmpdir(prefix_suffix=nil, *rest)
+ path = Tmpname.create(prefix_suffix || "d", *rest) {|n| mkdir(n, 0700)}
+ if block_given?
+ begin
+ yield path
+ ensure
+ FileUtils.remove_entry_secure path
+ end
else
- raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
+ path
end
- tmpdir ||= Dir.tmpdir
- t = Time.now.strftime("%Y%m%d")
- n = nil
- begin
- path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
+ end
+
+ module Tmpname
+ module_function
+
+ def tmpdir
+ Dir.tmpdir
+ end
+
+ def make_tmpname(prefix_suffix, n)
+ case prefix_suffix
+ when String
+ prefix = prefix_suffix
+ suffix = ""
+ when Array
+ prefix = prefix_suffix[0]
+ suffix = prefix_suffix[1]
+ else
+ raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
+ end
+ t = Time.now.strftime("%Y%m%d")
+ path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
path << "-#{n}" if n
path << suffix
- Dir.mkdir(path, 0700)
- rescue Errno::EEXIST
- n ||= 0
- n += 1
- retry
end
- if block_given?
+ def create(basename, *rest)
+ if opts = Hash.try_convert(rest[-1])
+ opts = opts.dup if rest.pop.equal?(opts)
+ max_try = opts.delete(:max_try)
+ opts = [opts]
+ else
+ opts = []
+ end
+ tmpdir, = *rest
+ if $SAFE > 0 and tmpdir.tainted?
+ tmpdir = '/tmp'
+ else
+ tmpdir ||= tmpdir()
+ end
+ n = nil
begin
- yield path
- ensure
- FileUtils.remove_entry_secure path
+ path = File.expand_path(make_tmpname(basename, n), tmpdir)
+ yield(path, n, opts)
+ rescue Errno::EEXIST
+ n ||= 0
+ n += 1
+ retry if !max_try or n < max_try
+ raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'"
end
- else
path
end
end