Project

General

Profile

Actions

Bug #3556

closed

FileUtils.mkdir_p fails trying to create C: under Windows

Added by luislavena (Luis Lavena) over 14 years ago. Updated over 13 years ago.

Status:
Closed
Assignee:
-
Target version:
ruby -v:
1.8 and 1.9, including trunk
Backport:
[ruby-core:31177]

Description

=begin
Hello,

I've been experiencing weird problems with FileUtils.mkdir_p in RubyGems, as tried to document in [ruby-talk:365540]

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/365540

The root of this investigation is a report about gem installation under Windows:

http://groups.google.com/group/rubyinstaller/browse_thread/thread/df7b7c217ad7d882

We have been trying to reproduce this without avail.

Now, I was able to recreate a scenario:

ruby -v -rfileutils -e "system('rd C:\Foo /s/q'); puts FileUtils.mkdir_p('C:/Foo/Bar')"

C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:243:in mkdir': File exists - C: (Errno::EEXIST) from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:243:in fu_mkdir'
from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:217:in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:215:in reverse_each'
from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:215:in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:201:in each'
from C:/Users/Luis/Tools/Ruby/ruby-1.8.6-p398-i386-mingw32/lib/ruby/1.8/fileutils.rb:201:in `mkdir_p'
from -e:1

C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in mkdir': File exists - C: (Errno::EEXIST) from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in fu_mkdir'
from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:217:in block (2 levels) in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in reverse_each'
from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in block in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in each'
from C:/Users/Luis/Tools/Ruby/ruby-1.9.1-p378-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in mkdir_p' from -e:1:in '

C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in mkdir': File exists - C: (Errno::EEXIST) from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:243:in fu_mkdir'
from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:217:in block (2 levels) in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in reverse_each'
from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:215:in block in mkdir_p' from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in each'
from C:/Users/Luis/Tools/Ruby/ruby-1.9.2-rc1-i386-mingw32/lib/ruby/1.9.1/fileutils.rb:201:in mkdir_p' from -e:1:in '

And same happens with trunk.

After digging a little bit on test_fileutils.rb found that even running the tests fails:

  1. Error:
    test_mkdir_p(TestFileUtils):
    Errno::EEXIST: File exists - C:
    test/fileutils/test_fileutils.rb:767:in block in test_mkdir_p' test/fileutils/test_fileutils.rb:766:in each'
    test/fileutils/test_fileutils.rb:766:in `test_mkdir_p'

53 tests, 278 assertions, 0 failures, 1 errors, 0 skips

Further investigation pointed that the rescue of SystemCallError in mkdir_p is evaluating for File.directory? of dir, when dir has actually been altered inside fu_mkdir:

path = path.sub(%r</\z>, '')

But this change, been made in a local variable, is not seen by mkdir_p.

So:

  1. mkdir_p sends "C:/" to fu_mkdir
  2. fu_mkdir trims it to "C:"
  3. fu_mkdir invokes Dir.mkdir "C:" and Errno::EEXIST is raised
  4. mkdir_p catches it but evaluates File.directory? for "C:/" instead of "C:"
  5. mkdir_p re-raises the exception since File.directory?("C:/") == false

If I'm not missing something, that is wrong.

Attached is a simple patch that correct the issue, however, I think the real problem is File.stat that fails:

C:\Users\Luis>ruby -v -e "puts File.stat('C:').inspect; puts File.stat('C:/').inspect"
ruby 1.9.2dev (2010-07-02) [i386-mingw32]
#<File::Stat dev=0x2, ino=0, mode=040755, nlink=1, uid=0, gid=0, rdev=0x2, size=0, blksize=nil, blocks=nil, atime=2010-07-10 17:12:25 -0300, mtime=2010-07-10 17:12:25 -0300, ctime=2010-02-28 11:29:05 -0300>
-e:1:in stat': Permission denied - C:/ (Errno::EACCES) from -e:1:in '

You receive Errno::EACCES for C:/, but that doesn't happen on JRuby or IronRuby:

IronRuby 1.0.0.0 on .NET 4.0.30319.1

#<File::Stat dev=3, ino=0, mode=16768, nlink=1, uid=0, gid=0, rdev=3, size=0, blksize=nil, blocks=nil, atime=Sat Jul 10
17:12:25 -0300 2010, mtime=Sat Jul 10 17:12:25 -0300 2010, ctime=Sun Feb 28 11:29:05 -0300 2010
#<File::Stat dev=3, ino=0, mode=16768, nlink=1, uid=0, gid=0, rdev=3, size=0, blksize=nil, blocks=nil, atime=Sat Jul 10
16:48:38 -0300 2010, mtime=Sat Jul 10 16:48:38 -0300 2010, ctime=Mon Jul 13 23:38:56 -0300 2009

jruby 1.4.1 (ruby 1.8.7 patchlevel 174) (2010-04-26 ea6db6a) (Java HotSpot(TM) Client VM 1.6.0_18) [x86-java]

#<File::Stat dev=0x2, ino=0, mode=040777, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=0, blocks=0, atime=Tue Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>
#<File::Stat dev=0x2, ino=0, mode=040777, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=0, blocks=0, atime=Tue Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>

jruby 1.5.1 (ruby 1.8.7 patchlevel 249) (2010-06-06 f3a3480) (Java HotSpot(TM) Client VM 1.6.0_18) [x86-java]

#<File::Stat dev=0x2, ino=0, mode=040755, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=512, blocks=0, atime=Tue
Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>
#<File::Stat dev=0x2, ino=0, mode=040755, nlink=1, uid=0, gid=0, rdev=0x2, size=24576, blksize=512, blocks=0, atime=Tue
Jan 01 00:00:00 -0300 1980, mtime=Tue Jan 01 00:00:00 -0300 1980, ctime=Tue Jan 01 00:00:00 -0300 1980>
=end


Files

Actions #1

Updated by luislavena (Luis Lavena) over 14 years ago

=begin
Please disregard this bug report.

The root of the issue is a broken VirtualStore folder, used by File redirection service under x64 OS.

Either E-TextEditor or Cygwin installation broke the permissions of it.

Apologizes for the noise.

Thank you.
=end

Actions #2

Updated by marcandre (Marc-Andre Lafortune) over 14 years ago

  • Status changed from Open to Closed

=begin

=end

Actions #3

Updated by nobu (Nobuyoshi Nakada) over 14 years ago

=begin
Hi,

At Sun, 11 Jul 2010 05:20:01 +0900,
Luis Lavena wrote in [ruby-core:31177]:

Further investigation pointed that the rescue of
SystemCallError in mkdir_p is evaluating for File.directory?
of dir, when dir has actually been altered inside fu_mkdir:

path = path.sub(%r</\z>, '')

But this change, been made in a local variable, is not seen by mkdir_p.

This substitution is wrong on Windows.

So:

  1. mkdir_p sends "C:/" to fu_mkdir
  2. fu_mkdir trims it to "C:"
  3. fu_mkdir invokes Dir.mkdir "C:" and Errno::EEXIST is raised
  4. mkdir_p catches it but evaluates File.directory? for "C:/" instead of "C:"
  5. mkdir_p re-raises the exception since File.directory?("C:/") == false

If I'm not missing something, that is wrong.

Note that C:/ and C: don't refere same directory. The latter
is C:., the cwd of C: drive.

At Sun, 11 Jul 2010 08:05:18 +0900,
Luis Lavena wrote in [ruby-core:31179]:

The root of the issue is a broken VirtualStore folder, used
by File redirection service under x64 OS.

That means that File.stat on VirtualStore folders isn't
working. It seems like a bug.

--
Nobu Nakada

=end

Actions #4

Updated by luislavena (Luis Lavena) over 14 years ago

=begin
On Sat, Jul 10, 2010 at 9:39 PM, Nobuyoshi Nakada wrote:

Note that C:/ and C: don't refere same directory.  The latter
is C:., the cwd of C: drive.

Indeed, after tracing it over debug-land and reading forgotten MSDN
documentation found that I was wrong.

That means that File.stat on VirtualStore folders isn't
working.  It seems like a bug.

Is not a Ruby bug, it was actually a permission issue caused by a bug
or something by the installer process of E-TextEditor or the cygwin
bundled by it.

I was not able to cd ino %LOCALAPPDATA%\VirtualStore after that.

WOW64 redirection is automatically enabled once a 32bits application
start working on a x64 version of Windows, due the permission issues,
it was not possible FindFirstFileW or GetFileAttributeW to it.

Thank you for the time you took answering this and again apologize the
noise I have caused.

Luis Lavena
AREA 17

Perfection in design is achieved not when there is nothing more to add,
but rather when there is nothing more to take away.
Antoine de Saint-Exupéry

=end

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0