1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/lib/tmpdir.rb
nobu 1fae154c07 tmpdir.rb: permission of user given directory
* lib/tmpdir.rb (Dir.mktmpdir): check if the permission of the
  parent directory only when using the default temporary
  directory, and no check against user given directory.  the
  security is the user's responsibility in that case.
  [ruby-core:91216] [Bug #15555]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66909 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2019-01-23 06:06:47 +00:00

145 lines
4.2 KiB
Ruby

# frozen_string_literal: true
#
# tmpdir - retrieve temporary directory path
#
# $Id$
#
require 'fileutils'
begin
require 'etc.so'
rescue LoadError # rescue LoadError for miniruby
end
class Dir
@@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
##
# Returns the operating system's temporary file path.
def self.tmpdir
if $SAFE > 0
@@systmpdir.dup
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
end
raise ArgumentError, "could not find a temporary directory" unless tmp
tmp
end
end
# Dir.mktmpdir creates a temporary directory.
#
# The directory is created with 0700 permission.
# Application should not change the permission to make the temporary directory accessible from other users.
#
# The prefix and suffix of the name of the directory is specified by
# the optional first argument, <i>prefix_suffix</i>.
# - If it is not specified or nil, "d" is used as the prefix and no suffix is used.
# - If it is a string, it is used as the prefix and no suffix is used.
# - If it is an array, first element is used as the prefix and second element is used as a suffix.
#
# Dir.mktmpdir {|dir| dir is ".../d..." }
# Dir.mktmpdir("foo") {|dir| dir is ".../foo..." }
# Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" }
#
# The directory is created under Dir.tmpdir or
# the optional second argument <i>tmpdir</i> if non-nil value is given.
#
# Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." }
# Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." }
#
# If a block is given,
# it is yielded with the path of the directory.
# The directory and its contents are removed
# using FileUtils.remove_entry before Dir.mktmpdir returns.
# The value of the block is returned.
#
# Dir.mktmpdir {|dir|
# # use the directory...
# open("#{dir}/foo", "w") { ... }
# }
#
# If a block is not given,
# The path of the directory is returned.
# In this case, Dir.mktmpdir doesn't remove the directory.
#
# dir = Dir.mktmpdir
# begin
# # use the directory...
# open("#{dir}/foo", "w") { ... }
# ensure
# # remove the directory.
# FileUtils.remove_entry dir
# end
#
def self.mktmpdir(prefix_suffix=nil, *rest)
base = nil
path = Tmpname.create(prefix_suffix || "d", *rest) {|path, _, _, d|
base = d
mkdir(path, 0700)
}
if block_given?
begin
yield path
ensure
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
else
path
end
end
module Tmpname # :nodoc:
module_function
def tmpdir
Dir.tmpdir
end
def create(basename, tmpdir=nil, max_try: nil, **opts)
if $SAFE > 0 and tmpdir.tainted?
tmpdir = '/tmp'
else
origdir = tmpdir
tmpdir ||= tmpdir()
end
n = nil
prefix, suffix = basename
prefix = (String.try_convert(prefix) or
raise ArgumentError, "unexpected prefix: #{prefix.inspect}")
prefix = prefix.delete("#{File::SEPARATOR}#{File::ALT_SEPARATOR}")
suffix &&= (String.try_convert(suffix) or
raise ArgumentError, "unexpected suffix: #{suffix.inspect}")
suffix &&= suffix.delete("#{File::SEPARATOR}#{File::ALT_SEPARATOR}")
begin
t = Time.now.strftime("%Y%m%d")
path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"\
"#{n ? %[-#{n}] : ''}#{suffix||''}"
path = File.join(tmpdir, path)
yield(path, n, opts, origdir)
rescue Errno::EEXIST
n ||= 0
n += 1
retry if !max_try or n < max_try
raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'"
end
path
end
end
end