Switch getattr / statfs to an object oriented interface.

This commit is contained in:
dzsekijo 2006-05-28 13:56:28 +00:00
parent 4158d7b0f7
commit 0a3be77f65
5 changed files with 154 additions and 112 deletions

View file

@ -1,3 +1,9 @@
2006-05-28 Csaba Henk <csaba.henk@creo.hu>
* Switch getattr / statfs to an object oriented interface:
- Revert the addition of the statvfs method.
- Implement compat conversion for old getattr / statfs
results.
2006-05-27 Csaba Henk <csaba.henk@creo.hu>
* setup.py related fixes:
- fix missing installation of fuse.py
@ -19,7 +25,7 @@
deprecated, keep statfs useable via statfs -> statvfs conversion
2006-05-24 Csaba Henk <csaba.henk@creo.hu>
* Revamp fs initialization code.
* Revamp fs initialization code:
- Get rid of both of the kopts/lopts and the fuse_opt stuff,
just keep opts in a dict and assemble a simple argc/argv pair
from that. This means that for all supported API versions we can
@ -36,12 +42,12 @@
- Fix indetation, uniformize look.
2006-05-23 Csaba Henk <csaba.henk@creo.hu>
* Fix statfs index mismatch in xmp.py.
* Rebase build system on pkg-config.
* Fix statfs index mismatch in xmp.py:
* Rebase build system on pkg-config:
- Credits: setup.py based on that of shout-python (python bindings to
libshout, part of the icecast project)
* Update code so that it can be compiled against FUSE libs with API from
21 to 26
21 to 26:
- Credits: aggregated from contributions, code snippets and ideas of
Simon Barner, Csaba Henk, Roman Shterenzon and Miklos Szeredi
* Result of argument type check was ignored in FuseInvalidate(), fix

View file

@ -42,9 +42,34 @@ routine (that's a short piece of code). However, you are encouraged to
switch to the new parsing interface, which serves you with easy but
powerful commandline parsing.
We also changed the ``getattr`` and ``statfs`` fs methods.
We switched to an object oriented interface. Instead of returning a
sequence, you have to return an object with appropriate attributes
(if any of them is lacking, the fs user will get an ``EINVAL``).
For ``getattr``, the attributes are just like those of the return
value of ``os.stat()``: ``st_mode``, ``st_ino``, ... For ``statfs``,
the attributes are just like those of the return value of ``os.statvfs()``:
``f_bsize``, ``f_frsize``, ... [#]_
If you start from scratch (ie., you are not passing on an ``os.stat()`` or
``os.statvfs()`` result), you can use the auxiliary classes ``fuse.Stat`` and
``fuse.StatVFS`` for instantiating appropriate objects. For ``fuse.Stat``, you
have to define each of these attributes, for ``fuse.StatVfs`` they are initated
with a 0 default value [#]_.
.. _statvfs: http://docs.python.org/lib/module-statvfs.html
.. [#] We follow the convention that we refer to instance attributes like
``Klass#attr``. If it's a method, we'll use ``Klass#meth()``.
.. [#] Traditionally, ``os.stat()`` and ``os.statvfs()`` returned tuples.
Since Python 2.2, they return dedicated object which both implement the
sequence protocol and have the aforementioned attributes (when you print
them, they look like a tuple).
.. [#] We might go stricter and leave some of the ``statfs`` attributes
undef'd.
What's on the gain side?
------------------------
@ -104,11 +129,3 @@ This is what's addressed by the new API.
partially parsed pieces of the FUSE command line to the C code, which
used these directly in low level functions of the library, getting behind
the main commandline parsing routine of the FUSE lib with no real reason.
Anything else?
--------------
We deprecated the ``statfs()`` method (which was to return a tuple containing
some fs characteristics, in a somewhat ad hoc order). Instead of that, you are
suggested to implement ``statvfs()`` which is to return a tuple of the same
layout as of ``os.statvfs()`` return values.

View file

@ -72,34 +72,31 @@ OUT: \
static int
getattr_func(const char *path, struct stat *st)
{
int i;
PyObject *tmp;
PyObject *v = PyObject_CallFunction(getattr_cb, "s", path);
PROLOGUE
if (!PySequence_Check(v))
goto OUT_DECREF;
#define fetchattr(st, attr) \
if (!(tmp = PyObject_GetAttrString(v, #attr))) \
goto OUT_DECREF; \
if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) \
goto OUT_DECREF; \
st->attr = PyInt_AsLong(tmp);
if(PySequence_Size(v) < 10)
goto OUT_DECREF;
for(i=0; i<10; i++) {
PyObject *tmp = PySequence_GetItem(v, i);
if (!(PyInt_Check(tmp) || PyLong_Check(tmp)))
goto OUT_DECREF;
}
st->st_mode = PyInt_AsLong(PySequence_GetItem(v, 0));
st->st_ino = PyInt_AsLong(PySequence_GetItem(v, 1));
st->st_dev = PyInt_AsLong(PySequence_GetItem(v, 2));
st->st_nlink = PyInt_AsLong(PySequence_GetItem(v, 3));
st->st_uid = PyInt_AsLong(PySequence_GetItem(v, 4));
st->st_gid = PyInt_AsLong(PySequence_GetItem(v, 5));
st->st_size = PyInt_AsLong(PySequence_GetItem(v, 6));
st->st_atime = PyInt_AsLong(PySequence_GetItem(v, 7));
st->st_mtime = PyInt_AsLong(PySequence_GetItem(v, 8));
st->st_ctime = PyInt_AsLong(PySequence_GetItem(v, 9));
fetchattr(st, st_mode);
fetchattr(st, st_ino);
fetchattr(st, st_dev);
fetchattr(st, st_nlink);
fetchattr(st, st_uid);
fetchattr(st, st_gid);
fetchattr(st, st_size);
fetchattr(st, st_atime);
fetchattr(st, st_mtime);
fetchattr(st, st_ctime);
#undef fetchattr
/* Fill in fields not provided by Python lstat() */
st->st_blksize= 4096;
st->st_blocks= (st->st_size + 511)/512;
@ -118,7 +115,7 @@ readlink_func(const char *path, char *link, size_t size)
PROLOGUE
if(!PyString_Check(v)) {
ret = -EINVAL;
ret = -EINVAL;
goto OUT_DECREF;
}
s = PyString_AsString(v);
@ -374,45 +371,38 @@ static int
statfs_func(const char *dummy, struct statfs *fst)
#endif
{
int i;
long retvalues[10];
PyObject *tmp;
PyObject *v = PyObject_CallFunction(statfs_cb, "");
PROLOGUE
if (!PySequence_Check(v))
goto OUT_DECREF;
if (PySequence_Size(v) < 10)
goto OUT_DECREF;
#define fetchattr(st, attr) \
if (!(tmp = PyObject_GetAttrString(v, #attr))) \
goto OUT_DECREF; \
if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) \
goto OUT_DECREF; \
st->attr = PyInt_Check(tmp) ? PyInt_AsLong(tmp) : \
(PyLong_Check(tmp) ? PyLong_AsLong(tmp) : 0);
for(i = 0; i < 10; i++) {
PyObject *tmp = PySequence_GetItem(v, i);
retvalues[i] = PyInt_Check(tmp) ? PyInt_AsLong(tmp) :
(PyLong_Check(tmp) ? PyLong_AsLong(tmp) : 0);
}
/*
* To be completely theoretically correct, we should identify
* the indices via Python's statvfs module, but these indices
* are unlikely to change, so we just use direct idexing.
*/
fst->f_bsize = retvalues[0];
fetchattr(fst, f_bsize);
#if FUSE_VERSION >= 25
fst->f_frsize = retvalues[1];
fetchattr(fst, f_frsize);
#endif
fst->f_blocks = retvalues[2];
fst->f_bfree = retvalues[3];
fst->f_bavail = retvalues[4];
fst->f_files = retvalues[5];
fst->f_ffree = retvalues[6];
fetchattr(fst, f_blocks);
fetchattr(fst, f_bfree);
fetchattr(fst, f_bavail);
fetchattr(fst, f_files);
fetchattr(fst, f_ffree);
#if FUSE_VERSION >= 25
fst->f_favail = retvalues[7];
fst->f_flag = retvalues[8];
fst->f_namemax = retvalues[9];
fetchattr(fst, f_favail);
fetchattr(fst, f_flag);
fetchattr(fst, f_namemax);
#else
fst->f_namelen = retvalues[9];
fetchattr(fst, f_namelen);
#endif
#undef fetchattr
ret = 0;
@ -496,7 +486,7 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
"getattr", "readlink", "getdir", "mknod",
"mkdir", "unlink", "rmdir", "symlink", "rename",
"link", "chmod", "chown", "truncate", "utime",
"open", "read", "write", "release", "statvfs", "fsync",
"open", "read", "write", "release", "statfs", "fsync",
"fuse_args", "multithreaded", NULL};
memset(&op, 0, sizeof(op));

98
fuse.py
View file

@ -405,7 +405,7 @@ class FuseOptParse(OptionParser):
##########
class ErrnoWrapper:
class ErrnoWrapper(object):
def __init__(self, func):
self.func = func
@ -419,6 +419,35 @@ class ErrnoWrapper:
return -detail
class Stat(object):
"""
Auxiliary class which can be filled up stat attributes.
The attributes are undefined by default.
"""
pass
class StatVfs(object):
"""
Auxiliary class which can be filled up statvfs attributes.
The attributes are 0 by default.
"""
def __init__(self):
self.f_bsize = 0
self.f_frsize = 0
self.f_blocks = 0
self.f_bfree = 0
self.f_bavail = 0
self.f_files = 0
self.f_ffree = 0
self.f_favail = 0
self.f_flag = 0
self.f_namemax = 0
class Fuse(object):
"""
Python interface to FUSE.
@ -427,7 +456,7 @@ class Fuse(object):
_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir',
'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod',
'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release',
'statvfs', 'fsync']
'statfs', 'fsync']
fusage = "%prog [mountpoint] [options]"
@ -436,35 +465,6 @@ class Fuse(object):
self.fuse_args = \
kw.has_key('fuse_args') and kw.pop('fuse_args') or FuseArgs()
# Convert statfs to the new, Python statvfs compatible statvfs method
if not hasattr(self, 'statvfs') and hasattr(self, 'statfs'):
def statvfs(self):
import statvfs
if not compat_0_1:
from warnings import warn
warn("`statfs' fs method is deprecated, use `statvfs' instead",
DeprecationWarning, stacklevel=1)
oout = self.statfs()
lo = len(oout)
nout = [0] * 10
nout[statvfs.F_BSIZE] = oout[0] # 0
nout[statvfs.F_FRSIZE] = oout[lo >= 8 and 7 or 0] # 1
nout[statvfs.F_BLOCKS] = oout[1] # 2
nout[statvfs.F_BFREE] = oout[2] # 3
nout[statvfs.F_BAVAIL] = oout[3] # 4
nout[statvfs.F_FILES] = oout[4] # 5
nout[statvfs.F_FFREE] = oout[5] # 6
nout[statvfs.F_FAVAIL] = lo >= 9 and oout[8] or 0 # 7
nout[statvfs.F_FLAG] = lo >= 10 and oout[9] or 0 # 8
nout[statvfs.F_NAMEMAX] = oout[6] # 9
return nout
self.__class__.statvfs = statvfs
if compat_0_1:
return self.__init_0_1__(*args, **kw)
@ -506,7 +506,11 @@ class Fuse(object):
for a in self._attrs:
if hasattr(self,a):
d[a] = ErrnoWrapper(getattr(self, a))
b = a
if compat_0_1:
if self.compatmap.has_key(a):
b = self.compatmap[a]
d[a] = ErrnoWrapper(getattr(self, b))
domount = True
if not args:
@ -614,8 +618,34 @@ class Fuse(object):
if hasattr(self, 'debug'):
self.fuse_args.add('debug')
if hasattr(self,'allow_other'):
if hasattr(self, 'allow_other'):
self.fuse_args.add('allow_other')
if hasattr(self,'kernel_cache'):
if hasattr(self, 'kernel_cache'):
self.fuse_args.add('kernel_cache')
def tuple2stat(self, *a):
from os import stat_result
return stat_result(self.getattr(*a))
def statfs2statvfs(self, *a):
oout = self.statfs(*a)
lo = len(oout)
svf = StatVfs()
svf.f_bsize = oout[0] # 0
svf.f_frsize = oout[lo >= 8 and 7 or 0] # 1
svf.f_blocks = oout[1] # 2
svf.f_bfree = oout[2] # 3
svf.f_bavail = oout[3] # 4
svf.f_files = oout[4] # 5
svf.f_ffree = oout[5] # 6
svf.f_favail = lo >= 9 and oout[8] or 0 # 7
svf.f_flag = lo >= 10 and oout[9] or 0 # 8
svf.f_namemax = oout[6] # 9
return svf
compatmap = { 'getattr' : 'tuple2stat', 'statfs' : 'statfs2statvfs' }

27
xmp.py
View file

@ -123,24 +123,23 @@ class Xmp(Fuse):
print "xmp.py:Xmp:release: %s %s" % (path, flags)
return 0
def statvfs(self):
def statfs(self):
"""
Should return a tuple like those returned by os.statvfs().
Should return an object with statvfs attributes (f_bsize, f_frsize...).
Eg., the return value of os.statvfs() is such a thing (since py 2.2).
If you are not reusing an existing statvfs object, start with
fuse.StatVFS(), and define the attributes.
Feel free to set any of the above values to 0, which tells
the kernel that the info is not available.
To provide usable information (ie., you want sensible df(1)
output, you are suggested to specify the following attributes:
However, to provide usable information (ie., you want sensible df(1)
output, you are suggested to specify at least the following 7 values
(in that order):
- blocksize - preferred size of file blocks, in bytes
- frsize - fundamental size of file blcoks, in bytes
- f_bsize - preferred size of file blocks, in bytes
- f_frsize - fundamental size of file blcoks, in bytes
[if you have no idea, use the same as blocksize]
- totalblocks - total number of blocks in the filesystem
- freeblocks - number of free blocks
- totalfiles - total number of file inodes
- freefiles - nunber of free file inodes
- f_blocks - total number of blocks in the filesystem
- f_bfree - number of free blocks
- f_files - total number of file inodes
- f_ffree - nunber of free file inodes
"""
return os.statvfs(self.root)