Amaury Forgeot d'Arc  committed 5e890c5 Draft

Correctly detects the presence of fchmod and fchown.
Tests run and pass even with an old pypy which does (yet) not provide the functions.

os.fchmod and os.fchown are not used anymore, they could probably be removed from

  • Participants
  • Parent commits 69e12d1
  • Branches missing-os-functions

Comments (0)

Files changed (4)

File pypy/module/posix/

 # Package initialisation
 from pypy.interpreter.mixedmodule import MixedModule
 from rpython.rtyper.module.ll_os import RegisterOs
+from rpython.rlib import rposix
 import os, sys
 exec 'import %s as posix' %
     for name in '''
-            wait wait3 wait4 chown lchown fchown fchmod ftruncate
+            wait wait3 wait4 chown lchown ftruncate
             fsync fdatasync fchdir putenv unsetenv killpg getpid
             link symlink readlink
             fork openpty forkpty waitpid execv execve uname sysconf fpathconf
         if hasattr(posix, name):
             interpleveldefs[name] = 'interp_posix.%s' % (name,)
+    for name in '''fchmod fchown
+                '''.split():
+        symbol = 'HAS_' + name.upper()
+        if getattr(rposix, symbol):
+            interpleveldefs[name] = 'interp_posix.%s' % (name,)
     for constant in '''

File pypy/module/posix/

 c_int = "c_int"
+def oserror_from_errno(space):
+    errno = rposix.get_errno()
+    return wrap_oserror(space, OSError(errno, "OSError"))
 # CPython 2.7 semantics are too messy to follow exactly,
 # e.g. setuid(-2) works on 32-bit but not on 64-bit.  As a result,
 # we decided to just accept any 'int', i.e. any C signed long, and
     """Change the access permissions of the file given by file
 descriptor fd."""
     fd = space.c_filedescriptor_w(w_fd)
-    try:
-        os.fchmod(fd, mode)
-    except OSError, e:
-        raise wrap_oserror(space, e)
+    res = rposix.c_fchmod(fd, mode)
+    if res == -1:
+        raise oserror_from_errno(space)
 def rename(space, w_old, w_new):
     "Rename a file or directory."
     fd = space.c_filedescriptor_w(w_fd)
     check_uid_range(space, uid)
     check_uid_range(space, gid)
-    try:
-        os.fchown(fd, uid, gid)
-    except OSError, e:
-        raise wrap_oserror(space, e)
+    res = rposix.c_fchown(fd, uid, gid)
+    if res == -1:
+        raise oserror_from_errno(space)
 def getloadavg(space):

File pypy/module/posix/test/

 from rpython.tool.udir import udir
 from pypy.tool.pytest.objspace import gettestobjspace
 from pypy.conftest import pypydir
+from rpython.rlib import rposix
 from rpython.rtyper.module.ll_os import RegisterOs
 from rpython.translator.c.test.test_extfunc import need_sparse_files
 import os
             os.symlink('foobar', self.path)
             os.lchown(self.path, os.getuid(), os.getgid())
-    if hasattr(os, 'fchown'):
+    if rposix.HAS_FCHOWN:
         def test_fchown(self):
             os = self.posix
             f = open(self.path, "w")
                 os.chmod(self.path, 0200)
                 assert (os.stat(self.path).st_mode & 0777) == 0200
-    if hasattr(os, 'fchmod'):
+    if rposix.HAS_FCHMOD:
         def test_fchmod(self):
             os = self.posix
             f = open(self.path, "w")

File rpython/rlib/

 import os
 from rpython.rtyper.lltypesystem.rffi import CConstant, CExternVariable, INT
 from rpython.rtyper.lltypesystem import ll2ctypes, rffi
+from rpython.rtyper.tool import rffi_platform
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 from rpython.rlib.rarithmetic import intmask
 from rpython.rlib.objectmodel import specialize
     separate_module_sources = []
     export_symbols = []
-    includes=['errno.h','stdio.h']
-errno_eci = ExternalCompilationInfo(
+    includes=['errno.h', 'stdio.h', 'unistd.h', 'sys/stat.h']
+rposix_eci = ExternalCompilationInfo(
-_get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci,
+class CConfig:
+    _compilation_info_ = rposix_eci
+    HAS_FCHMOD = rffi_platform.Has("fchmod")
+    HAS_FCHOWN = rffi_platform.Has("fchown")
+_get_errno, _set_errno = CExternVariable(INT, 'errno', rposix_eci,
                                          CConstantErrno, sandboxsafe=True,
                                          _nowrapper=True, c_type='int')
 # the default wrapper for set_errno is not suitable for use in critical places
 if == 'nt':
     is_valid_fd = rffi.llexternal(
         "_PyVerify_fd", [rffi.INT], rffi.INT,
-        compilation_info=errno_eci,
+        compilation_info=rposix_eci,
     def validate_fd(fd):
         except OSError:
+# Expose posix functions
+def external(name, args, result):
+    return rffi.llexternal(name, args, result,
+                           compilation_info=CConfig._compilation_info_)
+c_fchmod = external('fchmod', [rffi.INT, rffi.MODE_T], rffi.INT)
+c_fchown = external('fchown', [rffi.INT, rffi.INT, rffi.INT], rffi.INT)
 # Wrappers around posix functions, that accept either strings, or
 # instances with a "as_bytes()" method.