[pypy-commit] pypy default: add validate_fd for windows and test it

mattip noreply at buildbot.pypy.org
Thu Apr 26 20:26:20 CEST 2012


Author: Matti Picus <matti.picus at gmail.com>
Branch: 
Changeset: r54766:31add8845fcc
Date: 2012-04-26 19:21 +0300
http://bitbucket.org/pypy/pypy/changeset/31add8845fcc/

Log:	add validate_fd for windows and test it

diff --git a/pypy/rlib/rposix.py b/pypy/rlib/rposix.py
--- a/pypy/rlib/rposix.py
+++ b/pypy/rlib/rposix.py
@@ -1,9 +1,11 @@
 import os
-from pypy.rpython.lltypesystem.rffi import CConstant, CExternVariable, INT
+from pypy.rpython.lltypesystem.rffi import (CConstant, CExternVariable,
+        INT, CCHARPP)
 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
+from pypy.rlib import jit
 
 class CConstantErrno(CConstant):
     # these accessors are used when calling get_errno() or set_errno()
@@ -18,9 +20,69 @@
     def __setitem__(self, index, value):
         assert index == 0
         ll2ctypes.TLS.errno = value
+if os.name == 'nt':
+    separate_module_sources =['''
+        /* Lifted completely from CPython 3.3 Modules/posix_module.c */
+        #include <malloc.h> /* for _msize */
+        typedef struct {
+            intptr_t osfhnd;
+            char osfile;
+        } my_ioinfo;
+        extern __declspec(dllimport) char * __pioinfo[];
+        #define IOINFO_L2E 5
+        #define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
+        #define IOINFO_ARRAYS 64
+        #define _NHANDLE_           (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
+        #define FOPEN 0x01
+        #define _NO_CONSOLE_FILENO (intptr_t)-2
 
+        /* This function emulates what the windows CRT
+            does to validate file handles */
+        int
+        _PyVerify_fd(int fd)
+        {
+            const int i1 = fd >> IOINFO_L2E;
+            const int i2 = fd & ((1 << IOINFO_L2E) - 1);
+
+            static size_t sizeof_ioinfo = 0;
+
+            /* Determine the actual size of the ioinfo structure,
+             * as used by the CRT loaded in memory
+             */
+            if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
+                sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
+            }
+            if (sizeof_ioinfo == 0) {
+                /* This should not happen... */
+                goto fail;
+            }
+
+            /* See that it isn't a special CLEAR fileno */
+                if (fd != _NO_CONSOLE_FILENO) {
+                /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that.  Instead
+                 * we check pointer validity and other info
+                 */
+                if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) {
+                    /* finally, check that the file is open */
+                    my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo);
+                    if (info->osfile & FOPEN) {
+                        return 1;
+                    }
+                }
+            }
+          fail:
+            errno = EBADF;
+            return 0;
+        }
+    ''',]
+    export_symbols = ['_PyVerify_fd']
+else:
+    separate_module_sources = []
+    export_symbols = []
 errno_eci = ExternalCompilationInfo(
-    includes=['errno.h']
+    includes=['errno.h','stdio.h'],
+    separate_module_sources = separate_module_sources,
+    export_symbols = export_symbols,
 )
 
 _get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci,
@@ -35,6 +97,21 @@
 def set_errno(errno):
     _set_errno(rffi.cast(INT, errno))
 
+if os.name == 'nt':
+    _validate_fd = rffi.llexternal(
+        "_PyVerify_fd", [rffi.INT], rffi.INT,
+        compilation_info=errno_eci,
+        )
+    @jit.dont_look_inside
+    def validate_fd(fd):
+        if not _validate_fd(fd):
+            raise OSError(get_errno(), 'Bad file descriptor')
+else:
+    def _validate_fd(fd):
+        return 1
+
+    def validate_fd(fd):
+        return 1
 
 def closerange(fd_low, fd_high):
     # this behaves like os.closerange() from Python 2.6.
diff --git a/pypy/rlib/test/test_rposix.py b/pypy/rlib/test/test_rposix.py
--- a/pypy/rlib/test/test_rposix.py
+++ b/pypy/rlib/test/test_rposix.py
@@ -131,3 +131,13 @@
                 os.rmdir(self.ufilename)
             except Exception:
                 pass
+
+    def test_validate_fd(self):
+        assert rposix._validate_fd(0) == 1
+        fid = open(str(udir.join('validate_test.txt')), 'w')
+        fd = fid.fileno()
+        assert rposix._validate_fd(fd) == 1
+        fid.close()
+        assert rposix._validate_fd(fd) == 0
+
+


More information about the pypy-commit mailing list