diff options
Diffstat (limited to 'lib/tmpdir.rb')
| -rw-r--r-- | lib/tmpdir.rb | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/lib/tmpdir.rb b/lib/tmpdir.rb index 70bd010de5..f78fd721b7 100644 --- a/lib/tmpdir.rb +++ b/lib/tmpdir.rb @@ -16,15 +16,14 @@ class Dir # Class variables are inaccessible from non-main Ractor. # And instance variables too, in Ruby 3.0. - # System-wide temporary directory path - SYSTMPDIR = (defined?(Etc.systmpdir) ? Etc.systmpdir.freeze : '/tmp') - private_constant :SYSTMPDIR - ## # Returns the operating system's temporary file path. + # + # require 'tmpdir' + # Dir.tmpdir # => "/tmp" def self.tmpdir - ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', SYSTMPDIR], ['/tmp']*2, ['.']*2].find do |name, dir| + Tmpname::TMPDIR_CANDIDATES.find do |name, dir| unless dir next if !(dir = ENV[name] rescue next) or dir.empty? end @@ -33,7 +32,9 @@ class Dir case when !stat.directory? warn "#{name} is not a directory: #{dir}" - when !stat.writable? + when !File.writable?(dir) + # We call File.writable?, not stat.writable?, because you can't tell if a dir is actually + # writable just from stat; OS mechanisms other than user/group/world bits can affect this. warn "#{name} is not writable: #{dir}" when stat.world_writable? && !stat.sticky? warn "#{name} is world-writable: #{dir}" @@ -45,6 +46,11 @@ class Dir # Dir.mktmpdir creates a temporary directory. # + # require 'tmpdir' + # Dir.mktmpdir {|dir| + # # use the directory + # } + # # The directory is created with 0700 permission. # Application should not change the permission to make the temporary directory accessible from other users. # @@ -88,20 +94,21 @@ class Dir # FileUtils.remove_entry dir # end # - def self.mktmpdir(prefix_suffix=nil, *rest, **options) + def self.mktmpdir(prefix_suffix=nil, *rest, **options, &block) base = nil path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|path, _, _, d| base = d mkdir(path, 0700) } - if block_given? + if block begin yield path.dup ensure unless base - stat = File.stat(File.dirname(path)) + base = File.dirname(path) + stat = File.stat(base) if stat.world_writable? and !stat.sticky? - raise ArgumentError, "parent directory is world writable but not sticky" + raise ArgumentError, "parent directory is world writable but not sticky: #{base}" end end FileUtils.remove_entry path @@ -115,6 +122,18 @@ class Dir module Tmpname # :nodoc: module_function + # System-wide temporary directory path + systmpdir = (defined?(Etc.systmpdir) ? Etc.systmpdir.freeze : '/tmp') + + # Temporary directory candidates consisting of environment variable + # names or description and path pairs. + TMPDIR_CANDIDATES = [ + 'TMPDIR', 'TMP', 'TEMP', + ['system temporary path', systmpdir], + %w[/tmp /tmp], + %w[. .], + ].each(&:freeze).freeze + def tmpdir Dir.tmpdir end @@ -138,8 +157,12 @@ class Dir # Generates and yields random names to create a temporary name def create(basename, tmpdir=nil, max_try: nil, **opts) - origdir = tmpdir - tmpdir ||= tmpdir() + if tmpdir + origdir = tmpdir = File.path(tmpdir) + raise ArgumentError, "empty parent path" if tmpdir.empty? + else + tmpdir = tmpdir() + end n = nil prefix, suffix = basename prefix = (String.try_convert(prefix) or |
