mercurial/pure/osutil.py
changeset 29600 7a157639b8f2
parent 27971 f7d0c28d34b3
child 29698 f15f31505f12
equal deleted inserted replaced
29599:e3dc96834126 29600:7a157639b8f2
    11 import ctypes.util
    11 import ctypes.util
    12 import os
    12 import os
    13 import socket
    13 import socket
    14 import stat as statmod
    14 import stat as statmod
    15 import sys
    15 import sys
       
    16 
       
    17 from . import policy
       
    18 modulepolicy = policy.policy
       
    19 policynocffi = policy.policynocffi
    16 
    20 
    17 def _mode_to_kind(mode):
    21 def _mode_to_kind(mode):
    18     if statmod.S_ISREG(mode):
    22     if statmod.S_ISREG(mode):
    19         return statmod.S_IFREG
    23         return statmod.S_IFREG
    20     if statmod.S_ISDIR(mode):
    24     if statmod.S_ISDIR(mode):
    29         return statmod.S_IFIFO
    33         return statmod.S_IFIFO
    30     if statmod.S_ISSOCK(mode):
    34     if statmod.S_ISSOCK(mode):
    31         return statmod.S_IFSOCK
    35         return statmod.S_IFSOCK
    32     return mode
    36     return mode
    33 
    37 
    34 def listdir(path, stat=False, skip=None):
    38 def listdirpure(path, stat=False, skip=None):
    35     '''listdir(path, stat=False) -> list_of_tuples
    39     '''listdir(path, stat=False) -> list_of_tuples
    36 
    40 
    37     Return a sorted list containing information about the entries
    41     Return a sorted list containing information about the entries
    38     in the directory.
    42     in the directory.
    39 
    43 
    58         if stat:
    62         if stat:
    59             result.append((fn, _mode_to_kind(st.st_mode), st))
    63             result.append((fn, _mode_to_kind(st.st_mode), st))
    60         else:
    64         else:
    61             result.append((fn, _mode_to_kind(st.st_mode)))
    65             result.append((fn, _mode_to_kind(st.st_mode)))
    62     return result
    66     return result
       
    67 
       
    68 ffi = None
       
    69 if modulepolicy not in policynocffi and sys.platform == 'darwin':
       
    70     try:
       
    71         from _osutil_cffi import ffi, lib
       
    72     except ImportError:
       
    73         if modulepolicy == 'cffi': # strict cffi import
       
    74             raise
       
    75 
       
    76 if sys.platform == 'darwin' and ffi is not None:
       
    77     listdir_batch_size = 4096
       
    78     # tweakable number, only affects performance, which chunks
       
    79     # of bytes do we get back from getattrlistbulk
       
    80 
       
    81     attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty
       
    82 
       
    83     attrkinds[lib.VREG] = statmod.S_IFREG
       
    84     attrkinds[lib.VDIR] = statmod.S_IFDIR
       
    85     attrkinds[lib.VLNK] = statmod.S_IFLNK
       
    86     attrkinds[lib.VBLK] = statmod.S_IFBLK
       
    87     attrkinds[lib.VCHR] = statmod.S_IFCHR
       
    88     attrkinds[lib.VFIFO] = statmod.S_IFIFO
       
    89     attrkinds[lib.VSOCK] = statmod.S_IFSOCK
       
    90 
       
    91     class stat_res(object):
       
    92         def __init__(self, st_mode, st_mtime, st_size):
       
    93             self.st_mode = st_mode
       
    94             self.st_mtime = st_mtime
       
    95             self.st_size = st_size
       
    96 
       
    97     tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec")
       
    98     buf = ffi.new("char[]", listdir_batch_size)
       
    99 
       
   100     def listdirinternal(dfd, req, stat, skip):
       
   101         ret = []
       
   102         while True:
       
   103             r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0)
       
   104             if r == 0:
       
   105                 break
       
   106             if r == -1:
       
   107                 raise OSError(ffi.errno, os.strerror(ffi.errno))
       
   108             cur = ffi.cast("val_attrs_t*", buf)
       
   109             for i in range(r):
       
   110                 lgt = cur.length
       
   111                 assert lgt == ffi.cast('uint32_t*', cur)[0]
       
   112                 ofs = cur.name_info.attr_dataoffset
       
   113                 str_lgt = cur.name_info.attr_length
       
   114                 base_ofs = ffi.offsetof('val_attrs_t', 'name_info')
       
   115                 name = str(ffi.buffer(ffi.cast("char*", cur) + base_ofs + ofs,
       
   116                            str_lgt - 1))
       
   117                 tp = attrkinds[cur.obj_type]
       
   118                 if name == "." or name == "..":
       
   119                     continue
       
   120                 if skip == name and tp == statmod.S_ISDIR:
       
   121                     return []
       
   122                 if stat:
       
   123                     mtime = cur.time.tv_sec
       
   124                     mode = (cur.accessmask & ~lib.S_IFMT)| tp
       
   125                     ret.append((name, tp, stat_res(st_mode=mode, st_mtime=mtime,
       
   126                                 st_size=cur.datalength)))
       
   127                 else:
       
   128                     ret.append((name, tp))
       
   129                 cur += lgt
       
   130         return ret
       
   131 
       
   132     def listdir(path, stat=False, skip=None):
       
   133         req = ffi.new("struct attrlist*")
       
   134         req.bitmapcount = lib.ATTR_BIT_MAP_COUNT
       
   135         req.commonattr = (lib.ATTR_CMN_RETURNED_ATTRS |
       
   136                           lib.ATTR_CMN_NAME |
       
   137                           lib.ATTR_CMN_OBJTYPE |
       
   138                           lib.ATTR_CMN_ACCESSMASK |
       
   139                           lib.ATTR_CMN_MODTIME)
       
   140         req.fileattr = lib.ATTR_FILE_DATALENGTH
       
   141         dfd = lib.open(path, lib.O_RDONLY, 0)
       
   142         if dfd == -1:
       
   143             raise OSError(ffi.errno, os.strerror(ffi.errno))
       
   144 
       
   145         try:
       
   146             ret = listdirinternal(dfd, req, stat, skip)
       
   147         finally:
       
   148             try:
       
   149                 lib.close(dfd)
       
   150             except BaseException:
       
   151                 pass # we ignore all the errors from closing, not
       
   152                 # much we can do about that
       
   153         return ret
       
   154 else:
       
   155     listdir = listdirpure
    63 
   156 
    64 if os.name != 'nt':
   157 if os.name != 'nt':
    65     posixfile = open
   158     posixfile = open
    66 
   159 
    67     _SCM_RIGHTS = 0x01
   160     _SCM_RIGHTS = 0x01