mercurial/cffi/osutil.py
branchstable
changeset 33572 857876ebaed4
parent 30346 9cc438bf7d9a
parent 32512 0e8b0b9a7acc
child 34647 dacfcdd8b94e
equal deleted inserted replaced
33202:c1994c986d77 33572:857876ebaed4
       
     1 # osutil.py - CFFI version of osutil.c
       
     2 #
       
     3 # Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
       
     4 #
       
     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.
       
     7 
     1 from __future__ import absolute_import
     8 from __future__ import absolute_import
     2 
     9 
     3 import cffi
    10 import os
       
    11 import stat as statmod
     4 
    12 
     5 ffi = cffi.FFI()
    13 from ..pure.osutil import *
     6 ffi.set_source("_osutil_cffi", """
       
     7 #include <sys/attr.h>
       
     8 #include <sys/vnode.h>
       
     9 #include <unistd.h>
       
    10 #include <fcntl.h>
       
    11 #include <time.h>
       
    12 
    14 
    13 typedef struct val_attrs {
    15 from .. import (
    14     uint32_t          length;
    16     pycompat,
    15     attribute_set_t   returned;
    17 )
    16     attrreference_t   name_info;
       
    17     fsobj_type_t      obj_type;
       
    18     struct timespec   mtime;
       
    19     uint32_t          accessmask;
       
    20     off_t             datalength;
       
    21 } __attribute__((aligned(4), packed)) val_attrs_t;
       
    22 """, include_dirs=['mercurial'])
       
    23 ffi.cdef('''
       
    24 
    18 
    25 typedef uint32_t attrgroup_t;
    19 if pycompat.sysplatform == 'darwin':
       
    20     from . import _osutil
    26 
    21 
    27 typedef struct attrlist {
    22     ffi = _osutil.ffi
    28     uint16_t     bitmapcount; /* number of attr. bit sets in list */
    23     lib = _osutil.lib
    29     uint16_t   reserved;    /* (to maintain 4-byte alignment) */
       
    30     attrgroup_t commonattr;  /* common attribute group */
       
    31     attrgroup_t volattr;     /* volume attribute group */
       
    32     attrgroup_t dirattr;     /* directory attribute group */
       
    33     attrgroup_t fileattr;    /* file attribute group */
       
    34     attrgroup_t forkattr;    /* fork attribute group */
       
    35     ...;
       
    36 };
       
    37 
    24 
    38 typedef struct attribute_set {
    25     listdir_batch_size = 4096
    39     ...;
    26     # tweakable number, only affects performance, which chunks
    40 } attribute_set_t;
    27     # of bytes do we get back from getattrlistbulk
    41 
    28 
    42 typedef struct attrreference {
    29     attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty
    43     int attr_dataoffset;
       
    44     int attr_length;
       
    45     ...;
       
    46 } attrreference_t;
       
    47 
    30 
    48 typedef int ... off_t;
    31     attrkinds[lib.VREG] = statmod.S_IFREG
       
    32     attrkinds[lib.VDIR] = statmod.S_IFDIR
       
    33     attrkinds[lib.VLNK] = statmod.S_IFLNK
       
    34     attrkinds[lib.VBLK] = statmod.S_IFBLK
       
    35     attrkinds[lib.VCHR] = statmod.S_IFCHR
       
    36     attrkinds[lib.VFIFO] = statmod.S_IFIFO
       
    37     attrkinds[lib.VSOCK] = statmod.S_IFSOCK
    49 
    38 
    50 typedef struct val_attrs {
    39     class stat_res(object):
    51     uint32_t          length;
    40         def __init__(self, st_mode, st_mtime, st_size):
    52     attribute_set_t   returned;
    41             self.st_mode = st_mode
    53     attrreference_t   name_info;
    42             self.st_mtime = st_mtime
    54     uint32_t          obj_type;
    43             self.st_size = st_size
    55     struct timespec   mtime;
       
    56     uint32_t          accessmask;
       
    57     off_t             datalength;
       
    58     ...;
       
    59 } val_attrs_t;
       
    60 
    44 
    61 /* the exact layout of the above struct will be figured out during build time */
    45     tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec")
       
    46     buf = ffi.new("char[]", listdir_batch_size)
    62 
    47 
    63 typedef int ... time_t;
    48     def listdirinternal(dfd, req, stat, skip):
       
    49         ret = []
       
    50         while True:
       
    51             r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0)
       
    52             if r == 0:
       
    53                 break
       
    54             if r == -1:
       
    55                 raise OSError(ffi.errno, os.strerror(ffi.errno))
       
    56             cur = ffi.cast("val_attrs_t*", buf)
       
    57             for i in range(r):
       
    58                 lgt = cur.length
       
    59                 assert lgt == ffi.cast('uint32_t*', cur)[0]
       
    60                 ofs = cur.name_info.attr_dataoffset
       
    61                 str_lgt = cur.name_info.attr_length
       
    62                 base_ofs = ffi.offsetof('val_attrs_t', 'name_info')
       
    63                 name = str(ffi.buffer(ffi.cast("char*", cur) + base_ofs + ofs,
       
    64                            str_lgt - 1))
       
    65                 tp = attrkinds[cur.obj_type]
       
    66                 if name == "." or name == "..":
       
    67                     continue
       
    68                 if skip == name and tp == statmod.S_ISDIR:
       
    69                     return []
       
    70                 if stat:
       
    71                     mtime = cur.mtime.tv_sec
       
    72                     mode = (cur.accessmask & ~lib.S_IFMT)| tp
       
    73                     ret.append((name, tp, stat_res(st_mode=mode, st_mtime=mtime,
       
    74                                 st_size=cur.datalength)))
       
    75                 else:
       
    76                     ret.append((name, tp))
       
    77                 cur = ffi.cast("val_attrs_t*", int(ffi.cast("intptr_t", cur))
       
    78                     + lgt)
       
    79         return ret
    64 
    80 
    65 typedef struct timespec {
    81     def listdir(path, stat=False, skip=None):
    66     time_t tv_sec;
    82         req = ffi.new("struct attrlist*")
    67     ...;
    83         req.bitmapcount = lib.ATTR_BIT_MAP_COUNT
    68 };
    84         req.commonattr = (lib.ATTR_CMN_RETURNED_ATTRS |
       
    85                           lib.ATTR_CMN_NAME |
       
    86                           lib.ATTR_CMN_OBJTYPE |
       
    87                           lib.ATTR_CMN_ACCESSMASK |
       
    88                           lib.ATTR_CMN_MODTIME)
       
    89         req.fileattr = lib.ATTR_FILE_DATALENGTH
       
    90         dfd = lib.open(path, lib.O_RDONLY, 0)
       
    91         if dfd == -1:
       
    92             raise OSError(ffi.errno, os.strerror(ffi.errno))
    69 
    93 
    70 int getattrlist(const char* path, struct attrlist * attrList, void * attrBuf,
    94         try:
    71                 size_t attrBufSize, unsigned int options);
    95             ret = listdirinternal(dfd, req, stat, skip)
    72 
    96         finally:
    73 int getattrlistbulk(int dirfd, struct attrlist * attrList, void * attrBuf,
    97             try:
    74                     size_t attrBufSize, uint64_t options);
    98                 lib.close(dfd)
    75 
    99             except BaseException:
    76 #define ATTR_BIT_MAP_COUNT ...
   100                 pass # we ignore all the errors from closing, not
    77 #define ATTR_CMN_NAME ...
   101                 # much we can do about that
    78 #define ATTR_CMN_OBJTYPE ...
   102         return ret
    79 #define ATTR_CMN_MODTIME ...
       
    80 #define ATTR_CMN_ACCESSMASK ...
       
    81 #define ATTR_CMN_ERROR ...
       
    82 #define ATTR_CMN_RETURNED_ATTRS ...
       
    83 #define ATTR_FILE_DATALENGTH ...
       
    84 
       
    85 #define VREG ...
       
    86 #define VDIR ...
       
    87 #define VLNK ...
       
    88 #define VBLK ...
       
    89 #define VCHR ...
       
    90 #define VFIFO ...
       
    91 #define VSOCK ...
       
    92 
       
    93 #define S_IFMT ...
       
    94 
       
    95 int open(const char *path, int oflag, int perm);
       
    96 int close(int);
       
    97 
       
    98 #define O_RDONLY ...
       
    99 ''')
       
   100 
       
   101 if __name__ == '__main__':
       
   102     ffi.compile()