2 # tempfile - manipulates temporary files
11 # A class for managing temporary files. This library is written to be
13 class Tempfile < DelegateClass(File)
18 # Creates a temporary file of mode 0600 in the temporary directory,
19 # opens it with mode "w+", and returns a Tempfile object which
20 # represents the created temporary file. A Tempfile object can be
21 # treated just like a normal File object.
23 # The basename parameter is used to determine the name of a
24 # temporary file. If an Array is given, the first element is used
25 # as prefix string and the second as suffix string, respectively.
26 # Otherwise it is treated as prefix string.
28 # If tmpdir is omitted, the temporary directory is determined by
29 # Dir::tmpdir provided by 'tmpdir.rb'.
30 # When $SAFE > 0 and the given tmpdir is tainted, it uses
31 # /tmp. (Note that ENV values are tainted by default)
32 def initialize(basename, tmpdir=Dir::tmpdir)
33 if $SAFE > 0 and tmpdir.tainted?
42 tmpname = File.join(tmpdir, make_tmpname(basename, n))
43 lock = tmpname + '.lock'
45 end while @@cleanlist.include?(tmpname) or
46 File.exist?(lock) or File.exist?(tmpname)
50 retry if failure < MAX_TRY
51 raise "cannot generate tempfile `%s'" % tmpname
56 @clean_proc = Tempfile.callback(@data)
57 ObjectSpace.define_finalizer(self, @clean_proc)
59 @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
61 @@cleanlist << @tmpname
63 @data[2] = @@cleanlist
67 # Now we have all the File/IO methods defined, you must not
68 # carelessly put bare puts(), etc. after this.
73 def make_tmpname(basename, n)
76 prefix, suffix = *basename
78 prefix, suffix = basename, ''
81 t = Time.now.strftime("%Y%m%d")
82 path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}"
86 # Opens or reopens the file with mode "r+".
88 @tmpfile.close if @tmpfile
89 @tmpfile = File.open(@tmpname, 'r+')
95 @tmpfile.close if @tmpfile
97 @data[1] = nil if @data
101 #Closes the file. If the optional flag is true, unlinks the file
104 # If you don't explicitly unlink the temporary file, the removal
105 # will be delayed until the object is finalized.
106 def close(unlink_now=false)
114 # Closes and unlinks the file.
118 ObjectSpace.undefine_finalizer(self)
119 @data = @tmpname = nil
122 # Unlinks the file. On UNIX-like systems, it is often a good idea
123 # to unlink a temporary file immediately after creating and opening
124 # it, because it leaves other programs zero chance to access the
127 # keep this order for thread safeness
129 File.unlink(@tmpname) if File.exist?(@tmpname)
130 @@cleanlist.delete(@tmpname)
131 @data = @tmpname = nil
132 ObjectSpace.undefine_finalizer(self)
134 # may not be able to unlink on Windows; just ignore
139 # Returns the full path name of the temporary file.
144 # Returns the size of the temporary file. As a side effect, the IO
145 # buffer is flushed before determining the size.
157 def callback(data) # :nodoc:
161 path, tmpfile, cleanlist = *data
163 print "removing ", path, "..." if $DEBUG
165 tmpfile.close if tmpfile
167 # keep this order for thread safeness
168 File.unlink(path) if File.exist?(path)
169 cleanlist.delete(path) if cleanlist
171 print "done\n" if $DEBUG
176 # If no block is given, this is a synonym for new().
178 # If a block is given, it will be passed tempfile as an argument,
179 # and the tempfile will automatically be closed when the block
180 # terminates. In this case, open() returns nil.
182 tempfile = new(*args)
201 f = Tempfile.new("foo")
205 p f.gets # => "foo\n"