Eryk Sun <eryk...@gmail.com> added the comment:

Assign an errcheck function to check the return value and raise an OSError 
exception on failure. Load the C library with use_errno=True to get the value 
of C errno. Make sure to properly handle encoding Unicode strings for the 
file-system encoding, including conversion of __fspath__ paths (e.g. 3.x 
pathlib). Finally, don't load libraries and define prototypes in API functions. 
It's redundant and inefficient. You're just needlessly increasing the loaders 
reference count on the shared library and needlessly redefining prototypes that 
never change. Load it once at module or class level.

For example:

    import os
    import sys
    import ctypes
    import ctypes.util
    import contextlib

    libc = ctypes.CDLL(ctypes.util.find_library("c"), use_errno=True)

    class DIR(ctypes.Structure):
        """Opaque type for directory entries""" 

    PDIR = ctypes.POINTER(DIR)

    class c_fschar_p(ctypes.c_char_p):
        if sys.version_info[0] >= 3:
            @classmethod
            def from_param(cls, param):
                if isinstance(param, (str, bytes, os.PathLike)):
                    param = os.fsencode(param)
                return super().from_param(param)
        else:
            @classmethod
            def from_param(cls, param):
                if isinstance(param, unicode):
                    param = param.encode(sys.getfilesystemencoding())
                return super(c_fschar_p, cls).from_param(param)

    def check_bool(result, func, args):
        if not result:
            err = ctypes.get_errno()
            raise OSError(err, os.strerror(err))
        return args

    def check_int(result, func, args):
        if result == -1:
            err = ctypes.get_errno()
            raise OSError(err, os.strerror(err))
        return args

    libc.opendir.errcheck = check_bool
    libc.opendir.argtypes = (c_fschar_p,)
    libc.opendir.restype = PDIR
    libc.dirfd.errcheck = check_int
    libc.dirfd.argtypes = (PDIR,)
    libc.closedir.errcheck = check_int
    libc.closedir.argtypes = (PDIR,)

    @contextlib.contextmanager
    def get_directory_file_descriptor(directory):
        dir_p = libc.opendir(directory)
        try:
            if __debug__:
                print("dir_p = %s:%r" % (directory, dir_p))
            dir_fd = libc.dirfd(dir_p)
            if __debug__:
                print("dir_fd = %r" % dir_fd)
            yield dir_fd
        finally:
            libc.closedir(dir_p)
            if __debug__:
                print("closed %r" % dir_p)

----------
nosy: +eryksun

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue35180>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to