diff options
| author | rsc <devnull@localhost> | 2006-07-23 03:02:03 +0000 |
|---|---|---|
| committer | rsc <devnull@localhost> | 2006-07-23 03:02:03 +0000 |
| commit | 5551e51d2b9df4e289ea3cb1350db4d5f5444df2 (patch) | |
| tree | 9374211c6c3d9d18765ccfe4c5895b086a9e6928 /src/cmd/9pfuse/fuse.c | |
| parent | 30f8beab329834c1968c391e35890e3cd9917895 (diff) | |
| download | plan9port-5551e51d2b9df4e289ea3cb1350db4d5f5444df2.tar.gz plan9port-5551e51d2b9df4e289ea3cb1350db4d5f5444df2.zip | |
9pfuse
Diffstat (limited to 'src/cmd/9pfuse/fuse.c')
| -rw-r--r-- | src/cmd/9pfuse/fuse.c | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/src/cmd/9pfuse/fuse.c b/src/cmd/9pfuse/fuse.c new file mode 100644 index 00000000..0e61f72f --- /dev/null +++ b/src/cmd/9pfuse/fuse.c @@ -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; +} + |
