f70500
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
f70500
index 13eb25bd26..9b1cb3a142 100644
f70500
--- a/lib/rubygems/package.rb
f70500
+++ b/lib/rubygems/package.rb
f70500
@@ -332,7 +332,16 @@ EOM
f70500
 
f70500
         FileUtils.rm_rf destination
f70500
 
f70500
-        FileUtils.mkdir_p File.dirname destination
f70500
+        mkdir_options = {}
f70500
+        mkdir_options[:mode] = entry.header.mode if entry.directory?
f70500
+        mkdir =
f70500
+          if entry.directory? then
f70500
+            destination
f70500
+          else
f70500
+            File.dirname destination
f70500
+          end
f70500
+
f70500
+        mkdir_p_safe mkdir, mkdir_options, destination_dir, entry.full_name
f70500
 
f70500
         open destination, 'wb', entry.header.mode do |out|
f70500
           out.write entry.read
f70500
@@ -367,12 +376,9 @@ EOM
f70500
     raise Gem::Package::PathError.new(filename, destination_dir) if
f70500
       filename.start_with? '/'
f70500
 
f70500
-    destination_dir = File.realpath destination_dir if
f70500
-      File.respond_to? :realpath
f70500
+    destination_dir = realpath destination_dir
f70500
 
f70500
     destination = File.join destination_dir, filename
f70500
-    destination = File.realpath destination if
f70500
-      File.respond_to? :realpath
f70500
     destination = File.expand_path destination
f70500
 
f70500
     raise Gem::Package::PathError.new(destination, destination_dir) unless
f70500
@@ -382,6 +388,22 @@ EOM
f70500
     destination
f70500
   end
f70500
 
f70500
+  def mkdir_p_safe mkdir, mkdir_options, destination_dir, file_name
f70500
+    destination_dir = realpath File.expand_path(destination_dir)
f70500
+    parts = mkdir.split(File::SEPARATOR)
f70500
+    parts.reduce do |path, basename|
f70500
+      path = realpath path  unless path == ""
f70500
+      path = File.expand_path(path + File::SEPARATOR + basename)
f70500
+      lstat = File.lstat path rescue nil
f70500
+      if !lstat || !lstat.directory?
f70500
+        unless path.start_with? destination_dir and (FileUtils.mkdir path, mkdir_options rescue false)
f70500
+          raise Gem::Package::PathError.new(file_name, destination_dir)
f70500
+        end
f70500
+      end
f70500
+      path
f70500
+    end
f70500
+  end
f70500
+
f70500
   ##
f70500
   # Loads a Gem::Specification from the TarEntry +entry+
f70500
 
f70500
@@ -560,6 +582,16 @@ EOM
f70500
     raise Gem::Package::FormatError.new(e.message, entry.full_name)
f70500
   end
f70500
 
f70500
+  if File.respond_to? :realpath
f70500
+    def realpath file
f70500
+      File.realpath file
f70500
+    end
f70500
+  else
f70500
+    def realpath file
f70500
+      file
f70500
+    end
f70500
+  end
f70500
+
f70500
 end
f70500
 
f70500
 require 'rubygems/package/digest_io'
f70500
-- 
f70500
2.20.1
f70500