osutil.py
115 lines
| 3.8 KiB
| text/x-python
|
PythonLexer
Yuya Nishihara
|
r32512 | # 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. | ||||
Matt Harbison
|
r52756 | from __future__ import annotations | ||
Yuya Nishihara
|
r32512 | |||
import os | ||||
import stat as statmod | ||||
from ..pure.osutil import * | ||||
Augie Fackler
|
r43346 | from .. import pycompat | ||
Yuya Nishihara
|
r32512 | |||
Jun Wu
|
r34648 | if pycompat.isdarwin: | ||
Matt Harbison
|
r47543 | from . import _osutil # pytype: disable=import-error | ||
Yuya Nishihara
|
r32512 | |||
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 | ||||
Augie Fackler
|
r43346 | attrkinds = [None] * 20 # we need the max no for enum VXXX, 20 is plenty | ||
Yuya Nishihara
|
r32512 | |||
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 | ||||
Gregory Szorc
|
r49801 | class stat_res: | ||
Yuya Nishihara
|
r32512 | def __init__(self, st_mode, st_mtime, st_size): | ||
self.st_mode = st_mode | ||||
self.st_mtime = st_mtime | ||||
self.st_size = st_size | ||||
Manuel Jacob
|
r52683 | tv_sec_ofs = ffi.offsetof("struct timespec", "tv_sec") | ||
buf = ffi.new("char[]", listdir_batch_size) | ||||
Yuya Nishihara
|
r32512 | |||
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)) | ||||
Manuel Jacob
|
r52683 | cur = ffi.cast("val_attrs_t*", buf) | ||
Yuya Nishihara
|
r32512 | for i in range(r): | ||
lgt = cur.length | ||||
Manuel Jacob
|
r52683 | assert lgt == ffi.cast('uint32_t*', cur)[0] | ||
Yuya Nishihara
|
r32512 | ofs = cur.name_info.attr_dataoffset | ||
str_lgt = cur.name_info.attr_length | ||||
Manuel Jacob
|
r52683 | base_ofs = ffi.offsetof('val_attrs_t', 'name_info') | ||
Matt Harbison
|
r50496 | name = bytes( | ||
Augie Fackler
|
r43346 | ffi.buffer( | ||
Manuel Jacob
|
r52683 | ffi.cast("char*", cur) + base_ofs + ofs, str_lgt - 1 | ||
Augie Fackler
|
r43346 | ) | ||
) | ||||
Yuya Nishihara
|
r32512 | tp = attrkinds[cur.obj_type] | ||
Augie Fackler
|
r43347 | if name == b"." or name == b"..": | ||
Yuya Nishihara
|
r32512 | continue | ||
if skip == name and tp == statmod.S_ISDIR: | ||||
return [] | ||||
if stat: | ||||
mtime = cur.mtime.tv_sec | ||||
Augie Fackler
|
r43346 | mode = (cur.accessmask & ~lib.S_IFMT) | tp | ||
ret.append( | ||||
( | ||||
name, | ||||
tp, | ||||
stat_res( | ||||
st_mode=mode, | ||||
st_mtime=mtime, | ||||
st_size=cur.datalength, | ||||
), | ||||
) | ||||
) | ||||
Yuya Nishihara
|
r32512 | else: | ||
ret.append((name, tp)) | ||||
Augie Fackler
|
r43346 | cur = ffi.cast( | ||
Manuel Jacob
|
r52683 | "val_attrs_t*", int(ffi.cast("intptr_t", cur)) + lgt | ||
Augie Fackler
|
r43346 | ) | ||
Yuya Nishihara
|
r32512 | return ret | ||
def listdir(path, stat=False, skip=None): | ||||
Manuel Jacob
|
r52683 | req = ffi.new("struct attrlist*") | ||
Yuya Nishihara
|
r32512 | req.bitmapcount = lib.ATTR_BIT_MAP_COUNT | ||
Augie Fackler
|
r43346 | req.commonattr = ( | ||
lib.ATTR_CMN_RETURNED_ATTRS | ||||
| lib.ATTR_CMN_NAME | ||||
| lib.ATTR_CMN_OBJTYPE | ||||
| lib.ATTR_CMN_ACCESSMASK | ||||
| lib.ATTR_CMN_MODTIME | ||||
) | ||||
Yuya Nishihara
|
r32512 | 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: | ||||
Augie Fackler
|
r43346 | pass # we ignore all the errors from closing, not | ||
Yuya Nishihara
|
r32512 | # much we can do about that | ||
return ret | ||||