[pypy-svn] r76267 - in pypy/trunk/pypy: interpreter interpreter/test module/_file module/_file/test module/posix module/posix/test rlib rlib/test rpython rpython/lltypesystem rpython/module rpython/module/test rpython/test

afa at codespeak.net afa at codespeak.net
Fri Jul 16 23:46:25 CEST 2010


Author: afa
Date: Fri Jul 16 23:46:23 2010
New Revision: 76267

Added:
   pypy/trunk/pypy/rlib/test/test_rposix.py
      - copied, changed from r76265, pypy/branch/unicode_filename-2/pypy/rlib/test/test_rposix.py
   pypy/trunk/pypy/rpython/module/ll_win32file.py
      - copied, changed from r76265, pypy/branch/unicode_filename-2/pypy/rpython/module/ll_win32file.py
Modified:
   pypy/trunk/pypy/interpreter/baseobjspace.py
   pypy/trunk/pypy/interpreter/error.py
   pypy/trunk/pypy/interpreter/gateway.py
   pypy/trunk/pypy/interpreter/test/test_gateway.py
   pypy/trunk/pypy/module/_file/interp_file.py
   pypy/trunk/pypy/module/_file/test/test_file.py
   pypy/trunk/pypy/module/posix/interp_posix.py
   pypy/trunk/pypy/module/posix/test/test_posix2.py
   pypy/trunk/pypy/rlib/rposix.py
   pypy/trunk/pypy/rlib/rwin32.py
   pypy/trunk/pypy/rlib/streamio.py
   pypy/trunk/pypy/rpython/extfunc.py
   pypy/trunk/pypy/rpython/lltypesystem/rffi.py
   pypy/trunk/pypy/rpython/module/ll_os.py
   pypy/trunk/pypy/rpython/module/ll_os_stat.py
   pypy/trunk/pypy/rpython/module/test/test_ll_os_stat.py
   pypy/trunk/pypy/rpython/test/test_extfunc.py
Log:
Merge branch/unicode_filename-2

In general, it's wrong to encode filenames with sys.filesystemencoding; on
Windows for example, the 'mbcs' codec silently loose characters.

This change lets the backends provide unicode versions of posix functions; when
they do, the unicode string is passed untranslated.  When they don't, the
encoding passed by the posix module is used and the string function is called.

Use this extensively on Windows, which provides a "wide" version for every
function (stat -> wstat, FindFirstFile -> FindFirstFileW).
This fixes test_pep277 and test_unicode_file.

This could also be used by ootype backends (jvm and cli typically handle unicode
better than byte strings) but they seem completely broken at the moment.


Modified: pypy/trunk/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/trunk/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/trunk/pypy/interpreter/baseobjspace.py	Fri Jul 16 23:46:23 2010
@@ -1102,17 +1102,6 @@
                                  self.wrap('argument must be a unicode'))
         return self.unicode_w(w_obj)
 
-    def path_w(self, w_obj):
-        """ Like str_w, but if the object is unicode, encode it using
-        filesystemencoding
-        """
-        filesystemencoding = self.sys.filesystemencoding
-        if (filesystemencoding and
-            self.is_true(self.isinstance(w_obj, self.w_unicode))):
-            w_obj = self.call_method(w_obj, "encode",
-                                     self.wrap(filesystemencoding))
-        return self.str_w(w_obj)
-
     def bool_w(self, w_obj):
         # Unwraps a bool, also accepting an int for compatibility.
         # This is here mostly just for gateway.int_unwrapping_space_method().

Modified: pypy/trunk/pypy/interpreter/error.py
==============================================================================
--- pypy/trunk/pypy/interpreter/error.py	(original)
+++ pypy/trunk/pypy/interpreter/error.py	Fri Jul 16 23:46:23 2010
@@ -344,7 +344,7 @@
 else:
     _WINDOWS = True
 
-    def wrap_windowserror(space, e, filename=None):
+    def wrap_windowserror(space, e, w_filename=None):
         from pypy.rlib import rwin32
 
         winerror = e.winerror
@@ -353,19 +353,19 @@
         except ValueError:
             msg = 'Windows Error %d' % winerror
         exc = space.w_WindowsError
-        if filename is not None:
+        if w_filename is not None:
             w_error = space.call_function(exc, space.wrap(winerror),
-                                          space.wrap(msg), space.wrap(filename))
+                                          space.wrap(msg), w_filename)
         else:
             w_error = space.call_function(exc, space.wrap(winerror),
                                           space.wrap(msg))
         return OperationError(exc, w_error)
 
-def wrap_oserror(space, e, filename=None, exception_name='w_OSError'): 
+def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError'): 
     assert isinstance(e, OSError)
 
     if _WINDOWS and isinstance(e, WindowsError):
-        return wrap_windowserror(space, e, filename)
+        return wrap_windowserror(space, e, w_filename)
 
     errno = e.errno
     try:
@@ -373,10 +373,21 @@
     except ValueError:
         msg = 'error %d' % errno
     exc = getattr(space, exception_name)
-    if filename is not None:
+    if w_filename is not None:
         w_error = space.call_function(exc, space.wrap(errno),
-                                      space.wrap(msg), space.wrap(filename))
+                                      space.wrap(msg), w_filename)
     else:
-        w_error = space.call_function(exc, space.wrap(errno), space.wrap(msg))
+        w_error = space.call_function(exc, space.wrap(errno),
+                                      space.wrap(msg))
     return OperationError(exc, w_error)
+wrap_oserror2._annspecialcase_ = 'specialize:arg(3)'
+
+def wrap_oserror(space, e, filename=None, exception_name='w_OSError'):
+    if filename is not None:
+        return wrap_oserror2(space, e, space.wrap(filename),
+                             exception_name=exception_name)
+    else:
+        return wrap_oserror2(space, e, None,
+                             exception_name=exception_name)
 wrap_oserror._annspecialcase_ = 'specialize:arg(3)'
+

Modified: pypy/trunk/pypy/interpreter/gateway.py
==============================================================================
--- pypy/trunk/pypy/interpreter/gateway.py	(original)
+++ pypy/trunk/pypy/interpreter/gateway.py	Fri Jul 16 23:46:23 2010
@@ -137,9 +137,6 @@
     def visit_c_nonnegint(self, el, app_sig):
         self.checked_space_method(el, app_sig)
 
-    def visit_path(self, el, app_sig):
-        self.checked_space_method(el, app_sig)
-
     def visit__Wrappable(self, el, app_sig):
         name = el.__name__
         argname = self.orig_arg()
@@ -241,9 +238,6 @@
     def visit_bufferstr(self, typ):
         self.run_args.append("space.bufferstr_w(%s)" % (self.scopenext(),))
 
-    def visit_path(self, typ):
-        self.run_args.append("space.path_w(%s)" % (self.scopenext(),))
-
     def visit_nonnegint(self, typ):
         self.run_args.append("space.nonnegint_w(%s)" % (self.scopenext(),))
 
@@ -371,9 +365,6 @@
     def visit_bufferstr(self, typ):
         self.unwrap.append("space.bufferstr_w(%s)" % (self.nextarg(),))
 
-    def visit_path(self, typ):
-        self.unwrap.append("space.path_w(%s)" % (self.nextarg(),))
-
     def visit_nonnegint(self, typ):
         self.unwrap.append("space.nonnegint_w(%s)" % (self.nextarg(),))
 

Modified: pypy/trunk/pypy/interpreter/test/test_gateway.py
==============================================================================
--- pypy/trunk/pypy/interpreter/test/test_gateway.py	(original)
+++ pypy/trunk/pypy/interpreter/test/test_gateway.py	Fri Jul 16 23:46:23 2010
@@ -454,16 +454,6 @@
         assert len(l) == 1
         assert space.eq_w(l[0], w("foo"))
 
-    def test_interp2app_unwrap_spec_path(self, monkeypatch):
-        space = self.space
-        def g(space, p):
-            return p
-
-        app_g = gateway.interp2app(g, unwrap_spec=[gateway.ObjSpace, 'path'])
-        w_app_g = space.wrap(app_g)
-        monkeypatch.setattr(space.sys, "filesystemencoding", "utf-8")
-        w_res = space.call_function(w_app_g, space.wrap(u"ą"))
-
     def test_interp2app_classmethod(self):
         space = self.space
         w = space.wrap

Modified: pypy/trunk/pypy/module/_file/interp_file.py
==============================================================================
--- pypy/trunk/pypy/module/_file/interp_file.py	(original)
+++ pypy/trunk/pypy/module/_file/interp_file.py	Fri Jul 16 23:46:23 2010
@@ -4,6 +4,7 @@
 from pypy.rlib.rarithmetic import r_longlong
 from pypy.module._file.interp_stream import W_AbstractStream
 from pypy.module._file.interp_stream import StreamErrors, wrap_streamerror
+from pypy.module.posix.interp_posix import dispatch_filename
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.gateway import ObjSpace, W_Root, Arguments
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
@@ -81,11 +82,11 @@
     # file lock.  They don't convert StreamErrors to OperationErrors, too.
 
     def direct___init__(self, w_name, mode='r', buffering=-1):
-        name = self.space.str_w(w_name)
         self.direct_close()
         self.w_name = w_name
         self.check_mode_ok(mode)
-        stream = streamio.open_file_as_stream(name, mode, buffering)
+        stream = dispatch_filename(streamio.open_file_as_stream)(
+            self.space, w_name, mode, buffering)
         fd = stream.try_to_find_file_descriptor()
         self.fdopenstream(stream, fd, mode)
 

Modified: pypy/trunk/pypy/module/_file/test/test_file.py
==============================================================================
--- pypy/trunk/pypy/module/_file/test/test_file.py	(original)
+++ pypy/trunk/pypy/module/_file/test/test_file.py	Fri Jul 16 23:46:23 2010
@@ -125,6 +125,15 @@
         assert type(res) is str
         f.close()
 
+    def test_unicode_filename(self):
+        import sys
+        try:
+            u'\xe9'.encode(sys.getfilesystemencoding())
+        except UnicodeEncodeError:
+            skip("encoding not good enough")
+        f = self.file(self.temppath + u'\xe9', "w")
+        f.close()
+
     def test_oserror_has_filename(self):
         try:
             f = self.file("file that is clearly not there")

Modified: pypy/trunk/pypy/module/posix/interp_posix.py
==============================================================================
--- pypy/trunk/pypy/module/posix/interp_posix.py	(original)
+++ pypy/trunk/pypy/module/posix/interp_posix.py	Fri Jul 16 23:46:23 2010
@@ -1,8 +1,9 @@
 from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped
 from pypy.rlib import rposix
+from pypy.rlib.objectmodel import specialize
 from pypy.rlib.rarithmetic import r_longlong
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.interpreter.error import OperationError, wrap_oserror
+from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2
 from pypy.rpython.module.ll_os import RegisterOs
 from pypy.rpython.module import ll_os_stat
 from pypy.rpython.lltypesystem import rffi, lltype
@@ -12,15 +13,78 @@
 import os, sys
 _WIN = sys.platform == 'win32'
 
-def open(space, fname, flag, mode=0777):
+class FileEncoder:
+    def __init__(self, space, w_obj):
+        self.space = space
+        self.w_obj = w_obj
+
+    def as_bytes(self):
+        from pypy.module.sys.interp_encoding import getfilesystemencoding
+        space = self.space
+        w_bytes = space.call_method(self.w_obj, 'encode',
+                                    getfilesystemencoding(space))
+        return space.str_w(w_bytes)
+
+    def as_unicode(self):
+        return self.space.unicode_w(self.w_obj)
+
+class FileDecoder:
+    def __init__(self, space, w_obj):
+        self.space = space
+        self.w_obj = w_obj
+
+    def as_bytes(self):
+        return self.space.str_w(self.w_obj)
+
+    def as_unicode(self):
+        from pypy.module.sys.interp_encoding import getfilesystemencoding
+        space = self.space
+        w_unicode = space.call_method(self.w_obj, 'decode',
+                                      getfilesystemencoding(space))
+        return space.unicode_w(w_unicode)
+
+ at specialize.memo()
+def dispatch_filename(func, tag=0):
+    def dispatch(space, w_fname, *args):
+        if space.isinstance_w(w_fname, space.w_unicode):
+            fname = FileEncoder(space, w_fname)
+            return func(fname, *args)
+        else:
+            fname = space.str_w(w_fname)
+            return func(fname, *args)
+    return dispatch
+
+ at specialize.memo()
+def dispatch_filename_2(func):
+    def dispatch(space, w_fname1, w_fname2, *args):
+        if space.isinstance_w(w_fname1, space.w_unicode):
+            fname1 = FileEncoder(space, w_fname1)
+            if space.isinstance_w(w_fname2, space.w_unicode):
+                fname2 = FileEncoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+            else:
+                fname2 = FileDecoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+        else:
+            fname1 = FileDecoder(space, w_fname1)
+            if space.isinstance_w(w_fname2, space.w_unicode):
+                fname2 = FileEncoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+            else:
+                fname2 = FileDecoder(space, w_fname2)
+                return func(fname1, fname2, *args)
+    return dispatch
+
+def open(space, w_fname, flag, mode=0777):
     """Open a file (for low level IO).
 Return a file descriptor (a small integer)."""
-    try: 
-        fd = os.open(fname, flag, mode)
+    try:
+        fd = dispatch_filename(rposix.open)(
+            space, w_fname, flag, mode)
     except OSError, e: 
-        raise wrap_oserror(space, e, fname)
+        raise wrap_oserror2(space, e, w_fname)
     return space.wrap(fd)
-open.unwrap_spec = [ObjSpace, 'path', "c_int", "c_int"]
+open.unwrap_spec = [ObjSpace, W_Root, "c_int", "c_int"]
 
 def lseek(space, fd, pos, how):
     """Set the current position of a file descriptor.  Return the new position.
@@ -159,7 +223,7 @@
         return build_stat_result(space, st)
 fstat.unwrap_spec = [ObjSpace, "c_int"]
 
-def stat(space, path):
+def stat(space, w_path):
     """Perform a stat system call on the given path.  Return an object
 with (at least) the following attributes:
     st_mode
@@ -175,22 +239,22 @@
 """
 
     try:
-        st = os.stat(path)
+        st = dispatch_filename(rposix.stat)(space, w_path)
     except OSError, e: 
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path)
     else: 
         return build_stat_result(space, st)
-stat.unwrap_spec = [ObjSpace, 'path']
+stat.unwrap_spec = [ObjSpace, W_Root]
 
-def lstat(space, path):
+def lstat(space, w_path):
     "Like stat(path), but do no follow symbolic links."
     try:
-        st = os.lstat(path)
+        st = dispatch_filename(rposix.lstat)(space, w_path)
     except OSError, e:
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path)
     else:
         return build_stat_result(space, st)
-lstat.unwrap_spec = [ObjSpace, 'path']
+lstat.unwrap_spec = [ObjSpace, W_Root]
 
 class StatState(object):
     def __init__(self, space):
@@ -231,7 +295,7 @@
         raise wrap_oserror(space, e) 
 dup2.unwrap_spec = [ObjSpace, "c_int", "c_int"]
 
-def access(space, path, mode):
+def access(space, w_path, mode):
     """
     access(path, mode) -> 1 if granted, 0 otherwise
 
@@ -242,12 +306,12 @@
     existence, or the inclusive-OR of R_OK, W_OK, and X_OK.
     """
     try:
-        ok = os.access(path, mode)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
+        ok = dispatch_filename(rposix.access)(space, w_path, mode)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
     else:
         return space.wrap(ok)
-access.unwrap_spec = [ObjSpace, str, "c_int"]
+access.unwrap_spec = [ObjSpace, W_Root, "c_int"]
 
 
 def times(space):
@@ -278,32 +342,38 @@
         return space.wrap(rc)
 system.unwrap_spec = [ObjSpace, str]
 
-def unlink(space, path):
+def unlink(space, w_path):
     """Remove a file (same as remove(path))."""
     try:
-        os.unlink(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-unlink.unwrap_spec = [ObjSpace, 'path']
+        dispatch_filename(rposix.unlink)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+unlink.unwrap_spec = [ObjSpace, W_Root]
 
-def remove(space, path):
+def remove(space, w_path):
     """Remove a file (same as unlink(path))."""
     try:
-        os.unlink(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-remove.unwrap_spec = [ObjSpace, 'path']
+        dispatch_filename(rposix.unlink)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+remove.unwrap_spec = [ObjSpace, W_Root]
 
-def _getfullpathname(space, path):
+def _getfullpathname(space, w_path):
     """helper for ntpath.abspath """
-    posix = __import__(os.name) # nt specific
     try:
-        fullpath = posix._getfullpathname(path)
+        if space.isinstance_w(w_path, space.w_unicode):
+            path = FileEncoder(space, w_path)
+            fullpath = rposix._getfullpathname(path)
+            w_fullpath = space.wrap(fullpath)
+        else:
+            path = space.str_w(w_path)
+            fullpath = rposix._getfullpathname(path)
+            w_fullpath = space.wrap(fullpath)
     except OSError, e:
-        raise wrap_oserror(space, e, path)
-    else: 
-        return space.wrap(fullpath)
-_getfullpathname.unwrap_spec = [ObjSpace, str]
+        raise wrap_oserror2(space, e, w_path)
+    else:
+        return w_fullpath
+_getfullpathname.unwrap_spec = [ObjSpace, W_Root]
 
 def getcwd(space):
     """Return the current working directory."""
@@ -315,35 +385,46 @@
         return space.wrap(cur)
 getcwd.unwrap_spec = [ObjSpace]
 
-def getcwdu(space):
-    """Return the current working directory as a unicode string."""
-    # XXX ascii encoding for now
-    return space.call_method(getcwd(space), 'decode')
+if sys.platform == 'win32':
+    def getcwdu(space):
+        """Return the current working directory as a unicode string."""
+        try:
+            cur = os.getcwdu()
+        except OSError, e:
+            raise wrap_oserror(space, e)
+        else:
+            return space.wrap(cur)
+else:
+    def getcwdu(space):
+        """Return the current working directory as a unicode string."""
+        filesystemencoding = space.sys.filesystemencoding
+        return space.call_method(getcwd(space), 'decode',
+                                 space.wrap(filesystemencoding))
 getcwdu.unwrap_spec = [ObjSpace]
 
-def chdir(space, path):
+def chdir(space, w_path):
     """Change the current working directory to the specified path."""
     try:
-        os.chdir(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-chdir.unwrap_spec = [ObjSpace, str]
+        dispatch_filename(rposix.chdir)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+chdir.unwrap_spec = [ObjSpace, W_Root]
 
-def mkdir(space, path, mode=0777):
+def mkdir(space, w_path, mode=0777):
     """Create a directory."""
     try:
-        os.mkdir(path, mode)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-mkdir.unwrap_spec = [ObjSpace, str, "c_int"]
+        dispatch_filename(rposix.mkdir)(space, w_path, mode)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+mkdir.unwrap_spec = [ObjSpace, W_Root, "c_int"]
 
-def rmdir(space, path):
+def rmdir(space, w_path):
     """Remove a directory."""
     try:
-        os.rmdir(path)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-rmdir.unwrap_spec = [ObjSpace, str]
+        dispatch_filename(rposix.rmdir)(space, w_path)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+rmdir.unwrap_spec = [ObjSpace, W_Root]
 
 def strerror(space, errno):
     """Translate an error code to a message string."""
@@ -410,7 +491,7 @@
 unsetenv.unwrap_spec = [ObjSpace, str]
 
 
-def listdir(space, dirname):
+def listdir(space, w_dirname):
     """Return a list containing the names of the entries in the directory.
 
 \tpath: path of directory to list
@@ -418,12 +499,18 @@
 The list is in arbitrary order.  It does not include the special
 entries '.' and '..' even if they are present in the directory."""
     try:
-        result = os.listdir(dirname)
+        if space.isinstance_w(w_dirname, space.w_unicode):
+            dirname = FileEncoder(space, w_dirname)
+            result = rposix.listdir(dirname)
+            result_w = [space.wrap(s) for s in result]
+        else:
+            dirname = space.str_w(w_dirname)
+            result = rposix.listdir(dirname)
+            result_w = [space.wrap(s) for s in result]
     except OSError, e:
-        raise wrap_oserror(space, e, dirname)
-    result_w = [space.wrap(s) for s in result]
+        raise wrap_oserror2(space, e, w_dirname)
     return space.newlist(result_w)
-listdir.unwrap_spec = [ObjSpace, str]
+listdir.unwrap_spec = [ObjSpace, W_Root]
 
 def pipe(space):
     "Create a pipe.  Returns (read_end, write_end)."
@@ -434,21 +521,21 @@
     return space.newtuple([space.wrap(fd1), space.wrap(fd2)])
 pipe.unwrap_spec = [ObjSpace]
 
-def chmod(space, path, mode):
+def chmod(space, w_path, mode):
     "Change the access permissions of a file."
-    try: 
-        os.chmod(path, mode)
-    except OSError, e: 
-        raise wrap_oserror(space, e, path)
-chmod.unwrap_spec = [ObjSpace, str, "c_int"]
+    try:
+        dispatch_filename(rposix.chmod)(space, w_path, mode)
+    except OSError, e:
+        raise wrap_oserror2(space, e, w_path)
+chmod.unwrap_spec = [ObjSpace, W_Root, "c_int"]
 
-def rename(space, old, new):
+def rename(space, w_old, w_new):
     "Rename a file or directory."
-    try: 
-        os.rename(old, new)
-    except OSError, e: 
+    try:
+        dispatch_filename_2(rposix.rename)(space, w_old, w_new)
+    except OSError, e:
         raise wrap_oserror(space, e) 
-rename.unwrap_spec = [ObjSpace, str, str]
+rename.unwrap_spec = [ObjSpace, W_Root, W_Root]
 
 def umask(space, mask):
     "Set the current numeric umask and return the previous umask."
@@ -576,7 +663,7 @@
         raise wrap_oserror(space, e)
 execve.unwrap_spec = [ObjSpace, str, W_Root, W_Root]
 
-def utime(space, path, w_tuple):
+def utime(space, w_path, w_tuple):
     """ utime(path, (atime, mtime))
 utime(path, None)
 
@@ -585,10 +672,10 @@
     """
     if space.is_w(w_tuple, space.w_None):
         try:
-            os.utime(path, None)
+            dispatch_filename(rposix.utime, 1)(space, w_path, None)
             return
         except OSError, e:
-            raise wrap_oserror(space, e, path)
+            raise wrap_oserror2(space, e, w_path)
     try:
         msg = "utime() arg 2 must be a tuple (atime, mtime) or None"
         args_w = space.fixedview(w_tuple)
@@ -596,14 +683,14 @@
             raise OperationError(space.w_TypeError, space.wrap(msg))
         actime = space.float_w(args_w[0])
         modtime = space.float_w(args_w[1])
-        os.utime(path, (actime, modtime))
+        dispatch_filename(rposix.utime, 2)(space, w_path, (actime, modtime))
     except OSError, e:
-        raise wrap_oserror(space, e, path)
+        raise wrap_oserror2(space, e, w_path)
     except OperationError, e:
         if not e.match(space, space.w_TypeError):
             raise
         raise OperationError(space.w_TypeError, space.wrap(msg))
-utime.unwrap_spec = [ObjSpace, str, W_Root]
+utime.unwrap_spec = [ObjSpace, W_Root, W_Root]
 
 def setsid(space):
     """setsid() -> pid

Modified: pypy/trunk/pypy/module/posix/test/test_posix2.py
==============================================================================
--- pypy/trunk/pypy/module/posix/test/test_posix2.py	(original)
+++ pypy/trunk/pypy/module/posix/test/test_posix2.py	Fri Jul 16 23:46:23 2010
@@ -32,6 +32,9 @@
     # even when running on top of CPython 2.4.
     os.stat_float_times(True)
 
+    # Initialize sys.filesystemencoding
+    space.call_method(space.getbuiltinmodule('sys'), 'getfilesystemencoding')
+
 def need_sparse_files():
     if sys.platform == 'darwin':
         py.test.skip("no sparse files on default Mac OS X file system")
@@ -706,6 +709,28 @@
         except OSError:
             pass
 
+class AppTestUnicodeFilename:
+    def setup_class(cls):
+        ufilename = (unicode(udir.join('test_unicode_filename_')) +
+                     u'\u65e5\u672c.txt') # "Japan"
+        try:
+            f = file(ufilename, 'w')
+        except UnicodeEncodeError:
+            py.test.skip("encoding not good enough")
+        f.write("test")
+        f.close()
+        cls.space = space
+        cls.w_filename = space.wrap(ufilename)
+        cls.w_posix = space.appexec([], GET_POSIX)
+
+    def test_open(self):
+        fd = self.posix.open(self.filename, self.posix.O_RDONLY)
+        try:
+            content = self.posix.read(fd, 50)
+        finally:
+            self.posix.close(fd)
+        assert content == "test"
+
 
 class TestPexpect(object):
     # XXX replace with AppExpectTest class as soon as possible

Modified: pypy/trunk/pypy/rlib/rposix.py
==============================================================================
--- pypy/trunk/pypy/rlib/rposix.py	(original)
+++ pypy/trunk/pypy/rlib/rposix.py	Fri Jul 16 23:46:23 2010
@@ -3,6 +3,7 @@
 from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rlib.rarithmetic import intmask
+from pypy.rlib.objectmodel import specialize
 
 class CConstantErrno(CConstant):
     # these accessors are used when calling get_errno() or set_errno()
@@ -42,3 +43,102 @@
             os.close(fd)
         except OSError:
             pass
+
+#___________________________________________________________________
+# Wrappers around posix functions, that accept either strings, or
+# instances with a "as_bytes()" method.
+# - pypy.modules.posix.interp_posix passes an object containing a unicode path
+#   which can encode itself with sys.filesystemencoding.
+# - but pypy.rpython.module.ll_os.py on Windows will replace these functions
+#   with other wrappers that directly handle unicode strings.
+ at specialize.argtype(0)
+def open(path, flags, mode):
+    if isinstance(path, str):
+        return os.open(path, flags, mode)
+    else:
+        return os.open(path.as_bytes(), flags, mode)
+
+ at specialize.argtype(0)
+def stat(path):
+    if isinstance(path, str):
+        return os.stat(path)
+    else:
+        return os.stat(path.as_bytes())
+
+ at specialize.argtype(0)
+def lstat(path):
+    if isinstance(path, str):
+        return os.lstat(path)
+    else:
+        return os.lstat(path.as_bytes())
+
+ at specialize.argtype(0)
+def unlink(path):
+    if isinstance(path, str):
+        return os.unlink(path)
+    else:
+        return os.unlink(path.as_bytes())
+
+ at specialize.argtype(0, 1)
+def rename(path1, path2):
+    if isinstance(path1, str):
+        return os.rename(path1, path2)
+    else:
+        return os.rename(path1.as_bytes(), path2.as_bytes())
+
+ at specialize.argtype(0)
+def listdir(dirname):
+    if isinstance(dirname, str):
+        return os.listdir(dirname)
+    else:
+        return os.listdir(dirname.as_bytes())
+
+ at specialize.argtype(0)
+def access(path, mode):
+    if isinstance(path, str):
+        return os.access(path, mode)
+    else:
+        return os.access(path.as_bytes(), mode)
+
+ at specialize.argtype(0)
+def chmod(path, mode):
+    if isinstance(path, str):
+        return os.chmod(path, mode)
+    else:
+        return os.chmod(path.as_bytes(), mode)
+
+ at specialize.argtype(0, 1)
+def utime(path, times):
+    if isinstance(path, str):
+        return os.utime(path, times)
+    else:
+        return os.utime(path.as_bytes(), times)
+
+ at specialize.argtype(0)
+def chdir(path):
+    if isinstance(path, str):
+        return os.chdir(path)
+    else:
+        return os.chdir(path.as_bytes())
+
+ at specialize.argtype(0)
+def mkdir(path, mode=0777):
+    if isinstance(path, str):
+        return os.mkdir(path, mode)
+    else:
+        return os.mkdir(path.as_bytes(), mode)
+
+ at specialize.argtype(0)
+def rmdir(path):
+    if isinstance(path, str):
+        return os.rmdir(path)
+    else:
+        return os.rmdir(path.as_bytes())
+
+if os.name == 'nt':
+    import nt
+    def _getfullpathname(path):
+        if isinstance(path, str):
+            return nt._getfullpathname(path)
+        else:
+            return nt._getfullpathname(path.as_bytes())

Modified: pypy/trunk/pypy/rlib/rwin32.py
==============================================================================
--- pypy/trunk/pypy/rlib/rwin32.py	(original)
+++ pypy/trunk/pypy/rlib/rwin32.py	Fri Jul 16 23:46:23 2010
@@ -31,6 +31,7 @@
         DWORD = rffi_platform.SimpleType("DWORD", rffi.UINT)
         BOOL = rffi_platform.SimpleType("BOOL", rffi.LONG)
         BYTE = rffi_platform.SimpleType("BYTE", rffi.UCHAR)
+        WCHAR = rffi_platform.SimpleType("WCHAR", rffi.UCHAR)
         INT = rffi_platform.SimpleType("INT", rffi.INT)
         LONG = rffi_platform.SimpleType("LONG", rffi.LONG)
         PLONG = rffi_platform.SimpleType("PLONG", rffi.LONGP)
@@ -38,6 +39,8 @@
         LPCVOID = rffi_platform.SimpleType("LPCVOID", rffi.VOIDP)
         LPSTR = rffi_platform.SimpleType("LPSTR", rffi.CCHARP)
         LPCSTR = rffi_platform.SimpleType("LPCSTR", rffi.CCHARP)
+        LPWSTR = rffi_platform.SimpleType("LPWSTR", rffi.CWCHARP)
+        LPCWSTR = rffi_platform.SimpleType("LPCWSTR", rffi.CWCHARP)
         LPDWORD = rffi_platform.SimpleType("LPDWORD", rffi.INTP)
         SIZE_T = rffi_platform.SimpleType("SIZE_T", rffi.SIZE_T)
         ULONG_PTR = rffi_platform.SimpleType("ULONG_PTR", rffi.ULONG)
@@ -87,6 +90,10 @@
     GetLastError = winexternal('GetLastError', [], DWORD)
     SetLastError = winexternal('SetLastError', [DWORD], lltype.Void)
 
+    # In tests, the first call to GetLastError is always wrong, because error
+    # is hidden by operations in ll2ctypes.  Call it now.
+    GetLastError()
+
     LoadLibrary = winexternal('LoadLibraryA', [rffi.CCHARP], rffi.VOIDP)
     GetProcAddress = winexternal('GetProcAddress',
                                  [rffi.VOIDP, rffi.CCHARP],

Modified: pypy/trunk/pypy/rlib/streamio.py
==============================================================================
--- pypy/trunk/pypy/rlib/streamio.py	(original)
+++ pypy/trunk/pypy/rlib/streamio.py	Fri Jul 16 23:46:23 2010
@@ -38,7 +38,9 @@
 #
 
 import os, sys
+from pypy.rlib.objectmodel import specialize
 from pypy.rlib.rarithmetic import r_longlong, intmask
+from pypy.rlib import rposix
 
 from os import O_RDONLY, O_WRONLY, O_RDWR, O_CREAT, O_TRUNC
 O_BINARY = getattr(os, "O_BINARY", 0)
@@ -71,6 +73,7 @@
     return s.join(string.split(c))
 
 
+ at specialize.argtype(0)
 def open_file_as_stream(path, mode="r", buffering=-1):
     os_flags, universal, reading, writing, basemode, binary = decode_mode(mode)
     stream = open_path_helper(path, os_flags, basemode == "a")
@@ -89,9 +92,10 @@
     return construct_stream_tower(stream, buffering, universal, reading,
                                   writing, binary)
 
+ at specialize.argtype(0)
 def open_path_helper(path, os_flags, append):
     # XXX for now always return DiskFile
-    fd = os.open(path, os_flags, 0666)
+    fd = rposix.open(path, os_flags, 0666)
     if append:
         try:
             os.lseek(fd, 0, 2)

Copied: pypy/trunk/pypy/rlib/test/test_rposix.py (from r76265, pypy/branch/unicode_filename-2/pypy/rlib/test/test_rposix.py)
==============================================================================
--- pypy/branch/unicode_filename-2/pypy/rlib/test/test_rposix.py	(original)
+++ pypy/trunk/pypy/rlib/test/test_rposix.py	Fri Jul 16 23:46:23 2010
@@ -2,6 +2,7 @@
 from pypy.tool.udir import udir
 from pypy.rlib import rposix
 import os, sys
+import py
 
 def ll_to_string(s):
     return ''.join(s.chars)
@@ -28,7 +29,10 @@
     def setup_method(self, method):
         self.ufilename = (unicode(udir.join('test_open')) +
                           u'\u65e5\u672c.txt') # "Japan"
-        f = file(self.ufilename, 'w')
+        try:
+            f = file(self.ufilename, 'w')
+        except UnicodeEncodeError:
+            py.test.skip("encoding not good enough")
         f.write("test")
         f.close()
 

Modified: pypy/trunk/pypy/rpython/extfunc.py
==============================================================================
--- pypy/trunk/pypy/rpython/extfunc.py	(original)
+++ pypy/trunk/pypy/rpython/extfunc.py	Fri Jul 16 23:46:23 2010
@@ -52,7 +52,10 @@
                         return super(ExtRegistryEntry, self).__getattr__(attr)
                     raise exc, exc_inst, tb
 
-def registering(func):
+def registering(func, condition=True):
+    if not condition:
+        return lambda method: None
+
     def decorator(method):
         method._registering_func = func
         return method
@@ -63,11 +66,9 @@
         func = getattr(ns, name)
     except AttributeError:
         condition = False
+        func = None
 
-    if condition:
-        return registering(func)
-    else:
-        return lambda method: None
+    return registering(func, condition=condition)
 
 class LazyRegisteringMeta(type):
     def __new__(self, _name, _type, _vars):
@@ -167,8 +168,6 @@
         return signature_args
 
     def compute_result_annotation(self, *args_s):
-        if hasattr(self, 'ann_hook'):
-            self.ann_hook()
         self.normalize_args(*args_s)   # check arguments
         return self.signature_result
 
@@ -235,7 +234,6 @@
 def register_external(function, args, result=None, export_name=None,
                        llimpl=None, ooimpl=None,
                        llfakeimpl=None, oofakeimpl=None,
-                       annotation_hook=None,
                        sandboxsafe=False):
     """
     function: the RPython function that will be rendered as an external function (e.g.: math.floor)
@@ -244,7 +242,6 @@
     export_name: the name of the function as it will be seen by the backends
     llimpl, ooimpl: optional; if provided, these RPython functions are called instead of the target function
     llfakeimpl, oofakeimpl: optional; if provided, they are called by the llinterpreter
-    annotationhook: optional; a callable that is called during annotation, useful for genc hacks
     sandboxsafe: use True if the function performs no I/O (safe for --sandbox)
     """
 
@@ -271,8 +268,6 @@
             lltypefakeimpl = staticmethod(llfakeimpl)
         if oofakeimpl:
             ootypefakeimpl = staticmethod(oofakeimpl)
-        if annotation_hook:
-            ann_hook = staticmethod(annotation_hook)
 
     if export_name:
         FunEntry.__name__ = export_name

Modified: pypy/trunk/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/rffi.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/rffi.py	Fri Jul 16 23:46:23 2010
@@ -176,6 +176,15 @@
                     # XXX leaks if a str2charp() fails with MemoryError
                     # and was not the first in this function
                     freeme = arg
+            elif TARGET == CWCHARP:
+                if arg is None:
+                    arg = lltype.nullptr(CWCHARP.TO)   # None => (wchar_t*)NULL
+                    freeme = arg
+                elif isinstance(arg, unicode):
+                    arg = unicode2wcharp(arg)
+                    # XXX leaks if a unicode2wcharp() fails with MemoryError
+                    # and was not the first in this function
+                    freeme = arg
             elif _isfunctype(TARGET) and not _isllptr(arg):
                 # XXX pass additional arguments
                 if invoke_around_handlers:

Modified: pypy/trunk/pypy/rpython/module/ll_os.py
==============================================================================
--- pypy/trunk/pypy/rpython/module/ll_os.py	(original)
+++ pypy/trunk/pypy/rpython/module/ll_os.py	Fri Jul 16 23:46:23 2010
@@ -6,12 +6,15 @@
 # might be found in doc/rffi.txt
 
 import os, sys, errno
+import py
 from pypy.rpython.module.support import ll_strcpy, OOSupport
-from pypy.tool.sourcetools import func_with_new_name
+from pypy.tool.sourcetools import func_with_new_name, func_renamer
 from pypy.rlib.rarithmetic import r_longlong
-from pypy.rpython.extfunc import BaseLazyRegistering
+from pypy.rpython.extfunc import (
+    BaseLazyRegistering, lazy_register, register_external)
 from pypy.rpython.extfunc import registering, registering_if, extdef
-from pypy.annotation.model import SomeInteger, SomeString, SomeTuple, SomeFloat
+from pypy.annotation.model import (
+    SomeInteger, SomeString, SomeTuple, SomeFloat, SomeUnicodeString)
 from pypy.annotation.model import s_ImpossibleValue, s_None, s_Bool
 from pypy.rpython.lltypesystem import rffi
 from pypy.rpython.lltypesystem import lltype
@@ -26,7 +29,99 @@
 from pypy.rpython.lltypesystem.rstr import STR
 from pypy.rpython.annlowlevel import llstr
 from pypy.rlib import rgc
-from pypy.rlib.objectmodel import keepalive_until_here
+from pypy.rlib.objectmodel import keepalive_until_here, specialize
+
+def monkeypatch_rposix(posixfunc, unicodefunc, signature):
+    func_name = posixfunc.__name__
+
+    if hasattr(signature, '_default_signature_'):
+        signature = signature._default_signature_
+    arglist = ['arg%d' % (i,) for i in range(len(signature))]
+    transformed_arglist = arglist[:]
+    for i, arg in enumerate(signature):
+        if arg is unicode:
+            transformed_arglist[i] = transformed_arglist[i] + '.as_unicode()'
+
+    args = ', '.join(arglist)
+    transformed_args = ', '.join(transformed_arglist)
+    main_arg = 'arg%d' % (signature.index(unicode),)
+
+    source = py.code.Source("""
+    def %(func_name)s(%(args)s):
+        if isinstance(%(main_arg)s, str):
+            return posixfunc(%(args)s)
+        else:
+            return unicodefunc(%(transformed_args)s)
+    """ % locals())
+    miniglobals = {'posixfunc'  : posixfunc,
+                   'unicodefunc': unicodefunc,
+                   '__name__':    __name__, # for module name propagation
+                   }
+    exec source.compile() in miniglobals
+    new_func = miniglobals[func_name]
+    specialized_args = [i for i in range(len(signature))
+                        if signature[i] in (unicode, None)]
+    new_func = specialize.argtype(*specialized_args)(new_func)
+
+    # Monkeypatch the function in pypy.rlib.rposix
+    setattr(rposix, func_name, new_func)
+
+class StringTraits:
+    str = str
+    CHAR = rffi.CHAR
+    CCHARP = rffi.CCHARP
+    charp2str = staticmethod(rffi.charp2str)
+    str2charp = staticmethod(rffi.str2charp)
+    free_charp = staticmethod(rffi.free_charp)
+
+    @staticmethod
+    def posix_function_name(name):
+        return underscore_on_windows + name
+
+    @staticmethod
+    def ll_os_name(name):
+        return 'll_os.ll_os_' + name
+
+class UnicodeTraits:
+    str = unicode
+    CHAR = rffi.WCHAR_T
+    CCHARP = rffi.CWCHARP
+    charp2str = staticmethod(rffi.wcharp2unicode)
+    str2charp = staticmethod(rffi.unicode2wcharp)
+    free_charp = staticmethod(rffi.free_wcharp)
+
+    @staticmethod
+    def posix_function_name(name):
+        return underscore_on_windows + 'w' + name
+
+    @staticmethod
+    def ll_os_name(name):
+        return 'll_os.ll_os_w' + name
+
+def registering_str_unicode(posixfunc, condition=True):
+    if not condition:
+        return registering(None, condition=False)
+
+    func_name = posixfunc.__name__
+
+    def register_posixfunc(self, method):
+        val = method(self, StringTraits())
+        register_external(posixfunc, *val.def_args, **val.def_kwds)
+
+        if sys.platform == 'win32':
+            val = method(self, UnicodeTraits())
+            @func_renamer(func_name + "_unicode")
+            def unicodefunc(*args):
+                return posixfunc(*args)
+            register_external(unicodefunc, *val.def_args, **val.def_kwds)
+            signature = val.def_args[0]
+            monkeypatch_rposix(posixfunc, unicodefunc, signature)
+
+    def decorator(method):
+        decorated = lambda self: register_posixfunc(self, method)
+        decorated._registering_func = posixfunc
+        return decorated
+    return decorator
 
 posix = __import__(os.name)
 
@@ -282,8 +377,8 @@
         return extdef([int, int], s_None, llimpl=dup2_llimpl,
                       export_name="ll_os.ll_os_dup2")
 
-    @registering(os.utime)
-    def register_os_utime(self):
+    @registering_str_unicode(os.utime)
+    def register_os_utime(self, traits):
         UTIMBUFP = lltype.Ptr(self.UTIMBUF)
         os_utime = self.llexternal('utime', [rffi.CCHARP, UTIMBUFP], rffi.INT)
 
@@ -336,6 +431,9 @@
         # tp is known to be None, and one version where it is known
         # to be a tuple of 2 floats.
         if not _WIN32:
+            assert traits.str is str
+
+            @specialize.argtype(1)
             def os_utime_llimpl(path, tp):
                 if tp is None:
                     error = os_utime(path, lltype.nullptr(UTIMBUFP.TO))
@@ -346,85 +444,13 @@
                 if error == -1:
                     raise OSError(rposix.get_errno(), "os_utime failed")
         else:
-            from pypy.rlib import rwin32
-            from pypy.rpython.module.ll_os_stat import time_t_to_FILE_TIME
-
-            class CConfig:
-                _compilation_info_ = ExternalCompilationInfo(
-                    includes = ['windows.h'],
-                    )
-
-                FILE_WRITE_ATTRIBUTES = platform.ConstantInteger(
-                    'FILE_WRITE_ATTRIBUTES')
-                OPEN_EXISTING = platform.ConstantInteger(
-                    'OPEN_EXISTING')
-                FILE_FLAG_BACKUP_SEMANTICS = platform.ConstantInteger(
-                    'FILE_FLAG_BACKUP_SEMANTICS')
-            globals().update(platform.configure(CConfig))
-
-            CreateFile = rffi.llexternal(
-                'CreateFileA',
-                [rwin32.LPCSTR, rwin32.DWORD, rwin32.DWORD,
-                 rwin32.LPSECURITY_ATTRIBUTES, rwin32.DWORD, rwin32.DWORD,
-                 rwin32.HANDLE],
-                rwin32.HANDLE,
-                calling_conv='win')
-
-            GetSystemTime = rffi.llexternal(
-                'GetSystemTime',
-                [lltype.Ptr(rwin32.SYSTEMTIME)],
-                lltype.Void,
-                calling_conv='win')
-
-            SystemTimeToFileTime = rffi.llexternal(
-                'SystemTimeToFileTime',
-                [lltype.Ptr(rwin32.SYSTEMTIME),
-                 lltype.Ptr(rwin32.FILETIME)],
-                rwin32.BOOL,
-                calling_conv='win')
-
-            SetFileTime = rffi.llexternal(
-                'SetFileTime',
-                [rwin32.HANDLE,
-                 lltype.Ptr(rwin32.FILETIME),
-                 lltype.Ptr(rwin32.FILETIME),
-                 lltype.Ptr(rwin32.FILETIME)],
-                rwin32.BOOL,
-                calling_conv = 'win')
+            from pypy.rpython.module.ll_win32file import make_utime_impl
+            os_utime_llimpl = make_utime_impl(traits)
 
-            def os_utime_llimpl(path, tp):
-                hFile = CreateFile(path, 
-                                   FILE_WRITE_ATTRIBUTES, 0, 
-                                   None, OPEN_EXISTING,
-                                   FILE_FLAG_BACKUP_SEMANTICS, 0)
-                if hFile == rwin32.INVALID_HANDLE_VALUE:
-                    raise rwin32.lastWindowsError()
-                ctime = lltype.nullptr(rwin32.FILETIME)
-                atime = lltype.malloc(rwin32.FILETIME, flavor='raw')
-                mtime = lltype.malloc(rwin32.FILETIME, flavor='raw')
-                try:
-                    if tp is None:
-                        now = lltype.malloc(rwin32.SYSTEMTIME, flavor='raw')
-                        try:
-                            GetSystemTime(now)
-                            if (not SystemTimeToFileTime(now, atime) or
-                                not SystemTimeToFileTime(now, mtime)):
-                                raise rwin32.lastWindowsError()
-                        finally:
-                            lltype.free(now, flavor='raw')
-                    else:
-                        actime, modtime = tp
-                        time_t_to_FILE_TIME(actime, atime)
-                        time_t_to_FILE_TIME(modtime, mtime)
-                    if not SetFileTime(hFile, ctime, atime, mtime):
-                        raise rwin32.lastWindowsError()
-                finally:
-                    rwin32.CloseHandle(hFile)
-                    lltype.free(atime, flavor='raw')
-                    lltype.free(mtime, flavor='raw')
-        os_utime_llimpl._annspecialcase_ = 'specialize:argtype(1)'
-
-        s_string = SomeString()
+        if traits.str is str:
+            s_string = SomeString()
+        else:
+            s_string = SomeUnicodeString()
         s_tuple_of_2_floats = SomeTuple([SomeFloat(), SomeFloat()])
 
         def os_utime_normalize_args(s_path, s_times):
@@ -445,12 +471,12 @@
             else:
                 raise Exception("os.utime() arg 2 must be None or a tuple of "
                                 "2 floats, got %s" % (s_times,))
+        os_utime_normalize_args._default_signature_ = [traits.str, None]
 
         return extdef(os_utime_normalize_args, s_None,
                       "ll_os.ll_os_utime",
                       llimpl=os_utime_llimpl)
 
-
     @registering(os.times)
     def register_os_times(self):
         if sys.platform.startswith('win'):
@@ -687,22 +713,21 @@
     def register_os_setsid(self):
         return self.extdef_for_os_function_returning_int('setsid')
 
-    @registering(os.open)
-    def register_os_open(self):
-        os_open = self.llexternal(underscore_on_windows+'open',
-                                  [rffi.CCHARP, rffi.INT, rffi.MODE_T],
+    @registering_str_unicode(os.open)
+    def register_os_open(self, traits):
+        os_open = self.llexternal(traits.posix_function_name('open'),
+                                  [traits.CCHARP, rffi.INT, rffi.MODE_T],
                                   rffi.INT)
-
         def os_open_llimpl(path, flags, mode):
             result = rffi.cast(rffi.LONG, os_open(path, flags, mode))
             if result == -1:
                 raise OSError(rposix.get_errno(), "os_open failed")
             return result
 
-        def os_open_oofakeimpl(o_path, flags, mode):
-            return os.open(o_path._str, flags, mode)
+        def os_open_oofakeimpl(path, flags, mode):
+            return os.open(OOSupport.from_rstr(path), flags, mode)
 
-        return extdef([str, int, int], int, "ll_os.ll_os_open",
+        return extdef([traits.str, int, int], int, traits.ll_os_name('open'),
                       llimpl=os_open_llimpl, oofakeimpl=os_open_oofakeimpl)
 
 # ------------------------------- os.read -------------------------------
@@ -862,10 +887,10 @@
                       llimpl=fdatasync_llimpl,
                       export_name="ll_os.ll_os_fdatasync")
 
-    @registering(os.access)
-    def register_os_access(self):
-        os_access = self.llexternal(underscore_on_windows + 'access',
-                                    [rffi.CCHARP, rffi.INT],
+    @registering_str_unicode(os.access)
+    def register_os_access(self, traits):
+        os_access = self.llexternal(traits.posix_function_name('access'),
+                                    [traits.CCHARP, rffi.INT],
                                     rffi.INT)
 
         if sys.platform.startswith('win'):
@@ -882,44 +907,22 @@
         def os_access_oofakeimpl(path, mode):
             return os.access(OOSupport.from_rstr(path), mode)
 
-        return extdef([str, int], s_Bool, llimpl=access_llimpl,
-                      export_name="ll_os.ll_os_access",
+        return extdef([traits.str, int], s_Bool, llimpl=access_llimpl,
+                      export_name=traits.ll_os_name("access"),
                       oofakeimpl=os_access_oofakeimpl)
 
-    @registering_if(posix, '_getfullpathname')
-    def register_posix__getfullpathname(self):
-        from pypy.rlib import rwin32
+    @registering_str_unicode(getattr(posix, '_getfullpathname', None),
+                             condition=sys.platform=='win32')
+    def register_posix__getfullpathname(self, traits):
         # this nt function is not exposed via os, but needed
         # to get a correct implementation of os.abspath
-        # XXX why do we ignore WINAPI conventions everywhere?
-        LPSTRP = rffi.CArrayPtr(rwin32.LPSTR)
-        # XXX unicode?
-        GetFullPathName = self.llexternal(
-            'GetFullPathNameA',
-            [rwin32.LPCSTR,
-             rwin32.DWORD,
-             rwin32.LPSTR,
-             rffi.CArrayPtr(rwin32.LPSTR)],
-            rwin32.DWORD)
-
-        def _getfullpathname_llimpl(lpFileName):
-            nBufferLength = rwin32.MAX_PATH + 1
-            lpBuffer = lltype.malloc(rwin32.LPSTR.TO, nBufferLength, flavor='raw')
-            try:
-                res = GetFullPathName(
-                    lpFileName, rffi.cast(rwin32.DWORD, nBufferLength),
-                    lpBuffer, lltype.nullptr(LPSTRP.TO))
-                if res == 0:
-                    raise rwin32.lastWindowsError("_getfullpathname failed")
-                result = rffi.charp2str(lpBuffer)
-                return result
-            finally:
-                lltype.free(lpBuffer, flavor='raw')
+        from pypy.rpython.module.ll_win32file import make_getfullpathname_impl
+        getfullpathname_llimpl = make_getfullpathname_impl(traits)
 
-        return extdef([str],  # a single argument which is a str
-                      str,    # returns a string
-                      "ll_os.posix__getfullpathname",
-                      llimpl=_getfullpathname_llimpl)
+        return extdef([traits.str],  # a single argument which is a str
+                      traits.str,    # returns a string
+                      traits.ll_os_name('_getfullpathname'),
+                      llimpl=getfullpathname_llimpl)
 
     @registering(os.getcwd)
     def register_os_getcwd(self):
@@ -953,71 +956,42 @@
                       "ll_os.ll_os_getcwd", llimpl=os_getcwd_llimpl,
                       oofakeimpl=os_getcwd_oofakeimpl)
 
-    @registering(os.listdir)
-    def register_os_listdir(self):
-        # we need a different approach on Windows and on Posix
-        if sys.platform.startswith('win'):
-            from pypy.rlib import rwin32
-            class CConfig:
-                _compilation_info_ = ExternalCompilationInfo(
-                    includes = ['windows.h']
-                )
-                WIN32_FIND_DATA = platform.Struct('struct _WIN32_FIND_DATAA',
-                    [('cFileName', lltype.FixedSizeArray(rffi.CHAR, 1))])
-                ERROR_FILE_NOT_FOUND = platform.ConstantInteger(
-                    'ERROR_FILE_NOT_FOUND')
-                ERROR_NO_MORE_FILES = platform.ConstantInteger(
-                    'ERROR_NO_MORE_FILES')
+    @registering(os.getcwdu, condition=sys.platform=='win32')
+    def register_os_getcwdu(self):
+        os_wgetcwd = self.llexternal(underscore_on_windows + 'wgetcwd',
+                                     [rffi.CWCHARP, rffi.SIZE_T],
+                                     rffi.CWCHARP)
 
-            config = platform.configure(CConfig)
-            WIN32_FIND_DATA      = config['WIN32_FIND_DATA']
-            ERROR_FILE_NOT_FOUND = config['ERROR_FILE_NOT_FOUND']
-            ERROR_NO_MORE_FILES  = config['ERROR_NO_MORE_FILES']
-            LPWIN32_FIND_DATA    = lltype.Ptr(WIN32_FIND_DATA)
-
-            FindFirstFile = self.llexternal('FindFirstFile',
-                                            [rwin32.LPCSTR, LPWIN32_FIND_DATA],
-                                            rwin32.HANDLE)
-            FindNextFile = self.llexternal('FindNextFile',
-                                           [rwin32.HANDLE, LPWIN32_FIND_DATA],
-                                           rwin32.BOOL)
-            FindClose = self.llexternal('FindClose',
-                                        [rwin32.HANDLE],
-                                        rwin32.BOOL)
+        def os_getcwd_llimpl():
+            bufsize = 256
+            while True:
+                buf = lltype.malloc(rffi.CWCHARP.TO, bufsize, flavor='raw')
+                res = os_wgetcwd(buf, rffi.cast(rffi.SIZE_T, bufsize))
+                if res:
+                    break   # ok
+                error = rposix.get_errno()
+                lltype.free(buf, flavor='raw')
+                if error != errno.ERANGE:
+                    raise OSError(error, "getcwd failed")
+                # else try again with a larger buffer, up to some sane limit
+                bufsize *= 4
+                if bufsize > 1024*1024:  # xxx hard-coded upper limit
+                    raise OSError(error, "getcwd result too large")
+            result = rffi.wcharp2unicode(res)
+            lltype.free(buf, flavor='raw')
+            return result
 
-            def os_listdir_llimpl(path):
-                if path and path[-1] not in ('/', '\\', ':'):
-                    path += '/'
-                path += '*.*'
-                filedata = lltype.malloc(WIN32_FIND_DATA, flavor='raw')
-                try:
-                    result = []
-                    hFindFile = FindFirstFile(path, filedata)
-                    if hFindFile == rwin32.INVALID_HANDLE_VALUE:
-                        error = rwin32.GetLastError()
-                        if error == ERROR_FILE_NOT_FOUND:
-                            return result
-                        else:
-                            raise WindowsError(error,  "FindFirstFile failed")
-                    while True:
-                        name = rffi.charp2str(rffi.cast(rffi.CCHARP,
-                                                        filedata.c_cFileName))
-                        if name != "." and name != "..":   # skip these
-                            result.append(name)
-                        if not FindNextFile(hFindFile, filedata):
-                            break
-                    # FindNextFile sets error to ERROR_NO_MORE_FILES if
-                    # it got to the end of the directory
-                    error = rwin32.GetLastError()
-                    FindClose(hFindFile)
-                    if error == ERROR_NO_MORE_FILES:
-                        return result
-                    else:
-                        raise WindowsError(error,  "FindNextFile failed")
-                finally:
-                    lltype.free(filedata, flavor='raw')
+        return extdef([], unicode,
+                      "ll_os.ll_os_wgetcwd", llimpl=os_getcwd_llimpl)
 
+    @registering_str_unicode(os.listdir)
+    def register_os_listdir(self, traits):
+        # we need a different approach on Windows and on Posix
+        if sys.platform.startswith('win'):
+            from pypy.rpython.module.ll_win32file import make_listdir_impl
+            os_listdir_llimpl = make_listdir_impl(traits)
         else:
+            assert traits.str is str
             compilation_info = ExternalCompilationInfo(
                 includes = ['sys/types.h', 'dirent.h']
             )
@@ -1057,9 +1031,9 @@
                     raise OSError(error, "os_readdir failed")
                 return result
 
-        return extdef([str],  # a single argument which is a str
-                      [str],  # returns a list of strings
-                      "ll_os.ll_os_listdir",
+        return extdef([traits.str],  # a single argument which is a str
+                      [traits.str],  # returns a list of strings
+                      traits.ll_os_name('listdir'),
                       llimpl=os_listdir_llimpl)
 
     @registering(os.pipe)
@@ -1234,38 +1208,40 @@
         return extdef([str], int, llimpl=system_llimpl,
                       export_name="ll_os.ll_os_system")
 
-    @registering(os.unlink)
-    def register_os_unlink(self):
-        os_unlink = self.llexternal(underscore_on_windows+'unlink', [rffi.CCHARP], rffi.INT)
+    @registering_str_unicode(os.unlink)
+    def register_os_unlink(self, traits):
+        os_unlink = self.llexternal(traits.posix_function_name('unlink'),
+                                    [traits.CCHARP], rffi.INT)
 
         def unlink_llimpl(pathname):
             res = rffi.cast(lltype.Signed, os_unlink(pathname))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_unlink failed")
 
-        return extdef([str], s_None, llimpl=unlink_llimpl,
-                      export_name="ll_os.ll_os_unlink")
+        return extdef([traits.str], s_None, llimpl=unlink_llimpl,
+                      export_name=traits.ll_os_name('unlink'))
 
-    @registering(os.chdir)
-    def register_os_chdir(self):
-        os_chdir = self.llexternal(underscore_on_windows+'chdir', [rffi.CCHARP], rffi.INT)
+    @registering_str_unicode(os.chdir)
+    def register_os_chdir(self, traits):
+        os_chdir = self.llexternal(traits.posix_function_name('chdir'),
+                                   [traits.CCHARP], rffi.INT)
 
         def chdir_llimpl(path):
             res = rffi.cast(lltype.Signed, os_chdir(path))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_chdir failed")
 
-        return extdef([str], s_None, llimpl=chdir_llimpl,
-                      export_name="ll_os.ll_os_chdir")
+        return extdef([traits.str], s_None, llimpl=chdir_llimpl,
+                      export_name=traits.ll_os_name('chdir'))
 
-    @registering(os.mkdir)
-    def register_os_mkdir(self):
+    @registering_str_unicode(os.mkdir)
+    def register_os_mkdir(self, traits):
         if os.name == 'nt':
             ARG2 = []         # no 'mode' argument on Windows - just ignored
         else:
             ARG2 = [rffi.MODE_T]
-        os_mkdir = self.llexternal(underscore_on_windows+'mkdir',
-                                   [rffi.CCHARP]+ARG2, rffi.INT)
+        os_mkdir = self.llexternal(traits.posix_function_name('mkdir'),
+                                   [traits.CCHARP] + ARG2, rffi.INT)
         IGNORE_MODE = len(ARG2) == 0
 
         def mkdir_llimpl(pathname, mode):
@@ -1277,46 +1253,47 @@
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_mkdir failed")
 
-        return extdef([str, int], s_None, llimpl=mkdir_llimpl,
-                      export_name="ll_os.ll_os_mkdir")
+        return extdef([traits.str, int], s_None, llimpl=mkdir_llimpl,
+                      export_name=traits.ll_os_name('mkdir'))
 
-    @registering(os.rmdir)
-    def register_os_rmdir(self):
-        os_rmdir = self.llexternal(underscore_on_windows+'rmdir', [rffi.CCHARP], rffi.INT)
+    @registering_str_unicode(os.rmdir)
+    def register_os_rmdir(self, traits):
+        os_rmdir = self.llexternal(traits.posix_function_name('rmdir'),
+                                   [traits.CCHARP], rffi.INT)
 
         def rmdir_llimpl(pathname):
             res = rffi.cast(lltype.Signed, os_rmdir(pathname))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_rmdir failed")
 
-        return extdef([str], s_None, llimpl=rmdir_llimpl,
-                      export_name="ll_os.ll_os_rmdir")
+        return extdef([traits.str], s_None, llimpl=rmdir_llimpl,
+                      export_name=traits.ll_os_name('rmdir'))
 
-    @registering(os.chmod)
-    def register_os_chmod(self):
-        os_chmod = self.llexternal(underscore_on_windows+'chmod', [rffi.CCHARP, rffi.MODE_T],
-                                   rffi.INT)
+    @registering_str_unicode(os.chmod)
+    def register_os_chmod(self, traits):
+        os_chmod = self.llexternal(traits.posix_function_name('chmod'),
+                                   [traits.CCHARP, rffi.MODE_T], rffi.INT)
 
         def chmod_llimpl(path, mode):
             res = rffi.cast(lltype.Signed, os_chmod(path, rffi.cast(rffi.MODE_T, mode)))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_chmod failed")
 
-        return extdef([str, int], s_None, llimpl=chmod_llimpl,
-                      export_name="ll_os.ll_os_chmod")
+        return extdef([traits.str, int], s_None, llimpl=chmod_llimpl,
+                      export_name=traits.ll_os_name('chmod'))
 
-    @registering(os.rename)
-    def register_os_rename(self):
-        os_rename = self.llexternal('rename', [rffi.CCHARP, rffi.CCHARP],
-                                    rffi.INT)
+    @registering_str_unicode(os.rename)
+    def register_os_rename(self, traits):
+        os_rename = self.llexternal(traits.posix_function_name('rename'),
+                                    [traits.CCHARP, traits.CCHARP], rffi.INT)
 
         def rename_llimpl(oldpath, newpath):
             res = rffi.cast(lltype.Signed, os_rename(oldpath, newpath))
             if res < 0:
                 raise OSError(rposix.get_errno(), "os_rename failed")
 
-        return extdef([str, str], s_None, llimpl=rename_llimpl,
-                      export_name="ll_os.ll_os_rename")
+        return extdef([traits.str, traits.str], s_None, llimpl=rename_llimpl,
+                      export_name=traits.ll_os_name('rename'))
 
     @registering(os.umask)
     def register_os_umask(self):
@@ -1425,17 +1402,17 @@
     @registering(os.fstat)
     def register_os_fstat(self):
         from pypy.rpython.module import ll_os_stat
-        ll_os_stat.register_stat_variant('fstat')
+        return ll_os_stat.register_stat_variant('fstat', StringTraits())
 
-    @registering(os.stat)
-    def register_os_stat(self):
+    @registering_str_unicode(os.stat)
+    def register_os_stat(self, traits):
         from pypy.rpython.module import ll_os_stat
-        ll_os_stat.register_stat_variant('stat')
+        return ll_os_stat.register_stat_variant('stat', traits)
 
-    @registering(os.lstat)
-    def register_os_lstat(self):
+    @registering_str_unicode(os.lstat)
+    def register_os_lstat(self, traits):
         from pypy.rpython.module import ll_os_stat
-        ll_os_stat.register_stat_variant('lstat')
+        return ll_os_stat.register_stat_variant('lstat', traits)
 
     # ------------------------------- os.W* ---------------------------------
 

Modified: pypy/trunk/pypy/rpython/module/ll_os_stat.py
==============================================================================
--- pypy/trunk/pypy/rpython/module/ll_os_stat.py	(original)
+++ pypy/trunk/pypy/rpython/module/ll_os_stat.py	Fri Jul 16 23:46:23 2010
@@ -5,13 +5,14 @@
 import os, sys
 from pypy.annotation import model as annmodel
 from pypy.tool.pairtype import pairtype
-from pypy.tool.sourcetools import func_with_new_name
+from pypy.tool.sourcetools import func_with_new_name, func_renamer
 from pypy.rpython import extregistry
-from pypy.rpython.extfunc import register_external
+from pypy.rpython.extfunc import register_external, extdef
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.tool import rffi_platform as platform
 from pypy.rpython.lltypesystem.rtupletype import TUPLE_TYPE
 from pypy.rlib import rposix
+from pypy.rlib.objectmodel import specialize
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rpython.annlowlevel import hlstr
 
@@ -211,13 +212,27 @@
     return make_stat_result(result)
 
 
-def register_stat_variant(name):
-    if sys.platform.startswith('win'):
-        _functions = {'stat':  '_stati64',
-                      'fstat': '_fstati64',
-                      'lstat': '_stati64'}    # no lstat on Windows
-        c_func_name = _functions[name]
-    elif sys.platform.startswith('linux'):
+def register_stat_variant(name, traits):
+    if name != 'fstat':
+        arg_is_path = True
+        s_arg = traits.str
+        ARG1 = traits.CCHARP
+    else:
+        arg_is_path = False
+        s_arg = int
+        ARG1 = rffi.INT
+
+    if sys.platform == 'win32':
+        # See Win32 implementation below
+        posix_stat_llimpl = make_win32_stat_impl(name, traits)
+
+        return extdef(
+            [s_arg], s_StatResult, traits.ll_os_name(name),
+            llimpl=posix_stat_llimpl)
+
+    assert traits.str is str
+
+    if sys.platform.startswith('linux'):
         # because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler 
         _functions = {'stat':  'stat64',
                       'fstat': 'fstat64',
@@ -226,22 +241,26 @@
     else:
         c_func_name = name
 
-    arg_is_path = (name != 'fstat')
+    posix_mystat = rffi.llexternal(c_func_name,
+                                   [ARG1, STAT_STRUCT], rffi.INT,
+                                   compilation_info=compilation_info)
 
+    @func_renamer('os_%s_llimpl' % (name,))
     def posix_stat_llimpl(arg):
         stresult = lltype.malloc(STAT_STRUCT.TO, flavor='raw')
         try:
             if arg_is_path:
-                arg = rffi.str2charp(arg)
+                arg = traits.str2charp(arg)
             error = rffi.cast(rffi.LONG, posix_mystat(arg, stresult))
             if arg_is_path:
-                rffi.free_charp(arg)
+                traits.free_charp(arg)
             if error != 0:
                 raise OSError(rposix.get_errno(), "os_?stat failed")
             return build_stat_result(stresult)
         finally:
             lltype.free(stresult, flavor='raw')
 
+    @func_renamer('os_%s_fake' % (name,))
     def posix_fakeimpl(arg):
         if s_arg == str:
             arg = hlstr(arg)
@@ -259,40 +278,17 @@
                 setattr(ll_tup, 'item%d' % i, val)
         return ll_tup
 
-    if arg_is_path:
-        s_arg = str
-        ARG1 = rffi.CCHARP
-    else:
-        s_arg = int
-        ARG1 = rffi.INT
+    return extdef(
+        [s_arg], s_StatResult, "ll_os.ll_os_%s" % (name,),
+        llimpl=posix_stat_llimpl, llfakeimpl=posix_fakeimpl)
 
-    if sys.platform != 'win32':
-        posix_mystat = rffi.llexternal(c_func_name,
-                                       [ARG1, STAT_STRUCT], rffi.INT,
-                                       compilation_info=compilation_info)
-
-        register_external(
-            getattr(os, name), [s_arg], s_StatResult,
-            "ll_os.ll_os_%s" % (name,),
-            llimpl=func_with_new_name(posix_stat_llimpl,
-                                      'os_%s_llimpl' % (name,)),
-            llfakeimpl=func_with_new_name(posix_fakeimpl,
-                                          'os_%s_fake' % (name,)),
-            )
-    else:
-        # See Win32 implementation below
-        register_external(
-            getattr(os, name), [s_arg], s_StatResult,
-            "ll_os.ll_os_%s" % (name,),
-            llimpl=func_with_new_name(globals()['win32_%s_llimpl' % (name,)],
-                                      'os_%s_llimpl' % (name,)),
-            )
+def make_win32_stat_impl(name, traits):
+    from pypy.rlib import rwin32
+    from pypy.rpython.module.ll_win32file import make_win32_traits
+    win32traits = make_win32_traits(traits)
 
-# ____________________________________________________________
-if sys.platform == 'win32':
     # The CRT of Windows has a number of flaws wrt. its stat() implementation:
-    # - for when we implement subsecond resolution in RPython, time stamps
-    #   would be restricted to second resolution
+    # - time stamps are restricted to second resolution
     # - file modification times suffer from forth-and-back conversions between
     #   UTC and local time
     # Therefore, we implement our own stat, based on the Win32 API directly.
@@ -302,122 +298,18 @@
 
     assert len(STAT_FIELDS) == 10    # no extra fields on Windows
 
-    class CConfig:
-        _compilation_info_ = ExternalCompilationInfo(
-            includes = ['windows.h', 'winbase.h', 'sys/stat.h'],
-            )
-
-        GetFileExInfoStandard = platform.ConstantInteger(
-            'GetFileExInfoStandard')
-        FILE_ATTRIBUTE_DIRECTORY = platform.ConstantInteger(
-            'FILE_ATTRIBUTE_DIRECTORY')
-        FILE_ATTRIBUTE_READONLY = platform.ConstantInteger(
-            'FILE_ATTRIBUTE_READONLY')
-        ERROR_SHARING_VIOLATION = platform.ConstantInteger(
-            'ERROR_SHARING_VIOLATION')
-        _S_IFDIR = platform.ConstantInteger('_S_IFDIR')
-        _S_IFREG = platform.ConstantInteger('_S_IFREG')
-        _S_IFCHR = platform.ConstantInteger('_S_IFCHR')
-        _S_IFIFO = platform.ConstantInteger('_S_IFIFO')
-        FILE_TYPE_UNKNOWN = platform.ConstantInteger('FILE_TYPE_UNKNOWN')
-        FILE_TYPE_CHAR = platform.ConstantInteger('FILE_TYPE_CHAR')
-        FILE_TYPE_PIPE = platform.ConstantInteger('FILE_TYPE_PIPE')
-
-        WIN32_FILE_ATTRIBUTE_DATA = platform.Struct(
-            'WIN32_FILE_ATTRIBUTE_DATA',
-            [('dwFileAttributes', rwin32.DWORD),
-             ('nFileSizeHigh', rwin32.DWORD),
-             ('nFileSizeLow', rwin32.DWORD),
-             ('ftCreationTime', rwin32.FILETIME),
-             ('ftLastAccessTime', rwin32.FILETIME),
-             ('ftLastWriteTime', rwin32.FILETIME)])
-
-        BY_HANDLE_FILE_INFORMATION = platform.Struct(
-            'BY_HANDLE_FILE_INFORMATION',
-            [('dwFileAttributes', rwin32.DWORD),
-             ('nFileSizeHigh', rwin32.DWORD),
-             ('nFileSizeLow', rwin32.DWORD),
-             ('nNumberOfLinks', rwin32.DWORD),
-             ('nFileIndexHigh', rwin32.DWORD),
-             ('nFileIndexLow', rwin32.DWORD),
-             ('ftCreationTime', rwin32.FILETIME),
-             ('ftLastAccessTime', rwin32.FILETIME),
-             ('ftLastWriteTime', rwin32.FILETIME)])
-
-        WIN32_FIND_DATA = platform.Struct(
-            'WIN32_FIND_DATAA',
-            # Only interesting fields
-            [('dwFileAttributes', rwin32.DWORD),
-             ('nFileSizeHigh', rwin32.DWORD),
-             ('nFileSizeLow', rwin32.DWORD),
-             ('ftCreationTime', rwin32.FILETIME),
-             ('ftLastAccessTime', rwin32.FILETIME),
-             ('ftLastWriteTime', rwin32.FILETIME)])
-
-    globals().update(platform.configure(CConfig))
-    GET_FILEEX_INFO_LEVELS = rffi.ULONG # an enumeration
-
-    GetFileAttributesEx = rffi.llexternal(
-        'GetFileAttributesExA',
-        [rffi.CCHARP, GET_FILEEX_INFO_LEVELS,
-         lltype.Ptr(WIN32_FILE_ATTRIBUTE_DATA)],
-        rwin32.BOOL,
-        calling_conv='win')
-
-    GetFileInformationByHandle = rffi.llexternal(
-        'GetFileInformationByHandle',
-        [rwin32.HANDLE, lltype.Ptr(BY_HANDLE_FILE_INFORMATION)],
-        rwin32.BOOL,
-        calling_conv='win')
-
-    GetFileType = rffi.llexternal(
-        'GetFileType',
-        [rwin32.HANDLE],
-        rwin32.DWORD,
-        calling_conv='win')
-
-    FindFirstFile = rffi.llexternal(
-        'FindFirstFileA',
-        [rffi.CCHARP, lltype.Ptr(WIN32_FIND_DATA)],
-        rwin32.HANDLE,
-        calling_conv='win')
-
-    FindClose = rffi.llexternal(
-        'FindClose',
-        [rwin32.HANDLE],
-        rwin32.BOOL,
-        calling_conv='win')
-
     def attributes_to_mode(attributes):
         m = 0
-        if attributes & FILE_ATTRIBUTE_DIRECTORY:
-            m |= _S_IFDIR | 0111 # IFEXEC for user,group,other
+        if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY:
+            m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other
         else:
-            m |= _S_IFREG
-        if attributes & FILE_ATTRIBUTE_READONLY:
+            m |= win32traits._S_IFREG
+        if attributes & win32traits.FILE_ATTRIBUTE_READONLY:
             m |= 0444
         else:
             m |= 0666
         return m
 
-    def make_longlong(high, low):
-        return (lltype.r_longlong(high) << 32) + lltype.r_longlong(low)
-
-    # Seconds between 1.1.1601 and 1.1.1970
-    secs_between_epochs = lltype.r_longlong(11644473600)
-
-    def FILE_TIME_to_time_t_nsec(filetime):
-        ft = make_longlong(filetime.c_dwHighDateTime, filetime.c_dwLowDateTime)
-        # FILETIME is in units of 100 nsec
-        nsec = (ft % 10000000) * 100
-        time = (ft / 10000000) - secs_between_epochs
-        return time, nsec
-
-    def time_t_to_FILE_TIME(time, filetime):
-        ft = lltype.r_longlong((time + secs_between_epochs) * 10000000)
-        filetime.c_dwHighDateTime = lltype.r_uint(ft >> 32)
-        filetime.c_dwLowDateTime = lltype.r_uint(ft & ((1 << 32) - 1))
-        
     def attribute_data_to_stat(info):
         st_mode = attributes_to_mode(info.c_dwFileAttributes)
         st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
@@ -456,65 +348,94 @@
         return make_stat_result(result)
 
     def attributes_from_dir(l_path, data):
-        filedata = lltype.malloc(WIN32_FIND_DATA, flavor='raw')
-        hFindFile = FindFirstFile(l_path, filedata)
-        if hFindFile == rwin32.INVALID_HANDLE_VALUE:
-            return 0
-        FindClose(hFindFile)
-        data.c_dwFileAttributes = filedata.c_dwFileAttributes
-        rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime)
-        rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime)
-        rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime)
-        data.c_nFileSizeHigh    = filedata.c_nFileSizeHigh
-        data.c_nFileSizeLow     = filedata.c_nFileSizeLow
-        return 1
+        filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw')
+        try:
+            hFindFile = win32traits.FindFirstFile(l_path, filedata)
+            if hFindFile == rwin32.INVALID_HANDLE_VALUE:
+                return 0
+            win32traits.FindClose(hFindFile)
+            data.c_dwFileAttributes = filedata.c_dwFileAttributes
+            rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime)
+            rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime)
+            rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime)
+            data.c_nFileSizeHigh    = filedata.c_nFileSizeHigh
+            data.c_nFileSizeLow     = filedata.c_nFileSizeLow
+            return 1
+        finally:
+            lltype.free(filedata, flavor='raw')
 
     def win32_stat_llimpl(path):
-        data = lltype.malloc(WIN32_FILE_ATTRIBUTE_DATA, flavor='raw')
+        data = lltype.malloc(win32traits.WIN32_FILE_ATTRIBUTE_DATA, flavor='raw')
         try:
-            l_path = rffi.str2charp(path)
-            res = GetFileAttributesEx(l_path, GetFileExInfoStandard, data)
+            l_path = traits.str2charp(path)
+            res = win32traits.GetFileAttributesEx(l_path, win32traits.GetFileExInfoStandard, data)
             errcode = rwin32.GetLastError()
             if res == 0:
-                if errcode == ERROR_SHARING_VIOLATION:
+                if errcode == win32traits.ERROR_SHARING_VIOLATION:
                     res = attributes_from_dir(l_path, data)
                     errcode = rwin32.GetLastError()
-            rffi.free_charp(l_path)
+            traits.free_charp(l_path)
             if res == 0:
                 raise WindowsError(errcode, "os_stat failed")
             return attribute_data_to_stat(data)
         finally:
             lltype.free(data, flavor='raw')
-    win32_lstat_llimpl = win32_stat_llimpl
 
     def win32_fstat_llimpl(fd):
         handle = rwin32._get_osfhandle(fd)
 
-        filetype = GetFileType(handle)
-        if filetype == FILE_TYPE_CHAR:
+        filetype = win32traits.GetFileType(handle)
+        if filetype == win32traits.FILE_TYPE_CHAR:
             # console or LPT device
-            return make_stat_result((_S_IFCHR,
+            return make_stat_result((win32traits._S_IFCHR,
                                      0, 0, 0, 0, 0,
                                      0, 0, 0, 0))
-        elif filetype == FILE_TYPE_PIPE:
+        elif filetype == win32traits.FILE_TYPE_PIPE:
             # socket or named pipe
-            return make_stat_result((_S_IFIFO,
+            return make_stat_result((win32traits._S_IFIFO,
                                      0, 0, 0, 0, 0,
                                      0, 0, 0, 0))
-        elif filetype == FILE_TYPE_UNKNOWN:
+        elif filetype == win32traits.FILE_TYPE_UNKNOWN:
             error = rwin32.GetLastError()
             if error != 0:
                 raise WindowsError(error, "os_fstat failed")
             # else: unknown but valid file
 
         # normal disk file (FILE_TYPE_DISK)
-        info = lltype.malloc(BY_HANDLE_FILE_INFORMATION, flavor='raw',
-                             zero=True)
+        info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION,
+                             flavor='raw', zero=True)
         try:
-            res = GetFileInformationByHandle(handle, info)
+            res = win32traits.GetFileInformationByHandle(handle, info)
             if res == 0:
                 raise WindowsError(rwin32.GetLastError(), "os_fstat failed")
             return by_handle_info_to_stat(info)
         finally:
             lltype.free(info, flavor='raw')
 
+    if name == 'fstat':
+        return win32_fstat_llimpl
+    else:
+        return win32_stat_llimpl
+
+
+#__________________________________________________
+# Helper functions for win32
+
+def make_longlong(high, low):
+    return (lltype.r_longlong(high) << 32) + lltype.r_longlong(low)
+
+# Seconds between 1.1.1601 and 1.1.1970
+secs_between_epochs = lltype.r_longlong(11644473600)
+
+def FILE_TIME_to_time_t_nsec(filetime):
+    ft = make_longlong(filetime.c_dwHighDateTime, filetime.c_dwLowDateTime)
+    # FILETIME is in units of 100 nsec
+    nsec = (ft % 10000000) * 100
+    time = (ft / 10000000) - secs_between_epochs
+    return time, nsec
+
+def time_t_to_FILE_TIME(time, filetime):
+    ft = lltype.r_longlong((time + secs_between_epochs) * 10000000)
+    filetime.c_dwHighDateTime = lltype.r_uint(ft >> 32)
+    filetime.c_dwLowDateTime = lltype.r_uint(ft & ((1 << 32) - 1))
+

Copied: pypy/trunk/pypy/rpython/module/ll_win32file.py (from r76265, pypy/branch/unicode_filename-2/pypy/rpython/module/ll_win32file.py)
==============================================================================
--- pypy/branch/unicode_filename-2/pypy/rpython/module/ll_win32file.py	(original)
+++ pypy/trunk/pypy/rpython/module/ll_win32file.py	Fri Jul 16 23:46:23 2010
@@ -76,8 +76,9 @@
     config = platform.configure(CConfig)
 
     def external(*args, **kwargs):
-            kwargs['compilation_info'] = CConfig._compilation_info_
-            return rffi.llexternal(calling_conv='win', *args, **kwargs)
+        kwargs['compilation_info'] = CConfig._compilation_info_
+        llfunc = rffi.llexternal(calling_conv='win', *args, **kwargs)
+        return staticmethod(llfunc)
 
     class Win32Traits:
         apisuffix = suffix

Modified: pypy/trunk/pypy/rpython/module/test/test_ll_os_stat.py
==============================================================================
--- pypy/trunk/pypy/rpython/module/test/test_ll_os_stat.py	(original)
+++ pypy/trunk/pypy/rpython/module/test/test_ll_os_stat.py	Fri Jul 16 23:46:23 2010
@@ -1,4 +1,4 @@
-from pypy.rpython.module import ll_os_stat
+from pypy.rpython.module import ll_os_stat, ll_os
 import sys, os
 import py
 
@@ -8,14 +8,18 @@
             py.test.skip("win32 specific tests")
 
     def test_stat(self):
-        stat = ll_os_stat.win32_stat_llimpl
+        stat = ll_os_stat.make_win32_stat_impl('stat', ll_os.StringTraits())
+        wstat = ll_os_stat.make_win32_stat_impl('stat', ll_os.UnicodeTraits())
         def check(f):
-            assert stat(f).st_mtime == os.stat(f).st_mtime
+            expected = os.stat(f).st_mtime
+            assert stat(f).st_mtime == expected
+            assert wstat(unicode(f)).st_mtime == expected
 
         check('c:/')
         check('c:/temp')
         check('c:/pagefile.sys')
 
     def test_fstat(self):
-        stat = ll_os_stat.win32_fstat_llimpl(0) # stdout
+        fstat = ll_os_stat.make_win32_stat_impl('fstat', ll_os.StringTraits())
+        stat = fstat(0) # stdout
         assert stat.st_mode != 0

Modified: pypy/trunk/pypy/rpython/test/test_extfunc.py
==============================================================================
--- pypy/trunk/pypy/rpython/test/test_extfunc.py	(original)
+++ pypy/trunk/pypy/rpython/test/test_extfunc.py	Fri Jul 16 23:46:23 2010
@@ -6,150 +6,164 @@
 from pypy.annotation.policy import AnnotatorPolicy
 from pypy.rpython.test.test_llinterp import interpret
 
-def b(x):
-    return eval("x+40")
+class TestExtFuncEntry:
 
-class BTestFuncEntry(ExtFuncEntry):
-    _about_ = b
-    name = 'b'
-    signature_args = [annmodel.SomeInteger()]
-    signature_result = annmodel.SomeInteger()
-
-def test_annotation_b():
-    def f():
-        return b(1)
-    
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeInteger)
-
-def test_rtyping_b():
-    def f():
-        return b(2)
-
-    res = interpret(f, [])
-    assert res == 42
-
-def c(y, x):
-    yyy
-
-class CTestFuncEntry(ExtFuncEntry):
-    _about_ = c
-    name = 'ccc'
-    signature_args = [annmodel.SomeInteger()] * 2
-    signature_result = annmodel.SomeInteger()
-
-    def lltypeimpl(y, x):
-        return y + x
-    lltypeimpl = staticmethod(lltypeimpl)
-
-def test_interp_c():
-    def f():
-        return c(3, 4)
-
-    res = interpret(f, [])
-    assert res == 7
-
-def d(y):
-    return eval("y()")
-
-class DTestFuncEntry(ExtFuncEntry):
-    _about_ = d
-    name = 'd'
-    signature_args = [annmodel.SomeGenericCallable(args=[], result=
-                                                   annmodel.SomeFloat())]
-    signature_result = annmodel.SomeFloat()
-
-def test_callback():
-    def callback():
-        return 2.5
-
-    def f():
-        return d(callback)
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeFloat)
-    assert a.translator._graphof(callback)
-
-def dd():
-    pass
-
-register_external(dd, [int], int)
-
-def test_register_external_signature():
-    def f():
-        return dd(3)
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeInteger)
-
-
-def function_with_tuple_arg():
-    """
-    Dummy function which is declared via register_external to take a tuple as
-    an argument so that register_external's behavior for tuple-taking functions
-    can be verified.
-    """
-register_external(function_with_tuple_arg, [(int,)], int)
-
-def test_register_external_tuple_args():
-    """
-    Verify the annotation of a registered external function which takes a tuple
-    argument.
-    """
-    def f():
-        return function_with_tuple_arg((1,))
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-
-    # Not a very good assertion, but at least it means _something_ happened.
-    assert isinstance(s, annmodel.SomeInteger)
-
-def function_with_list():
-    pass
-register_external(function_with_list, [[int]], int)
-
-def function_returning_list():
-    pass
-register_external(function_returning_list, [], [int])
-
-def test_register_external_return_goes_back():
-    """
-    Check whether it works to pass the same list from one external
-    fun to another
-    [bookkeeper and list joining issues]
-    """
-    def f():
-        return function_with_list(function_returning_list())
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeInteger)
-
-def function_withspecialcase(arg):
-    return repr(arg)
-register_external(function_withspecialcase, args=None, result=str)
-
-def test_register_external_specialcase():
-    def f():
-        x = function_withspecialcase
-        return x(33) + x("aaa") + x([]) + "\n"
-
-    policy = AnnotatorPolicy()
-    policy.allow_someobjects = False
-    a = RPythonAnnotator(policy=policy)
-    s = a.build_types(f, [])
-    assert isinstance(s, annmodel.SomeString)
+    def test_basic(self):
+        """
+        A ExtFuncEntry provides an annotation for a function, no need to flow
+        its graph.
+        """
+        def b(x):
+            "NOT_RPYTHON"
+            return eval("x+40")
+
+        class BTestFuncEntry(ExtFuncEntry):
+            _about_ = b
+            name = 'b'
+            signature_args = [annmodel.SomeInteger()]
+            signature_result = annmodel.SomeInteger()
+
+        def f():
+            return b(2)
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeInteger)
+
+        res = interpret(f, [])
+        assert res == 42
+
+    def test_lltypeimpl(self):
+        """
+        interpret() calls lltypeimpl instead of of the function/
+        """
+        def c(y, x):
+            yyy
+
+        class CTestFuncEntry(ExtFuncEntry):
+            _about_ = c
+            name = 'ccc'
+            signature_args = [annmodel.SomeInteger()] * 2
+            signature_result = annmodel.SomeInteger()
+
+            def lltypeimpl(y, x):
+                return y + x
+            lltypeimpl = staticmethod(lltypeimpl)
+
+        def f():
+            return c(3, 4)
+
+        res = interpret(f, [])
+        assert res == 7
+
+    def test_callback(self):
+        """
+        Verify annotation when a callback function is in the arguments list.
+        """
+        def d(y):
+            return eval("y()")
+
+        class DTestFuncEntry(ExtFuncEntry):
+            _about_ = d
+            name = 'd'
+            signature_args = [annmodel.SomeGenericCallable(args=[], result=
+                                                           annmodel.SomeFloat())]
+            signature_result = annmodel.SomeFloat()
+
+        def callback():
+            return 2.5
+
+        def f():
+            return d(callback)
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeFloat)
+        assert a.translator._graphof(callback)
+
+    def test_register_external_signature(self):
+        """
+        Test the standard interface for external functions.
+        """
+        def dd():
+            pass
+        register_external(dd, [int], int)
+
+        def f():
+            return dd(3)
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeInteger)
+
+    def test_register_external_tuple_args(self):
+        """
+        Verify the annotation of a registered external function which takes a
+        tuple argument.
+        """
+
+        def function_with_tuple_arg():
+            """
+            Dummy function which is declared via register_external to take a
+            tuple as an argument so that register_external's behavior for
+            tuple-taking functions can be verified.
+            """
+        register_external(function_with_tuple_arg, [(int,)], int)
+
+        def f():
+            return function_with_tuple_arg((1,))
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+
+        # Not a very good assertion, but at least it means _something_ happened.
+        assert isinstance(s, annmodel.SomeInteger)
+
+    def test_register_external_return_goes_back(self):
+        """
+        Check whether it works to pass the same list from one external
+        fun to another
+        [bookkeeper and list joining issues]
+        """
+        def function_with_list():
+            pass
+        register_external(function_with_list, [[int]], int)
+
+        def function_returning_list():
+            pass
+        register_external(function_returning_list, [], [int])
+
+        def f():
+            return function_with_list(function_returning_list())
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeInteger)
+
+    def test_register_external_specialcase(self):
+        """
+        When args=None, the external function accepts any arguments unmodified.
+        """
+        def function_withspecialcase(arg):
+            return repr(arg)
+        register_external(function_withspecialcase, args=None, result=str)
+
+        def f():
+            x = function_withspecialcase
+            return x(33) + x("aaa") + x([]) + "\n"
+
+        policy = AnnotatorPolicy()
+        policy.allow_someobjects = False
+        a = RPythonAnnotator(policy=policy)
+        s = a.build_types(f, [])
+        assert isinstance(s, annmodel.SomeString)



More information about the Pypy-commit mailing list