This commit is contained in:
rsc 2006-07-23 03:02:03 +00:00
parent 30f8beab32
commit 5551e51d2b
7 changed files with 2395 additions and 0 deletions

62
man/man4/9pfuse.4 Normal file
View file

@ -0,0 +1,62 @@
.TH 9PFUSE 4
.SH NAME
9pfuse \- mount 9P service via FUSE
.SH SYNOPSIS
.B 9pfuse
[
.B -D
]
[
.B -a
.I t
]
[
.B -e
.I t
]
.I addr
.I mtpt
.SH DESCRIPTION
.I 9pfuse
mounts the 9P service running at
.I addr
onto
.I mtpt
using the FUSE user-level file system driver.
.PP
.I 9pfuse
sets up the initial mount and then forks itself
into the background, where it serves the FUSE
protocol, translating the requests into 9P.
.PP
The options are:
.TP
.B -D
Print each FUSE and 9P message to standard error.
.TP
.B -a\fI t
Set the kernel cache timeout for attribute information
to
.I t
(default 1.0) seconds.
.TP
.B -e\fI t
Set the kernel cache timeout for directory entries to
.I t
(default 1.0) seconds.
.PD
.PP
The
.I fusermount
binary must exist in the current search path.
.PP
FUSE is available for Linux 2.4.21 and later,
Linux 2.6, and FreeBSD 6.x and later.
.SH SEE ALSO
FUSE Homepage,
.HR http://fuse.sourceforge.net
.PP
FUSE for FreeBSD,
.HR http://fuse4bsd.creo.hu
.SH SOURCE
.B \*9/src/cmd/9pfuse

17
src/cmd/9pfuse/COPYRIGHT Normal file
View file

@ -0,0 +1,17 @@
The files in this directory are subject to the following license.
The author of this software is Russ Cox.
Copyright (c) 2006 Russ Cox
Permission to use, copy, modify, and distribute this software for any
purpose without fee is hereby granted, provided that this entire notice
is included in all copies of any software which is or includes a copy
or modification of this software and in all copies of the supporting
documentation for such software.
THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
FITNESS FOR ANY PARTICULAR PURPOSE.

51
src/cmd/9pfuse/a.h Normal file
View file

@ -0,0 +1,51 @@
#include <u.h>
#include <errno.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9pclient.h>
#include "fuse_kernel.h"
/* Somehow the FUSE guys forgot to define this one! */
struct fuse_create_out {
struct fuse_entry_out e;
struct fuse_open_out o;
};
typedef struct FuseMsg FuseMsg;
struct FuseMsg
{
FuseMsg *next;
uchar *buf;
int nbuf;
struct fuse_in_header *hdr; /* = buf */
void *tx; /* = hdr+1 */
};
extern int debug;
extern int fusefd;
extern int fuseeof;
extern int fusebufsize;
extern int fusemaxwrite;
extern FuseMsg *fusemsglist;
extern char *fusemtpt;
void freefusemsg(FuseMsg *m);
int fusefmt(Fmt*);
void initfuse(char *mtpt);
FuseMsg* readfusemsg(void);
void replyfuse(FuseMsg *m, void *arg, int narg);
void replyfuseerrno(FuseMsg *m, int e);
void replyfuseerrstr(FuseMsg*);
void request9p(Fcall *tx);
void* emalloc(size_t n);
void* erealloc(void *p, size_t n);
char* estrdup(char *p);
int errstr2errno(void);
void unmountatexit(void);

772
src/cmd/9pfuse/fuse.c Normal file
View file

@ -0,0 +1,772 @@
#include "a.h"
int fusefd;
int fuseeof;
int fusebufsize;
int fusemaxwrite;
FuseMsg *fusemsglist;
FuseMsg*
allocfusemsg(void)
{
FuseMsg *m;
void *vbuf;
if((m = fusemsglist) != nil){
fusemsglist = m->next;
return m;
}
m = emalloc(sizeof(*m) + fusebufsize);
vbuf = m+1;
m->buf = vbuf;
m->nbuf = 0;
m->hdr = vbuf;
m->tx = m->hdr+1;
return m;
}
void
freefusemsg(FuseMsg *m)
{
m->next = fusemsglist;
fusemsglist = m;
}
FuseMsg*
readfusemsg(void)
{
FuseMsg *m;
int n;
m = allocfusemsg();
errno = 0;
/*
* The FUSE kernel device apparently guarantees
* that this read will return exactly one message.
* You get an error return if you ask for just the
* length (first 4 bytes).
* FUSE returns an ENODEV error, not EOF,
* when the connection is unmounted.
*/
if((n = read(fusefd, m->buf, fusebufsize)) < 0){
if(errno != ENODEV)
sysfatal("readfusemsg: %r");
}
if(n <= 0){
fuseeof = 1;
freefusemsg(m);
return nil;
}
m->nbuf = n;
if(m->hdr->len != n)
sysfatal("readfusemsg: got %d wanted %d",
n, m->hdr->len);
m->hdr->len -= sizeof(m->hdr);
/*
* Paranoia.
* Make sure lengths are long enough.
* Make sure string arguments are NUL terminated.
* (I don't trust the kernel module.)
*/
switch(m->hdr->opcode){
default:
/*
* Could sysfatal here, but can also let message go
* and assume higher-level code will return an
* "I don't know what you mean" error and recover.
*/
break;
case FUSE_LOOKUP:
case FUSE_UNLINK:
case FUSE_RMDIR:
case FUSE_REMOVEXATTR:
/* just a string */
if(((char*)m->tx)[m->hdr->len-1] != 0)
bad:
sysfatal("readfusemsg: bad message");
break;
case FUSE_FORGET:
if(m->hdr->len < sizeof(struct fuse_forget_in))
goto bad;
break;
case FUSE_GETATTR:
break;
case FUSE_SETATTR:
if(m->hdr->len < sizeof(struct fuse_setattr_in))
goto bad;
break;
case FUSE_READLINK:
break;
case FUSE_SYMLINK:
/* two strings */
if(((char*)m->tx)[m->hdr->len-1] != 0
|| memchr(m->tx, 0, m->hdr->len-1) == 0)
goto bad;
break;
case FUSE_MKNOD:
if(m->hdr->len <= sizeof(struct fuse_mknod_in)
|| ((char*)m->tx)[m->hdr->len-1] != 0)
goto bad;
break;
case FUSE_MKDIR:
if(m->hdr->len <= sizeof(struct fuse_mkdir_in)
|| ((char*)m->tx)[m->hdr->len-1] != 0)
goto bad;
break;
case FUSE_RENAME:
/* a struct and two strings */
if(m->hdr->len <= sizeof(struct fuse_rename_in)
|| ((char*)m->tx)[m->hdr->len-1] != 0
|| memchr((uchar*)m->tx+sizeof(struct fuse_rename_in), 0, m->hdr->len-sizeof(struct fuse_rename_in)-1) == 0)
goto bad;
break;
case FUSE_LINK:
if(m->hdr->len <= sizeof(struct fuse_link_in)
|| ((char*)m->tx)[m->hdr->len-1] != 0)
goto bad;
break;
case FUSE_OPEN:
case FUSE_OPENDIR:
if(m->hdr->len < sizeof(struct fuse_open_in))
goto bad;
break;
case FUSE_READ:
case FUSE_READDIR:
if(m->hdr->len < sizeof(struct fuse_read_in))
goto bad;
break;
case FUSE_WRITE:
/* no strings, but check that write length is sane */
if(m->hdr->len < sizeof(struct fuse_write_in)+((struct fuse_write_in*)m->tx)->size)
goto bad;
break;
case FUSE_STATFS:
break;
case FUSE_RELEASE:
case FUSE_RELEASEDIR:
if(m->hdr->len < sizeof(struct fuse_release_in))
goto bad;
break;
case FUSE_FSYNC:
case FUSE_FSYNCDIR:
if(m->hdr->len < sizeof(struct fuse_fsync_in))
goto bad;
break;
case FUSE_SETXATTR:
/* struct and two strings */
if(m->hdr->len <= sizeof(struct fuse_setxattr_in)
|| ((char*)m->tx)[m->hdr->len-1] != 0
|| memchr((uchar*)m->tx+sizeof(struct fuse_setxattr_in), 0, m->hdr->len-sizeof(struct fuse_setxattr_in)-1) == 0)
goto bad;
break;
case FUSE_GETXATTR:
/* struct and one string */
if(m->hdr->len <= sizeof(struct fuse_getxattr_in)
|| ((char*)m->tx)[m->hdr->len-1] != 0)
goto bad;
break;
case FUSE_LISTXATTR:
if(m->hdr->len < sizeof(struct fuse_getxattr_in))
goto bad;
break;
case FUSE_FLUSH:
if(m->hdr->len < sizeof(struct fuse_flush_in))
goto bad;
break;
case FUSE_INIT:
if(m->hdr->len < sizeof(struct fuse_init_in))
goto bad;
break;
case FUSE_ACCESS:
if(m->hdr->len < sizeof(struct fuse_access_in))
goto bad;
break;
case FUSE_CREATE:
if(m->hdr->len <= sizeof(struct fuse_open_in)
|| ((char*)m->tx)[m->hdr->len-1] != 0)
goto bad;
break;
}
if(debug)
fprint(2, "FUSE -> %G\n", m->hdr, m->tx);
return m;
}
/*
* Reply to FUSE request m using additonal
* argument buffer arg of size narg bytes.
* Perhaps should free the FuseMsg here?
*/
void
replyfuse(FuseMsg *m, void *arg, int narg)
{
struct iovec vec[2];
struct fuse_out_header hdr;
int nvec;
hdr.len = sizeof hdr + narg;
hdr.error = 0;
hdr.unique = m->hdr->unique;
if(debug)
fprint(2, "FUSE <- %#G\n", m->hdr, &hdr, arg);
vec[0].iov_base = &hdr;
vec[0].iov_len = sizeof hdr;
nvec = 1;
if(arg && narg){
vec[1].iov_base = arg;
vec[1].iov_len = narg;
nvec++;
}
if(writev(fusefd, vec, nvec) < 0)
sysfatal("replyfuse: %r");
}
/*
* Reply to FUSE request m with errno e.
*/
void
replyfuseerrno(FuseMsg *m, int e)
{
struct fuse_out_header hdr;
hdr.len = sizeof hdr;
hdr.error = -e; /* FUSE sends negative errnos. */
hdr.unique = m->hdr->unique;
if(debug)
fprint(2, "FUSE <- %#G\n", m->hdr, &hdr, 0);
if(write(fusefd, &hdr, sizeof hdr) < 0)
sysfatal("replyfuseerror: %r");
}
void
replyfuseerrstr(FuseMsg *m)
{
replyfuseerrno(m, errstr2errno());
}
/*
* Mounts a fuse file system on mtpt and returns
* a file descriptor for the corresponding fuse
* message conversation.
*/
int
mountfuse(char *mtpt)
{
int p[2], pid, fd;
char buf[20];
if(socketpair(AF_UNIX, SOCK_STREAM, 0, p) < 0)
return -1;
pid = fork();
if(pid < 0)
return -1;
if(pid == 0){
close(p[1]);
snprint(buf, sizeof buf, "%d", p[0]);
putenv("_FUSE_COMMFD", buf);
execlp("fusermount", "fusermount", "--", mtpt, nil);
fprint(2, "exec fusermount: %r\n");
_exit(1);
}
close(p[0]);
fd = recvfd(p[1]);
close(p[1]);
waitpid();
return fd;
}
void
unmountfuse(char *mtpt)
{
int pid;
pid = fork();
if(pid < 0)
return;
if(pid == 0){
atexitdont(unmountatexit);
execlp("fusermount", "fusermount", "-u", "-z", "--", mtpt, nil);
fprint(2, "exec fusermount -u: %r\n");
_exit(1);
}
waitpid();
}
char *fusemtpt;
void
unmountatexit(void)
{
if(fusemtpt)
unmountfuse(fusemtpt);
}
void
initfuse(char *mtpt)
{
FuseMsg *m;
struct fuse_init_in *tx;
struct fuse_init_out rx;
fusemtpt = mtpt;
/*
* The 4096 is for the message headers.
* It's a lot, but it's what the FUSE libraries ask for.
*/
fusemaxwrite = getpagesize();
fusebufsize = 4096 + fusemaxwrite;
if((fusefd = mountfuse(mtpt)) < 0)
sysfatal("mountfuse: %r");
if((m = readfusemsg()) == nil)
sysfatal("readfusemsg: %r");
if(m->hdr->opcode != FUSE_INIT)
sysfatal("fuse: expected FUSE_INIT (26) got %d", m->hdr->opcode);
tx = m->tx;
/*
* Complain if the kernel is too new.
* We could forge ahead, but at least the one time I tried,
* the kernel rejected the newer version by making the
* writev fail in replyfuse, which is a much more confusing
* error message. In the future, might be nice to try to
* support older versions that differ only slightly.
*/
if(tx->major < FUSE_KERNEL_VERSION
|| (tx->major == FUSE_KERNEL_VERSION && tx->minor < FUSE_KERNEL_MINOR_VERSION))
sysfatal("fuse: too kernel version %d.%d older than program version %d.%d",
tx->major, tx->minor, FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
memset(&rx, 0, sizeof rx);
rx.major = FUSE_KERNEL_VERSION;
rx.minor = FUSE_KERNEL_MINOR_VERSION;
rx.max_write = fusemaxwrite;
replyfuse(m, &rx, sizeof rx);
freefusemsg(m);
}
/*
* Print FUSE messages. Assuming it is installed as %G,
* use %G with hdr, arg arguments to format a request,
* and %#G with reqhdr, hdr, arg arguments to format a response.
* The reqhdr is necessary in the %#G form because the
* response does not contain an opcode tag.
*/
int
fusefmt(Fmt *fmt)
{
struct fuse_in_header *hdr = va_arg(fmt->args, void*);
if((fmt->flags&FmtSharp) == 0){ /* "%G", hdr, arg */
void *a = va_arg(fmt->args, void*);
fmtprint(fmt, "len %d unique %#llux uid %d gid %d pid %d ",
hdr->len, hdr->unique, hdr->uid, hdr->gid, hdr->pid);
switch(hdr->opcode){
default: {
fmtprint(fmt, "??? opcode %d", hdr->opcode);
break;
}
case FUSE_LOOKUP: {
fmtprint(fmt, "Lookup nodeid %#llux name %#q",
hdr->nodeid, a);
break;
}
case FUSE_FORGET: {
struct fuse_forget_in *tx = a;
/* nlookup (a ref count) is a vlong! */
fmtprint(fmt, "Forget nodeid %#llux nlookup %lld",
hdr->nodeid, tx->nlookup);
break;
}
case FUSE_GETATTR: {
fmtprint(fmt, "Getattr nodeid %#llux", hdr->nodeid);
break;
}
case FUSE_SETATTR: {
struct fuse_setattr_in *tx = a;
fmtprint(fmt, "Setattr nodeid %#llux", hdr->nodeid);
if(tx->valid&FATTR_FH)
fmtprint(fmt, " fh %#llux", tx->fh);
if(tx->valid&FATTR_SIZE)
fmtprint(fmt, " size %lld", tx->size);
if(tx->valid&FATTR_ATIME)
fmtprint(fmt, " atime %.20g", tx->atime+tx->atimensec*1e-9);
if(tx->valid&FATTR_MTIME)
fmtprint(fmt, " mtime %.20g", tx->mtime+tx->mtimensec*1e-9);
if(tx->valid&FATTR_MODE)
fmtprint(fmt, " mode %#uo", tx->mode);
if(tx->valid&FATTR_UID)
fmtprint(fmt, " uid %d", tx->uid);
if(tx->valid&FATTR_GID)
fmtprint(fmt, " gid %d", tx->gid);
break;
}
case FUSE_READLINK: {
fmtprint(fmt, "Readlink nodeid %#llux", hdr->nodeid);
break;
}
case FUSE_SYMLINK: {
char *old, *new;
old = a;
new = a + strlen(a) + 1;
fmtprint(fmt, "Symlink nodeid %#llux old %#q new %#q",
hdr->nodeid, old, new);
break;
}
case FUSE_MKNOD: {
struct fuse_mknod_in *tx = a;
fmtprint(fmt, "Mknod nodeid %#llux mode %#uo rdev %#ux name %#q",
hdr->nodeid, tx->mode, tx->rdev, tx+1);
break;
}
case FUSE_MKDIR: {
struct fuse_mkdir_in *tx = a;
fmtprint(fmt, "Mkdir nodeid %#llux mode %#uo name %#q",
hdr->nodeid, tx->mode, tx+1);
break;
}
case FUSE_UNLINK: {
fmtprint(fmt, "Unlink nodeid %#llux name %#q",
hdr->nodeid, a);
break;
}
case FUSE_RMDIR: {
fmtprint(fmt, "Rmdir nodeid %#llux name %#q",
hdr->nodeid, a);
break;
}
case FUSE_RENAME: {
struct fuse_rename_in *tx = a;
char *old = (char*)(tx+1);
char *new = old + strlen(old) + 1;
fmtprint(fmt, "Rename nodeid %#llux old %#q newdir %#llux new %#q",
hdr->nodeid, old, tx->newdir, new);
break;
}
case FUSE_LINK: {
struct fuse_link_in *tx = a;
fmtprint(fmt, "Link oldnodeid %#llux nodeid %#llux name %#q",
tx->oldnodeid, hdr->nodeid, tx+1);
break;
}
case FUSE_OPEN: {
struct fuse_open_in *tx = a;
/* Should one or both of flags and mode be octal? */
fmtprint(fmt, "Open nodeid %#llux flags %#ux mode %#ux",
hdr->nodeid, tx->flags, tx->mode);
break;
}
case FUSE_READ: {
struct fuse_read_in *tx = a;
fmtprint(fmt, "Read nodeid %#llux fh %#llux offset %lld size %ud",
hdr->nodeid, tx->fh, tx->offset, tx->size);
break;
}
case FUSE_WRITE: {
struct fuse_write_in *tx = a;
fmtprint(fmt, "Write nodeid %#llux fh %#llux offset %lld size %ud flags %#ux",
hdr->nodeid, tx->fh, tx->offset, tx->size, tx->write_flags);
break;
}
case FUSE_STATFS: {
fmtprint(fmt, "Statfs");
break;
}
case FUSE_RELEASE: {
struct fuse_release_in *tx = a;
fmtprint(fmt, "Release nodeid %#llux fh %#llux flags %#ux",
hdr->nodeid, tx->fh, tx->flags);
break;
}
case FUSE_FSYNC: {
struct fuse_fsync_in *tx = a;
fmtprint(fmt, "Fsync nodeid %#llux fh %#llux flags %#ux",
hdr->nodeid, tx->fh, tx->fsync_flags);
break;
}
case FUSE_SETXATTR: {
struct fuse_setxattr_in *tx = a;
char *name = (char*)(tx+1);
char *value = name + strlen(name) + 1;
fmtprint(fmt, "Setxattr nodeid %#llux size %d flags %#ux name %#q value %#q",
hdr->nodeid, tx->size, tx->flags, name, value);
break;
}
case FUSE_GETXATTR: {
struct fuse_getxattr_in *tx = a;
fmtprint(fmt, "Getxattr nodeid %#llux size %d name %#q",
hdr->nodeid, tx->size, tx+1);
break;
}
case FUSE_LISTXATTR: {
struct fuse_getxattr_in *tx = a;
fmtprint(fmt, "Listxattr nodeid %#llux size %d",
hdr->nodeid, tx->size);
break;
}
case FUSE_REMOVEXATTR: {
fmtprint(fmt, "Removexattr nodeid %#llux name %#q",
hdr->nodeid, a);
break;
}
case FUSE_FLUSH: {
struct fuse_flush_in *tx = a;
fmtprint(fmt, "Flush nodeid %#llux fh %#llux flags %#ux",
hdr->nodeid, tx->fh, tx->flush_flags);
break;
}
case FUSE_INIT: {
struct fuse_init_in *tx = a;
fmtprint(fmt, "Init major %d minor %d",
tx->major, tx->minor);
break;
}
case FUSE_OPENDIR: {
struct fuse_open_in *tx = a;
fmtprint(fmt, "Opendir nodeid %#llux flags %#ux mode %#ux",
hdr->nodeid, tx->flags, tx->mode);
break;
}
case FUSE_READDIR: {
struct fuse_read_in *tx = a;
fmtprint(fmt, "Readdir nodeid %#llux fh %#llux offset %lld size %ud",
hdr->nodeid, tx->fh, tx->offset, tx->size);
break;
}
case FUSE_RELEASEDIR: {
struct fuse_release_in *tx = a;
fmtprint(fmt, "Releasedir nodeid %#llux fh %#llux flags %#ux",
hdr->nodeid, tx->fh, tx->flags);
break;
}
case FUSE_FSYNCDIR: {
struct fuse_fsync_in *tx = a;
fmtprint(fmt, "Fsyncdir nodeid %#llux fh %#llux flags %#ux",
hdr->nodeid, tx->fh, tx->fsync_flags);
break;
}
case FUSE_ACCESS: {
struct fuse_access_in *tx = a;
fmtprint(fmt, "Access nodeid %#llux mask %#ux",
hdr->nodeid, tx->mask);
break;
}
case FUSE_CREATE: {
struct fuse_open_in *tx = a;
fmtprint(fmt, "Create nodeid %#llx flags %#ux mode %#ux name %#q",
hdr->nodeid, tx->flags, tx->mode, tx+1);
break;
}
}
}else{ /* "%#G", reqhdr, hdr, arg - use reqhdr only for type */
struct fuse_out_header *ohdr = va_arg(fmt->args, void*);
void *a = va_arg(fmt->args, void*);
int len = ohdr->len - sizeof *ohdr;
fmtprint(fmt, "unique %#llux ", ohdr->unique);
if(ohdr->error){
fmtprint(fmt, "error %d %s", ohdr->error, strerror(-ohdr->error));
}else
switch(hdr->opcode){
default: {
fmtprint(fmt, "??? opcode %d", hdr->opcode);
break;
}
case FUSE_LOOKUP: {
/*
* For a negative entry, can send back ENOENT
* or rx->ino == 0.
* In protocol version 7.4 and before, can only use
* the ENOENT method.
* Presumably the benefit of sending rx->ino == 0
* is that you can specify the length of time to cache
* the negative result.
*/
struct fuse_entry_out *rx;
fmtprint(fmt, "(Lookup) ");
fmt_entry_out:
rx = a;
fmtprint(fmt, "nodeid %#llux gen %#llux entry_valid %.20g attr_valid %.20g ",
rx->nodeid, rx->generation,
rx->entry_valid+rx->entry_valid_nsec*1e-9,
rx->attr_valid+rx->attr_valid_nsec*1e-9);
fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux",
rx->attr.ino, rx->attr.size, rx->attr.blocks,
rx->attr.atime+rx->attr.atimensec*1e-9,
rx->attr.mtime+rx->attr.mtimensec*1e-9,
rx->attr.ctime+rx->attr.ctimensec*1e-9,
rx->attr.mode, rx->attr.nlink, rx->attr.uid,
rx->attr.gid, rx->attr.rdev);
break;
}
case FUSE_FORGET: {
/* Can't happen! No reply. */
fmtprint(fmt, "(Forget) can't happen");
break;
}
case FUSE_GETATTR: {
struct fuse_attr_out *rx;
fmtprint(fmt, "(Getattr) ");
fmt_attr_out:
rx = a;
fmtprint(fmt, "attr_valid %.20g",
rx->attr_valid+rx->attr_valid_nsec*1e-9);
fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux",
rx->attr.ino, rx->attr.size, rx->attr.blocks,
rx->attr.atime+rx->attr.atimensec*1e-9,
rx->attr.mtime+rx->attr.mtimensec*1e-9,
rx->attr.ctime+rx->attr.ctimensec*1e-9,
rx->attr.mode, rx->attr.nlink, rx->attr.uid,
rx->attr.gid, rx->attr.rdev);
break;
}
case FUSE_SETATTR: {
fmtprint(fmt, "(Setattr) ");
goto fmt_attr_out;
break;
}
case FUSE_READLINK: {
fmtprint(fmt, "(Readlink) %#.*q",
utfnlen(a, len), a);
break;
}
case FUSE_SYMLINK: {
fmtprint(fmt, "(Symlink) ");
goto fmt_entry_out;
break;
}
case FUSE_MKNOD: {
fmtprint(fmt, "(Mknod) ");
goto fmt_entry_out;
break;
}
case FUSE_MKDIR: {
fmtprint(fmt, "(Mkdir) ");
goto fmt_entry_out;
break;
}
case FUSE_UNLINK: {
fmtprint(fmt, "(Unlink)");
break;
}
case FUSE_RMDIR: {
fmtprint(fmt, "(Rmdir)");
break;
}
case FUSE_RENAME: {
fmtprint(fmt, "(Rename)");
break;
}
case FUSE_LINK: {
fmtprint(fmt, "(Link) ");
goto fmt_entry_out;
break;
}
case FUSE_OPEN: {
struct fuse_open_out *rx;
fmtprint(fmt, "(Open) ");
fmt_open_out:
rx = a;
fmtprint(fmt, "fh %#llux flags %#ux", rx->fh, rx->open_flags);
break;
}
case FUSE_READ: {
fmtprint(fmt, "(Read) size %d", len);
break;
}
case FUSE_WRITE: {
struct fuse_write_out *rx = a;
fmtprint(fmt, "(Write) size %d", rx->size);
break;
}
case FUSE_STATFS: {
/*
* Before protocol version 7.4, only first 48 bytes are used.
*/
struct fuse_statfs_out *rx = a;
fmtprint(fmt, "(Statfs) blocks %lld bfree %lld bavail %lld files %lld ffree %lld bsize %ud namelen %ud frsize %ud",
rx->st.blocks, rx->st.bfree, rx->st.bavail,
rx->st.files, rx->st.ffree, rx->st.bsize,
rx->st.namelen, rx->st.frsize);
break;
}
case FUSE_RELEASE: {
fmtprint(fmt, "(Release)");
break;
}
case FUSE_FSYNC: {
fmtprint(fmt, "(Fsync)");
break;
}
case FUSE_SETXATTR: {
fmtprint(fmt, "(Serxattr)");
break;
}
case FUSE_GETXATTR: {
fmtprint(fmt, "(Getxattr) size %d", len);
break;
}
case FUSE_LISTXATTR: {
fmtprint(fmt, "(Lisrxattr) size %d", len);
break;
}
case FUSE_REMOVEXATTR: {
fmtprint(fmt, "(Removexattr)");
break;
}
case FUSE_FLUSH: {
fmtprint(fmt, "(Flush)");
break;
}
case FUSE_INIT: {
struct fuse_init_out *rx = a;
fmtprint(fmt, "(Init) major %d minor %d max_write %d",
rx->major, rx->minor, rx->max_write);
break;
}
case FUSE_OPENDIR: {
fmtprint(fmt, "(Opendir) ");
goto fmt_open_out;
break;
}
case FUSE_READDIR: {
fmtprint(fmt, "(Readdir) size %d", len);
break;
}
case FUSE_RELEASEDIR: {
fmtprint(fmt, "(Releasedir)");
break;
}
case FUSE_FSYNCDIR: {
fmtprint(fmt, "(Fsyncdir)");
break;
}
case FUSE_ACCESS: {
fmtprint(fmt, "(Access)");
break;
}
case FUSE_CREATE: {
struct fuse_create_out *rx = a;
fmtprint(fmt, "(Create) ");
fmtprint(fmt, "nodeid %#llux gen %#llux entry_valid %.20g attr_valid %.20g ",
rx->e.nodeid, rx->e.generation,
rx->e.entry_valid+rx->e.entry_valid_nsec*1e-9,
rx->e.attr_valid+rx->e.attr_valid_nsec*1e-9);
fmtprint(fmt, " ino %#llux size %lld blocks %lld atime %.20g mtime %.20g ctime %.20g mode %#uo nlink %d uid %d gid %d rdev %#ux",
rx->e.attr.ino, rx->e.attr.size, rx->e.attr.blocks,
rx->e.attr.atime+rx->e.attr.atimensec*1e-9,
rx->e.attr.mtime+rx->e.attr.mtimensec*1e-9,
rx->e.attr.ctime+rx->e.attr.ctimensec*1e-9,
rx->e.attr.mode, rx->e.attr.nlink, rx->e.attr.uid,
rx->e.attr.gid, rx->e.attr.rdev);
fmtprint(fmt, " fh %#llux flags %#ux", rx->o.fh, rx->o.open_flags);
break;
}
}
}
return 0;
}

View file

@ -0,0 +1,312 @@
/* This file defines the kernel interface of FUSE */
/*
This -- and only this -- header file may also be distributed under
the terms of the BSD Licence as follows:
Copyright (C) 2001-2006 Miklos Szeredi. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
/* RSC changed these lines */
#include <inttypes.h>
#define __u64 uint64_t
#define __u32 uint32_t
#define __s32 int32_t
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 5
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
/** The major number of the fuse character device */
#define FUSE_MAJOR 10
/** The minor number of the fuse character device */
#define FUSE_MINOR 229
/* Make sure all structures are padded to 64bit boundary, so 32bit
userspace works under 64bit kernels */
struct fuse_attr {
__u64 ino;
__u64 size;
__u64 blocks;
__u64 atime;
__u64 mtime;
__u64 ctime;
__u32 atimensec;
__u32 mtimensec;
__u32 ctimensec;
__u32 mode;
__u32 nlink;
__u32 uid;
__u32 gid;
__u32 rdev;
};
struct fuse_kstatfs {
__u64 blocks;
__u64 bfree;
__u64 bavail;
__u64 files;
__u64 ffree;
__u32 bsize;
__u32 namelen;
__u32 frsize;
__u32 padding;
__u32 spare[6];
};
#define FATTR_MODE (1 << 0)
#define FATTR_UID (1 << 1)
#define FATTR_GID (1 << 2)
#define FATTR_SIZE (1 << 3)
#define FATTR_ATIME (1 << 4)
#define FATTR_MTIME (1 << 5)
#define FATTR_FH (1 << 6)
/**
* Flags returned by the OPEN request
*
* FOPEN_DIRECT_IO: bypass page cache for this open file
* FOPEN_KEEP_CACHE: don't invalidate the data cache on open
*/
#define FOPEN_DIRECT_IO (1 << 0)
#define FOPEN_KEEP_CACHE (1 << 1)
enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
FUSE_GETATTR = 3,
FUSE_SETATTR = 4,
FUSE_READLINK = 5,
FUSE_SYMLINK = 6,
FUSE_MKNOD = 8,
FUSE_MKDIR = 9,
FUSE_UNLINK = 10,
FUSE_RMDIR = 11,
FUSE_RENAME = 12,
FUSE_LINK = 13,
FUSE_OPEN = 14,
FUSE_READ = 15,
FUSE_WRITE = 16,
FUSE_STATFS = 17,
FUSE_RELEASE = 18,
FUSE_FSYNC = 20,
FUSE_SETXATTR = 21,
FUSE_GETXATTR = 22,
FUSE_LISTXATTR = 23,
FUSE_REMOVEXATTR = 24,
FUSE_FLUSH = 25,
FUSE_INIT = 26,
FUSE_OPENDIR = 27,
FUSE_READDIR = 28,
FUSE_RELEASEDIR = 29,
FUSE_FSYNCDIR = 30,
FUSE_ACCESS = 34,
FUSE_CREATE = 35
};
/* The read buffer is required to be at least 8k, but may be much larger */
#define FUSE_MIN_READ_BUFFER 8192
struct fuse_entry_out {
__u64 nodeid; /* Inode ID */
__u64 generation; /* Inode generation: nodeid:gen must
be unique for the fs's lifetime */
__u64 entry_valid; /* Cache timeout for the name */
__u64 attr_valid; /* Cache timeout for the attributes */
__u32 entry_valid_nsec;
__u32 attr_valid_nsec;
struct fuse_attr attr;
};
struct fuse_forget_in {
__u64 nlookup;
};
struct fuse_attr_out {
__u64 attr_valid; /* Cache timeout for the attributes */
__u32 attr_valid_nsec;
__u32 dummy;
struct fuse_attr attr;
};
struct fuse_mknod_in {
__u32 mode;
__u32 rdev;
};
struct fuse_mkdir_in {
__u32 mode;
__u32 padding;
};
struct fuse_rename_in {
__u64 newdir;
};
struct fuse_link_in {
__u64 oldnodeid;
};
struct fuse_setattr_in {
__u32 valid;
__u32 padding;
__u64 fh;
__u64 size;
__u64 unused1;
__u64 atime;
__u64 mtime;
__u64 unused2;
__u32 atimensec;
__u32 mtimensec;
__u32 unused3;
__u32 mode;
__u32 unused4;
__u32 uid;
__u32 gid;
__u32 unused5;
};
struct fuse_open_in {
__u32 flags;
__u32 mode;
};
struct fuse_open_out {
__u64 fh;
__u32 open_flags;
__u32 padding;
};
struct fuse_release_in {
__u64 fh;
__u32 flags;
__u32 padding;
};
struct fuse_flush_in {
__u64 fh;
__u32 flush_flags;
__u32 padding;
};
struct fuse_read_in {
__u64 fh;
__u64 offset;
__u32 size;
__u32 padding;
};
struct fuse_write_in {
__u64 fh;
__u64 offset;
__u32 size;
__u32 write_flags;
};
struct fuse_write_out {
__u32 size;
__u32 padding;
};
#define FUSE_COMPAT_STATFS_SIZE 48
struct fuse_statfs_out {
struct fuse_kstatfs st;
};
struct fuse_fsync_in {
__u64 fh;
__u32 fsync_flags;
__u32 padding;
};
struct fuse_setxattr_in {
__u32 size;
__u32 flags;
};
struct fuse_getxattr_in {
__u32 size;
__u32 padding;
};
struct fuse_getxattr_out {
__u32 size;
__u32 padding;
};
struct fuse_access_in {
__u32 mask;
__u32 padding;
};
struct fuse_init_in {
__u32 major;
__u32 minor;
};
struct fuse_init_out {
__u32 major;
__u32 minor;
__u32 unused[3];
__u32 max_write;
};
struct fuse_in_header {
__u32 len;
__u32 opcode;
__u64 unique;
__u64 nodeid;
__u32 uid;
__u32 gid;
__u32 pid;
__u32 padding;
};
struct fuse_out_header {
__u32 len;
__s32 error;
__u64 unique;
};
/* RSC changed name[0] to name[1] for old C compilers */
struct fuse_dirent {
__u64 ino;
__u64 off;
__u32 namelen;
__u32 type;
char name[1];
};
#define FUSE_NAME_OFFSET ((unsigned) ((struct fuse_dirent *) 0)->name)
#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
#define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)

1169
src/cmd/9pfuse/main.c Normal file

File diff suppressed because it is too large Load diff

12
src/cmd/9pfuse/mkfile Normal file
View file

@ -0,0 +1,12 @@
<$PLAN9/src/mkhdr
TARG=9pfuse
OFILES=\
fuse.$O\
main.$O\
HFILES=a.h
<$PLAN9/src/mkone