mercurial/pure/osutil.py
changeset 27474 e517a89c24e1
parent 27338 810337ae1b76
child 27512 e2aa9c4030c4
equal deleted inserted replaced
27473:34a37a2e03e6 27474:e517a89c24e1
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
       
    10 import ctypes
       
    11 import ctypes.util
    10 import os
    12 import os
       
    13 import socket
    11 import stat as statmod
    14 import stat as statmod
       
    15 import sys
    12 
    16 
    13 def _mode_to_kind(mode):
    17 def _mode_to_kind(mode):
    14     if statmod.S_ISREG(mode):
    18     if statmod.S_ISREG(mode):
    15         return statmod.S_IFREG
    19         return statmod.S_IFREG
    16     if statmod.S_ISDIR(mode):
    20     if statmod.S_ISDIR(mode):
    57             result.append((fn, _mode_to_kind(st.st_mode)))
    61             result.append((fn, _mode_to_kind(st.st_mode)))
    58     return result
    62     return result
    59 
    63 
    60 if os.name != 'nt':
    64 if os.name != 'nt':
    61     posixfile = open
    65     posixfile = open
       
    66 
       
    67     _SCM_RIGHTS = 0x01
       
    68     _socklen_t = ctypes.c_uint
       
    69 
       
    70     if sys.platform == 'linux2':
       
    71         # socket.h says "the type should be socklen_t but the definition of
       
    72         # the kernel is incompatible with this."
       
    73         _cmsg_len_t = ctypes.c_size_t
       
    74         _msg_controllen_t = ctypes.c_size_t
       
    75         _msg_iovlen_t = ctypes.c_size_t
       
    76     else:
       
    77         _cmsg_len_t = _socklen_t
       
    78         _msg_controllen_t = _socklen_t
       
    79         _msg_iovlen_t = ctypes.c_int
       
    80 
       
    81     class _iovec(ctypes.Structure):
       
    82         _fields_ = [
       
    83             ('iov_base', ctypes.c_void_p),
       
    84             ('iov_len', ctypes.c_size_t),
       
    85         ]
       
    86 
       
    87     class _msghdr(ctypes.Structure):
       
    88         _fields_ = [
       
    89             ('msg_name', ctypes.c_void_p),
       
    90             ('msg_namelen', _socklen_t),
       
    91             ('msg_iov', ctypes.POINTER(_iovec)),
       
    92             ('msg_iovlen', _msg_iovlen_t),
       
    93             ('msg_control', ctypes.c_void_p),
       
    94             ('msg_controllen', _msg_controllen_t),
       
    95             ('msg_flags', ctypes.c_int),
       
    96         ]
       
    97 
       
    98     class _cmsghdr(ctypes.Structure):
       
    99         _fields_ = [
       
   100             ('cmsg_len', _cmsg_len_t),
       
   101             ('cmsg_level', ctypes.c_int),
       
   102             ('cmsg_type', ctypes.c_int),
       
   103             ('cmsg_data', ctypes.c_ubyte * 0),
       
   104         ]
       
   105 
       
   106     _libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
       
   107     _recvmsg = _libc.recvmsg
       
   108     _recvmsg.restype = ctypes.c_ssize_t
       
   109     _recvmsg.argtypes = (ctypes.c_int, ctypes.POINTER(_msghdr), ctypes.c_int)
       
   110 
       
   111     def _CMSG_FIRSTHDR(msgh):
       
   112         if msgh.msg_controllen < ctypes.sizeof(_cmsghdr):
       
   113             return
       
   114         cmsgptr = ctypes.cast(msgh.msg_control, ctypes.POINTER(_cmsghdr))
       
   115         return cmsgptr.contents
       
   116 
       
   117     # The pure version is less portable than the native version because the
       
   118     # handling of socket ancillary data heavily depends on C preprocessor.
       
   119     # Also, some length fields are wrongly typed in Linux kernel.
       
   120     def recvfds(sockfd):
       
   121         """receive list of file descriptors via socket"""
       
   122         dummy = (ctypes.c_ubyte * 1)()
       
   123         iov = _iovec(ctypes.cast(dummy, ctypes.c_void_p), ctypes.sizeof(dummy))
       
   124         cbuf = ctypes.create_string_buffer(256)
       
   125         msgh = _msghdr(None, 0,
       
   126                        ctypes.pointer(iov), 1,
       
   127                        ctypes.cast(cbuf, ctypes.c_void_p), ctypes.sizeof(cbuf),
       
   128                        0)
       
   129         r = _recvmsg(sockfd, ctypes.byref(msgh), 0)
       
   130         if r < 0:
       
   131             e = ctypes.get_errno()
       
   132             raise OSError(e, os.strerror(e))
       
   133         # assumes that the first cmsg has fds because it isn't easy to write
       
   134         # portable CMSG_NXTHDR() with ctypes.
       
   135         cmsg = _CMSG_FIRSTHDR(msgh)
       
   136         if not cmsg:
       
   137             return []
       
   138         if (cmsg.cmsg_level != socket.SOL_SOCKET or
       
   139             cmsg.cmsg_type != _SCM_RIGHTS):
       
   140             return []
       
   141         rfds = ctypes.cast(cmsg.cmsg_data, ctypes.POINTER(ctypes.c_int))
       
   142         rfdscount = ((cmsg.cmsg_len - _cmsghdr.cmsg_data.offset) /
       
   143                      ctypes.sizeof(ctypes.c_int))
       
   144         return [rfds[i] for i in xrange(rfdscount)]
       
   145 
    62 else:
   146 else:
    63     import ctypes
       
    64     import msvcrt
   147     import msvcrt
    65 
   148 
    66     _kernel32 = ctypes.windll.kernel32
   149     _kernel32 = ctypes.windll.kernel32
    67 
   150 
    68     _DWORD = ctypes.c_ulong
   151     _DWORD = ctypes.c_ulong