summaryrefslogtreecommitdiff
path: root/lib/tempfile.rb
blob: 66d96200b50c1c0cf21cdd190f61d2a6310bcb31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
#
# $Id$
#
# The class for temporary files.
#  o creates a temporary file, which name is "basename.pid.n" with mode "w+".
#  o Tempfile objects can be used like IO object.
#  o with tmpfile.close(true) created temporary files are removed.
#  o created files are also removed on script termination.
#  o with Tempfile#open, you can reopen the temporary file.
#  o file mode of the temporary files are 0600.

require 'delegate'
require 'final'

class Tempfile < SimpleDelegater
  Max_try = 10

  def initialize(basename, tmpdir = '/tmp')
    umask = File.umask(0177)
    begin
      n = 0
      while true
	begin
	  @tmpname = sprintf('%s/%s.%d.%d', tmpdir, basename, $$, n)
	  unless File.exist?(@tmpname)
	    File.symlink(tmpdir, @tmpname + '.lock')
	    break
	  end
	rescue
	  raise "cannot generate tmpfile `%s'" % @tmpname if n >= Max_try
	  #sleep(1)
	end
	n += 1
      end

      @clean_files = proc {|id| 
	if File.exist?(@tmpname)
	  File.unlink(@tmpname) 
	end
	if File.exist?(@tmpname + '.lock')
	  File.unlink(@tmpname + '.lock')
	end
      }
      ObjectSpace.define_finalizer(self, @clean_files)

      @tmpfile = File.open(@tmpname, 'w+')
      super(@tmpfile)
      File.unlink(@tmpname + '.lock')
    ensure
      File.umask(umask)
    end
  end

  def Tempfile.open(*args)
    Tempfile.new(*args)
  end

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

  def close(real=false)
    @tmpfile.close if @tmpfile
    @tmpfile = nil
    if real
      @clean_files.call
      ObjectSpace.undefine_finalizer(self)
    end
  end
end