Author: Alex Gaynor <[email protected]>
Branch: add-statvfs
Changeset: r65565:b0c0ac749b6b
Date: 2013-07-23 09:59 -0700
http://bitbucket.org/pypy/pypy/changeset/b0c0ac749b6b/
Log: PyPy level statvfs and fstatvfs seem to work
diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -17,12 +17,13 @@
'setregid', 'setreuid', 'setsid', 'setuid', 'stat_float_times', 'statvfs',
'statvfs_result', 'symlink', 'sysconf', 'sysconf_names', 'tcgetpgrp',
'tcsetpgrp',
'ttyname', 'uname', 'wait', 'wait3', 'wait4'
- ]
+]
# the Win32 urandom implementation isn't going to translate on JVM or CLI so
# we have to remove it
lltype_only_defs.append('urandom')
+
class Module(MixedModule):
"""This module provides access to operating system functionality that is
standardized by the C Standard and the POSIX standard (a thinly
@@ -32,21 +33,21 @@
applevel_name = os.name
appleveldefs = {
- 'error' : 'app_posix.error',
- 'stat_result': 'app_posix.stat_result',
- 'statvfs_result': 'app_posix.statvfs_result',
- 'fdopen' : 'app_posix.fdopen',
- 'tmpfile' : 'app_posix.tmpfile',
- 'popen' : 'app_posix.popen',
- 'tmpnam' : 'app_posix.tmpnam',
- 'tempnam' : 'app_posix.tempnam',
+ 'error': 'app_posix.error',
+ 'stat_result': 'app_posix.stat_result',
+ 'statvfs_result': 'app_posix.statvfs_result',
+ 'fdopen': 'app_posix.fdopen',
+ 'tmpfile': 'app_posix.tmpfile',
+ 'popen': 'app_posix.popen',
+ 'tmpnam': 'app_posix.tmpnam',
+ 'tempnam': 'app_posix.tempnam',
}
if os.name == 'nt':
appleveldefs.update({
- 'popen2' : 'app_posix.popen2',
- 'popen3' : 'app_posix.popen3',
- 'popen4' : 'app_posix.popen4',
- })
+ 'popen2': 'app_posix.popen2',
+ 'popen3': 'app_posix.popen3',
+ 'popen4': 'app_posix.popen4',
+ })
if hasattr(os, 'wait'):
appleveldefs['wait'] = 'app_posix.wait'
@@ -54,44 +55,49 @@
appleveldefs['wait3'] = 'app_posix.wait3'
if hasattr(os, 'wait4'):
appleveldefs['wait4'] = 'app_posix.wait4'
-
+
interpleveldefs = {
- 'open' : 'interp_posix.open',
- 'lseek' : 'interp_posix.lseek',
- 'write' : 'interp_posix.write',
- 'isatty' : 'interp_posix.isatty',
- 'read' : 'interp_posix.read',
- 'close' : 'interp_posix.close',
- 'closerange': 'interp_posix.closerange',
- 'fstat' : 'interp_posix.fstat',
- 'stat' : 'interp_posix.stat',
- 'lstat' : 'interp_posix.lstat',
- 'stat_float_times' : 'interp_posix.stat_float_times',
- 'dup' : 'interp_posix.dup',
- 'dup2' : 'interp_posix.dup2',
- 'access' : 'interp_posix.access',
- 'times' : 'interp_posix.times',
- 'system' : 'interp_posix.system',
- 'unlink' : 'interp_posix.unlink',
- 'remove' : 'interp_posix.remove',
- 'getcwd' : 'interp_posix.getcwd',
- 'getcwdu' : 'interp_posix.getcwdu',
- 'chdir' : 'interp_posix.chdir',
- 'mkdir' : 'interp_posix.mkdir',
- 'rmdir' : 'interp_posix.rmdir',
- 'environ' : 'interp_posix.get(space).w_environ',
- 'listdir' : 'interp_posix.listdir',
- 'strerror' : 'interp_posix.strerror',
- 'pipe' : 'interp_posix.pipe',
- 'chmod' : 'interp_posix.chmod',
- 'rename' : 'interp_posix.rename',
- 'umask' : 'interp_posix.umask',
- '_exit' : 'interp_posix._exit',
- 'utime' : 'interp_posix.utime',
- '_statfields': 'interp_posix.getstatfields(space)',
- 'kill' : 'interp_posix.kill',
- 'abort' : 'interp_posix.abort',
- 'urandom' : 'interp_posix.urandom',
+ 'open': 'interp_posix.open',
+ 'lseek': 'interp_posix.lseek',
+ 'write': 'interp_posix.write',
+ 'isatty': 'interp_posix.isatty',
+ 'read': 'interp_posix.read',
+ 'close': 'interp_posix.close',
+ 'closerange': 'interp_posix.closerange',
+
+ 'fstat': 'interp_posix.fstat',
+ 'stat': 'interp_posix.stat',
+ 'lstat': 'interp_posix.lstat',
+ 'stat_float_times': 'interp_posix.stat_float_times',
+
+ 'fstatvfs': 'interp_posix.fstatvfs',
+ 'statvfs': 'interp_posix.statvfs',
+
+ 'dup': 'interp_posix.dup',
+ 'dup2': 'interp_posix.dup2',
+ 'access': 'interp_posix.access',
+ 'times': 'interp_posix.times',
+ 'system': 'interp_posix.system',
+ 'unlink': 'interp_posix.unlink',
+ 'remove': 'interp_posix.remove',
+ 'getcwd': 'interp_posix.getcwd',
+ 'getcwdu': 'interp_posix.getcwdu',
+ 'chdir': 'interp_posix.chdir',
+ 'mkdir': 'interp_posix.mkdir',
+ 'rmdir': 'interp_posix.rmdir',
+ 'environ': 'interp_posix.get(space).w_environ',
+ 'listdir': 'interp_posix.listdir',
+ 'strerror': 'interp_posix.strerror',
+ 'pipe': 'interp_posix.pipe',
+ 'chmod': 'interp_posix.chmod',
+ 'rename': 'interp_posix.rename',
+ 'umask': 'interp_posix.umask',
+ '_exit': 'interp_posix._exit',
+ 'utime': 'interp_posix.utime',
+ '_statfields': 'interp_posix.getstatfields(space)',
+ 'kill': 'interp_posix.kill',
+ 'abort': 'interp_posix.abort',
+ 'urandom': 'interp_posix.urandom',
}
if hasattr(os, 'chown'):
@@ -168,8 +174,8 @@
interpleveldefs['getlogin'] = 'interp_posix.getlogin'
for name in ['setsid', 'getuid', 'geteuid', 'getgid', 'getegid', 'setuid',
- 'seteuid', 'setgid', 'setegid', 'getgroups', 'getpgrp',
- 'setpgrp', 'getppid', 'getpgid', 'setpgid', 'setreuid',
+ 'seteuid', 'setgid', 'setegid', 'getgroups', 'getpgrp',
+ 'setpgrp', 'getppid', 'getpgid', 'setpgid', 'setreuid',
'setregid', 'getsid', 'setsid']:
if hasattr(os, name):
interpleveldefs[name] = 'interp_posix.%s' % (name,)
@@ -178,7 +184,7 @@
interpleveldefs['_getfullpathname'] = 'interp_posix._getfullpathname'
if hasattr(os, 'chroot'):
interpleveldefs['chroot'] = 'interp_posix.chroot'
-
+
for name in RegisterOs.w_star:
if hasattr(os, name):
interpleveldefs[name] = 'interp_posix.' + name
@@ -187,7 +193,7 @@
# if it's an ootype translation, remove all the defs that are lltype
# only
backend = space.config.translation.backend
- if backend == 'cli' or backend == 'jvm':
+ if backend == 'cli' or backend == 'jvm' :
for name in lltype_only_defs:
self.interpleveldefs.pop(name, None)
MixedModule.__init__(self, space, w_name)
@@ -195,7 +201,7 @@
def startup(self, space):
from pypy.module.posix import interp_posix
interp_posix.get(space).startup(space)
-
+
for constant in dir(os):
value = getattr(os, constant)
if constant.isupper() and type(value) is int:
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,15 +1,17 @@
-from pypy.interpreter.gateway import unwrap_spec
+import os
+import sys
+
from rpython.rlib import rposix, 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 rpython.rtyper.module.ll_os import RegisterOs
+
+from pypy.interpreter.gateway import unwrap_spec
from pypy.interpreter.error import OperationError, wrap_oserror, wrap_oserror2
-from rpython.rtyper.module.ll_os import RegisterOs
-from rpython.rtyper.module import ll_os_stat
from pypy.module.sys.interp_encoding import getfilesystemencoding
-import os
-import sys
_WIN32 = sys.platform == 'win32'
if _WIN32:
@@ -213,6 +215,7 @@
STAT_FIELDS = unrolling_iterable(enumerate(ll_os_stat.STAT_FIELDS))
PORTABLE_STAT_FIELDS = unrolling_iterable(
enumerate(ll_os_stat.PORTABLE_STAT_FIELDS))
+STATVFS_FIELDS = unrolling_iterable(enumerate(ll_os_stat.STATVFS_FIELDS))
def build_stat_result(space, st):
if space.config.translation.type_system == 'ootype':
@@ -253,6 +256,16 @@
space.wrap('stat_result'))
return space.call_function(w_stat_result, w_tuple, w_keywords)
+
+def build_statvfs_result(space, st):
+ vals_w = [None] * len(ll_os_stat.STATVFS_FIELDS)
+ for i, (name, _) in STATVFS_FIELDS:
+ vals_w[i] = space.wrap(getattr(st, name))
+ w_tuple = space.newtuple(vals_w)
+ w_statvfs_result = space.getattr(space.getbuiltinmodule(os.name),
space.wrap('statvfs_result'))
+ return space.call_function(w_statvfs_result, w_tuple)
+
+
@unwrap_spec(fd=c_int)
def fstat(space, fd):
"""Perform a stat system call on the file referenced to by an open
@@ -314,6 +327,26 @@
else:
state.stat_float_times = space.bool_w(w_value)
+
+@unwrap_spec(fd=c_int)
+def fstatvfs(space, fd):
+ try:
+ st = os.fstat(fd)
+ except OSError as e:
+ raise wrap_oserror(space, e)
+ else:
+ return build_statvfs_result(space, st)
+
+
+def statvfs(space, w_path):
+ try:
+ st = dispatch_filename(rposix.statvfs)(space, w_path)
+ except OSError as e:
+ raise wrap_oserror2(space, e, w_path)
+ else:
+ return build_statvfs_result(space, st)
+
+
@unwrap_spec(fd=c_int)
def dup(space, fd):
"""Create a copy of the file descriptor. Return the new file
diff --git a/pypy/module/posix/test/test_posix2.py
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -169,7 +169,8 @@
assert stat.S_ISDIR(st.st_mode)
def test_stat_exception(self):
- import sys, errno
+ import sys
+ import errno
for fn in [self.posix.stat, self.posix.lstat]:
try:
fn("nonexistentdir/nonexistentfile")
@@ -183,6 +184,15 @@
assert isinstance(e, WindowsError)
assert e.winerror == 3
+ def test_statvfs(self):
+ st = self.posix.statvfs(".")
+ assert isinstance(st, self.posix.statvfs_result)
+ for field in [
+ 'f_bsize', 'f_frsize', 'f_blocks', 'f_bfree', 'f_bavail',
+ 'f_files', 'f_ffree', 'f_favail', 'f_flag', 'f_namemax',
+ ]:
+ assert hasattr(st, field)
+
def test_pickle(self):
import pickle, os
st = self.posix.stat(os.curdir)
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -154,6 +154,15 @@
else:
return os.lstat(path.as_bytes())
+
[email protected](0)
+def statvfs(path):
+ if isinstance(path, str):
+ return os.statvfs(path)
+ else:
+ return os.statvfs(path.as_bytes())
+
+
@specialize.argtype(0)
def unlink(path):
if isinstance(path, str):
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
@@ -1698,6 +1698,12 @@
from rpython.rtyper.module import ll_os_stat
return ll_os_stat.register_stat_variant('lstat', traits)
+ @registering(os.fstatvfs)
+ def register_os_fstatvfs(self):
+ from rpython.rtyper.module import ll_os_stat
+ return ll_os_stat.register_statvfs_variant('fstatvfs', StringTraits())
+
+
# ------------------------------- os.W* ---------------------------------
w_star = ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED',
diff --git a/rpython/rtyper/module/ll_os_stat.py
b/rpython/rtyper/module/ll_os_stat.py
--- a/rpython/rtyper/module/ll_os_stat.py
+++ b/rpython/rtyper/module/ll_os_stat.py
@@ -2,20 +2,22 @@
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
+
+import os
+import sys
+
from rpython.annotator import model as annmodel
-from rpython.tool.pairtype import pairtype
-from rpython.tool.sourcetools import func_with_new_name, func_renamer
-from rpython.rtyper import extregistry
-from rpython.rtyper.extfunc import register_external, extdef
-from rpython.rtyper.lltypesystem import rffi, lltype
-from rpython.rtyper.tool import rffi_platform as platform
-from rpython.rtyper.lltypesystem.rtupletype import TUPLE_TYPE
from rpython.rlib import rposix
from rpython.rlib.rarithmetic import intmask
-from rpython.rlib.objectmodel import specialize
+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.lltypesystem.rtupletype 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
-from rpython.rtyper.annlowlevel import hlstr
# Support for float times is here.
# - ALL_STAT_FIELDS contains Float fields if the system can retrieve
@@ -47,12 +49,26 @@
("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
@@ -79,6 +95,7 @@
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([annmodel.lltype_to_annotation(TYPE)
@@ -86,6 +103,23 @@
extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS))
return s_reduced, stat_result_reduce, stat_result_recreate
+
+class SomeStatvfsResult(annmodel.SomeObject):
+ knowntype = os.statvfs_result
+
+ def rtyper_makerepr(self, rtyper):
+ from rpython.rtyper.module import r_os_stat
+ return r_os_stat.StatvfsResultRepr(rtyper)
+
+ def rtyper_makekey_ex(self, rtyper):
+ return self.__class__,
+
+ def getattr(self, s_attr):
+ assert s_attr.is_constant()
+ TYPE = STATVFS_FIELD_TYPES[s_attr.const]
+ return annmodel.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"
@@ -94,8 +128,17 @@
name, TYPE = STAT_FIELDS[index]
return annmodel.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 annmodel.lltype_to_annotation(TYPE)
+
+
s_StatResult = SomeStatResult()
+
def make_stat_result(tup):
"""Turn a tuple into an os.stat_result object."""
positional = tup[:N_INDEXABLE_FIELDS]
@@ -104,6 +147,11 @@
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
@@ -120,16 +168,16 @@
if sys.platform.startswith('win'):
_name_struct_stat = '_stati64'
- INCLUDES = ['sys/types.h', 'sys/stat.h']
+ INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h']
else:
_name_struct_stat = 'stat'
- INCLUDES = ['sys/types.h', 'sys/stat.h', 'unistd.h']
+ 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
+ includes=INCLUDES
)
if TIMESPEC is not None:
@@ -141,7 +189,7 @@
def posix_declaration(try_to_add=None):
- global STAT_STRUCT
+ global STAT_STRUCT, STATVFS_STRUCT
LL_STAT_FIELDS = STAT_FIELDS[:]
if try_to_add:
@@ -173,15 +221,17 @@
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)
+ 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)
@@ -202,6 +252,9 @@
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
@@ -233,6 +286,21 @@
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
@@ -301,6 +369,61 @@
[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
+ )
+
+ @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_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)
+ 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_statvfs_llimpl, llfakeimpl=posix_fakeimpl
+ )
+
+
def make_win32_stat_impl(name, traits):
from rpython.rlib import rwin32
from rpython.rtyper.module.ll_win32file import make_win32_traits
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit