[pypy-commit] pypy more-rposix: Move ll_os_stat to rposix_stat.
amauryfa
noreply at buildbot.pypy.org
Mon Apr 6 13:58:31 CEST 2015
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: more-rposix
Changeset: r76721:8ff6cf17a905
Date: 2015-04-06 13:42 +0200
http://bitbucket.org/pypy/pypy/changeset/8ff6cf17a905/
Log: Move ll_os_stat to rposix_stat.
Not tested at all on Windows.
diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py
--- a/pypy/module/_io/interp_io.py
+++ b/pypy/module/_io/interp_io.py
@@ -7,7 +7,9 @@
from pypy.module.exceptions.interp_exceptions import W_IOError
from pypy.module._io.interp_fileio import W_FileIO
from pypy.module._io.interp_textio import W_TextIOWrapper
-from rpython.rtyper.module.ll_os_stat import STAT_FIELD_TYPES
+from rpython.rlib.rposix_stat import STAT_FIELD_TYPES
+
+HAS_BLKSIZE = 'st_blksize' in STAT_FIELD_TYPES
class Cache:
@@ -118,7 +120,7 @@
if buffering < 0:
buffering = DEFAULT_BUFFER_SIZE
- if space.config.translation.type_system == 'lltype' and 'st_blksize' in STAT_FIELD_TYPES:
+ if HAS_BLKSIZE:
fileno = space.c_int_w(space.call_method(w_raw, "fileno"))
try:
st = os.fstat(fileno)
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -1,11 +1,11 @@
import os
import sys
-from rpython.rlib import rposix, objectmodel, rurandom
+from rpython.rlib import rposix, rposix_stat
+from rpython.rlib import objectmodel, rurandom
from rpython.rlib.objectmodel import specialize
from rpython.rlib.rarithmetic import r_longlong
from rpython.rlib.unroll import unrolling_iterable
-from rpython.rtyper.module import ll_os_stat
from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2
@@ -215,13 +215,13 @@
# ____________________________________________________________
-STAT_FIELDS = unrolling_iterable(enumerate(ll_os_stat.STAT_FIELDS))
+STAT_FIELDS = unrolling_iterable(enumerate(rposix_stat.STAT_FIELDS))
-STATVFS_FIELDS = unrolling_iterable(enumerate(ll_os_stat.STATVFS_FIELDS))
+STATVFS_FIELDS = unrolling_iterable(enumerate(rposix_stat.STATVFS_FIELDS))
def build_stat_result(space, st):
FIELDS = STAT_FIELDS # also when not translating at all
- lst = [None] * ll_os_stat.N_INDEXABLE_FIELDS
+ lst = [None] * rposix_stat.N_INDEXABLE_FIELDS
w_keywords = space.newdict()
stat_float_times = space.fromcache(StatState).stat_float_times
for i, (name, TYPE) in FIELDS:
@@ -229,7 +229,7 @@
if name in ('st_atime', 'st_mtime', 'st_ctime'):
value = int(value) # rounded to an integer for indexed access
w_value = space.wrap(value)
- if i < ll_os_stat.N_INDEXABLE_FIELDS:
+ if i < rposix_stat.N_INDEXABLE_FIELDS:
lst[i] = w_value
else:
space.setitem(w_keywords, space.wrap(name), w_value)
@@ -257,7 +257,7 @@
def build_statvfs_result(space, st):
- vals_w = [None] * len(ll_os_stat.STATVFS_FIELDS)
+ vals_w = [None] * len(rposix_stat.STATVFS_FIELDS)
for i, (name, _) in STATVFS_FIELDS:
vals_w[i] = space.wrap(getattr(st, name))
w_tuple = space.newtuple(vals_w)
@@ -270,7 +270,7 @@
"""Perform a stat system call on the file referenced to by an open
file descriptor."""
try:
- st = os.fstat(fd)
+ st = rposix_stat.fstat(fd)
except OSError, e:
raise wrap_oserror(space, e)
else:
@@ -292,7 +292,7 @@
"""
try:
- st = dispatch_filename(rposix.stat)(space, w_path)
+ st = dispatch_filename(rposix_stat.stat)(space, w_path)
except OSError, e:
raise wrap_oserror2(space, e, w_path)
else:
@@ -301,7 +301,7 @@
def lstat(space, w_path):
"Like stat(path), but do no follow symbolic links."
try:
- st = dispatch_filename(rposix.lstat)(space, w_path)
+ st = dispatch_filename(rposix_stat.lstat)(space, w_path)
except OSError, e:
raise wrap_oserror2(space, e, w_path)
else:
@@ -330,7 +330,7 @@
@unwrap_spec(fd=c_int)
def fstatvfs(space, fd):
try:
- st = os.fstatvfs(fd)
+ st = rposix_stat.fstatvfs(fd)
except OSError as e:
raise wrap_oserror(space, e)
else:
@@ -339,7 +339,7 @@
def statvfs(space, w_path):
try:
- st = dispatch_filename(rposix.statvfs)(space, w_path)
+ st = dispatch_filename(rposix_stat.statvfs)(space, w_path)
except OSError as e:
raise wrap_oserror2(space, e, w_path)
else:
diff --git a/rpython/rlib/_rposix_repr.py b/rpython/rlib/_rposix_repr.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/_rposix_repr.py
@@ -0,0 +1,122 @@
+"""
+RTyping support for os.stat_result objects.
+They are rtyped just like a tuple of the correct length supporting
+only indexing and the st_xxx attributes. We need a custom StatResultRepr
+because when rtyping for LL backends we have extra platform-dependent
+items at the end of the tuple, but for OO backends we only want the
+portable items. This allows the OO backends to assume a fixed shape for
+the tuples returned by os.stat().
+"""
+from rpython.annotator import model as annmodel
+from rpython.rtyper.llannotation import lltype_to_annotation
+from rpython.flowspace.model import Constant
+from rpython.flowspace.operation import op
+from rpython.tool.pairtype import pairtype
+from rpython.rtyper.rmodel import Repr
+from rpython.rtyper.rint import IntegerRepr
+from rpython.rtyper.error import TyperError
+from rpython.rlib import rposix_stat
+
+
+class StatResultRepr(Repr):
+
+ def __init__(self, rtyper):
+ self.rtyper = rtyper
+ self.stat_fields = rposix_stat.STAT_FIELDS
+
+ self.stat_field_indexes = {}
+ for i, (name, TYPE) in enumerate(self.stat_fields):
+ self.stat_field_indexes[name] = i
+
+ self.s_tuple = annmodel.SomeTuple([lltype_to_annotation(TYPE)
+ for name, TYPE in self.stat_fields])
+ self.r_tuple = rtyper.getrepr(self.s_tuple)
+ self.lowleveltype = self.r_tuple.lowleveltype
+
+ def redispatch_getfield(self, hop, index):
+ rtyper = self.rtyper
+ s_index = rtyper.annotator.bookkeeper.immutablevalue(index)
+ hop2 = hop.copy()
+ spaceop = op.getitem(hop.args_v[0], Constant(index))
+ spaceop.result = hop.spaceop.result
+ hop2.spaceop = spaceop
+ hop2.args_v = spaceop.args
+ hop2.args_s = [self.s_tuple, s_index]
+ hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)]
+ return hop2.dispatch()
+
+ def rtype_getattr(self, hop):
+ s_attr = hop.args_s[1]
+ attr = s_attr.const
+ try:
+ index = self.stat_field_indexes[attr]
+ except KeyError:
+ raise TyperError("os.stat().%s: field not available" % (attr,))
+ return self.redispatch_getfield(hop, index)
+
+
+class __extend__(pairtype(StatResultRepr, IntegerRepr)):
+
+ def rtype_getitem((r_sta, r_int), hop):
+ s_int = hop.args_s[1]
+ index = s_int.const
+ return r_sta.redispatch_getfield(hop, index)
+
+
+def specialize_make_stat_result(hop):
+ r_StatResult = hop.rtyper.getrepr(rposix_stat.s_StatResult)
+ [v_result] = hop.inputargs(r_StatResult.r_tuple)
+ # no-op conversion from r_StatResult.r_tuple to r_StatResult
+ hop.exception_cannot_occur()
+ return v_result
+
+
+class StatvfsResultRepr(Repr):
+
+ def __init__(self, rtyper):
+ self.rtyper = rtyper
+ self.statvfs_fields = rposix_stat.STATVFS_FIELDS
+
+ self.statvfs_field_indexes = {}
+ for i, (name, TYPE) in enumerate(self.statvfs_fields):
+ self.statvfs_field_indexes[name] = i
+
+ self.s_tuple = annmodel.SomeTuple([lltype_to_annotation(TYPE)
+ for name, TYPE in self.statvfs_fields])
+ self.r_tuple = rtyper.getrepr(self.s_tuple)
+ self.lowleveltype = self.r_tuple.lowleveltype
+
+ def redispatch_getfield(self, hop, index):
+ rtyper = self.rtyper
+ s_index = rtyper.annotator.bookkeeper.immutablevalue(index)
+ hop2 = hop.copy()
+ spaceop = op.getitem(hop.args_v[0], Constant(index))
+ spaceop.result = hop.spaceop.result
+ hop2.spaceop = spaceop
+ hop2.args_v = spaceop.args
+ hop2.args_s = [self.s_tuple, s_index]
+ hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)]
+ return hop2.dispatch()
+
+ def rtype_getattr(self, hop):
+ s_attr = hop.args_s[1]
+ attr = s_attr.const
+ try:
+ index = self.statvfs_field_indexes[attr]
+ except KeyError:
+ raise TyperError("os.statvfs().%s: field not available" % (attr,))
+ return self.redispatch_getfield(hop, index)
+
+
+class __extend__(pairtype(StatvfsResultRepr, IntegerRepr)):
+ def rtype_getitem((r_sta, r_int), hop):
+ s_int = hop.args_s[1]
+ index = s_int.const
+ return r_sta.redispatch_getfield(hop, index)
+
+
+def specialize_make_statvfs_result(hop):
+ r_StatvfsResult = hop.rtyper.getrepr(rposix_stat.s_StatvfsResult)
+ [v_result] = hop.inputargs(r_StatvfsResult.r_tuple)
+ hop.exception_cannot_occur()
+ return v_result
diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -534,7 +534,7 @@
else:
r_int64 = int
-# needed for ll_os_stat.time_t_to_FILE_TIME in the 64 bit case
+# needed for rposix_stat.time_t_to_FILE_TIME in the 64 bit case
r_uint32 = build_int('r_uint32', False, 32)
SHRT_MIN = -2**(_get_bitsize('h') - 1)
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -355,18 +355,6 @@
def _preferred_traits(path):
return string_traits
- at specialize.argtype(0)
-def stat(path):
- return os.stat(_as_bytes(path))
-
- at specialize.argtype(0)
-def lstat(path):
- return os.lstat(_as_bytes(path))
-
- at specialize.argtype(0)
-def statvfs(path):
- return os.statvfs(_as_bytes(path))
-
@specialize.argtype(0, 1)
def putenv(name, value):
os.environ[_as_bytes(name)] = _as_bytes(value)
@@ -1284,7 +1272,7 @@
if not _WIN32:
l_tmsbuf = lltype.malloc(TMSP.TO, flavor='raw')
try:
- handle_posix_error('times', c_times(l_tmsbuf))
+ result = handle_posix_error('times', c_times(l_tmsbuf))
return (
rffi.cast(lltype.Signed, l_tmsbuf.c_tms_utime)
/ CLOCK_TICKS_PER_SECOND,
diff --git a/rpython/rlib/rposix_stat.py b/rpython/rlib/rposix_stat.py
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/rposix_stat.py
@@ -0,0 +1,523 @@
+"""Annotation and rtyping support for the result of os.stat(), os.lstat()
+and os.fstat(). In RPython like in plain Python the stat result can be
+indexed like a tuple but also exposes the st_xxx attributes.
+"""
+
+import os, sys
+
+from rpython.annotator import model as annmodel
+from rpython.rtyper import extregistry
+from rpython.tool.pairtype import pairtype
+from rpython.rtyper.tool import rffi_platform as platform
+from rpython.rtyper.llannotation import lltype_to_annotation
+
+from rpython.rlib.objectmodel import (
+ specialize)
+from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.translator.tool.cbuild import ExternalCompilationInfo
+from rpython.rlib.rposix import (
+ replace_os_function, handle_posix_error, _as_bytes0)
+
+_WIN32 = sys.platform.startswith('win')
+_LINUX = sys.platform.startswith('linux')
+
+# Support for float times is here.
+# - ALL_STAT_FIELDS contains Float fields if the system can retrieve
+# sub-second timestamps.
+# - TIMESPEC is defined when the "struct stat" contains st_atim field.
+
+if sys.platform.startswith('linux') or sys.platform.startswith('openbsd'):
+ TIMESPEC = platform.Struct('struct timespec',
+ [('tv_sec', rffi.TIME_T),
+ ('tv_nsec', rffi.LONG)])
+else:
+ TIMESPEC = None
+
+# all possible fields - some of them are not available on all platforms
+ALL_STAT_FIELDS = [
+ ("st_mode", lltype.Signed),
+ ("st_ino", lltype.SignedLongLong),
+ ("st_dev", lltype.SignedLongLong),
+ ("st_nlink", lltype.Signed),
+ ("st_uid", lltype.Signed),
+ ("st_gid", lltype.Signed),
+ ("st_size", lltype.SignedLongLong),
+ ("st_atime", lltype.Float),
+ ("st_mtime", lltype.Float),
+ ("st_ctime", lltype.Float),
+ ("st_blksize", lltype.Signed),
+ ("st_blocks", lltype.Signed),
+ ("st_rdev", lltype.Signed),
+ ("st_flags", lltype.Signed),
+ #("st_gen", lltype.Signed), -- new in CPy 2.5, not implemented
+ #("st_birthtime", lltype.Float), -- new in CPy 2.5, not implemented
+]
+N_INDEXABLE_FIELDS = 10
+
+# For OO backends, expose only the portable fields (the first 10).
+PORTABLE_STAT_FIELDS = ALL_STAT_FIELDS[:N_INDEXABLE_FIELDS]
+
+STATVFS_FIELDS = [
+ ("f_bsize", lltype.Signed),
+ ("f_frsize", lltype.Signed),
+ ("f_blocks", lltype.Signed),
+ ("f_bfree", lltype.Signed),
+ ("f_bavail", lltype.Signed),
+ ("f_files", lltype.Signed),
+ ("f_ffree", lltype.Signed),
+ ("f_favail", lltype.Signed),
+ ("f_flag", lltype.Signed),
+ ("f_namemax", lltype.Signed),
+]
+
+
+# ____________________________________________________________
+#
+# Annotation support
+
+class SomeStatResult(annmodel.SomeObject):
+ knowntype = os.stat_result
+
+ def rtyper_makerepr(self, rtyper):
+ from rpython.rlib import _rposix_repr
+ return _rposix_repr.StatResultRepr(rtyper)
+
+ def rtyper_makekey(self):
+ return self.__class__,
+
+ def getattr(self, s_attr):
+ assert s_attr.is_constant(), "non-constant attr name in getattr()"
+ attrname = s_attr.const
+ TYPE = STAT_FIELD_TYPES[attrname]
+ return lltype_to_annotation(TYPE)
+
+ def _get_rmarshall_support_(self): # for rlib.rmarshal
+ # reduce and recreate stat_result objects from 10-tuples
+ # (we ignore the extra values here for simplicity and portability)
+ def stat_result_reduce(st):
+ return (st[0], st[1], st[2], st[3], st[4],
+ st[5], st[6], st[7], st[8], st[9])
+
+ def stat_result_recreate(tup):
+ return make_stat_result(tup + extra_zeroes)
+ s_reduced = annmodel.SomeTuple([lltype_to_annotation(TYPE)
+ for name, TYPE in PORTABLE_STAT_FIELDS])
+ extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS))
+ return s_reduced, stat_result_reduce, stat_result_recreate
+
+
+class SomeStatvfsResult(annmodel.SomeObject):
+ if hasattr(os, 'statvfs_result'):
+ knowntype = os.statvfs_result
+ else:
+ knowntype = None # will not be used
+
+ def rtyper_makerepr(self, rtyper):
+ from rpython.rlib import _rposix_repr
+ return _rposix_repr.StatvfsResultRepr(rtyper)
+
+ def rtyper_makekey(self):
+ return self.__class__,
+
+ def getattr(self, s_attr):
+ assert s_attr.is_constant()
+ TYPE = STATVFS_FIELD_TYPES[s_attr.const]
+ return lltype_to_annotation(TYPE)
+
+
+class __extend__(pairtype(SomeStatResult, annmodel.SomeInteger)):
+ def getitem((s_sta, s_int)):
+ assert s_int.is_constant(), "os.stat()[index]: index must be constant"
+ index = s_int.const
+ assert 0 <= index < N_INDEXABLE_FIELDS, "os.stat()[index] out of range"
+ name, TYPE = STAT_FIELDS[index]
+ return lltype_to_annotation(TYPE)
+
+
+class __extend__(pairtype(SomeStatvfsResult, annmodel.SomeInteger)):
+ def getitem((s_stat, s_int)):
+ assert s_int.is_constant()
+ name, TYPE = STATVFS_FIELDS[s_int.const]
+ return lltype_to_annotation(TYPE)
+
+
+s_StatResult = SomeStatResult()
+s_StatvfsResult = SomeStatvfsResult()
+
+
+def make_stat_result(tup):
+ """Turn a tuple into an os.stat_result object."""
+ positional = tup[:N_INDEXABLE_FIELDS]
+ kwds = {}
+ for i, name in enumerate(STAT_FIELD_NAMES[N_INDEXABLE_FIELDS:]):
+ kwds[name] = tup[N_INDEXABLE_FIELDS + i]
+ return os.stat_result(positional, kwds)
+
+
+def make_statvfs_result(tup):
+ return os.statvfs_result(tup)
+
+
+class MakeStatResultEntry(extregistry.ExtRegistryEntry):
+ _about_ = make_stat_result
+
+ def compute_result_annotation(self, s_tup):
+ return s_StatResult
+
+ def specialize_call(self, hop):
+ from rpython.rlib import _rposix_repr
+ return _rposix_repr.specialize_make_stat_result(hop)
+
+
+class MakeStatvfsResultEntry(extregistry.ExtRegistryEntry):
+ _about_ = make_statvfs_result
+
+ def compute_result_annotation(self, s_tup):
+ return s_StatvfsResult
+
+ def specialize_call(self, hop):
+ from rpython.rlib import _rposix_repr
+ return _rposix_repr.specialize_make_statvfs_result(hop)
+
+# ____________________________________________________________
+#
+# RFFI support
+
+if sys.platform.startswith('win'):
+ _name_struct_stat = '_stati64'
+ INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h']
+else:
+ if _LINUX:
+ _name_struct_stat = 'stat64'
+ else:
+ _name_struct_stat = 'stat'
+ INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h', 'unistd.h']
+
+compilation_info = ExternalCompilationInfo(
+ # This must be set to 64 on some systems to enable large file support.
+ #pre_include_bits = ['#define _FILE_OFFSET_BITS 64'],
+ # ^^^ nowadays it's always set in all C files we produce.
+ includes=INCLUDES
+)
+
+if TIMESPEC is not None:
+ class CConfig_for_timespec:
+ _compilation_info_ = compilation_info
+ TIMESPEC = TIMESPEC
+ TIMESPEC = lltype.Ptr(
+ platform.configure(CConfig_for_timespec)['TIMESPEC'])
+
+
+def posix_declaration(try_to_add=None):
+ global STAT_STRUCT, STATVFS_STRUCT
+
+ LL_STAT_FIELDS = STAT_FIELDS[:]
+ if try_to_add:
+ LL_STAT_FIELDS.append(try_to_add)
+
+ if TIMESPEC is not None:
+
+ def _expand(lst, originalname, timespecname):
+ for i, (_name, _TYPE) in enumerate(lst):
+ if _name == originalname:
+ # replace the 'st_atime' field of type rffi.DOUBLE
+ # with a field 'st_atim' of type 'struct timespec'
+ lst[i] = (timespecname, TIMESPEC.TO)
+ break
+
+ _expand(LL_STAT_FIELDS, 'st_atime', 'st_atim')
+ _expand(LL_STAT_FIELDS, 'st_mtime', 'st_mtim')
+ _expand(LL_STAT_FIELDS, 'st_ctime', 'st_ctim')
+
+ del _expand
+ else:
+ # Replace float fields with integers
+ for name in ('st_atime', 'st_mtime', 'st_ctime', 'st_birthtime'):
+ for i, (_name, _TYPE) in enumerate(LL_STAT_FIELDS):
+ if _name == name:
+ LL_STAT_FIELDS[i] = (_name, lltype.Signed)
+ break
+
+ class CConfig:
+ _compilation_info_ = compilation_info
+ STAT_STRUCT = platform.Struct('struct %s' % _name_struct_stat, LL_STAT_FIELDS)
+ STATVFS_STRUCT = platform.Struct('struct statvfs', STATVFS_FIELDS)
+
+ try:
+ config = platform.configure(CConfig, ignore_errors=try_to_add is not None)
+ except platform.CompilationError:
+ if try_to_add:
+ return # failed to add this field, give up
+ raise
+
+ STAT_STRUCT = lltype.Ptr(config['STAT_STRUCT'])
+ STATVFS_STRUCT = lltype.Ptr(config['STATVFS_STRUCT'])
+ if try_to_add:
+ STAT_FIELDS.append(try_to_add)
+
+
+# This lists only the fields that have been found on the underlying platform.
+# Initially only the PORTABLE_STAT_FIELDS, but more may be added by the
+# following loop.
+STAT_FIELDS = PORTABLE_STAT_FIELDS[:]
+
+if sys.platform != 'win32':
+ posix_declaration()
+ for _i in range(len(PORTABLE_STAT_FIELDS), len(ALL_STAT_FIELDS)):
+ posix_declaration(ALL_STAT_FIELDS[_i])
+ del _i
+
+# these two global vars only list the fields defined in the underlying platform
+STAT_FIELD_TYPES = dict(STAT_FIELDS) # {'st_xxx': TYPE}
+STAT_FIELD_NAMES = [_name for (_name, _TYPE) in STAT_FIELDS]
+del _name, _TYPE
+
+STATVFS_FIELD_TYPES = dict(STATVFS_FIELDS)
+STATVFS_FIELD_NAMES = [name for name, tp in STATVFS_FIELDS]
+
+def build_stat_result(st):
+ # only for LL backends
+ if TIMESPEC is not None:
+ atim = st.c_st_atim; atime = int(atim.c_tv_sec) + 1E-9 * int(atim.c_tv_nsec)
+ mtim = st.c_st_mtim; mtime = int(mtim.c_tv_sec) + 1E-9 * int(mtim.c_tv_nsec)
+ ctim = st.c_st_ctim; ctime = int(ctim.c_tv_sec) + 1E-9 * int(ctim.c_tv_nsec)
+ else:
+ atime = st.c_st_atime
+ mtime = st.c_st_mtime
+ ctime = st.c_st_ctime
+
+ result = (st.c_st_mode,
+ st.c_st_ino,
+ st.c_st_dev,
+ st.c_st_nlink,
+ st.c_st_uid,
+ st.c_st_gid,
+ st.c_st_size,
+ atime,
+ mtime,
+ ctime)
+
+ if "st_blksize" in STAT_FIELD_TYPES: result += (st.c_st_blksize,)
+ if "st_blocks" in STAT_FIELD_TYPES: result += (st.c_st_blocks,)
+ if "st_rdev" in STAT_FIELD_TYPES: result += (st.c_st_rdev,)
+ if "st_flags" in STAT_FIELD_TYPES: result += (st.c_st_flags,)
+
+ return make_stat_result(result)
+
+
+def build_statvfs_result(st):
+ return make_statvfs_result((
+ st.c_f_bsize,
+ st.c_f_frsize,
+ st.c_f_blocks,
+ st.c_f_bfree,
+ st.c_f_bavail,
+ st.c_f_files,
+ st.c_f_ffree,
+ st.c_f_favail,
+ st.c_f_flag,
+ st.c_f_namemax
+ ))
+
+
+# Implement and register os.stat() & variants
+
+c_fstat = rffi.llexternal('fstat64' if _LINUX else 'fstat',
+ [rffi.INT, STAT_STRUCT], rffi.INT,
+ compilation_info=compilation_info,
+ save_err=rffi.RFFI_SAVE_ERRNO,
+ macro=True)
+c_stat = rffi.llexternal('stat64' if _LINUX else 'stat',
+ [rffi.CCHARP, STAT_STRUCT], rffi.INT,
+ compilation_info=compilation_info,
+ save_err=rffi.RFFI_SAVE_ERRNO,
+ macro=True)
+c_lstat = rffi.llexternal('lstat64' if _LINUX else 'lstat',
+ [rffi.CCHARP, STAT_STRUCT], rffi.INT,
+ compilation_info=compilation_info,
+ save_err=rffi.RFFI_SAVE_ERRNO,
+ macro=True)
+
+c_fstatvfs = rffi.llexternal('fstatvfs',
+ [rffi.INT, STATVFS_STRUCT], rffi.INT,
+ compilation_info=compilation_info,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+c_statvfs = rffi.llexternal('statvfs',
+ [rffi.CCHARP, STATVFS_STRUCT], rffi.INT,
+ compilation_info=compilation_info,
+ save_err=rffi.RFFI_SAVE_ERRNO)
+
+ at replace_os_function('fstat')
+def fstat(fd):
+ with lltype.scoped_alloc(STAT_STRUCT.TO) as stresult:
+ if not _WIN32:
+ handle_posix_error('fstat', c_fstat(fd, stresult))
+ return build_stat_result(stresult)
+ else:
+ handle = rwin32.get_osfhandle(fd)
+ filetype = win32traits.GetFileType(handle)
+ if filetype == win32traits.FILE_TYPE_CHAR:
+ # console or LPT device
+ return make_stat_result((win32traits._S_IFCHR,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0))
+ elif filetype == win32traits.FILE_TYPE_PIPE:
+ # socket or named pipe
+ return make_stat_result((win32traits._S_IFIFO,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0))
+ elif filetype == win32traits.FILE_TYPE_UNKNOWN:
+ error = rwin32.GetLastError_saved()
+ if error != 0:
+ raise WindowsError(error, "os_fstat failed")
+ # else: unknown but valid file
+
+ # normal disk file (FILE_TYPE_DISK)
+ info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION,
+ flavor='raw', zero=True)
+ try:
+ res = win32traits.GetFileInformationByHandle(handle, info)
+ if res == 0:
+ raise WindowsError(rwin32.GetLastError_saved(),
+ "os_fstat failed")
+ return win32_by_handle_info_to_stat(info)
+ finally:
+ lltype.free(info, flavor='raw')
+
+ at replace_os_function('stat')
+ at specialize.argtype(0)
+def stat(path):
+ with lltype.scoped_alloc(STAT_STRUCT.TO) as stresult:
+ if not _WIN32:
+ arg = _as_bytes0(path)
+ handle_posix_error('stat', c_stat(arg, stresult))
+ return build_stat_result(stresult)
+ else:
+ traits = _preferred_traits(path)
+ path = traits._as_str0(path)
+ return win32_xstat(path, traverse=True)
+
+ at replace_os_function('lstat')
+ at specialize.argtype(0)
+def lstat(path):
+ with lltype.scoped_alloc(STAT_STRUCT.TO) as stresult:
+ if not _WIN32:
+ arg = _as_bytes0(path)
+ handle_posix_error('lstat', c_stat(arg, stresult))
+ else:
+ traits = _preferred_traits(path)
+ arg = traits._as_str0(path)
+ handle_posix_error('lstat', c_stat(arg, stresult))
+ return build_stat_result(stresult)
+
+ at replace_os_function('fstatvfs')
+def fstatvfs(fd):
+ with lltype.scoped_alloc(STATVFS_STRUCT.TO) as stresult:
+ handle_posix_error('fstatvfs', c_fstatvfs(fd, stresult))
+ return build_statvfs_result(stresult)
+
+ at replace_os_function('statvfs')
+def statvfs(path):
+ with lltype.scoped_alloc(STATVFS_STRUCT.TO) as stresult:
+ arg = _as_bytes0(path)
+ handle_posix_error('statvfs', c_statvfs(arg, stresult))
+ return build_statvfs_result(stresult)
+
+#__________________________________________________
+# Helper functions for win32
+if _WIN32:
+
+ def make_longlong(high, low):
+ return (rffi.r_longlong(high) << 32) + rffi.r_longlong(low)
+
+ # Seconds between 1.1.1601 and 1.1.1970
+ secs_between_epochs = rffi.r_longlong(11644473600)
+
+ def FILE_TIME_to_time_t_float(filetime):
+ ft = make_longlong(filetime.c_dwHighDateTime, filetime.c_dwLowDateTime)
+ # FILETIME is in units of 100 nsec
+ return float(ft) * (1.0 / 10000000.0) - secs_between_epochs
+
+ def time_t_to_FILE_TIME(time, filetime):
+ ft = rffi.r_longlong((time + secs_between_epochs) * 10000000)
+ filetime.c_dwHighDateTime = rffi.r_uint(ft >> 32)
+ filetime.c_dwLowDateTime = rffi.r_uint(ft) # masking off high bits
+
+ def win32_xstat(traits, path, traverse=False):
+ win32traits = make_win32_traits(traits)
+ with lltype.scoped_alloc(
+ win32traits.WIN32_FILE_ATTRIBUTE_DATA) as data:
+ res = win32traits.GetFileAttributesEx(
+ path, win32traits.GetFileExInfoStandard, data)
+ if res == 0:
+ errcode = rwin32.GetLastError_saved()
+ if errcode == win32traits.ERROR_SHARING_VIOLATION:
+ res = win32_attributes_from_dir(path, data)
+ if res == 0:
+ errcode = rwin32.GetLastError_saved()
+ raise WindowsError(errcode, "os_stat failed")
+ return attribute_data_to_stat(data)
+
+ def win32_attributes_to_mode(attributes):
+ m = 0
+ attributes = intmask(attributes)
+ if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY:
+ m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other
+ else:
+ m |= win32traits._S_IFREG
+ if attributes & win32traits.FILE_ATTRIBUTE_READONLY:
+ m |= 0444
+ else:
+ m |= 0666
+ return m
+
+ def win32_attribute_data_to_stat(info):
+ st_mode = win32_attributes_to_mode(info.c_dwFileAttributes)
+ st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
+ ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime)
+ mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime)
+ atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime)
+
+ result = (st_mode,
+ 0, 0, 0, 0, 0,
+ st_size,
+ atime, mtime, ctime)
+
+ return make_stat_result(result)
+
+ def win32_by_handle_info_to_stat(info):
+ # similar to the one above
+ st_mode = win32_attributes_to_mode(info.c_dwFileAttributes)
+ st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
+ ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime)
+ mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime)
+ atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime)
+
+ # specific to fstat()
+ st_ino = make_longlong(info.c_nFileIndexHigh, info.c_nFileIndexLow)
+ st_nlink = info.c_nNumberOfLinks
+
+ result = (st_mode,
+ st_ino, 0, st_nlink, 0, 0,
+ st_size,
+ atime, mtime, ctime)
+
+ return make_stat_result(result)
+
+ def win32_attributes_from_dir(l_path, data):
+ filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw')
+ try:
+ hFindFile = win32traits.FindFirstFile(l_path, filedata)
+ if hFindFile == rwin32.INVALID_HANDLE_VALUE:
+ return 0
+ win32traits.FindClose(hFindFile)
+ data.c_dwFileAttributes = filedata.c_dwFileAttributes
+ rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime)
+ rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime)
+ rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime)
+ data.c_nFileSizeHigh = filedata.c_nFileSizeHigh
+ data.c_nFileSizeLow = filedata.c_nFileSizeLow
+ return 1
+ finally:
+ lltype.free(filedata, flavor='raw')
+
diff --git a/rpython/rlib/test/test_rmarshal.py b/rpython/rlib/test/test_rmarshal.py
--- a/rpython/rlib/test/test_rmarshal.py
+++ b/rpython/rlib/test/test_rmarshal.py
@@ -167,7 +167,7 @@
def test_stat_result():
import os
from rpython.translator.c.test.test_genc import compile
- from rpython.rtyper.module.ll_os_stat import s_StatResult
+ from rpython.rlib.rposix_stat import s_StatResult
marshal_stat_result = get_marshaller(s_StatResult)
unmarshal_stat_result = get_unmarshaller(s_StatResult)
def f(path):
diff --git a/rpython/rlib/test/test_rposix.py b/rpython/rlib/test/test_rposix.py
--- a/rpython/rlib/test/test_rposix.py
+++ b/rpython/rlib/test/test_rposix.py
@@ -1,7 +1,7 @@
from rpython.rtyper.test.test_llinterp import interpret
from rpython.translator.c.test.test_genc import compile
from rpython.tool.udir import udir
-from rpython.rlib import rposix, rstring
+from rpython.rlib import rposix, rposix_stat, rstring
import os, sys
import py
@@ -60,7 +60,7 @@
def test_stat(self):
def f():
- return rposix.stat(self.path).st_mtime
+ return rposix_stat.stat(self.path).st_mtime
if sys.platform == 'win32':
# double vs. float, be satisfied with sub-millisec resolution
assert abs(interpret(f, []) - os.stat(self.ufilename).st_mtime) < 1e-4
diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py
--- a/rpython/rtyper/module/ll_os.py
+++ b/rpython/rtyper/module/ll_os.py
@@ -119,40 +119,6 @@
)
-class RegisterOs(BaseLazyRegistering):
-
- def __init__(self):
- self.configure(CConfig)
-
-# --------------------------- os.stat & variants ---------------------------
-
- @registering(os.fstat)
- def register_os_fstat(self):
- from rpython.rtyper.module import ll_os_stat
- return ll_os_stat.register_stat_variant('fstat', StringTraits())
-
- @registering_str_unicode(os.stat)
- def register_os_stat(self, traits):
- from rpython.rtyper.module import ll_os_stat
- return ll_os_stat.register_stat_variant('stat', traits)
-
- @registering_str_unicode(os.lstat)
- def register_os_lstat(self, traits):
- from rpython.rtyper.module import ll_os_stat
- return ll_os_stat.register_stat_variant('lstat', traits)
-
- @registering_if(os, 'fstatvfs')
- def register_os_fstatvfs(self):
- from rpython.rtyper.module import ll_os_stat
- return ll_os_stat.register_statvfs_variant('fstatvfs', StringTraits())
-
- if hasattr(os, 'statvfs'):
- @registering_str_unicode(os.statvfs)
- def register_os_statvfs(self, traits):
- from rpython.rtyper.module import ll_os_stat
- return ll_os_stat.register_statvfs_variant('statvfs', traits)
-
-
# ____________________________________________________________
# Support for os.environ
diff --git a/rpython/rtyper/module/ll_os_stat.py b/rpython/rtyper/module/ll_os_stat.py
deleted file mode 100644
--- a/rpython/rtyper/module/ll_os_stat.py
+++ /dev/null
@@ -1,592 +0,0 @@
-"""Annotation and rtyping support for the result of os.stat(), os.lstat()
-and os.fstat(). In RPython like in plain Python the stat result can be
-indexed like a tuple but also exposes the st_xxx attributes.
-"""
-
-import os
-import sys
-
-from rpython.annotator import model as annmodel
-from rpython.rtyper.llannotation import lltype_to_annotation
-from rpython.rlib import rposix
-from rpython.rlib.rarithmetic import intmask
-from rpython.rtyper import extregistry
-from rpython.rtyper.annlowlevel import hlstr
-from rpython.rtyper.extfunc import extdef
-from rpython.rtyper.lltypesystem import rffi, lltype
-from rpython.rtyper.rtuple import TUPLE_TYPE
-from rpython.rtyper.tool import rffi_platform as platform
-from rpython.tool.pairtype import pairtype
-from rpython.tool.sourcetools import func_renamer
-from rpython.translator.tool.cbuild import ExternalCompilationInfo
-
-# Support for float times is here.
-# - ALL_STAT_FIELDS contains Float fields if the system can retrieve
-# sub-second timestamps.
-# - TIMESPEC is defined when the "struct stat" contains st_atim field.
-
-if sys.platform.startswith('linux') or sys.platform.startswith('openbsd'):
- TIMESPEC = platform.Struct('struct timespec',
- [('tv_sec', rffi.TIME_T),
- ('tv_nsec', rffi.LONG)])
-else:
- TIMESPEC = None
-
-# all possible fields - some of them are not available on all platforms
-ALL_STAT_FIELDS = [
- ("st_mode", lltype.Signed),
- ("st_ino", lltype.SignedLongLong),
- ("st_dev", lltype.SignedLongLong),
- ("st_nlink", lltype.Signed),
- ("st_uid", lltype.Signed),
- ("st_gid", lltype.Signed),
- ("st_size", lltype.SignedLongLong),
- ("st_atime", lltype.Float),
- ("st_mtime", lltype.Float),
- ("st_ctime", lltype.Float),
- ("st_blksize", lltype.Signed),
- ("st_blocks", lltype.Signed),
- ("st_rdev", lltype.Signed),
- ("st_flags", lltype.Signed),
- #("st_gen", lltype.Signed), -- new in CPy 2.5, not implemented
- #("st_birthtime", lltype.Float), -- new in CPy 2.5, not implemented
-]
-N_INDEXABLE_FIELDS = 10
-
-# For OO backends, expose only the portable fields (the first 10).
-PORTABLE_STAT_FIELDS = ALL_STAT_FIELDS[:N_INDEXABLE_FIELDS]
-
-STATVFS_FIELDS = [
- ("f_bsize", lltype.Signed),
- ("f_frsize", lltype.Signed),
- ("f_blocks", lltype.Signed),
- ("f_bfree", lltype.Signed),
- ("f_bavail", lltype.Signed),
- ("f_files", lltype.Signed),
- ("f_ffree", lltype.Signed),
- ("f_favail", lltype.Signed),
- ("f_flag", lltype.Signed),
- ("f_namemax", lltype.Signed),
-]
-
-
-# ____________________________________________________________
-#
-# Annotation support
-
-class SomeStatResult(annmodel.SomeObject):
- knowntype = os.stat_result
-
- def rtyper_makerepr(self, rtyper):
- from rpython.rtyper.module import r_os_stat
- return r_os_stat.StatResultRepr(rtyper)
-
- def rtyper_makekey(self):
- return self.__class__,
-
- def getattr(self, s_attr):
- assert s_attr.is_constant(), "non-constant attr name in getattr()"
- attrname = s_attr.const
- TYPE = STAT_FIELD_TYPES[attrname]
- return lltype_to_annotation(TYPE)
-
- def _get_rmarshall_support_(self): # for rlib.rmarshal
- # reduce and recreate stat_result objects from 10-tuples
- # (we ignore the extra values here for simplicity and portability)
- def stat_result_reduce(st):
- return (st[0], st[1], st[2], st[3], st[4],
- st[5], st[6], st[7], st[8], st[9])
-
- def stat_result_recreate(tup):
- return make_stat_result(tup + extra_zeroes)
- s_reduced = annmodel.SomeTuple([lltype_to_annotation(TYPE)
- for name, TYPE in PORTABLE_STAT_FIELDS])
- extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS))
- return s_reduced, stat_result_reduce, stat_result_recreate
-
-
-class SomeStatvfsResult(annmodel.SomeObject):
- if hasattr(os, 'statvfs_result'):
- knowntype = os.statvfs_result
- else:
- knowntype = None # will not be used
-
- def rtyper_makerepr(self, rtyper):
- from rpython.rtyper.module import r_os_stat
- return r_os_stat.StatvfsResultRepr(rtyper)
-
- def rtyper_makekey(self):
- return self.__class__,
-
- def getattr(self, s_attr):
- assert s_attr.is_constant()
- TYPE = STATVFS_FIELD_TYPES[s_attr.const]
- return lltype_to_annotation(TYPE)
-
-
-class __extend__(pairtype(SomeStatResult, annmodel.SomeInteger)):
- def getitem((s_sta, s_int)):
- assert s_int.is_constant(), "os.stat()[index]: index must be constant"
- index = s_int.const
- assert 0 <= index < N_INDEXABLE_FIELDS, "os.stat()[index] out of range"
- name, TYPE = STAT_FIELDS[index]
- return lltype_to_annotation(TYPE)
-
-
-class __extend__(pairtype(SomeStatvfsResult, annmodel.SomeInteger)):
- def getitem((s_stat, s_int)):
- assert s_int.is_constant()
- name, TYPE = STATVFS_FIELDS[s_int.const]
- return lltype_to_annotation(TYPE)
-
-
-s_StatResult = SomeStatResult()
-s_StatvfsResult = SomeStatvfsResult()
-
-
-def make_stat_result(tup):
- """Turn a tuple into an os.stat_result object."""
- positional = tup[:N_INDEXABLE_FIELDS]
- kwds = {}
- for i, name in enumerate(STAT_FIELD_NAMES[N_INDEXABLE_FIELDS:]):
- kwds[name] = tup[N_INDEXABLE_FIELDS + i]
- return os.stat_result(positional, kwds)
-
-
-def make_statvfs_result(tup):
- return os.statvfs_result(tup)
-
-
-class MakeStatResultEntry(extregistry.ExtRegistryEntry):
- _about_ = make_stat_result
-
- def compute_result_annotation(self, s_tup):
- return s_StatResult
-
- def specialize_call(self, hop):
- from rpython.rtyper.module import r_os_stat
- return r_os_stat.specialize_make_stat_result(hop)
-
-
-class MakeStatvfsResultEntry(extregistry.ExtRegistryEntry):
- _about_ = make_statvfs_result
-
- def compute_result_annotation(self, s_tup):
- return s_StatvfsResult
-
- def specialize_call(self, hop):
- from rpython.rtyper.module import r_os_stat
- return r_os_stat.specialize_make_statvfs_result(hop)
-
-# ____________________________________________________________
-#
-# RFFI support
-
-if sys.platform.startswith('win'):
- _name_struct_stat = '_stati64'
- INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h']
-else:
- if sys.platform.startswith('linux'):
- _name_struct_stat = 'stat64'
- else:
- _name_struct_stat = 'stat'
- INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h', 'unistd.h']
-
-compilation_info = ExternalCompilationInfo(
- # This must be set to 64 on some systems to enable large file support.
- #pre_include_bits = ['#define _FILE_OFFSET_BITS 64'],
- # ^^^ nowadays it's always set in all C files we produce.
- includes=INCLUDES
-)
-
-if TIMESPEC is not None:
- class CConfig_for_timespec:
- _compilation_info_ = compilation_info
- TIMESPEC = TIMESPEC
- TIMESPEC = lltype.Ptr(
- platform.configure(CConfig_for_timespec)['TIMESPEC'])
-
-
-def posix_declaration(try_to_add=None):
- global STAT_STRUCT, STATVFS_STRUCT
-
- LL_STAT_FIELDS = STAT_FIELDS[:]
- if try_to_add:
- LL_STAT_FIELDS.append(try_to_add)
-
- if TIMESPEC is not None:
-
- def _expand(lst, originalname, timespecname):
- for i, (_name, _TYPE) in enumerate(lst):
- if _name == originalname:
- # replace the 'st_atime' field of type rffi.DOUBLE
- # with a field 'st_atim' of type 'struct timespec'
- lst[i] = (timespecname, TIMESPEC.TO)
- break
-
- _expand(LL_STAT_FIELDS, 'st_atime', 'st_atim')
- _expand(LL_STAT_FIELDS, 'st_mtime', 'st_mtim')
- _expand(LL_STAT_FIELDS, 'st_ctime', 'st_ctim')
-
- del _expand
- else:
- # Replace float fields with integers
- for name in ('st_atime', 'st_mtime', 'st_ctime', 'st_birthtime'):
- for i, (_name, _TYPE) in enumerate(LL_STAT_FIELDS):
- if _name == name:
- LL_STAT_FIELDS[i] = (_name, lltype.Signed)
- break
-
- class CConfig:
- _compilation_info_ = compilation_info
- STAT_STRUCT = platform.Struct('struct %s' % _name_struct_stat, LL_STAT_FIELDS)
- STATVFS_STRUCT = platform.Struct('struct statvfs', STATVFS_FIELDS)
-
- try:
- config = platform.configure(CConfig, ignore_errors=try_to_add is not None)
- except platform.CompilationError:
- if try_to_add:
- return # failed to add this field, give up
- raise
-
- STAT_STRUCT = lltype.Ptr(config['STAT_STRUCT'])
- STATVFS_STRUCT = lltype.Ptr(config['STATVFS_STRUCT'])
- if try_to_add:
- STAT_FIELDS.append(try_to_add)
-
-
-# This lists only the fields that have been found on the underlying platform.
-# Initially only the PORTABLE_STAT_FIELDS, but more may be added by the
-# following loop.
-STAT_FIELDS = PORTABLE_STAT_FIELDS[:]
-
-if sys.platform != 'win32':
- posix_declaration()
- for _i in range(len(PORTABLE_STAT_FIELDS), len(ALL_STAT_FIELDS)):
- posix_declaration(ALL_STAT_FIELDS[_i])
- del _i
-
-# these two global vars only list the fields defined in the underlying platform
-STAT_FIELD_TYPES = dict(STAT_FIELDS) # {'st_xxx': TYPE}
-STAT_FIELD_NAMES = [_name for (_name, _TYPE) in STAT_FIELDS]
-del _name, _TYPE
-
-STATVFS_FIELD_TYPES = dict(STATVFS_FIELDS)
-STATVFS_FIELD_NAMES = [name for name, tp in STATVFS_FIELDS]
-
-
-def build_stat_result(st):
- # only for LL backends
- if TIMESPEC is not None:
- atim = st.c_st_atim; atime = int(atim.c_tv_sec) + 1E-9 * int(atim.c_tv_nsec)
- mtim = st.c_st_mtim; mtime = int(mtim.c_tv_sec) + 1E-9 * int(mtim.c_tv_nsec)
- ctim = st.c_st_ctim; ctime = int(ctim.c_tv_sec) + 1E-9 * int(ctim.c_tv_nsec)
- else:
- atime = st.c_st_atime
- mtime = st.c_st_mtime
- ctime = st.c_st_ctime
-
- result = (st.c_st_mode,
- st.c_st_ino,
- st.c_st_dev,
- st.c_st_nlink,
- st.c_st_uid,
- st.c_st_gid,
- st.c_st_size,
- atime,
- mtime,
- ctime)
-
- if "st_blksize" in STAT_FIELD_TYPES: result += (st.c_st_blksize,)
- if "st_blocks" in STAT_FIELD_TYPES: result += (st.c_st_blocks,)
- if "st_rdev" in STAT_FIELD_TYPES: result += (st.c_st_rdev,)
- if "st_flags" in STAT_FIELD_TYPES: result += (st.c_st_flags,)
-
- return make_stat_result(result)
-
-
-def build_statvfs_result(st):
- return make_statvfs_result((
- st.c_f_bsize,
- st.c_f_frsize,
- st.c_f_blocks,
- st.c_f_bfree,
- st.c_f_bavail,
- st.c_f_files,
- st.c_f_ffree,
- st.c_f_favail,
- st.c_f_flag,
- st.c_f_namemax
- ))
-
-
-def register_stat_variant(name, traits):
- if name != 'fstat':
- arg_is_path = True
- s_arg = traits.str0
- ARG1 = traits.CCHARP
- else:
- arg_is_path = False
- s_arg = int
- ARG1 = rffi.INT
-
- if sys.platform == 'win32':
- # See Win32 implementation below
- posix_stat_llimpl = make_win32_stat_impl(name, traits)
-
- return extdef(
- [s_arg], s_StatResult, traits.ll_os_name(name),
- llimpl=posix_stat_llimpl)
-
- if sys.platform.startswith('linux'):
- # because we always use _FILE_OFFSET_BITS 64 - this helps things work that are not a c compiler
- _functions = {'stat': 'stat64',
- 'fstat': 'fstat64',
- 'lstat': 'lstat64'}
- c_func_name = _functions[name]
- else:
- c_func_name = name
-
- posix_mystat = rffi.llexternal(c_func_name,
- [ARG1, STAT_STRUCT], rffi.INT,
- compilation_info=compilation_info,
- save_err=rffi.RFFI_SAVE_ERRNO)
-
- @func_renamer('os_%s_llimpl' % (name,))
- def posix_stat_llimpl(arg):
- stresult = lltype.malloc(STAT_STRUCT.TO, flavor='raw')
- try:
- if arg_is_path:
- arg = traits.str2charp(arg)
- error = rffi.cast(rffi.LONG, posix_mystat(arg, stresult))
- if arg_is_path:
- traits.free_charp(arg)
- if error != 0:
- raise OSError(rposix.get_saved_errno(), "os_?stat failed")
- return build_stat_result(stresult)
- finally:
- lltype.free(stresult, flavor='raw')
-
- @func_renamer('os_%s_fake' % (name,))
- def posix_fakeimpl(arg):
- if s_arg == traits.str0:
- arg = hlstr(arg)
- st = getattr(os, name)(arg)
- fields = [TYPE for fieldname, TYPE in STAT_FIELDS]
- TP = TUPLE_TYPE(fields)
- ll_tup = lltype.malloc(TP.TO)
- for i, (fieldname, TYPE) in enumerate(STAT_FIELDS):
- val = getattr(st, fieldname)
- if isinstance(TYPE, lltype.Number):
- rffi.setintfield(ll_tup, 'item%d' % i, int(val))
- elif TYPE is lltype.Float:
- setattr(ll_tup, 'item%d' % i, float(val))
- else:
- setattr(ll_tup, 'item%d' % i, val)
- return ll_tup
-
- return extdef(
- [s_arg], s_StatResult, "ll_os.ll_os_%s" % (name,),
- llimpl=posix_stat_llimpl, llfakeimpl=posix_fakeimpl)
-
-
-def register_statvfs_variant(name, traits):
- if name != 'fstatvfs':
- arg_is_path = True
- s_arg = traits.str0
- ARG1 = traits.CCHARP
- else:
- arg_is_path = False
- s_arg = int
- ARG1 = rffi.INT
-
- posix_mystatvfs = rffi.llexternal(name,
- [ARG1, STATVFS_STRUCT], rffi.INT,
- compilation_info=compilation_info,
- save_err=rffi.RFFI_SAVE_ERRNO)
-
- @func_renamer('os_%s_llimpl' % (name,))
- def posix_statvfs_llimpl(arg):
- stresult = lltype.malloc(STATVFS_STRUCT.TO, flavor='raw')
- try:
- if arg_is_path:
- arg = traits.str2charp(arg)
- error = rffi.cast(rffi.LONG, posix_mystatvfs(arg, stresult))
- if arg_is_path:
- traits.free_charp(arg)
- if error != 0:
- raise OSError(rposix.get_saved_errno(), "os_?statvfs failed")
- return build_statvfs_result(stresult)
- finally:
- lltype.free(stresult, flavor='raw')
-
- @func_renamer('os_%s_fake' % (name,))
- def posix_fakeimpl(arg):
- if s_arg == traits.str0:
- arg = hlstr(arg)
- st = getattr(os, name)(arg)
- fields = [TYPE for fieldname, TYPE in STATVFS_FIELDS]
- TP = TUPLE_TYPE(fields)
- ll_tup = lltype.malloc(TP.TO)
- for i, (fieldname, TYPE) in enumerate(STATVFS_FIELDS):
- val = getattr(st, fieldname)
- rffi.setintfield(ll_tup, 'item%d' % i, int(val))
- return ll_tup
-
- return extdef(
- [s_arg], s_StatvfsResult, "ll_os.ll_os_%s" % (name,),
- llimpl=posix_statvfs_llimpl, llfakeimpl=posix_fakeimpl
- )
-
-
-def make_win32_stat_impl(name, traits):
- from rpython.rlib import rwin32
- from rpython.rlib.rwin32file import make_win32_traits
- win32traits = make_win32_traits(traits)
-
- # The CRT of Windows has a number of flaws wrt. its stat() implementation:
- # - time stamps are restricted to second resolution
- # - file modification times suffer from forth-and-back conversions between
- # UTC and local time
- # Therefore, we implement our own stat, based on the Win32 API directly.
- from rpython.rtyper.tool import rffi_platform as platform
- from rpython.translator.tool.cbuild import ExternalCompilationInfo
- from rpython.rlib import rwin32
-
- assert len(STAT_FIELDS) == 10 # no extra fields on Windows
-
- def attributes_to_mode(attributes):
- m = 0
- attributes = intmask(attributes)
- if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY:
- m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other
- else:
- m |= win32traits._S_IFREG
- if attributes & win32traits.FILE_ATTRIBUTE_READONLY:
- m |= 0444
- else:
- m |= 0666
- return m
-
- def attribute_data_to_stat(info):
- st_mode = attributes_to_mode(info.c_dwFileAttributes)
- st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
- ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime)
- mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime)
- atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime)
-
- result = (st_mode,
- 0, 0, 0, 0, 0,
- st_size,
- atime, mtime, ctime)
-
- return make_stat_result(result)
-
- def by_handle_info_to_stat(info):
- # similar to the one above
- st_mode = attributes_to_mode(info.c_dwFileAttributes)
- st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
- ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime)
- mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime)
- atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime)
-
- # specific to fstat()
- st_ino = make_longlong(info.c_nFileIndexHigh, info.c_nFileIndexLow)
- st_nlink = info.c_nNumberOfLinks
-
- result = (st_mode,
- st_ino, 0, st_nlink, 0, 0,
- st_size,
- atime, mtime, ctime)
-
- return make_stat_result(result)
-
- def attributes_from_dir(l_path, data):
- filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw')
- try:
- hFindFile = win32traits.FindFirstFile(l_path, filedata)
- if hFindFile == rwin32.INVALID_HANDLE_VALUE:
- return 0
- win32traits.FindClose(hFindFile)
- data.c_dwFileAttributes = filedata.c_dwFileAttributes
- rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime)
- rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime)
- rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime)
- data.c_nFileSizeHigh = filedata.c_nFileSizeHigh
- data.c_nFileSizeLow = filedata.c_nFileSizeLow
- return 1
- finally:
- lltype.free(filedata, flavor='raw')
-
- def win32_stat_llimpl(path):
- data = lltype.malloc(win32traits.WIN32_FILE_ATTRIBUTE_DATA, flavor='raw')
- try:
- l_path = traits.str2charp(path)
- res = win32traits.GetFileAttributesEx(l_path, win32traits.GetFileExInfoStandard, data)
- errcode = rwin32.GetLastError_saved()
- if res == 0:
- if errcode == win32traits.ERROR_SHARING_VIOLATION:
- res = attributes_from_dir(l_path, data)
- errcode = rwin32.GetLastError_saved()
- traits.free_charp(l_path)
- if res == 0:
- raise WindowsError(errcode, "os_stat failed")
- return attribute_data_to_stat(data)
- finally:
- lltype.free(data, flavor='raw')
-
- def win32_fstat_llimpl(fd):
- handle = rwin32.get_osfhandle(fd)
- filetype = win32traits.GetFileType(handle)
- if filetype == win32traits.FILE_TYPE_CHAR:
- # console or LPT device
- return make_stat_result((win32traits._S_IFCHR,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0))
- elif filetype == win32traits.FILE_TYPE_PIPE:
- # socket or named pipe
- return make_stat_result((win32traits._S_IFIFO,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0))
- elif filetype == win32traits.FILE_TYPE_UNKNOWN:
- error = rwin32.GetLastError_saved()
- if error != 0:
- raise WindowsError(error, "os_fstat failed")
- # else: unknown but valid file
-
- # normal disk file (FILE_TYPE_DISK)
- info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION,
- flavor='raw', zero=True)
- try:
- res = win32traits.GetFileInformationByHandle(handle, info)
- if res == 0:
- raise WindowsError(rwin32.GetLastError_saved(),
- "os_fstat failed")
- return by_handle_info_to_stat(info)
- finally:
- lltype.free(info, flavor='raw')
-
- if name == 'fstat':
- return win32_fstat_llimpl
- else:
- return win32_stat_llimpl
-
-
-#__________________________________________________
-# Helper functions for win32
-
-def make_longlong(high, low):
- return (rffi.r_longlong(high) << 32) + rffi.r_longlong(low)
-
-# Seconds between 1.1.1601 and 1.1.1970
-secs_between_epochs = rffi.r_longlong(11644473600)
-
-def FILE_TIME_to_time_t_float(filetime):
- ft = make_longlong(filetime.c_dwHighDateTime, filetime.c_dwLowDateTime)
- # FILETIME is in units of 100 nsec
- return float(ft) * (1.0 / 10000000.0) - secs_between_epochs
-
-def time_t_to_FILE_TIME(time, filetime):
- ft = rffi.r_longlong((time + secs_between_epochs) * 10000000)
- filetime.c_dwHighDateTime = rffi.r_uint(ft >> 32)
- filetime.c_dwLowDateTime = rffi.r_uint(ft) # masking off high bits
diff --git a/rpython/rtyper/module/r_os_stat.py b/rpython/rtyper/module/r_os_stat.py
deleted file mode 100644
--- a/rpython/rtyper/module/r_os_stat.py
+++ /dev/null
@@ -1,122 +0,0 @@
-"""
-RTyping support for os.stat_result objects.
-They are rtyped just like a tuple of the correct length supporting
-only indexing and the st_xxx attributes. We need a custom StatResultRepr
-because when rtyping for LL backends we have extra platform-dependent
-items at the end of the tuple, but for OO backends we only want the
-portable items. This allows the OO backends to assume a fixed shape for
-the tuples returned by os.stat().
-"""
-from rpython.annotator import model as annmodel
-from rpython.rtyper.llannotation import lltype_to_annotation
-from rpython.flowspace.model import Constant
-from rpython.flowspace.operation import op
-from rpython.tool.pairtype import pairtype
-from rpython.rtyper.rmodel import Repr
-from rpython.rtyper.rint import IntegerRepr
-from rpython.rtyper.error import TyperError
-from rpython.rtyper.module import ll_os_stat
-
-
-class StatResultRepr(Repr):
-
- def __init__(self, rtyper):
- self.rtyper = rtyper
- self.stat_fields = ll_os_stat.STAT_FIELDS
-
- self.stat_field_indexes = {}
- for i, (name, TYPE) in enumerate(self.stat_fields):
- self.stat_field_indexes[name] = i
-
- self.s_tuple = annmodel.SomeTuple([lltype_to_annotation(TYPE)
- for name, TYPE in self.stat_fields])
- self.r_tuple = rtyper.getrepr(self.s_tuple)
- self.lowleveltype = self.r_tuple.lowleveltype
-
- def redispatch_getfield(self, hop, index):
- rtyper = self.rtyper
- s_index = rtyper.annotator.bookkeeper.immutablevalue(index)
- hop2 = hop.copy()
- spaceop = op.getitem(hop.args_v[0], Constant(index))
- spaceop.result = hop.spaceop.result
- hop2.spaceop = spaceop
- hop2.args_v = spaceop.args
- hop2.args_s = [self.s_tuple, s_index]
- hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)]
- return hop2.dispatch()
-
- def rtype_getattr(self, hop):
- s_attr = hop.args_s[1]
- attr = s_attr.const
- try:
- index = self.stat_field_indexes[attr]
- except KeyError:
- raise TyperError("os.stat().%s: field not available" % (attr,))
- return self.redispatch_getfield(hop, index)
-
-
-class __extend__(pairtype(StatResultRepr, IntegerRepr)):
-
- def rtype_getitem((r_sta, r_int), hop):
- s_int = hop.args_s[1]
- index = s_int.const
- return r_sta.redispatch_getfield(hop, index)
-
-
-def specialize_make_stat_result(hop):
- r_StatResult = hop.rtyper.getrepr(ll_os_stat.s_StatResult)
- [v_result] = hop.inputargs(r_StatResult.r_tuple)
- # no-op conversion from r_StatResult.r_tuple to r_StatResult
- hop.exception_cannot_occur()
- return v_result
-
-
-class StatvfsResultRepr(Repr):
-
- def __init__(self, rtyper):
- self.rtyper = rtyper
- self.statvfs_fields = ll_os_stat.STATVFS_FIELDS
-
- self.statvfs_field_indexes = {}
- for i, (name, TYPE) in enumerate(self.statvfs_fields):
- self.statvfs_field_indexes[name] = i
-
- self.s_tuple = annmodel.SomeTuple([lltype_to_annotation(TYPE)
- for name, TYPE in self.statvfs_fields])
- self.r_tuple = rtyper.getrepr(self.s_tuple)
- self.lowleveltype = self.r_tuple.lowleveltype
-
- def redispatch_getfield(self, hop, index):
- rtyper = self.rtyper
- s_index = rtyper.annotator.bookkeeper.immutablevalue(index)
- hop2 = hop.copy()
- spaceop = op.getitem(hop.args_v[0], Constant(index))
- spaceop.result = hop.spaceop.result
- hop2.spaceop = spaceop
- hop2.args_v = spaceop.args
- hop2.args_s = [self.s_tuple, s_index]
- hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)]
- return hop2.dispatch()
-
- def rtype_getattr(self, hop):
- s_attr = hop.args_s[1]
- attr = s_attr.const
- try:
- index = self.statvfs_field_indexes[attr]
- except KeyError:
- raise TyperError("os.statvfs().%s: field not available" % (attr,))
- return self.redispatch_getfield(hop, index)
-
-
-class __extend__(pairtype(StatvfsResultRepr, IntegerRepr)):
- def rtype_getitem((r_sta, r_int), hop):
- s_int = hop.args_s[1]
- index = s_int.const
- return r_sta.redispatch_getfield(hop, index)
-
-
-def specialize_make_statvfs_result(hop):
- r_StatvfsResult = hop.rtyper.getrepr(ll_os_stat.s_StatvfsResult)
- [v_result] = hop.inputargs(r_StatvfsResult.r_tuple)
- hop.exception_cannot_occur()
- return v_result
More information about the pypy-commit
mailing list