* io.c (rb_open_file): encoding in mode string was ignored if perm is
[ruby-svn.git] / lib / tmpdir.rb
blob2e82aa528ee7726f1119de122fa05a7f1c836668
2 # tmpdir - retrieve temporary directory path
4 # $Id$
7 require 'fileutils'
9 class Dir
11   @@systmpdir = '/tmp'
13   begin
14     require 'Win32API'
15     CSIDL_LOCAL_APPDATA = 0x001c
16     max_pathlen = 260
17     windir = ' '*(max_pathlen+1)
18     begin
19       getdir = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L')
20       raise RuntimeError if getdir.call(0, CSIDL_LOCAL_APPDATA, 0, 0, windir) != 0
21       windir = File.expand_path(windir.rstrip)
22     rescue RuntimeError
23       begin
24         getdir = Win32API.new('kernel32', 'GetSystemWindowsDirectory', 'PL', 'L')
25       rescue RuntimeError
26         getdir = Win32API.new('kernel32', 'GetWindowsDirectory', 'PL', 'L')
27       end
28       len = getdir.call(windir, windir.size)
29       windir = File.expand_path(windir[0, len])
30     end
31     temp = File.join(windir.untaint, 'temp')
32     @@systmpdir = temp if File.directory?(temp) and File.writable?(temp)
33   rescue LoadError
34   end
36   ##
37   # Returns the operating system's temporary file path.
39   def Dir::tmpdir
40     tmp = '.'
41     if $SAFE > 0
42       tmp = @@systmpdir
43     else
44       for dir in [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'],
45                   ENV['USERPROFILE'], @@systmpdir, '/tmp']
46         if dir and File.directory?(dir) and File.writable?(dir)
47           tmp = dir
48           break
49         end
50       end
51       File.expand_path(tmp)
52     end
53   end
55   # Dir.mktmpdir creates a temporary directory.
56   #
57   # The directory is created with 0700 permission.
58   #
59   # The prefix and suffix of the name of the directory is specified by
60   # the optional first argument, <i>prefix_suffix</i>.
61   # - If it is not specified or nil, "d" is used as the prefix and no suffix is used.
62   # - If it is a string, it is used as the prefix and no suffix is used.
63   # - If it is an array, first element is used as the prefix and second element is used as a suffix.
64   #
65   #  Dir.mktmpdir {|dir| dir is ".../d..." }
66   #  Dir.mktmpdir("foo") {|dir| dir is ".../foo..." }
67   #  Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" }
68   #
69   # The directory is created under Dir.tmpdir or
70   # the optional second argument <i>tmpdir</i> if non-nil value is given.
71   #
72   #  Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." }
73   #  Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." }
74   #
75   # If a block is given,
76   # it is yielded with the path of the directory.
77   # The directory and its contents are removed
78   # using FileUtils.remove_entry_secure before Dir.mktmpdir returns.
79   # The value of the block is returned.
80   #
81   #  Dir.mktmpdir {|dir|
82   #    # use the directory...
83   #    open("#{dir}/foo", "w") { ... }
84   #  }
85   #
86   # If a block is not given,
87   # The path of the directory is returned.
88   # In this case, Dir.mktmpdir doesn't remove the directory.
89   #
90   #  dir = Dir.mktmpdir
91   #  begin
92   #    # use the directory...
93   #    open("#{dir}/foo", "w") { ... }
94   #  ensure
95   #    # remove the directory.
96   #    FileUtils.remove_entry_secure dir
97   #  end
98   #
99   def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil)
100     case prefix_suffix
101     when nil
102       prefix = "d"
103       suffix = ""
104     when String
105       prefix = prefix_suffix
106       suffix = ""
107     when Array
108       prefix = prefix_suffix[0]
109       suffix = prefix_suffix[1]
110     else
111       raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
112     end
113     tmpdir ||= Dir.tmpdir
114     t = Time.now.strftime("%Y%m%d")
115     n = nil
116     begin
117       path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
118       path << "-#{n}" if n
119       path << suffix
120       Dir.mkdir(path, 0700)
121     rescue Errno::EEXIST
122       n ||= 0
123       n += 1
124       retry
125     end
127     if block_given?
128       begin
129         yield path
130       ensure
131         FileUtils.remove_entry_secure path
132       end
133     else
134       path
135     end
136   end