Mercurial > public > mercurial-scm > hg
diff mercurial/cffi/osutil.py @ 32512:0e8b0b9a7acc
cffi: split modules from pure
The copyright lines are updated per change history.
cffi/osutil.py isn't tested since I have no access to OS X machine right now,
sorry.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Tue, 02 May 2017 21:15:31 +0900 |
parents | mercurial/pure/osutil.py@2dcb3d52ef41 |
children | 857876ebaed4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/cffi/osutil.py Tue May 02 21:15:31 2017 +0900 @@ -0,0 +1,102 @@ +# osutil.py - CFFI version of osutil.c +# +# Copyright 2016 Maciej Fijalkowski <fijall@gmail.com> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from __future__ import absolute_import + +import os +import stat as statmod + +from ..pure.osutil import * + +from .. import ( + pycompat, +) + +if pycompat.sysplatform == 'darwin': + from . import _osutil + + ffi = _osutil.ffi + lib = _osutil.lib + + listdir_batch_size = 4096 + # tweakable number, only affects performance, which chunks + # of bytes do we get back from getattrlistbulk + + attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty + + attrkinds[lib.VREG] = statmod.S_IFREG + attrkinds[lib.VDIR] = statmod.S_IFDIR + attrkinds[lib.VLNK] = statmod.S_IFLNK + attrkinds[lib.VBLK] = statmod.S_IFBLK + attrkinds[lib.VCHR] = statmod.S_IFCHR + attrkinds[lib.VFIFO] = statmod.S_IFIFO + attrkinds[lib.VSOCK] = statmod.S_IFSOCK + + class stat_res(object): + def __init__(self, st_mode, st_mtime, st_size): + self.st_mode = st_mode + self.st_mtime = st_mtime + self.st_size = st_size + + tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec") + buf = ffi.new("char[]", listdir_batch_size) + + def listdirinternal(dfd, req, stat, skip): + ret = [] + while True: + r = lib.getattrlistbulk(dfd, req, buf, listdir_batch_size, 0) + if r == 0: + break + if r == -1: + raise OSError(ffi.errno, os.strerror(ffi.errno)) + cur = ffi.cast("val_attrs_t*", buf) + for i in range(r): + lgt = cur.length + assert lgt == ffi.cast('uint32_t*', cur)[0] + ofs = cur.name_info.attr_dataoffset + str_lgt = cur.name_info.attr_length + base_ofs = ffi.offsetof('val_attrs_t', 'name_info') + name = str(ffi.buffer(ffi.cast("char*", cur) + base_ofs + ofs, + str_lgt - 1)) + tp = attrkinds[cur.obj_type] + if name == "." or name == "..": + continue + if skip == name and tp == statmod.S_ISDIR: + return [] + if stat: + mtime = cur.mtime.tv_sec + mode = (cur.accessmask & ~lib.S_IFMT)| tp + ret.append((name, tp, stat_res(st_mode=mode, st_mtime=mtime, + st_size=cur.datalength))) + else: + ret.append((name, tp)) + cur = ffi.cast("val_attrs_t*", int(ffi.cast("intptr_t", cur)) + + lgt) + return ret + + def listdir(path, stat=False, skip=None): + req = ffi.new("struct attrlist*") + req.bitmapcount = lib.ATTR_BIT_MAP_COUNT + req.commonattr = (lib.ATTR_CMN_RETURNED_ATTRS | + lib.ATTR_CMN_NAME | + lib.ATTR_CMN_OBJTYPE | + lib.ATTR_CMN_ACCESSMASK | + lib.ATTR_CMN_MODTIME) + req.fileattr = lib.ATTR_FILE_DATALENGTH + dfd = lib.open(path, lib.O_RDONLY, 0) + if dfd == -1: + raise OSError(ffi.errno, os.strerror(ffi.errno)) + + try: + ret = listdirinternal(dfd, req, stat, skip) + finally: + try: + lib.close(dfd) + except BaseException: + pass # we ignore all the errors from closing, not + # much we can do about that + return ret