aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--TODO2
-rw-r--r--example/fusexmp.c11
-rw-r--r--example/hello.c1
-rw-r--r--example/null.c6
-rw-r--r--include/fuse.h2
-rw-r--r--include/linux/fuse.h14
-rw-r--r--kernel/inode.c34
-rw-r--r--lib/fuse.c28
-rw-r--r--perl/.cvsignore1
-rw-r--r--perl/Fuse.pm27
-rw-r--r--perl/Fuse.xs47
-rwxr-xr-xperl/example.pl3
13 files changed, 167 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index cf7aaa8..d2a2c0b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2002-01-07 Mark Glines <mark@glines.org>
+
+ * Added statfs() support to kernel, lib, examples, and perl!
+
2001-12-20 Miklos Szeredi <mszeredi@inf.bme.hu>
* Added function fuse_get_context() to library API (inspired by
diff --git a/TODO b/TODO
index fbf6d70..971ea9e 100644
--- a/TODO
+++ b/TODO
@@ -2,6 +2,4 @@
- Integrate (parts of) fusermount into mount(8)
- - Statfs operation
-
- Etc, etc...
diff --git a/example/fusexmp.c b/example/fusexmp.c
index b9df79c..b921d56 100644
--- a/example/fusexmp.c
+++ b/example/fusexmp.c
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
+#include <sys/statfs.h>
static int xmp_getattr(const char *path, struct stat *stbuf)
{
@@ -231,6 +232,15 @@ static int xmp_write(const char *path, const char *buf, size_t size,
return res;
}
+static int xmp_statfs(struct statfs *fst)
+{
+ struct statfs st;
+ int rv = statfs("/",&st);
+ if(!rv)
+ memcpy(fst,&st,sizeof(st));
+ return rv;
+}
+
static struct fuse_operations xmp_oper = {
getattr: xmp_getattr,
readlink: xmp_readlink,
@@ -249,6 +259,7 @@ static struct fuse_operations xmp_oper = {
open: xmp_open,
read: xmp_read,
write: xmp_write,
+ statfs: xmp_statfs,
};
int main(int argc, char *argv[])
diff --git a/example/hello.c b/example/hello.c
index e0010cd..ccd4b5f 100644
--- a/example/hello.c
+++ b/example/hello.c
@@ -84,6 +84,7 @@ static struct fuse_operations hello_oper = {
open: hello_open,
read: hello_read,
write: NULL,
+ statfs: NULL,
};
int main(int argc, char *argv[])
diff --git a/example/null.c b/example/null.c
index 7be4ab4..71e9a19 100644
--- a/example/null.c
+++ b/example/null.c
@@ -64,6 +64,11 @@ static int null_write(const char *path, const char *UNUSED(buf), size_t size,
return size;
}
+static int null_statfs(struct statfs *st)
+{
+ return st->f_blocks = st->f_bavail = st->f_bsize = st->f_files =
+ st->f_ffree = st->f_namelen = 0;
+}
static struct fuse_operations null_oper = {
getattr: null_getattr,
@@ -83,6 +88,7 @@ static struct fuse_operations null_oper = {
open: null_open,
read: null_read,
write: null_write,
+ statfs: null_statfs,
};
int main(int argc, char *argv[])
diff --git a/include/fuse.h b/include/fuse.h
index bafa182..46fc87b 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -13,6 +13,7 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/statfs.h>
#include <utime.h>
/* ----------------------------------------------------------- *
@@ -81,6 +82,7 @@ struct fuse_operations {
int (*open) (const char *, int);
int (*read) (const char *, char *, size_t, off_t);
int (*write) (const char *, const char *, size_t, off_t);
+ int (*statfs) (struct statfs *);
};
/** Extra context that may be needed by some filesystems */
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 53cb3f0..40f3950 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -83,6 +83,7 @@ enum fuse_opcode {
FUSE_OPEN = 14,
FUSE_READ = 15,
FUSE_WRITE = 16,
+ FUSE_STATFS = 17,
};
/* Conservative buffer size for the client */
@@ -156,6 +157,19 @@ struct fuse_write_in {
char buf[0];
};
+typedef struct fuse_statfs {
+ long block_size;
+ long blocks;
+ long blocks_free;
+ long files;
+ long files_free;
+ long namelen;
+} fuse_statfs_t;
+
+struct fuse_statfs_out {
+ struct fuse_statfs st;
+};
+
struct fuse_in_header {
int unique;
enum fuse_opcode opcode;
diff --git a/kernel/inode.c b/kernel/inode.c
index 7fc5cfe..6c38708 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -70,10 +70,44 @@ static void fuse_put_super(struct super_block *sb)
spin_unlock(&fuse_lock);
}
+static void convert_fuse_statfs(struct statfs *stbuf, struct fuse_statfs *attr)
+{
+ stbuf->f_type = FUSE_SUPER_MAGIC;
+ stbuf->f_bsize = attr->block_size;
+ stbuf->f_blocks = attr->blocks;
+ stbuf->f_bfree = stbuf->f_bavail = attr->blocks_free;
+ stbuf->f_files = attr->files;
+ stbuf->f_ffree = attr->files_free;
+ /* Is this field necessary? Most filesystems ignore it...
+ stbuf->f_fsid.val[0] = (FUSE_SUPER_MAGIC>>16)&0xffff;
+ stbuf->f_fsid.val[1] = FUSE_SUPER_MAGIC &0xffff; */
+ stbuf->f_namelen = attr->namelen;
+}
+
+static int fuse_statfs(struct super_block *sb, struct statfs *st)
+{
+ struct fuse_conn *fc = sb->u.generic_sbp;
+ struct fuse_in in = FUSE_IN_INIT;
+ struct fuse_out out = FUSE_OUT_INIT;
+ struct fuse_statfs_out outarg;
+
+ in.numargs = 0;
+ in.h.opcode = FUSE_STATFS;
+ out.numargs = 1;
+ out.args[0].size = sizeof(outarg);
+ out.args[0].value = &outarg;
+ request_send(fc, &in, &out);
+ if(!out.h.error)
+ convert_fuse_statfs(st,&outarg.st);
+
+ return out.h.error;
+}
+
static struct super_operations fuse_super_operations = {
read_inode: fuse_read_inode,
clear_inode: fuse_clear_inode,
put_super: fuse_put_super,
+ statfs: fuse_statfs,
};
diff --git a/lib/fuse.c b/lib/fuse.c
index 98bab3f..88f3eae 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -306,6 +306,16 @@ static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
attr->_dummy = 4096;
}
+static void convert_statfs(struct statfs *st, struct fuse_statfs *fst)
+{
+ fst->block_size = st->f_bsize;
+ fst->blocks = st->f_blocks;
+ fst->blocks_free = st->f_bavail;
+ fst->files = st->f_files;
+ fst->files_free = st->f_ffree;
+ fst->namelen = st->f_namelen;
+}
+
static int fill_dir(struct fuse_dirhandle *dh, char *name, int type)
{
struct fuse_dirent dirent;
@@ -793,6 +803,20 @@ static void do_write(struct fuse *f, struct fuse_in_header *in,
send_reply(f, in, res, NULL, 0);
}
+static void do_statfs(struct fuse *f, struct fuse_in_header *in)
+{
+ int res;
+ struct statfs sbuf;
+ struct fuse_statfs_out arg;
+
+ res = -ENOSYS;
+ if(f->op.statfs)
+ res = f->op.statfs(&sbuf);
+ if(!res)
+ convert_statfs(&sbuf,&arg.st);
+ send_reply(f, in, res, &arg, sizeof(arg));
+}
+
static void free_cmd(struct fuse_cmd *cmd)
{
free(cmd->buf);
@@ -878,6 +902,10 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
do_write(f, in, (struct fuse_write_in *) inarg);
break;
+ case FUSE_STATFS:
+ do_statfs(f, in);
+ break;
+
default:
fprintf(stderr, "Operation %i not implemented\n", in->opcode);
send_reply(f, in, -ENOSYS, NULL, 0);
diff --git a/perl/.cvsignore b/perl/.cvsignore
new file mode 100644
index 0000000..5d5c2dc
--- /dev/null
+++ b/perl/.cvsignore
@@ -0,0 +1 @@
+Fuse.bs Fuse.c Makefile blib pm_to_blib
diff --git a/perl/Fuse.pm b/perl/Fuse.pm
index 93acfb6..3a20fd9 100644
--- a/perl/Fuse.pm
+++ b/perl/Fuse.pm
@@ -65,8 +65,8 @@ sub AUTOLOAD {
bootstrap Fuse $VERSION;
sub main {
- my (@subs) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
- my (@names) = qw(getattr readlink getdir mknod mkdir unlink rmdir symlink rename link chmod chown truncate utime open read write);
+ my (@subs) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+ my (@names) = qw(getattr readlink getdir mknod mkdir unlink rmdir symlink rename link chmod chown truncate utime open read write statfs);
my ($tmp) = 0;
my (%mapping) = map { $_ => $tmp++ } (@names);
my (%otherargs) = (debug=>0, threaded=>1, mountpoint=>"");
@@ -121,6 +121,14 @@ Every constant you need (file types, open() flags, error values,
etc) can be imported either from POSIX or from Fcntl, often both.
See their respective documentations, for more information.
+=head2 EXPORT
+
+None by default.
+
+=head2 EXPORTABLE CONSTANTS
+
+None.
+
=head2 FUNCTIONS YOUR FILESYSTEM MAY IMPLEMENT
=head3 getattr
@@ -278,13 +286,20 @@ Returns an errno.
Called in an attempt to write (or overwrite) a portion of the file. Be prepared because $buffer could contain random binary data with NULLs and all sorts of other wonderful stuff.
-=head2 EXPORT
+=head3 statfs
-None by default.
+Arguments: none
+Returns any of the following:
-=head2 Exportable constants
+-ENOANO()
-None.
+or
+
+$namelen, $files, $files_free, $blocks, $blocks_avail, $blocksize
+
+or
+
+-ENOANO(), $namelen, $files, $files_free, $blocks, $blocks_avail, $blocksize
=head1 AUTHOR
diff --git a/perl/Fuse.xs b/perl/Fuse.xs
index ca0459d..6061d9f 100644
--- a/perl/Fuse.xs
+++ b/perl/Fuse.xs
@@ -24,7 +24,7 @@ constant(char *name, int len, int arg)
return 0;
}
-SV *_PLfuse_callbacks[17];
+SV *_PLfuse_callbacks[18];
int _PLfuse_getattr(const char *file, struct stat *result) {
dSP;
@@ -472,6 +472,42 @@ int _PLfuse_write (const char *file, const char *buf, size_t buflen, off_t off)
return rv;
}
+int _PLfuse_statfs (struct statfs *st) {
+ int rv;
+ char *rvstr;
+ dSP;
+ DEBUGf("statfs begin\n");
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ PUTBACK;
+ rv = call_sv(_PLfuse_callbacks[17],G_ARRAY);
+ SPAGAIN;
+ if(rv > 5) {
+ st->f_bsize = POPi;
+ st->f_bavail = st->f_bfree = POPi;
+ st->f_blocks = POPi;
+ st->f_ffree = POPi;
+ st->f_files = POPi;
+ st->f_namelen = POPi;
+ if(rv > 6)
+ rv = POPi;
+ else
+ rv = 0;
+ } else
+ if(rv > 1)
+ croak("inappropriate number of returned values from statfs");
+ else
+ if(rv)
+ rv = POPi;
+ else
+ rv = -ENOSYS;
+ FREETMPS;
+ LEAVE;
+ DEBUGf("statfs end\n");
+ return rv;
+}
+
struct fuse_operations _available_ops = {
getattr: _PLfuse_getattr,
_PLfuse_readlink,
@@ -489,7 +525,8 @@ getattr: _PLfuse_getattr,
_PLfuse_utime,
_PLfuse_open,
_PLfuse_read,
- _PLfuse_write
+ _PLfuse_write,
+ _PLfuse_statfs
};
MODULE = Fuse PACKAGE = Fuse
@@ -512,13 +549,13 @@ constant(sv,arg)
void
perl_fuse_main(...)
PREINIT:
- struct fuse_operations fops = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
+ struct fuse_operations fops = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
int i, varnum = 0, threads, debug, argc;
char **argv;
STRLEN n_a;
STRLEN l;
INIT:
- if(items != 21) {
+ if(items != 22) {
fprintf(stderr,"Perl<->C inconsistency or internal error\n");
XSRETURN_UNDEF;
}
@@ -544,7 +581,7 @@ perl_fuse_main(...)
else
argc--;
- for(i=0;i<17;i++) {
+ for(i=0;i<18;i++) {
SV *var = ST(i+4);
if((var != &PL_sv_undef) && SvROK(var)) {
if(SvTYPE(SvRV(var)) == SVt_PVCV) {
diff --git a/perl/example.pl b/perl/example.pl
index bc62cad..d01278c 100755
--- a/perl/example.pl
+++ b/perl/example.pl
@@ -70,6 +70,8 @@ sub e_read {
return substr($files{$file}{cont},$off,$buf);
}
+sub e_statfs { return 255, 1, 1, 1, 1, 2 }
+
# If you run the script directly, it will run fusermount, which will in turn
# re-run this script. Hence the funky semantics.
my ($mountpoint) = "";
@@ -79,6 +81,7 @@ Fuse::main(
getattr=>\&e_getattr,
getdir=>\&e_getdir,
open=>\&e_open,
+ statfs=>\&e_statfs,
#read=>\&e_read,
#debug=>1, threaded=>0
);