# File common/lib/symbiosis/utils.rb, line 73 def mkdir_p(dir, options = {}) # Switch on verbosity.. options[:verbose] = true if $DEBUG # Find the first directory that exists, and the first non-existent one. parent = File.expand_path(dir) begin # # Check the parent. # lstat_parent = File.lstat(parent) rescue Errno::ENOENT lstat_parent = nil end return parent if !lstat_parent.nil? and lstat_parent.directory? # # Awooga, something already in the way. # raise Errno::EEXIST, parent unless lstat_parent.nil? # # Break down the directory until we find one that exists. # stack = [] while !File.exists?(parent) stack.unshift parent parent = File.dirname(parent) end # # Then set the options such that the uid/gid of the parent dir can be # propagated, but only if we're root. # if (options[:uid].nil? or options[:gid].nil?) and 0 == Process.euid parent_s = File.stat(parent) options[:gid] = parent_s.gid if options[:gid].nil? options[:uid] = parent_s.uid if options[:uid].nil? end # # Set up a sensible mode # unless options[:mode].is_a?(Integer) options[:mode] = (0777 - File.umask) end # # Create our stack of directories in real life. # stack.each do |sdir| begin # # If a symlink (or anything else) is in the way, an EEXIST exception # is raised. # Dir.mkdir(sdir, options[:mode]) rescue Errno::EEXIST => err # # If there is a directory in our way, skip and move on. This could # be a TOCTTOU problem. # next if File.directory?(sdir) # # Otherwise barf. # raise err end # # Use lchown to prevent accidentally chowning the target of a symlink, # instead chowning the symlink itself. This mitigates a TOCTTOU race # condition where the attacker replaces our new directory with a # symlink to a file he can't read, only to have us chown it. # File.lchown(options[:uid], options[:gid], sdir) end return dir end