home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / tempfile.rb < prev    next >
Encoding:
Ruby Source  |  2006-06-10  |  4.3 KB  |  194 lines

  1. #
  2. # tempfile - manipulates temporary files
  3. #
  4. # $Id: tempfile.rb,v 1.19.2.5 2006/06/10 23:27:38 matz Exp $
  5. #
  6.  
  7. require 'delegate'
  8. require 'tmpdir'
  9.  
  10. # A class for managing temporary files.  This library is written to be
  11. # thread safe.
  12. class Tempfile < DelegateClass(File)
  13.   MAX_TRY = 10
  14.   @@cleanlist = []
  15.  
  16.   # Creates a temporary file of mode 0600 in the temporary directory
  17.   # whose name is basename.pid.n and opens with mode "w+".  A Tempfile
  18.   # object works just like a File object.
  19.   #
  20.   # If tmpdir is omitted, the temporary directory is determined by
  21.   # Dir::tmpdir provided by 'tmpdir.rb'.
  22.   # When $SAFE > 0 and the given tmpdir is tainted, it uses
  23.   # /tmp. (Note that ENV values are tainted by default)
  24.   def initialize(basename, tmpdir=Dir::tmpdir)
  25.     if $SAFE > 0 and tmpdir.tainted?
  26.       tmpdir = '/tmp'
  27.     end
  28.  
  29.     lock = nil
  30.     n = failure = 0
  31.     
  32.     begin
  33.       Thread.critical = true
  34.  
  35.       begin
  36.     tmpname = File.join(tmpdir, make_tmpname(basename, n))
  37.     lock = tmpname + '.lock'
  38.     n += 1
  39.       end while @@cleanlist.include?(tmpname) or
  40.     File.exist?(lock) or File.exist?(tmpname)
  41.  
  42.       Dir.mkdir(lock)
  43.     rescue
  44.       failure += 1
  45.       retry if failure < MAX_TRY
  46.       raise "cannot generate tempfile `%s'" % tmpname
  47.     ensure
  48.       Thread.critical = false
  49.     end
  50.  
  51.     @data = [tmpname]
  52.     @clean_proc = Tempfile.callback(@data)
  53.     ObjectSpace.define_finalizer(self, @clean_proc)
  54.  
  55.     @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
  56.     @tmpname = tmpname
  57.     @@cleanlist << @tmpname
  58.     @data[1] = @tmpfile
  59.     @data[2] = @@cleanlist
  60.  
  61.     super(@tmpfile)
  62.  
  63.     # Now we have all the File/IO methods defined, you must not
  64.     # carelessly put bare puts(), etc. after this.
  65.  
  66.     Dir.rmdir(lock)
  67.   end
  68.  
  69.   def make_tmpname(basename, n)
  70.     sprintf('%s.%d.%d', basename, $$, n)
  71.   end
  72.   private :make_tmpname
  73.  
  74.   # Opens or reopens the file with mode "r+".
  75.   def open
  76.     @tmpfile.close if @tmpfile
  77.     @tmpfile = File.open(@tmpname, 'r+')
  78.     @data[1] = @tmpfile
  79.     __setobj__(@tmpfile)
  80.   end
  81.  
  82.   def _close    # :nodoc:
  83.     @tmpfile.close if @tmpfile
  84.     @data[1] = @tmpfile = nil
  85.   end    
  86.   protected :_close
  87.  
  88.   # Closes the file.  If the optional flag is true, unlinks the file
  89.   # after closing.
  90.   #
  91.   # If you don't explicitly unlink the temporary file, the removal
  92.   # will be delayed until the object is finalized.
  93.   def close(unlink_now=false)
  94.     if unlink_now
  95.       close!
  96.     else
  97.       _close
  98.     end
  99.   end
  100.  
  101.   # Closes and unlinks the file.
  102.   def close!
  103.     _close
  104.     @clean_proc.call
  105.     ObjectSpace.undefine_finalizer(self)
  106.   end
  107.  
  108.   # Unlinks the file.  On UNIX-like systems, it is often a good idea
  109.   # to unlink a temporary file immediately after creating and opening
  110.   # it, because it leaves other programs zero chance to access the
  111.   # file.
  112.   def unlink
  113.     # keep this order for thread safeness
  114.     begin
  115.       File.unlink(@tmpname) if File.exist?(@tmpname)
  116.       @@cleanlist.delete(@tmpname)
  117.       @data = @tmpname = nil
  118.       ObjectSpace.undefine_finalizer(self)
  119.     rescue Errno::EACCES
  120.       # may not be able to unlink on Windows; just ignore
  121.     end
  122.   end
  123.   alias delete unlink
  124.  
  125.   # Returns the full path name of the temporary file.
  126.   def path
  127.     @tmpname
  128.   end
  129.  
  130.   # Returns the size of the temporary file.  As a side effect, the IO
  131.   # buffer is flushed before determining the size.
  132.   def size
  133.     if @tmpfile
  134.       @tmpfile.flush
  135.       @tmpfile.stat.size
  136.     else
  137.       0
  138.     end
  139.   end
  140.   alias length size
  141.  
  142.   class << self
  143.     def callback(data)    # :nodoc:
  144.       pid = $$
  145.       lambda{
  146.     if pid == $$ 
  147.       path, tmpfile, cleanlist = *data
  148.  
  149.       print "removing ", path, "..." if $DEBUG
  150.  
  151.       tmpfile.close if tmpfile
  152.  
  153.       # keep this order for thread safeness
  154.       File.unlink(path) if File.exist?(path)
  155.       cleanlist.delete(path) if cleanlist
  156.  
  157.       print "done\n" if $DEBUG
  158.     end
  159.       }
  160.     end
  161.  
  162.     # If no block is given, this is a synonym for new().
  163.     #
  164.     # If a block is given, it will be passed tempfile as an argument,
  165.     # and the tempfile will automatically be closed when the block
  166.     # terminates.  In this case, open() returns nil.
  167.     def open(*args)
  168.       tempfile = new(*args)
  169.  
  170.       if block_given?
  171.     begin
  172.       yield(tempfile)
  173.     ensure
  174.       tempfile.close
  175.     end
  176.  
  177.     nil
  178.       else
  179.     tempfile
  180.       end
  181.     end
  182.   end
  183. end
  184.  
  185. if __FILE__ == $0
  186. #  $DEBUG = true
  187.   f = Tempfile.new("foo")
  188.   f.print("foo\n")
  189.   f.close
  190.   f.open
  191.   p f.gets # => "foo\n"
  192.   f.close!
  193. end
  194.