mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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
This commit is contained in:
parent
e6dd856d73
commit
032a314c50
3 changed files with 86 additions and 94 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
Tue Sep 8 22:37:59 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* lib/tempfile.rb, lib/tmpdir.rb (Tmpname): extracted new module.
|
||||||
|
[ruby-dev:39197]
|
||||||
|
|
||||||
Tue Sep 8 22:18:11 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Tue Sep 8 22:18:11 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* st.c (st_init_*table_with_size): use st_index_t.
|
* st.c (st_init_*table_with_size): use st_index_t.
|
||||||
|
|
|
@ -80,8 +80,7 @@ require 'thread'
|
||||||
# mutex.
|
# mutex.
|
||||||
class Tempfile < DelegateClass(File)
|
class Tempfile < DelegateClass(File)
|
||||||
MAX_TRY = 10 # :nodoc:
|
MAX_TRY = 10 # :nodoc:
|
||||||
@@cleanlist = []
|
include Dir::Tmpname
|
||||||
@@lock = Mutex.new
|
|
||||||
|
|
||||||
# call-seq:
|
# call-seq:
|
||||||
# new(basename, [tmpdir = Dir.tmpdir], [options])
|
# 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
|
# If Tempfile.new cannot find a unique filename within a limited
|
||||||
# number of tries, then it will raise an exception.
|
# number of tries, then it will raise an exception.
|
||||||
def initialize(basename, *rest)
|
def initialize(basename, *rest)
|
||||||
# I wish keyword argument settled soon.
|
@data = []
|
||||||
if opts = Hash.try_convert(rest[-1])
|
@clean_proc = self.class.callback(@data)
|
||||||
rest.pop
|
|
||||||
end
|
|
||||||
tmpdir = rest[0] || Dir::tmpdir
|
|
||||||
if $SAFE > 0 and tmpdir.tainted?
|
|
||||||
tmpdir = '/tmp'
|
|
||||||
end
|
|
||||||
|
|
||||||
lock = tmpname = nil
|
|
||||||
n = failure = 0
|
|
||||||
@@lock.synchronize {
|
|
||||||
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}'"
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
@data = [tmpname]
|
|
||||||
@clean_proc = Tempfile.callback(@data)
|
|
||||||
ObjectSpace.define_finalizer(self, @clean_proc)
|
ObjectSpace.define_finalizer(self, @clean_proc)
|
||||||
|
|
||||||
if opts.nil?
|
create(basename, *rest) do |tmpname, n, opts|
|
||||||
opts = []
|
lock = tmpname + '.lock'
|
||||||
else
|
self.class.mkdir(lock)
|
||||||
opts = [opts]
|
begin
|
||||||
|
@data[1] = @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600, *opts)
|
||||||
|
@data[0] = @tmpname = tmpname
|
||||||
|
ensure
|
||||||
|
self.class.rmdir(lock)
|
||||||
|
end
|
||||||
end
|
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)
|
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
|
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+".
|
# Opens or reopens the file with mode "r+".
|
||||||
def open
|
def open
|
||||||
@tmpfile.close if @tmpfile
|
@tmpfile.close if @tmpfile
|
||||||
|
@ -269,8 +222,7 @@ class Tempfile < DelegateClass(File)
|
||||||
if File.exist?(@tmpname)
|
if File.exist?(@tmpname)
|
||||||
File.unlink(@tmpname)
|
File.unlink(@tmpname)
|
||||||
end
|
end
|
||||||
@@cleanlist.delete(@tmpname)
|
# remove tmpname from callback
|
||||||
# remove tmpname and cleanlist from callback
|
|
||||||
@data[0] = @data[2] = nil
|
@data[0] = @data[2] = nil
|
||||||
@data = @tmpname = nil
|
@data = @tmpname = nil
|
||||||
rescue Errno::EACCES
|
rescue Errno::EACCES
|
||||||
|
@ -302,7 +254,7 @@ class Tempfile < DelegateClass(File)
|
||||||
pid = $$
|
pid = $$
|
||||||
Proc.new {
|
Proc.new {
|
||||||
if pid == $$
|
if pid == $$
|
||||||
path, tmpfile, cleanlist = *data
|
path, tmpfile = *data
|
||||||
|
|
||||||
STDERR.print "removing ", path, "..." if $DEBUG
|
STDERR.print "removing ", path, "..." if $DEBUG
|
||||||
|
|
||||||
|
@ -311,7 +263,6 @@ class Tempfile < DelegateClass(File)
|
||||||
# keep this order for thread safeness
|
# keep this order for thread safeness
|
||||||
if path
|
if path
|
||||||
File.unlink(path) if File.exist?(path)
|
File.unlink(path) if File.exist?(path)
|
||||||
cleanlist.delete(path) if cleanlist
|
|
||||||
end
|
end
|
||||||
|
|
||||||
STDERR.print "done\n" if $DEBUG
|
STDERR.print "done\n" if $DEBUG
|
||||||
|
@ -354,6 +305,13 @@ class Tempfile < DelegateClass(File)
|
||||||
tempfile
|
tempfile
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mkdir(*args)
|
||||||
|
Dir.mkdir(*args)
|
||||||
|
end
|
||||||
|
def rmdir(*args)
|
||||||
|
Dir.rmdir(*args)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,12 @@ class Dir
|
||||||
|
|
||||||
@@systmpdir = '/tmp'
|
@@systmpdir = '/tmp'
|
||||||
|
|
||||||
begin
|
if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and
|
||||||
require 'Win32API'
|
begin
|
||||||
|
require 'Win32API'
|
||||||
|
true
|
||||||
|
rescue LoadError
|
||||||
|
end
|
||||||
CSIDL_LOCAL_APPDATA = 0x001c
|
CSIDL_LOCAL_APPDATA = 0x001c
|
||||||
max_pathlen = 260
|
max_pathlen = 260
|
||||||
windir = "\0"*(max_pathlen+1)
|
windir = "\0"*(max_pathlen+1)
|
||||||
|
@ -30,7 +34,6 @@ class Dir
|
||||||
windir.force_encoding(Dir.pwd.encoding)
|
windir.force_encoding(Dir.pwd.encoding)
|
||||||
temp = File.expand_path('temp', windir.untaint)
|
temp = File.expand_path('temp', windir.untaint)
|
||||||
@@systmpdir = temp if File.directory?(temp) and File.writable?(temp)
|
@@systmpdir = temp if File.directory?(temp) and File.writable?(temp)
|
||||||
rescue LoadError
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -95,34 +98,8 @@ class Dir
|
||||||
# FileUtils.remove_entry_secure dir
|
# FileUtils.remove_entry_secure dir
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil)
|
def Dir.mktmpdir(prefix_suffix=nil, *rest)
|
||||||
case prefix_suffix
|
path = Tmpname.create(prefix_suffix || "d", *rest) {|n| mkdir(n, 0700)}
|
||||||
when nil
|
|
||||||
prefix = "d"
|
|
||||||
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
|
|
||||||
tmpdir ||= Dir.tmpdir
|
|
||||||
t = Time.now.strftime("%Y%m%d")
|
|
||||||
n = nil
|
|
||||||
begin
|
|
||||||
path = "#{tmpdir}/#{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?
|
if block_given?
|
||||||
begin
|
begin
|
||||||
yield path
|
yield path
|
||||||
|
@ -133,4 +110,56 @@ class Dir
|
||||||
path
|
path
|
||||||
end
|
end
|
||||||
end
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
path
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue