[pypy-svn] pypy default: On Windows, os.chdir() is supposed to raise WindowsErrors.
amauryfa
commits-noreply at bitbucket.org
Thu Jan 20 19:36:49 CET 2011
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch:
Changeset: r41069:08e757460def
Date: 2011-01-20 16:34 +0100
http://bitbucket.org/pypy/pypy/changeset/08e757460def/
Log: On Windows, os.chdir() is supposed to raise WindowsErrors. Use a
win32 implementation instead.
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -1277,12 +1277,17 @@
os_chdir = self.llexternal(traits.posix_function_name('chdir'),
[traits.CCHARP], rffi.INT)
- def chdir_llimpl(path):
+ def os_chdir_llimpl(path):
res = rffi.cast(lltype.Signed, os_chdir(path))
if res < 0:
raise OSError(rposix.get_errno(), "os_chdir failed")
- return extdef([traits.str], s_None, llimpl=chdir_llimpl,
+ # On Windows, use an implementation that will produce Win32 errors
+ if sys.platform == 'win32':
+ from pypy.rpython.module.ll_win32file import make_chdir_impl
+ os_chdir_llimpl = make_chdir_impl(traits)
+
+ return extdef([traits.str], s_None, llimpl=os_chdir_llimpl,
export_name=traits.ll_os_name('chdir'))
@registering_str_unicode(os.mkdir)
diff --git a/pypy/rpython/module/ll_win32file.py b/pypy/rpython/module/ll_win32file.py
--- a/pypy/rpython/module/ll_win32file.py
+++ b/pypy/rpython/module/ll_win32file.py
@@ -129,6 +129,21 @@
traits.CCHARP, LPSTRP],
rwin32.DWORD)
+ GetCurrentDirectory = external(
+ 'GetCurrentDirectory' + suffix,
+ [rwin32.DWORD, traits.CCHARP],
+ rwin32.DWORD)
+
+ SetCurrentDirectory = external(
+ 'SetCurrentDirectory' + suffix,
+ [traits.CCHARP],
+ rwin32.BOOL)
+
+ SetEnvironmentVariable = external(
+ 'SetEnvironmentVariable' + suffix,
+ [traits.CCHARP, traits.CCHARP],
+ rwin32.BOOL)
+
return Win32Traits
#_______________________________________________________________
@@ -189,6 +204,54 @@
return listdir_llimpl
#_______________________________________________________________
+# chdir
+
+def make_chdir_impl(traits):
+ from pypy.rlib import rwin32
+ win32traits = make_win32_traits(traits)
+
+ if traits.str is unicode:
+ def isUNC(path):
+ return path[0] == u'\\' or path[0] == u'/'
+ def magic_envvar(path):
+ return u'=' + path[0] + u':'
+ else:
+ def isUNC(path):
+ return path[0] == '\\' or path[0] == '/'
+ def magic_envvar(path):
+ return '=' + path[0] + ':'
+
+ @func_renamer('chdir_llimpl_%s' % traits.str.__name__)
+ def chdir_llimpl(path):
+ """This is a reimplementation of the C library's chdir function,
+ but one that produces Win32 errors instead of DOS error codes.
+ chdir is essentially a wrapper around SetCurrentDirectory; however,
+ it also needs to set "magic" environment variables indicating
+ the per-drive current directory, which are of the form =<drive>:
+ """
+ if not win32traits.SetCurrentDirectory(path):
+ raise rwin32.lastWindowsError()
+
+ with rffi.scoped_alloc_buffer(rwin32.MAX_PATH) as path:
+ res = win32traits.GetCurrentDirectory(rwin32.MAX_PATH + 1, path.raw)
+ if not res:
+ raise rwin32.lastWindowsError()
+ if res <= rwin32.MAX_PATH + 1:
+ new_path = path.str(rffi.cast(lltype.Signed, res))
+ else:
+ with rffi.scoped_alloc_buffer(rwin32.MAX_PATH) as path:
+ res = win32traits.GetCurrentDirectory(res, path.raw)
+ if not res:
+ raise rwin32.lastWindowsError()
+ new_path = path.str(rffi.cast(lltype.Signed, res))
+ if isUNC(new_path):
+ return
+ if not win32traits.SetEnvironmentVariable(magic_envvar(new_path), new_path):
+ raise rwin32.lastWindowsError()
+
+ return chdir_llimpl
+
+#_______________________________________________________________
# getfullpathname
def make_getfullpathname_impl(traits):
diff --git a/pypy/rpython/module/test/test_ll_os.py b/pypy/rpython/module/test/test_ll_os.py
--- a/pypy/rpython/module/test/test_ll_os.py
+++ b/pypy/rpython/module/test/test_ll_os.py
@@ -63,6 +63,25 @@
data = getllimpl(os.getcwd)()
assert data == os.getcwd()
+def test_chdir():
+ def check_special_envvar():
+ if sys.platform != 'win32':
+ return
+ pwd = os.getcwd()
+ import ctypes
+ buf = ctypes.create_string_buffer(1000)
+ ctypes.windll.kernel32.GetEnvironmentVariableA('=%c:' % pwd[0], buf, 1000)
+ assert str(buf.value) == pwd
+
+ pwd = os.getcwd()
+ try:
+ check_special_envvar()
+ getllimpl(os.chdir)('..')
+ assert os.getcwd() == os.path.dirname(pwd)
+ check_special_envvar()
+ finally:
+ os.chdir(pwd)
+
def test_strerror():
data = getllimpl(os.strerror)(2)
assert data == os.strerror(2)
More information about the Pypy-commit
mailing list