Added statfs support to kernel, lib, examples, and perl
authorMark Glines <mark@glines.org>
Mon, 7 Jan 2002 16:32:02 +0000 (16:32 +0000)
committerMark Glines <mark@glines.org>
Mon, 7 Jan 2002 16:32:02 +0000 (16:32 +0000)
other minor perl fixes (still unstable)

13 files changed:
ChangeLog
TODO
example/fusexmp.c
example/hello.c
example/null.c
include/fuse.h
include/linux/fuse.h
kernel/inode.c
lib/fuse.c
perl/.cvsignore [new file with mode: 0644]
perl/Fuse.pm
perl/Fuse.xs
perl/example.pl

index cf7aaa8b0a1f0776794937813c26c60f24e1b6b2..d2a2c0b009facdd98fcecd30448ac9b2db7b02f3 100644 (file)
--- 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 fbf6d70971bf019bed11811f802068f8dda47822..971ea9e011c911e8173c0ed193b0ac7ab67bfe67 100644 (file)
--- a/TODO
+++ b/TODO
@@ -2,6 +2,4 @@
 
  - Integrate (parts of) fusermount into mount(8)
 
- - Statfs operation
-
  - Etc, etc...
index b9df79c861f7cc3193975c767d0e27c238d5110e..b921d56b57bacb2088a2c311812fc7068eac5c6c 100644 (file)
@@ -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[])
index e0010cd92722d99da00f37f06a531730a6333953..ccd4b5f0424ea5944fd2f79383e5431a8002db69 100644 (file)
@@ -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[])
index 7be4ab41cefb7715154554ab64a53ed5aabc6ece..71e9a19de7fe01e9847b98eb570458fed94a5981 100644 (file)
@@ -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[])
index bafa1827dbbc269f96dbd8eb2180696734ad601b..46fc87b83d67a7e5915600250726ff046ab6fe97 100644 (file)
@@ -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 */
index 53cb3f005a20f02d7c9335de32908e07730f5339..40f395043ef0cf08cdf9300ba11749cf3f64230d 100644 (file)
@@ -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;
index 7fc5cfef20ab8f463369fd89de5d27836779bd9a..6c387080fab093cdeaae6160997b3dfd2241f8a8 100644 (file)
@@ -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,
 };
 
 
index 98bab3f4cd3fc73b8af51f00a6aeb6ad5107df5d..88f3eae7d6d159f1cc014505d5f9ffa9a157aaf3 100644 (file)
@@ -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 (file)
index 0000000..5d5c2dc
--- /dev/null
@@ -0,0 +1 @@
+Fuse.bs Fuse.c Makefile blib pm_to_blib
index 93acfb69ea2785c6fdb9bd97d070a260615197d9..3a20fd931f47ccf02d0220a1f6dbcecf720a8cc0 100644 (file)
@@ -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
 
index ca0459d7bfa2424558b6dd61d7372f566dcf4203..6061d9f8f51b3be8b9b3352ae96f48c634a22b54 100644 (file)
@@ -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) {
index bc62cadeffe5743f4b1cb052c0a7b3caeb3f2e67..d01278c3cc309e6477bc7670eafb7ab801010da7 100755 (executable)
@@ -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
 );