diff options
Diffstat (limited to 'lib/tmpdir.rb')
| -rw-r--r-- | lib/tmpdir.rb | 93 |
1 files changed, 54 insertions, 39 deletions
diff --git a/lib/tmpdir.rb b/lib/tmpdir.rb index 494725cb33..3b67164039 100644 --- a/lib/tmpdir.rb +++ b/lib/tmpdir.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # tmpdir - retrieve temporary directory path # @@ -18,22 +19,25 @@ class Dir # Returns the operating system's temporary file path. def self.tmpdir - if $SAFE > 0 - @@systmpdir - else - tmp = nil - [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp', '.'].each do |dir| - next if !dir - dir = File.expand_path(dir) - if stat = File.stat(dir) and stat.directory? and stat.writable? and - (!stat.world_writable? or stat.sticky?) - tmp = dir - break - end rescue nil + tmp = nil + ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @@systmpdir], ['/tmp']*2, ['.']*2].each do |name, dir = ENV[name]| + next if !dir + dir = File.expand_path(dir) + stat = File.stat(dir) rescue next + case + when !stat.directory? + warn "#{name} is not a directory: #{dir}" + when !stat.writable? + warn "#{name} is not writable: #{dir}" + when stat.world_writable? && !stat.sticky? + warn "#{name} is world-writable: #{dir}" + else + tmp = dir + break end - raise ArgumentError, "could not find a temporary directory" unless tmp - tmp end + raise ArgumentError, "could not find a temporary directory" unless tmp + tmp end # Dir.mktmpdir creates a temporary directory. @@ -65,7 +69,7 @@ class Dir # # Dir.mktmpdir {|dir| # # use the directory... - # open("#{dir}/foo", "w") { ... } + # open("#{dir}/foo", "w") { something using the file } # } # # If a block is not given, @@ -75,21 +79,27 @@ class Dir # dir = Dir.mktmpdir # begin # # use the directory... - # open("#{dir}/foo", "w") { ... } + # open("#{dir}/foo", "w") { something using the file } # ensure # # remove the directory. # FileUtils.remove_entry dir # end # - def Dir.mktmpdir(prefix_suffix=nil, *rest) - path = Tmpname.create(prefix_suffix || "d", *rest) {|n| mkdir(n, 0700)} + def self.mktmpdir(prefix_suffix=nil, *rest, **options) + base = nil + path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|path, _, _, d| + base = d + mkdir(path, 0700) + } if block_given? begin - yield path + yield path.dup ensure - stat = File.stat(File.dirname(path)) - if stat.world_writable? and !stat.sticky? - raise ArgumentError, "parent directory is world writable but not sticky" + unless base + stat = File.stat(File.dirname(path)) + if stat.world_writable? and !stat.sticky? + raise ArgumentError, "parent directory is world writable but not sticky" + end end FileUtils.remove_entry path end @@ -105,28 +115,33 @@ class Dir Dir.tmpdir end - def make_tmpname((prefix, suffix), n) - prefix = (String.try_convert(prefix) or - raise ArgumentError, "unexpected prefix: #{prefix.inspect}") - suffix &&= (String.try_convert(suffix) or - raise ArgumentError, "unexpected suffix: #{suffix.inspect}") - t = Time.now.strftime("%Y%m%d") - path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}" - path << "-#{n}" if n - path << suffix if suffix - path + UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~" + + class << (RANDOM = Random.new) + MAX = 36**6 # < 0x100000000 + def next + rand(MAX).to_s(36) + end end + private_constant :RANDOM def create(basename, tmpdir=nil, max_try: nil, **opts) - if $SAFE > 0 and tmpdir.tainted? - tmpdir = '/tmp' - else - tmpdir ||= tmpdir() - end + origdir = tmpdir + tmpdir ||= tmpdir() n = nil + prefix, suffix = basename + prefix = (String.try_convert(prefix) or + raise ArgumentError, "unexpected prefix: #{prefix.inspect}") + prefix = prefix.delete(UNUSABLE_CHARS) + suffix &&= (String.try_convert(suffix) or + raise ArgumentError, "unexpected suffix: #{suffix.inspect}") + suffix &&= suffix.delete(UNUSABLE_CHARS) begin - path = File.join(tmpdir, make_tmpname(basename, n)) - yield(path, n, opts) + t = Time.now.strftime("%Y%m%d") + path = "#{prefix}#{t}-#{$$}-#{RANDOM.next}"\ + "#{n ? %[-#{n}] : ''}#{suffix||''}" + path = File.join(tmpdir, path) + yield(path, n, opts, origdir) rescue Errno::EEXIST n ||= 0 n += 1 |
