Class: Tempfile

Inherits:
File
  • Object
show all
Defined in:
lib/tempfile.rb

Overview

A class for managing temporary files. This library is written to be thread safe.

Constant Summary collapse

MAX_TRY =
10
@@cleanlist =
[]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(basename, tmpdir = Dir::tmpdir) ⇒ Tempfile

Creates a temporary file of mode 0600 in the temporary directory, opens it with mode “w+”, and returns a Tempfile object which represents the created temporary file. A Tempfile object can be treated just like a normal File object.

The basename parameter is used to determine the name of a temporary file. If an Array is given, the first element is used as prefix string and the second as suffix string, respectively. Otherwise it is treated as prefix string.

If tmpdir is omitted, the temporary directory is determined by Dir::tmpdir provided by ‘tmpdir.rb’. When $SAFE > 0 and the given tmpdir is tainted, it uses /tmp. (Note that ENV values are tainted by default)



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/tempfile.rb', line 30

def initialize(basename, tmpdir=Dir::tmpdir)
  if $SAFE > 0 and tmpdir.tainted?
    tmpdir = '/tmp'
  end

  lock = nil
  n = failure = 0
  
  begin
    Thread.critical = true

    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 `%s'" % tmpname
  ensure
    Thread.critical = false
  end

  @data = [tmpname]
  @clean_proc = Tempfile.callback(@data)
  ObjectSpace.define_finalizer(self, @clean_proc)

  @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
  @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

Class Method Details

.callback(data) ⇒ Object

:nodoc:



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/tempfile.rb', line 159

def callback(data)  # :nodoc:
  pid = $$
  lambda{
  if pid == $$ 
    path, tmpfile, cleanlist = *data

    print "removing ", path, "..." if $DEBUG

    tmpfile.close if tmpfile

    # keep this order for thread safeness
    File.unlink(path) if File.exist?(path)
    cleanlist.delete(path) if cleanlist

    print "done\n" if $DEBUG
  end
  }
end

.open(*args) ⇒ Object

If no block is given, this is a synonym for new().

If a block is given, it will be passed tempfile as an argument, and the tempfile will automatically be closed when the block terminates. In this case, open() returns nil.



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/tempfile.rb', line 183

def open(*args)
  tempfile = new(*args)

  if block_given?
  begin
    yield(tempfile)
  ensure
    tempfile.close
  end

  nil
  else
  tempfile
  end
end

Instance Method Details

#close(unlink_now = false) ⇒ Object

Closes the file. If the optional flag is true, unlinks the file after closing.

If you don’t explicitly unlink the temporary file, the removal will be delayed until the object is finalized.



108
109
110
111
112
113
114
# File 'lib/tempfile.rb', line 108

def close(unlink_now=false)
  if unlink_now
    close!
  else
    _close
  end
end

#close!Object

Closes and unlinks the file.



117
118
119
120
121
122
# File 'lib/tempfile.rb', line 117

def close!
  _close
  @clean_proc.call
  ObjectSpace.undefine_finalizer(self)
  @data = @tmpname = nil
end

#openObject

Opens or reopens the file with mode “r+”.



89
90
91
92
93
94
# File 'lib/tempfile.rb', line 89

def open
  @tmpfile.close if @tmpfile
  @tmpfile = File.open(@tmpname, 'r+')
  @data[1] = @tmpfile
  __setobj__(@tmpfile)
end

#pathObject

Returns the full path name of the temporary file.



142
143
144
# File 'lib/tempfile.rb', line 142

def path
  @tmpname
end

#sizeObject Also known as: length

Returns the size of the temporary file. As a side effect, the IO buffer is flushed before determining the size.



148
149
150
151
152
153
154
155
# File 'lib/tempfile.rb', line 148

def size
  if @tmpfile
    @tmpfile.flush
    @tmpfile.stat.size
  else
    0
  end
end

Unlinks the file. On UNIX-like systems, it is often a good idea to unlink a temporary file immediately after creating and opening it, because it leaves other programs zero chance to access the file.



128
129
130
131
132
133
134
135
136
137
138
# File 'lib/tempfile.rb', line 128

def unlink
  # keep this order for thread safeness
  begin
    File.unlink(@tmpname) if File.exist?(@tmpname)
    @@cleanlist.delete(@tmpname)
    @data = @tmpname = nil
    ObjectSpace.undefine_finalizer(self)
  rescue Errno::EACCES
    # may not be able to unlink on Windows; just ignore
  end
end