On Tue, Mar 5, 2013 at 3:12 PM, Martin Pieuchot <
mpie...@nolizard.org> wrote:
> It looks to me that Sylvestre wrote it's own ISC-licensed implementation.
>
> Sylvestre that's a lot of work, and a lot of new code :) I'd suggest you
> to send your diff inline (maybe splitting the userland and kernel parts)
> so that people can comment on them.
>
> M.
Martin,
You will find inline the kernel patch
Index: arch/i386/i386/conf.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/conf.c,v
retrieving revision 1.141
diff -u -p -u -p -r1.141 conf.c
--- arch/i386/i386/conf.c 23 Aug 2012 06:12:49 -0000 1.141
+++ arch/i386/i386/conf.c 5 Mar 2013 15:16:08 -0000
@@ -185,6 +185,7 @@ cdev_decl(pci);
#include "amdmsr.h"
#include "vscsi.h"
#include "pppx.h"
+#include "fuse.h"
struct cdevsw cdevsw[] =
{
@@ -293,6 +294,7 @@ struct cdevsw cdevsw[] =
cdev_vscsi_init(NVSCSI,vscsi), /* 90: vscsi */
cdev_disk_init(1,diskmap), /* 91: disk mapper */
cdev_pppx_init(NPPPX,pppx), /* 92: pppx */
+ cdev_fuse_init(NFUSE, fuse), /* 93: fuse */
};
int nchrdev = nitems(cdevsw);
Index: conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/conf/GENERIC,v
retrieving revision 1.194
diff -u -p -u -p -r1.194 GENERIC
--- conf/GENERIC 1 Mar 2013 21:06:04 -0000 1.194
+++ conf/GENERIC 5 Mar 2013 15:16:08 -0000
@@ -45,6 +45,7 @@ option NFSSERVER # Network File System
option CD9660 # ISO 9660 + Rock Ridge file system
option UDF # UDF (DVD) file system
option MSDOSFS # MS-DOS file system
+option FUSE # Userland file system
option FIFO # FIFOs; RECOMMENDED
option SOCKET_SPLICE # Socket Splicing for TCP
@@ -73,6 +74,8 @@ scsibus* at softraid?
vscsi0 at root # Userland backed Virtual SCSI
scsibus* at vscsi?
+
+pseudo-device fuse # filesystem in user land
pseudo-device pf # packet filter
pseudo-device pflog # pf log if
Index: conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.540
diff -u -p -u -p -r1.540 files
--- conf/files 21 Jan 2013 11:17:48 -0000 1.540
+++ conf/files 5 Mar 2013 15:16:09 -0000
@@ -544,6 +544,15 @@ pseudo-device systrace
pseudo-device ksyms
file dev/ksyms.c ksyms needs-flag
+pseudo-device fuse
+file miscfs/fuse/fuse_device.c fuse needs-flag
+file miscfs/fuse/fuse_file.c fuse
+file miscfs/fuse/fuse_lookup.c fuse
+file miscfs/fuse/fuse_node.c fuse
+file miscfs/fuse/fuse_vfsops.c fuse
+file miscfs/fuse/fuse_vnops.c fuse
+file miscfs/fuse/fuse_subr.c fuse
+
pseudo-device pf: ifnet
file net/pf.c pf needs-flag
file net/pf_norm.c pf
Index: kern/vfs_init.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_init.c,v
retrieving revision 1.30
diff -u -p -u -p -r1.30 vfs_init.c
--- kern/vfs_init.c 23 Aug 2012 06:12:49 -0000 1.30
+++ kern/vfs_init.c 5 Mar 2013 15:16:09 -0000
@@ -85,6 +85,10 @@ extern const struct vfsops ntfs_vfsops;
extern const struct vfsops udf_vfsops;
#endif
+#ifdef FUSE
+extern const struct vfsops fusefs_vfsops;
+#endif
+
/* Set up the filesystem operations for vnodes. */
static struct vfsconf vfsconflist[] = {
#ifdef FFS
@@ -121,6 +125,10 @@ static struct vfsconf vfsconflist[] = {
#ifdef UDF
{ &udf_vfsops, MOUNT_UDF, 13, 0, MNT_LOCAL, NULL },
+#endif
+
+#ifdef FUSE
+ { &fusefs_vfsops, MOUNT_FUSEFS, 42, 0, MNT_LOCAL, NULL }, /* put
42 as type, I don't know witch number I can use*/
#endif
};
Index: miscfs/fuse/fuse_device.c
===================================================================
RCS file: miscfs/fuse/fuse_device.c
diff -N miscfs/fuse/fuse_device.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_device.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/poll.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/fcntl.h>
+#include <sys/vnode.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+struct fuse_dev {
+ int opened;
+ int end;
+};
+
+#define FUSE_OPEN 1
+#define FUSE_CLOSE 0
+#define FUSE_DONE 2
+
+static struct fuse_dev *fuse_devs[MAX_FUSE_DEV];
+
+void fuseattach(int);
+int fuseopen(dev_t, int, int, struct proc *);
+int fuseclose(dev_t, int, int, struct proc *);
+int fuseioctl(dev_t, u_long, caddr_t, int, struct proc *);
+int fuseread(dev_t, struct uio *, int);
+int fusewrite(dev_t, struct uio *, int);
+int fusepoll(dev_t, int, struct proc *);
+
+struct fuse_msg_head fmq_in;
+struct fuse_msg_head fmq_wait;
+
+#ifdef FUSE_DEV_DEBUG
+static void
+dump_buff(char *buff, int len)
+{
+ char text[17];
+ int i;
+
+ bzero(text, 17);
+ for (i = 0; i < len ; i++) {
+
+ if (i != 0 && (i % 16) == 0) {
+ printf(": %s\n", text);
+ bzero(text, 17);
+ }
+
+ printf("%.2x ", buff[i] & 0xff);
+
+ if (buff[i] > ' ' && buff[i] < '~')
+ text[i%16] = buff[i] & 0xff;
+ else
+ text[i%16] = '.';
+ }
+
+ if ((i % 16) != 0) {
+ while ((i % 16) != 0) {
+ printf(" ");
+ i++;
+ }
+ }
+ printf(": %s\n", text);
+}
+#endif
+
+void
+fuseattach(int num)
+{
+#ifdef FUSE_DEV_DEBUG
+ printf("fuse0 at root\n");
+#endif
+}
+
+int
+fuseopen(dev_t dev, int flags, int fmt, struct proc * p)
+{
+ if (minor(dev) >= MAX_FUSE_DEV &&
+ fuse_devs[minor(dev)]->opened != FUSE_CLOSE)
+ return (ENXIO);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("open dev %i\n", minor(dev));
+#endif
+
+ fuse_devs[minor(dev)] = malloc(sizeof(*fuse_devs[minor(dev)]),
+ M_FUSEFS, M_WAITOK | M_ZERO);
+ fuse_devs[minor(dev)]->opened = FUSE_OPEN;
+
+ return (0);
+}
+
+int
+fuseclose(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ if (minor(dev) >= MAX_FUSE_DEV)
+ return (ENXIO);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("close dev %i\n", minor(dev));
+#endif
+
+ fuse_devs[minor(dev)]->opened = FUSE_CLOSE;
+ free(fuse_devs[minor(dev)], M_FUSEFS);
+ fuse_devs[minor(dev)] = NULL;
+ return (0);
+}
+
+int
+fuseioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
+{
+ int error = 0;
+
+ switch (cmd) {
+ default:
+ printf("bad ioctl number %d\n", cmd);
+ return ENODEV;
+ }
+
+ return error;
+}
+
+int
+fuseread(dev_t dev, struct uio *uio, int ioflag)
+{
+ int error = 0;
+ struct fuse_msg *msg;
+
+#ifdef FUSE_DEV_DEBUG
+ printf("read 0x%x\n", dev);
+#endif
+
+ if (fuse_devs[minor(dev)]->opened != FUSE_OPEN) {
+ return ENODEV;
+ }
+
+again:
+ if (TAILQ_EMPTY(&fmq_in)) {
+
+ if (ioflag & O_NONBLOCK) {
+ return (EAGAIN);
+ }
+
+ error = tsleep(&fmq_in, PWAIT, "fuse read", 0);
+
+ if (error)
+ return error;
+ }
+ if (TAILQ_EMPTY(&fmq_in))
+ goto again;
+
+ if (!TAILQ_EMPTY(&fmq_in)) {
+ msg = TAILQ_FIRST(&fmq_in);
+
+ if (msg->hdr->opcode == FUSE_DESTROY) {
+#ifdef FUSE_DEV_DEBUG
+ printf("catch done\n");
+#endif
+ fuse_devs[minor(dev)]->opened = FUSE_DONE;
+ }
+
+ error = uiomove(msg->hdr, sizeof(struct fuse_in_header), uio);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("hdr r:\n");
+ dump_buff((char *)msg->hdr, sizeof(struct fuse_in_header));
+#endif
+
+ if (msg->len > 0) {
+ error = uiomove(msg->data, msg->len, uio);
+#ifdef FUSE_DEV_DEBUG
+ printf("data r:\n");
+ dump_buff(msg->data, msg->len);
+#endif
+ }
+
+#ifdef FUSE_DEV_DEBUG
+ printf("msg send : %i\n", msg->len);
+#endif
+
+ if (error)
+ return error;
+
+ /*
+ * msg moves from a tailq to another
+ */
+ TAILQ_REMOVE(&fmq_in, msg, node);
+ TAILQ_INSERT_TAIL(&fmq_wait, msg, node);
+ }
+
+ return error;
+}
+
+int
+fusewrite(dev_t dev, struct uio *uio, int ioflag)
+{
+ struct fuse_out_header hdr;
+ struct fuse_msg *msg;
+ int error = 0;
+ int catched = 0;
+ int len;
+ void *data;
+
+#ifdef FUSE_DEV_DEBUG
+ printf("write %x bytes\n", uio->uio_resid);
+#endif
+
+ if (uio->uio_resid < sizeof(struct fuse_out_header)) {
+ printf("uio goes wrong\n");
+ return (EINVAL);
+ }
+
+ /*
+ * get out header
+ */
+
+ if ((error = uiomove(&hdr, sizeof(struct fuse_out_header), uio)) != 0){
+ printf("uiomove failed\n");
+ return (error);
+ }
+#ifdef FUSE_DEV_DEBUG
+ printf("hdr w:\n");
+ dump_buff((char *)&hdr, sizeof(struct fuse_out_header));
+#endif
+ /*
+ * check header validity
+ */
+ if (uio->uio_resid + sizeof(struct fuse_out_header) != hdr.len ||
+ (uio->uio_resid && hdr.error) || TAILQ_EMPTY(&fmq_wait) ) {
+ printf("corrupted fuse header or queue empty\n");
+ return (EINVAL);
+ }
+
+ /* fuse errno are negative */
+ if (hdr.error)
+ hdr.error = -(hdr.error);
+
+ TAILQ_FOREACH(msg, &fmq_wait, node) {
+ if (msg->hdr->unique == hdr.unique) {
+#ifdef FUSE_DEV_DEBUG
+ printf("catch unique %i\n", msg->hdr->unique);
+#endif
+ catched = 1;
+ break;
+ }
+ }
+
+ if (catched) {
+ if (uio->uio_resid > 0) {
+ len = uio->uio_resid;
+ data = malloc(len, M_FUSEFS, M_WAITOK);
+ error = uiomove(data, len, uio);
+
+#ifdef FUSE_DEV_DEBUG
+ printf("data w:\n");
+ dump_buff(data, len);
+#endif
+
+ } else {
+ data = NULL;
+ }
+
+#ifdef FUSE_DEV_DEBUG
+ printf("call callback\n");
+#endif
+
+ if (!error)
+ msg->cb(msg, &hdr, data);
+
+ TAILQ_REMOVE(&fmq_wait, msg, node);
+
+ if (msg->type == msg_buff_async) {
+ free(msg->hdr, M_FUSEFS);
+ free(msg, M_FUSEFS);
+
+ if (data)
+ free(data, M_FUSEFS);
+ }
+
+ } else {
+ error = EINVAL;
+ }
+
+ return error;
+}
+
+int
+fusepoll(dev_t dev, int events, struct proc *p)
+{
+ int revents = 0;
+
+#ifdef FUSE_DEV_DEBUG
+ printf("fuse poll\n");
+#endif
+
+ if (events & (POLLIN | POLLRDNORM)) {
+ if (!TAILQ_EMPTY(&fmq_in))
+ revents |= events & (POLLIN | POLLRDNORM);
+ }
+
+ if (events & (POLLOUT | POLLWRNORM))
+ revents |= events & (POLLOUT | POLLWRNORM);
+
+ return (revents);
+}
Index: miscfs/fuse/fuse_file.c
===================================================================
RCS file: miscfs/fuse/fuse_file.c
diff -N miscfs/fuse/fuse_file.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_file.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+int
+fuse_file_open(struct fuse_mnt *fmp, struct fuse_node *ip,
+ enum fufh_type fufh_type, int flags, int isdir)
+{
+ struct fuse_open_out *open_out;
+ struct fuse_open_in open_in;
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ int error;
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.data = &open_in;
+ msg.len = sizeof(open_in);
+ msg.cb = &fuse_sync_resp;
+ msg.fmp = fmp;
+ msg.type = msg_buff;
+
+ open_in.flags = flags;
+ open_in.mode = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.rep.buff.len = sizeof(*open_out);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, ((isdir)?FUSE_OPENDIR:FUSE_OPEN),
+ ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse open", 0);
+
+ if (error)
+ return error;
+
+ open_out = (struct fuse_open_out *)msg.rep.buff.data_rcv;
+
+ ip->fufh[fufh_type].fh_id = open_out->fh;
+ ip->fufh[fufh_type].fh_type = fufh_type;
+
+ free(open_out, M_FUSEFS);
+
+ return 0;
+}
+
+int
+fuse_file_close(struct fuse_mnt *fmp, struct fuse_node * ip,
+ enum fufh_type fufh_type, int flags, int isdir)
+{
+ struct fuse_release_in rel;
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ int error;
+
+ bzero(&msg, sizeof(msg));
+ bzero(&rel, sizeof(rel));
+ msg.hdr = &hdr;
+ msg.data = &rel;
+ msg.len = sizeof(rel);
+ msg.cb = &fuse_sync_it;
+ msg.fmp = fmp;
+ msg.type = msg_intr;
+
+ rel.fh = ip->fufh[fufh_type].fh_id;
+ rel.flags = flags;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len,
((isdir)?FUSE_RELEASEDIR:FUSE_RELEASE),
+ ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse close", 0);
+
+ if (error)
+ return error;
+
+ error = msg.rep.it_res;
+ if (error)
+ printf("error %d\n", error);
+
+ ip->fufh[fufh_type].fh_id = (uint64_t)-1;
+ ip->fufh[fufh_type].fh_type = FUFH_INVALID;
+
+ return (error);
+}
Index: miscfs/fuse/fuse_kernel.h
===================================================================
RCS file: miscfs/fuse/fuse_kernel.h
diff -N miscfs/fuse/fuse_kernel.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_kernel.h 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,233 @@
+/*
+ Copyright (C) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ Copyright (C) 2001-2007 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.
+*/
+#ifndef __FUSE_KERNEL_H__
+#define __FUSE_KERNEL_H__
+
+#define FUSE_KERNEL_VERSION 7
+#define FUSE_KERNEL_MINOR_VERSION 8
+
+/** The node ID of the root inode */
+#define FUSE_ROOT_ID 1
+
+struct fuse_kstatfs {
+ uint64_t blocks;
+ uint64_t bfree;
+ uint64_t bavail;
+ uint64_t files;
+ uint64_t ffree;
+ uint32_t bsize;
+ uint32_t namelen;
+ uint32_t frsize;
+ uint32_t padding;
+ uint32_t spare[6];
+};
+
+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_GETLK = 31,
+ FUSE_SETLK = 32,
+ FUSE_SETLKW = 33,
+ FUSE_ACCESS = 34,
+ FUSE_CREATE = 35,
+ FUSE_INTERRUPT = 36,
+ FUSE_BMAP = 37,
+ FUSE_DESTROY = 38,
+};
+
+struct fuse_in_header {
+ uint32_t len;
+ uint32_t opcode;
+ uint64_t unique;
+ uint64_t nodeid;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t pid;
+ uint32_t padding;
+};
+
+struct fuse_init_in {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t max_readahead;
+ uint32_t flags;
+};
+
+struct fuse_out_header {
+ uint32_t len;
+ uint32_t error;
+ uint64_t unique;
+};
+
+struct fuse_init_out {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t max_readahead;
+ uint32_t flags;
+ uint32_t unused;
+ uint32_t max_write;
+};
+
+struct fuse_statfs_out {
+ struct fuse_kstatfs st;
+};
+
+struct fuse_attr {
+ uint64_t ino;
+ uint64_t size;
+ uint64_t blocks;
+ uint64_t atime;
+ uint64_t mtime;
+ uint64_t ctime;
+ uint32_t atimensec;
+ uint32_t mtimensec;
+ uint32_t ctimensec;
+ uint32_t mode;
+ uint32_t nlink;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t rdev;
+};
+
+struct fuse_attr_in {
+ uint32_t getattr_flags;
+ uint32_t dummy;
+ uint32_t fh;
+};
+
+struct fuse_attr_out {
+ uint64_t attr_valid;
+ uint32_t attr_valid_nsec;
+ uint32_t dummy;
+ struct fuse_attr attr;
+};
+
+struct fuse_access_in {
+ uint32_t mask;
+ uint32_t padding;
+};
+
+struct fuse_open_in {
+ uint32_t flags;
+ uint32_t mode;
+};
+
+struct fuse_open_out {
+ uint64_t fh;
+ uint32_t open_flags;
+ uint32_t padding;
+};
+
+struct fuse_release_in {
+ uint64_t fh;
+ uint32_t flags;
+ uint32_t release_flags;
+ uint64_t lock_owner;
+};
+
+struct fuse_read_in {
+ uint64_t fh;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t padding;
+};
+
+struct fuse_dirent {
+ uint64_t ino;
+ uint64_t off;
+ uint32_t namelen;
+ uint32_t type;
+ char name[0];
+};
+
+struct pseudo_dirent {
+ uint32_t d_namlen;
+};
+
+struct fuse_entry_out {
+ uint64_t nodeid;
+ uint64_t generation;
+
+ uint64_t entry_valid; /* Cache timeout for the name */
+ uint64_t attr_valid; /* Cache timeout for the attributes */
+ uint32_t entry_valid_nsec;
+ uint32_t attr_valid_nsec;
+ struct fuse_attr attr;
+};
+
+struct fuse_mkdir_in {
+ uint32_t mode;
+ uint32_t padding;
+};
+
+struct fuse_link_in {
+ uint64_t oldnodeid;
+};
+
+struct fuse_write_in {
+ uint64_t fh;
+ uint64_t offset;
+ uint32_t size;
+ uint32_t write_flags;
+};
+
+struct fuse_write_out {
+ uint32_t size;
+ uint32_t padding;
+};
+
+#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
+#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(uint64_t) - 1) &
~(sizeof(uint64_t) - 1))
+#define FUSE_DIRENT_SIZE(d) \
+ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
+
+#endif /* __FUSEFS_H__ */
Index: miscfs/fuse/fuse_lookup.c
===================================================================
RCS file: miscfs/fuse/fuse_lookup.c
diff -N miscfs/fuse/fuse_lookup.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_lookup.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+extern int fusefs_lookup(void *);
+
+int
+fusefs_lookup(void *v)
+{
+ struct vop_lookup_args *ap = v;
+ struct vnode *vdp; /* vnode for directory being searched */
+ struct fuse_node *dp; /* inode for directory being searched */
+ struct fuse_mnt *fmp; /* file system that directory is in */
+ int lockparent; /* 1 => lockparent flag is set */
+ struct vnode *tdp; /* returned by VOP_VGET */
+ struct fuse_in_header hdr;
+ struct fuse_msg msg;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct ucred *cred = cnp->cn_cred;
+ struct fuse_entry_out *feo = NULL;
+ int flags;
+ int nameiop = cnp->cn_nameiop;
+ /*struct proc *p = cnp->cn_proc;*/
+ int error = 0;
+ uint64_t nid;
+
+ flags = cnp->cn_flags;
+ *vpp = NULL;
+ vdp = ap->a_dvp;
+ dp = VTOI(vdp);
+ fmp = dp->i_mnt;
+ lockparent = flags & LOCKPARENT;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("lookup path %s\n", cnp->cn_pnbuf);
+ printf("lookup file %s\n", cnp->cn_nameptr);
+#endif
+
+ if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0)
+ return (error);
+
+ if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
+ (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
+ return (EROFS);
+
+ if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
+ return (error);
+
+ /* if we get ".." */
+ if (flags & ISDOTDOT) {
+ nid = dp->parent;
+ if (nid == 0) {
+ return ENOENT;
+ }
+ } else if (cnp->cn_namelen == 1 && *(cnp->cn_nameptr) == '.') {
/* if we get "." */
+ nid = dp->i_number;
+ } else { /* if we get a real entry */
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_LOOKUP,
dp->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse lookup", 0);
+
+ if (error)
+ return (error);
+
+ if (msg.error) {
+ if ((nameiop == CREATE || nameiop == RENAME) && (flags &
ISLASTCN) ) {
+ if (vdp->v_mount->mnt_flag & MNT_RDONLY)
+ return EROFS;
+
+ cnp->cn_flags |= SAVENAME;
+
+ if (!lockparent) {
+ VOP_UNLOCK(vdp, 0, curproc);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+
+ error = EJUSTRETURN;
+ goto out;
+ }
+
+ error = ENOENT;
+ goto out;
+ }
+
+ feo = (struct fuse_entry_out *)msg.rep.buff.data_rcv;
+ nid = feo->nodeid;
+ }
+
+ if (nameiop == DELETE && (flags & ISLASTCN)) {
+ /*
+ * Write access to directory required to delete files.
+ */
+ if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0)
+ return (error);
+
+ cnp->cn_flags |= SAVENAME;
+ }
+
+ if (flags & ISDOTDOT) {
+ printf("lookup for ..\n");
+ VOP_UNLOCK(vdp, 0, curproc); /* race to get the inode */
+ cnp->cn_flags |= PDIRUNLOCK;
+
+ error = VFS_VGET(fmp->mp, nid, &tdp);
+
+ if (error) {
+ if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, curproc) == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
+
+ return (error);
+ }
+
+ if (lockparent && (flags & ISLASTCN)) {
+ if ((error = vn_lock(vdp, LK_EXCLUSIVE, curproc))) {
+ vput(tdp);
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+ *vpp = tdp;
+
+ } else if (nid == dp->i_number) {
+ vref(vdp);
+ *vpp = vdp;
+ error = 0;
+ } else {
+ error = VFS_VGET(fmp->mp, nid, &tdp);
+
+ if (!error) {
+ tdp->v_type = IFTOVT(feo->attr.mode);
+ VTOI(tdp)->vtype = tdp->v_type;
+ }
+
+ fuse_internal_attr_fat2vat(fmp->mp, &feo->attr,
&(VTOI(tdp)->cached_attrs));
+ free(feo, M_FUSEFS);
+
+ if (error)
+ return (error);
+
+ if (vdp != NULL && vdp->v_type == VDIR) {
+ VTOI(tdp)->parent = dp->i_number;
+ }
+ if (!lockparent || !(flags & ISLASTCN)) {
+ VOP_UNLOCK(vdp, 0, curproc);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+
+ *vpp = tdp;
+ }
+
+out:
+ if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE && nameiop != DELETE )
+ cache_enter(vdp, *vpp, cnp);
+
+ return (error);
+}
Index: miscfs/fuse/fuse_node.c
===================================================================
RCS file: miscfs/fuse/fuse_node.c
diff -N miscfs/fuse/fuse_node.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_node.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+LIST_HEAD(ihashhead, fuse_node) *fhashtbl;
+u_long fhash; /* size of hash table - 1 */
+#define INOHASH(fd, inum) (&fhashtbl[((fd) + (inum)) & fhash])
+
+void
+fusefs_ihashinit(void)
+{
+ fhashtbl = hashinit(desiredvnodes, M_FUSEFS, M_WAITOK, &fhash);
+}
+
+
+/*
+ * Use the fd/inum pair to find the incore inode, and return a pointer
+ * to it. If it is in core, but locked, wait for it.
+ */
+struct vnode *
+fusefs_ihashget(int fd, ino_t inum)
+{
+ struct proc *p = curproc;
+ struct fuse_node *ip;
+ struct vnode *vp;
+loop:
+ /* XXXLOCKING lock hash list */
+ LIST_FOREACH(ip, INOHASH(fd, inum), i_hash) {
+ if (inum == ip->i_number && fd == ip->i_fd) {
+ vp = ITOV(ip);
+ /* XXXLOCKING unlock hash list? */
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ return (vp);
+ }
+ }
+ /* XXXLOCKING unlock hash list? */
+ return (NULL);
+}
+
+int
+fusefs_ihashins(struct fuse_node *ip)
+{
+ struct fuse_node *curip;
+ struct ihashhead *ipp;
+ int fd = ip->i_fd;
+ ino_t inum = ip->i_number;
+
+ /* lock the inode, then put it on the appropriate hash list */
+ lockmgr(&ip->i_lock, LK_EXCLUSIVE, NULL);
+
+ /* XXXLOCKING lock hash list */
+
+ LIST_FOREACH(curip, INOHASH(fd, inum), i_hash) {
+ if (inum == curip->i_number && fd == curip->i_fd) {
+ /* XXXLOCKING unlock hash list? */
+ lockmgr(&ip->i_lock, LK_RELEASE, NULL);
+ return (EEXIST);
+ }
+ }
+
+ ipp = INOHASH(fd, inum);
+ LIST_INSERT_HEAD(ipp, ip, i_hash);
+ /* XXXLOCKING unlock hash list? */
+
+ return (0);
+}
+/*
+ * Remove the inode from the hash table.
+ */
+void
+fusefs_ihashrem(struct fuse_node *ip)
+{
+ /* XXXLOCKING lock hash list */
+
+ if (ip->i_hash.le_prev == NULL)
+ return;
+
+ LIST_REMOVE(ip, i_hash);
+#ifdef DIAGNOSTIC
+ ip->i_hash.le_next = NULL;
+ ip->i_hash.le_prev = NULL;
+#endif
+ /* XXXLOCKING unlock hash list? */
+}
Index: miscfs/fuse/fuse_node.h
===================================================================
RCS file: miscfs/fuse/fuse_node.h
diff -N miscfs/fuse/fuse_node.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_node.h 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __FUSE_NODE_H__
+#define __FUSE_NODE_H__
+
+enum fufh_type {
+ FUFH_INVALID = -1,
+ FUFH_RDONLY = 0,
+ FUFH_WRONLY = 1,
+ FUFH_RDWR = 2,
+ FUFH_MAXTYPE = 3,
+};
+
+struct fuse_filehandle {
+ uint64_t fh_id;
+ enum fufh_type fh_type;
+};
+
+struct fuse_node {
+ LIST_ENTRY(fuse_node) i_hash; /* Hash chain */
+ struct vnode *i_vnode; /* vnode associated with this inode */
+ struct lockf *i_lockf; /* Head of byte-level lock list. */
+ struct lock i_lock; /* node lock */
+ ino_t i_number; /* the identity of the inode */
+ int i_fd; /* fd of fuse session */
+
+ struct fuse_mnt *i_mnt; /* filesystem associated with this inode */
+ uint64_t parent;
+
+ /** I/O **/
+ struct fuse_filehandle fufh[FUFH_MAXTYPE];
+
+ /** flags **/
+ uint32_t flag;
+
+ /** meta **/
+ struct vattr cached_attrs;
+ off_t filesize;
+ uint64_t nlookup;
+ enum vtype vtype;
+};
+
+extern struct fuse_node **fusehashtbl;
+extern u_long fusehash;
+
+void fusefs_ihashinit(void);
+struct vnode *fusefs_ihashget(int, ino_t);
+int fusefs_ihashins(struct fuse_node *ip);
+void fusefs_ihashrem(struct fuse_node *ip);
+#define ITOV(ip) ((ip)->i_vnode)
+#define VTOI(vp) ((struct fuse_node *)(vp)->v_data)
+
+#endif /* __FUSE_NODE_H__ */
Index: miscfs/fuse/fuse_subr.c
===================================================================
RCS file: miscfs/fuse/fuse_subr.c
diff -N miscfs/fuse/fuse_subr.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_subr.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+void
+fuse_make_in(struct mount *mp, struct fuse_in_header *hdr, int len,
+ enum fuse_opcode op, ino_t ino, struct proc *p)
+{
+ struct fuse_mnt *fmp;
+
+ fmp = VFSTOFUSEFS(mp);
+
+ fmp->unique++;
+
+ hdr->len = sizeof(*hdr) + len;
+ hdr->opcode = op;
+ hdr->nodeid = ino;
+ hdr->unique = fmp->unique;
+#ifdef FUSE_DEBUG_MSG
+ printf("creat unique %i\n", hdr->unique);
+#endif
+
+ if (!p) {
+ hdr->pid = curproc->p_pid;
+ hdr->uid = 0;
+ hdr->gid = 0;
+ } else {
+ hdr->pid = p->p_pid;
+ hdr->uid = p->p_cred->p_ruid;
+ hdr->gid = p->p_cred->p_rgid;
+ }
+}
+
+void
+fuse_init_resp(struct fuse_msg *msg, struct fuse_out_header *hdr, void *data)
+{
+ struct fuse_init_out *out = data;
+
+#ifdef FUSE_DEBUG_MSG
+ printf("async init unique %i\n", msg->hdr->unique);
+ printf("init_out flags %i\n", out->flags);
+ printf("init_out major %i\n", out->major);
+ printf("init_out minor %i\n", out->minor);
+ printf("init_out max_readahead %i\n", out->max_readahead);
+ printf("init_out max_write %i\n", out->max_write);
+ printf("init_out unused %i\n", out->unused);
+#endif
+
+ msg->fmp->sess_init = 1;
+ msg->fmp->max_write = out->max_readahead;
+}
+
+void
+fuse_sync_resp(struct fuse_msg *msg, struct fuse_out_header *hdr, void *data)
+{
+ size_t len;
+
+#ifdef FUSE_DEBUG_MSG
+ printf("buf unique %i\n", msg->hdr->unique);
+#endif
+
+ if (msg->type != msg_buff)
+ printf("bad msg type\n");
+
+ if (data != NULL && msg->rep.buff.len != 0) {
+ len = hdr->len - sizeof(*hdr);
+ if (msg->rep.buff.len != len) {
+ printf("fusefs: packet size error on opcode %i\n",
msg->hdr->opcode);
+ }
+
+ if (msg->rep.buff.len > len)
+ printf("buff unused byte : 0x%x\n", msg->rep.buff.len - len);
+
+ msg->rep.buff.data_rcv = malloc(msg->rep.buff.len, M_FUSEFS,
M_WAITOK | M_ZERO);
+ memcpy(msg->rep.buff.data_rcv, data, msg->rep.buff.len);
+
+ wakeup(msg);
+
+ } else if (data != NULL) {
+ len = hdr->len - sizeof(*hdr);
+ msg->rep.buff.data_rcv = malloc(len, M_FUSEFS, M_WAITOK | M_ZERO);
+ memcpy(msg->rep.buff.data_rcv, data, len);
+ msg->rep.buff.len = len;
+
+ wakeup(msg);
+ } else if (hdr->error) {
+ msg->error = hdr->error;
+#ifdef FUSE_DEBUG_MSG
+ printf("error %i\n", msg->error);
+#endif
+ wakeup(msg);
+ } else {
+ msg->error = -1;
+#ifdef FUSE_DEBUG_MSG
+ printf("ack for msg\n");
+#endif
+ wakeup(msg);
+ }
+}
+
+void
+fuse_sync_it(struct fuse_msg *msg, struct fuse_out_header *hdr, void *data)
+{
+#ifdef FUSE_DEBUG_MSG
+ printf("it unique %i\n", msg->hdr->unique);
+#endif
+
+ if (msg->type != msg_intr)
+ printf("bad msg type\n");
+
+ if (data != NULL)
+ printf("normally data should be Null\n");
+
+ msg->rep.it_res = hdr->error;
+#ifdef FUSE_DEBUG_MSG
+ printf("errno = %d\n");
+#endif
+
+ wakeup(msg);
+}
Index: miscfs/fuse/fuse_vfsops.c
===================================================================
RCS file: miscfs/fuse/fuse_vfsops.c
diff -N miscfs/fuse/fuse_vfsops.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_vfsops.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/lock.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+static int fusefs_mount(struct mount *mp, const char *path, void *data,
+ struct nameidata *ndp, struct proc *p);
+static int fusefs_start(struct mount *mp, int flags, struct proc *p);
+static int fusefs_unmount(struct mount *mp, int mntflags, struct proc *p);
+static int fusefs_root(struct mount *mp, struct vnode **vpp);
+static int fusefs_quotactl(struct mount *mp, int cmds, uid_t uid,
+ caddr_t arg, struct proc *p);
+static int fusefs_statfs(struct mount *mp, struct statfs *sbp,
+ struct proc *p);
+static int fusefs_sync(struct mount *mp, int waitfor, struct ucred *cred,
+ struct proc *p);
+static int fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
+static int fusefs_fhtovp(struct mount *mp, struct fid *fhp,
+ struct vnode **vpp);
+static int fusefs_vptofh(struct vnode *vp, struct fid *fhp);
+static int fusefs_init(struct vfsconf *);
+static int fusefs_sysctl(int *, u_int, void *, size_t *, void *,
+ size_t, struct proc *);
+static int fusefs_checkexp(struct mount *mp, struct mbuf *nam,
+ int *extflagsp, struct ucred **credanonp);
+
+const struct vfsops fusefs_vfsops = {
+ fusefs_mount,
+ fusefs_start,
+ fusefs_unmount,
+ fusefs_root,
+ fusefs_quotactl,
+ fusefs_statfs,
+ fusefs_sync,
+ fusefs_vget,
+ fusefs_fhtovp,
+ fusefs_vptofh,
+ fusefs_init,
+ fusefs_sysctl,
+ fusefs_checkexp
+};
+
+int
+fusefs_mount(struct mount *mp, const char *path, void *data,
+ struct nameidata *ndp, struct proc *p)
+{
+ struct fuse_mnt *fmp;
+ struct fuse_msg *msg;
+ struct fuse_init_in *init;
+ struct fusefs_args args;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("mount\n");
+#endif
+
+ if (mp->mnt_flag & MNT_UPDATE)
+ return (EOPNOTSUPP);
+
+ error = copyin(data, &args, sizeof(struct fusefs_args));
+ if (error)
+ return error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("fd = %d\n", args.fd);
+#endif
+
+ fmp = malloc(sizeof(*fmp), M_FUSEFS, M_WAITOK | M_ZERO);
+ fmp->mp = mp;
+ fmp->sess_init = 0;
+ fmp->unique = 0;
+ fmp->fd = args.fd;
+ mp->mnt_data = (qaddr_t)fmp;
+
+ mp->mnt_flag |= MNT_LOCAL;
+ vfs_getnewfsid(mp);
+
+ bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
+ strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
+ bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
+ bcopy("fusefs", mp->mnt_stat.f_mntfromname, sizeof("fusefs"));
+
+ msg = malloc(sizeof(struct fuse_msg), M_FUSEFS, M_WAITOK | M_ZERO);
+ msg->hdr = malloc(sizeof(struct fuse_in_header), M_FUSEFS,
M_WAITOK | M_ZERO);
+ init = malloc(sizeof(struct fuse_init_in), M_FUSEFS, M_WAITOK | M_ZERO);
+
+ init->major = FUSE_KERNEL_VERSION;
+ init->minor = FUSE_KERNEL_MINOR_VERSION;
+ init->max_readahead = 4096 * 16;
+ init->flags = 0;
+ msg->data = init;
+ msg->len = sizeof(*init);
+ msg->cb = &fuse_init_resp;
+ msg->fmp = fmp;
+ msg->type = msg_buff_async;
+
+ fuse_make_in(mp, msg->hdr, msg->len, FUSE_INIT, 0, p);
+
+ TAILQ_INSERT_TAIL(&fmq_in, msg, node);
+ wakeup(&fmq_in);
+
+ return (0);
+}
+
+int
+fusefs_start(struct mount *mp, int flags, struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("start\n");
+#endif
+ return (0);
+}
+
+int
+fusefs_unmount(struct mount *mp, int mntflags, struct proc *p)
+{
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ extern int doforce;
+ struct fuse_msg *m;
+ int flags = 0;
+ int error;
+
+ fmp = VFSTOFUSEFS(mp);
+
+ if (!fmp->sess_init)
+ return 0;
+
+ fmp->sess_init = 0;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("unmount\n");
+#endif
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.type = msg_intr;
+ msg.data = NULL;
+ msg.cb = &fuse_sync_it;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_DESTROY, 0, curproc);
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse unmount", 0);
+
+ if (error)
+ return (error);
+
+ error = msg.rep.it_res;
+
+ if (error)
+ printf("error from fuse\n");
+
+ /* clear FIFO IN*/
+ while ((m = TAILQ_FIRST(&fmq_in))) {
+ printf("warning some msg where not processed....\n");
+ }
+
+ /* clear FIFO WAIT*/
+ while ((m = TAILQ_FIRST(&fmq_wait))) {
+ printf("warning some msg where not processed....\n");
+ }
+
+ if (mntflags & MNT_FORCE) {
+ /* fusefs can never be rootfs so don't check for it */
+ if (!doforce)
+ return (EINVAL);
+ flags |= FORCECLOSE;
+ }
+
+ if ((error = vflush(mp, 0, flags)))
+ return (error);
+
+ free(fmp, M_FUSEFS);
+
+ return (error);
+}
+
+int
+fusefs_root(struct mount *mp, struct vnode **vpp)
+{
+ struct vnode *nvp;
+ struct fuse_node *ip;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("root\n");
+#endif
+
+ if ((error = VFS_VGET(mp, (ino_t)FUSE_ROOTINO, &nvp)) != 0)
+ return (error);
+
+ ip = VTOI(nvp);
+ nvp->v_type = VDIR;
+ ip->vtype = VDIR;
+
+ *vpp = nvp;
+ return (0);
+}
+
+int fusefs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
+ struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("quotactl\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
+{
+ struct fuse_statfs_out *stat;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("statfs\n");
+#endif
+
+ fmp = VFSTOFUSEFS(mp);
+
+ if (fmp->sess_init) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.rep.buff.data_rcv = NULL;
+ msg.rep.buff.len = sizeof(*stat);
+ msg.cb = &fuse_sync_resp;
+ msg.type = msg_buff;
+
+ fuse_make_in(mp, msg.hdr, msg.len, FUSE_STATFS, FUSE_ROOT_ID, NULL);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse stat", 0);
+ if (error) {
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return error;
+ }
+
+ stat = (struct fuse_statfs_out *)msg.rep.buff.data_rcv;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("statfs a: %i\n", stat->st.bavail);
+ printf("statfs a: %i\n", stat->st.bfree);
+ printf("statfs a: %i\n", stat->st.blocks);
+ printf("statfs a: %i\n", stat->st.bsize);
+ printf("statfs a: %i\n", stat->st.ffree);
+ printf("statfs a: %i\n", stat->st.files);
+ printf("statfs a: %i\n", stat->st.frsize);
+ printf("statfs a: %i\n", stat->st.namelen);
+ printf("statfs a: %i\n", stat->st.padding);
+#endif
+
+ sbp->f_bavail = stat->st.bavail;
+ sbp->f_bfree = stat->st.bfree;
+ sbp->f_blocks = stat->st.blocks;
+ sbp->f_ffree = stat->st.ffree;
+ sbp->f_files = stat->st.files;
+ sbp->f_bsize = stat->st.frsize;
+ sbp->f_namemax = stat->st.namelen;
+
+ free(stat, M_FUSEFS);
+ } else {
+ sbp->f_bavail = 0;
+ sbp->f_bfree = 0;
+ sbp->f_blocks = 0;
+ sbp->f_ffree = 0;
+ sbp->f_files = 0;
+ sbp->f_bsize = 0;
+ sbp->f_namemax = 0;
+ }
+
+
+ return (0);
+}
+
+int fusefs_sync(struct mount *mp, int waitfor, struct ucred *cred,
+ struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("sync\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
+{
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct vnode *nvp;
+ int i;
+ int error;
+
+#ifdef FUSE_DEBUG_VFS
+ printf("vget\n");
+#endif
+retry:
+ fmp = VFSTOFUSEFS(mp);
+ /*
+ * check if vnode is in hash.
+ */
+ if ((*vpp = fusefs_ihashget(fmp->fd, ino)) != NULLVP)
+ return (0);
+
+ /*
+ * if not create it
+ */
+ if ((error = getnewvnode(VT_FUSEFS, mp, &fusefs_vops, &nvp)) != 0) {
+ printf("getnewvnode error\n");
+ *vpp = NULLVP;
+ return (error);
+ }
+
+ ip = malloc(sizeof(*ip), M_FUSEFS, M_WAITOK | M_ZERO);
+ lockinit(&ip->i_lock, PINOD, "fuseinode", 0, 0);
+ nvp->v_data = ip;
+ ip->i_vnode = nvp;
+ ip->i_fd = fmp->fd;
+ ip->i_number = ino;
+ ip->parent = 0;
+
+ for (i = 0; i < FUFH_MAXTYPE; i++)
+ ip->fufh[i].fh_type = FUFH_INVALID;
+
+ error = fusefs_ihashins(ip);
+ if (error) {
+ vrele(nvp);
+
+ if (error == EEXIST)
+ goto retry;
+
+ return (error);
+ }
+
+ ip->i_mnt = fmp;
+
+ if (ino == FUSE_ROOTINO)
+ nvp->v_flag |= VROOT;
+
+ *vpp = nvp;
+
+ return (0);
+}
+
+int fusefs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("fhtovp\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_vptofh(struct vnode *vp, struct fid *fhp)
+{
+ #ifdef FUSE_DEBUG_VFS
+ printf("vptofh\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_init(struct vfsconf *vfc)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("init\n");
+#endif
+
+ TAILQ_INIT(&fmq_in);
+ TAILQ_INIT(&fmq_wait);
+
+ fusefs_ihashinit();
+ return (0);
+}
+
+int fusefs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplen,
+ void *newp, size_t newlen, struct proc *p)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("sysctl\n");
+#endif
+
+ return (0);
+}
+
+int fusefs_checkexp(struct mount *mp, struct mbuf *nam, int *extflagsp,
+ struct ucred **credanonp)
+{
+#ifdef FUSE_DEBUG_VFS
+ printf("checkexp\n");
+#endif
+
+ return (0);
+}
Index: miscfs/fuse/fuse_vnops.c
===================================================================
RCS file: miscfs/fuse/fuse_vnops.c
diff -N miscfs/fuse/fuse_vnops.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fuse_vnops.c 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,1341 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+#include <sys/specdev.h>
+#include <sys/poll.h>
+#include <sys/lockf.h>
+
+#include "fuse_kernel.h"
+#include "fuse_node.h"
+#include "fusefs.h"
+
+/*
+ * Prototypes for fusefs vnode ops
+ */
+extern int fusefs_lookup(void *);
+int fusefs_open(void *);
+int fusefs_close(void *);
+int fusefs_access(void *);
+int fusefs_getattr(void *);
+int fusefs_setattr(void *);
+int fusefs_ioctl(void *);
+int fusefs_link(void *);
+int fusefs_symlink(void *);
+int fusefs_readdir(void *);
+int fusefs_readlink(void *);
+int fusefs_inactive(void *);
+int fusefs_reclaim(void *);
+int fusefs_print(void *);
+int fusefs_create(void *);
+int fusefs_mknod(void *);
+int fusefs_read(void *);
+int fusefs_write(void *);
+int fusefs_poll(void *);
+int fusefs_fsync(void *);
+int fusefs_remove(void *);
+int fusefs_rename(void *);
+int fusefs_mkdir(void *);
+int fusefs_rmdir(void *);
+int fusefs_strategy(void *);
+int fusefs_lock(void *);
+int fusefs_unlock(void *);
+int fusefs_islocked(void *);
+int fusefs_advlock(void *);
+int readdir_process_data(void *buff, int len, struct uio *uio);
+
+struct vops fusefs_vops = {
+ .vop_lookup = fusefs_lookup,
+ .vop_create = fusefs_create,
+ .vop_mknod = fusefs_mknod,
+ .vop_open = fusefs_open,
+ .vop_close = fusefs_close,
+ .vop_access = fusefs_access,
+ .vop_getattr = fusefs_getattr,
+ .vop_setattr = fusefs_setattr,
+ .vop_read = fusefs_read,
+ .vop_write = fusefs_write,
+ .vop_ioctl = fusefs_ioctl,
+ .vop_poll = fusefs_poll,
+ .vop_fsync = fusefs_fsync,
+ .vop_remove = fusefs_remove,
+ .vop_link = fusefs_link,
+ .vop_rename = fusefs_rename,
+ .vop_mkdir = fusefs_mkdir,
+ .vop_rmdir = fusefs_rmdir,
+ .vop_symlink = fusefs_symlink,
+ .vop_readdir = fusefs_readdir,
+ .vop_readlink = fusefs_readlink,
+ .vop_abortop = vop_generic_abortop,
+ .vop_inactive = fusefs_inactive,
+ .vop_reclaim = fusefs_reclaim,
+ .vop_lock = fusefs_lock,
+ .vop_unlock = fusefs_unlock,
+ .vop_bmap = vop_generic_bmap,
+ .vop_strategy = fusefs_strategy,
+ .vop_print = fusefs_print,
+ .vop_islocked = fusefs_islocked,
+ .vop_pathconf = spec_pathconf,
+ .vop_advlock = fusefs_advlock,
+};
+
+
+void
+fuse_internal_attr_fat2vat(struct mount *mp,
+ struct fuse_attr *fat,
+ struct vattr *vap)
+{
+ vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
+ vap->va_fileid = fat->ino;/* XXX cast from 64 bits to 32 */
+ vap->va_mode = fat->mode & ~S_IFMT;
+ vap->va_nlink = fat->nlink;
+ vap->va_uid = fat->uid;
+ vap->va_gid = fat->gid;
+ vap->va_rdev = fat->rdev;
+ vap->va_size = fat->size;
+ vap->va_atime.tv_sec = fat->atime;
+ vap->va_atime.tv_nsec = fat->atimensec;
+ vap->va_mtime.tv_sec = fat->mtime;
+ vap->va_mtime.tv_nsec = fat->mtimensec;
+ vap->va_ctime.tv_sec = fat->ctime;
+ vap->va_ctime.tv_nsec = fat->ctimensec;
+ vap->va_blocksize = PAGE_SIZE;
+ vap->va_type = IFTOVT(fat->mode);
+
+#if (S_BLKSIZE == 512)
+ /* Optimize this case */
+ vap->va_bytes = fat->blocks << 9;
+#else
+ vap->va_bytes = fat->blocks * S_BLKSIZE;
+#endif
+
+}
+
+int
+fusefs_open(void *v)
+{
+ struct vop_open_args *ap;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ enum fufh_type fufh_type;
+ int flags;
+ int error;
+ int isdir;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_open\n");
+#endif
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("inode = %i mode=0x%x\n", ip->i_number, ap->a_mode);
+#endif
+ isdir = 0;
+ if (ip->vtype == VDIR) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ isdir = 1;
+ } else {
+ if ((ap->a_mode & FREAD) && (ap->a_mode & FWRITE)) {
+ fufh_type = FUFH_RDWR;
+ flags = O_RDWR;
+ }
+ else if (ap->a_mode & (FWRITE)) {
+ fufh_type = FUFH_WRONLY;
+ flags = O_WRONLY;
+ }
+ else if (ap->a_mode & (FREAD)) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ }
+ }
+
+ /* already open i think all is ok */
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ return 0;
+
+ error = fuse_file_open(fmp, ip, fufh_type, flags, isdir);
+
+ if (error)
+ return (error);
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("file open fd : %i\n", ip->fufh[fufh_type].fh_id);
+#endif
+ return (error);
+}
+
+int
+fusefs_close(void *v)
+{
+ struct vop_close_args *ap;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ enum fufh_type fufh_type;
+ int isdir, flags, i;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_close\n");
+#endif
+
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+ isdir = 0;
+ if (ip->vtype == VDIR) {
+ fufh_type = FUFH_RDONLY;
+ isdir = 1;
+
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ return fuse_file_close(fmp, ip, fufh_type, O_RDONLY, isdir);
+ } else {
+ if (ap->a_fflag & IO_NDELAY) {
+ return (0);
+ }
+
+ if ((ap->a_fflag & FREAD) && (ap->a_fflag & FWRITE)) {
+ fufh_type = FUFH_RDWR;
+ flags = O_RDWR;
+ }
+ else if (ap->a_fflag & (FWRITE)) {
+ fufh_type = FUFH_WRONLY;
+ flags = O_WRONLY;
+ }
+ else if (ap->a_fflag & (FREAD)) {
+ fufh_type = FUFH_RDONLY;
+ flags = O_RDONLY;
+ }
+ }
+
+ /*
+ * if fh not valid lookup for another valid fh in vnode.
+ * panic if there's not fh valid
+ */
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID) {
+ for (i = 0; i < FUFH_MAXTYPE; i++)
+ if (ip->fufh[fufh_type].fh_type != FUFH_INVALID)
+ break;
+ return (0);
+ }
+
+ return (0);
+}
+
+int
+fusefs_access(void *v)
+{
+ struct fuse_access_in access;
+ struct vop_access_args *ap;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ uint32_t mask = 0;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_access\n");
+#endif
+ ap = v;
+ ip = VTOI(ap->a_vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_ACCESS))
+ goto system_check;
+
+ if (ap->a_vp->v_type == VLNK)
+ goto system_check;
+
+ if (ap->a_vp->v_type == VREG && (ap->a_mode & VWRITE & VEXEC))
+ goto system_check;
+
+ if ((ap->a_mode & VWRITE) && (fmp->mp->mnt_flag & MNT_RDONLY))
+ return(EACCES);
+
+ if ((ap->a_mode & VWRITE) != 0) {
+ mask |= 0x2;
+ }
+ if ((ap->a_mode & VREAD) != 0) {
+ mask |= 0x4;
+ }
+ if ((ap->a_mode & VEXEC) != 0) {
+ mask |= 0x1;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ access.mask = mask;
+ msg.data = &access;
+ msg.len = sizeof(access);
+ msg.cb = &fuse_sync_it;
+ msg.fmp = fmp;
+ msg.type = msg_intr;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_ACCESS,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse access", 0);
+
+ if (error)
+ return error;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("it with value %x\n", msg.rep.it_res);
+#endif
+ error = msg.rep.it_res;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_ACCESS;
+ goto system_check;
+ }
+
+ return (error);
+
+system_check:
+#ifdef FUSE_DEBUG_VNOP
+ printf("Use kernel access\n");
+#endif
+ return (vaccess(ap->a_vp->v_type, ip->cached_attrs.va_mode & ALLPERMS,
+ ip->cached_attrs.va_uid, ip->cached_attrs.va_gid, ap->a_mode,
ap->a_cred));
+}
+
+int
+fusefs_getattr(void *v)
+{
+ struct vop_getattr_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_mnt *fmp;
+ struct vattr *vap = ap->a_vap;
+ struct fuse_in_header hdr;
+ struct fuse_attr_out *fat;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_getattr\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ goto fake;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.rep.buff.len = sizeof(*fat);
+ msg.rep.buff.data_rcv = NULL;
+ msg.type = msg_buff;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_GETATTR,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse getattr", 0);
+
+ if (error) {
+ if (msg.rep.buff.data_rcv != NULL)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+ }
+
+ fat = (struct fuse_attr_out *)msg.rep.buff.data_rcv;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("ino: %d\n", fat->attr.ino);
+ printf("size: %d\n", fat->attr.size);
+ printf("blocks: %d\n", fat->attr.blocks);
+ printf("atime: %d\n", fat->attr.atime);
+ printf("mtime: %d\n", fat->attr.mtime);
+ printf("ctime: %d\n", fat->attr.ctime);
+ printf("atimensec: %d\n", fat->attr.atimensec);
+ printf("mtimensec: %d\n", fat->attr.mtimensec);
+ printf("ctimensec: %d\n", fat->attr.ctimensec);
+ printf("mode: %d\n", fat->attr.mode);
+ printf("nlink: %d\n", fat->attr.nlink);
+ printf("uid: %d\n", fat->attr.uid);
+ printf("gid: %d\n", fat->attr.gid);
+ printf("rdev: %d\n", fat->attr.rdev);
+#endif
+
+ fuse_internal_attr_fat2vat(fmp->mp, &fat->attr, vap);
+
+ memcpy(&ip->cached_attrs, vap, sizeof(*vap));
+ free(fat, M_FUSEFS);
+
+ return (error);
+fake:
+ bzero(vap, sizeof(*vap));
+ vap->va_type = vp->v_type;
+ return (0);
+}
+
+int
+fusefs_setattr(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_setattr\n");
+#endif
+ return (0);
+}
+
+int
+fusefs_ioctl(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_ioctl\n");
+#endif
+ return (ENOTTY);
+}
+
+int
+fusefs_link(void *v)
+{
+ struct vop_link_args *ap = v;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ struct componentname *cnp = ap->a_cnp;
+ struct fuse_in_header hdr;
+ struct fuse_entry_out *feo;
+ struct fuse_link_in fli;
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_link\n");
+#endif
+
+ if (vp->v_type == VDIR) {
+ VOP_ABORTOP(dvp, cnp);
+ error = EISDIR;
+ goto out2;
+ }
+ if (dvp->v_mount != vp->v_mount) {
+ VOP_ABORTOP(dvp, cnp);
+ error = EXDEV;
+ goto out2;
+ }
+ if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, curproc))) {
+ VOP_ABORTOP(dvp, cnp);
+ goto out2;
+ }
+
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_LINK))
+ goto out1;
+
+ fli.oldnodeid = ip->i_number;
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fli);
+ msg.data = &fli;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.type = msg_buff;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_LINK, ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse link", 0);
+
+ if (error) {
+ if (msg.rep.buff.data_rcv != NULL)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ goto out1;
+ }
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_LINK;
+ }
+
+ goto out1;
+ }
+
+ feo = (struct fuse_entry_out *)msg.rep.buff.data_rcv;
+ free(feo, M_FUSEFS);
+
+out1:
+ if (dvp != vp)
+ VOP_UNLOCK(vp, 0, curproc);
+out2:
+ vput(dvp);
+ return (error);
+}
+
+int
+fusefs_symlink(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_symlink\n");
+#endif
+ return (0);
+}
+
+#define GENERIC_DIRSIZ(dp) \
+ ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+
+
+int
+readdir_process_data(void *buff, int len, struct uio *uio)
+{
+ struct fuse_dirent *fdir;
+ struct dirent dir;
+ int bytesavail;
+ int flen, error = 0;
+
+ if (len < FUSE_NAME_OFFSET) {
+ return 0;
+ }
+
+ while ( len > 0) {
+ if ( len < sizeof(*fdir)) {
+ error = 0;
+ break;
+ }
+
+ fdir = (struct fuse_dirent *)buff;
+ flen = FUSE_DIRENT_SIZE(fdir);
+
+ if (!fdir->namelen || fdir->namelen > MAXNAMLEN || len < flen) {
+ error = EINVAL;
+ break;
+ }
+
+ bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *) &fdir->namelen);
+ if (bytesavail > uio->uio_resid) {
+ error = 0;
+ break;
+ }
+
+ bzero(&dir, sizeof(dir));
+ dir.d_fileno = fdir->ino;
+ dir.d_reclen = bytesavail;
+ dir.d_type = fdir->type;
+ dir.d_namlen = fdir->namelen;
+ bcopy(fdir->name, dir.d_name, fdir->namelen);
+
+ uiomove(&dir, bytesavail , uio);
+ len -= flen;
+ /* ugly pointer arithmetic must find something else ...*/
+ buff = (void *)(((char *) buff) + flen);
+ uio->uio_offset = fdir->off;
+ }
+
+ return (error);
+}
+
+int
+fusefs_readdir(void *v)
+{
+ struct vop_readdir_args *ap = v;
+ struct fuse_read_in read;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ struct vnode *vp;
+ struct uio *uio;
+ int error = 0;
+
+ vp = ap->a_vp;
+ uio = ap->a_uio;
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init) {
+ return (0);
+ }
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_readdir\n");
+ printf("uio resid 0x%x\n", uio->uio_resid);
+#endif
+ if (uio->uio_resid == 0)
+ return (error);
+
+ while (uio->uio_resid > 0) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(read);
+ msg.type = msg_buff;
+
+ msg.rep.buff.len= 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.data = &read;
+ msg.cb = &fuse_sync_resp;
+
+ if (ip->fufh[FUFH_RDONLY].fh_type == FUFH_INVALID) {
+ printf("dir not open\n");
+ /* TODO open the file */
+ return (error);
+ }
+ read.fh = ip->fufh[FUFH_RDONLY].fh_id;
+ read.offset = uio->uio_offset;
+ read.size = MIN(uio->uio_resid, PAGE_SIZE);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READDIR,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ error = tsleep(&msg, PWAIT, "fuse getattr", 0);
+
+ if (error) {
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+ }
+
+ if (msg.error == -1) {
+ //ack for end of readdir
+ break;
+ }
+
+ if ((error = readdir_process_data(msg.rep.buff.data_rcv,
msg.rep.buff.len, uio))) {
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ break;
+ }
+
+ if (msg.rep.buff.len != 0)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ }
+
+ return (error);
+}
+
+int
+fusefs_inactive(void *v)
+{
+ struct vop_inactive_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ register struct fuse_node *ip = VTOI(vp);
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_inactive\n");
+#endif
+
+ ip->flag = 0;
+ VOP_UNLOCK(vp, 0, p);
+
+ /* not sure if it is ok to do like that ...*/
+ if (ip->cached_attrs.va_mode == 0)
+ vrecycle(vp, p);
+
+ return (error);
+}
+
+int
+fusefs_readlink(void *v)
+{
+ struct vop_readlink_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_in_header hdr;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ struct uio *uio;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_readlink\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+ uio = ap->a_uio;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_READLINK)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = 0;
+ msg.data = NULL;
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READLINK,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse readlink", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_READLINK;
+ }
+ goto out;
+ }
+
+ error = uiomove(msg.rep.buff.data_rcv, msg.rep.buff.len, uio);
+
+out:
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_reclaim(void *v)
+{
+ struct vop_reclaim_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_node *ip = VTOI(vp);
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_reclaim\n");
+#endif
+ /*
+ * Purge old data structures associated with the inode.
+ */
+ ip->parent = 0;
+
+ /*
+ * Remove the inode from its hash chain.
+ */
+ fusefs_ihashrem(ip);
+ cache_purge(vp);
+
+ /*close file if exist
+ if (ip->i_fd) {
+ vrele(ip->i_devvp);
+ ip->i_devvp = 0;
+ }*/
+
+ free(ip, M_FUSEFS);
+ vp->v_data = NULL;
+ return (0);
+}
+
+int
+fusefs_print(void *v)
+{
+ struct vop_print_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct fuse_node *ip = VTOI(vp);
+
+ /*
+ * Complete the information given by vprint().
+ */
+ printf("tag VT_FUSE, hash id %u ", ip->i_number);
+ lockmgr_printinfo(&ip->i_lock);
+ printf("\n");
+ return (0);
+}
+
+int
+fusefs_create(void *v)
+{
+ struct vop_create_args *ap = v;
+ struct componentname *cnp = ap->a_cnp;
+ struct vnode **vpp = ap->a_vpp;
+ struct vnode *dvp = ap->a_dvp;
+ struct vattr *vap = ap->a_vap;
+ struct fuse_entry_out *feo;
+ struct fuse_in_header hdr;
+ struct vnode *tdp = NULL;
+ struct fuse_open_in foi;
+ struct fuse_mnt *fmp;
+ struct fuse_node *ip;
+ struct fuse_msg msg;
+ int error = 0;
+ mode_t mode;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_create(cnp %08x, vap %08x\n", cnp, vap);
+#endif
+ ip = VTOI(dvp);
+ fmp = ip->i_mnt;
+ mode = MAKEIMODE(vap->va_type, vap->va_mode);
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_CREATE)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(foi) + cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out) + sizeof(struct
fuse_open_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ foi.mode = mode;
+ foi.flags = O_CREAT | O_RDWR;
+
+ memcpy(msg.data, &foi, sizeof(foi));
+ memcpy((char *)msg.data + sizeof(foi), cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[sizeof(foi) + cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_CREATE,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse create", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_CREATE;
+ }
+ goto out;
+ }
+
+ feo = msg.rep.buff.data_rcv;
+ if ((error = VFS_VGET(fmp->mp, feo->nodeid, &tdp)))
+ goto out;
+
+ tdp->v_type = IFTOVT(feo->attr.mode);
+ VTOI(tdp)->vtype = tdp->v_type;
+
+ if (dvp != NULL && dvp->v_type == VDIR)
+ VTOI(tdp)->parent = ip->i_number;
+
+ *vpp = tdp;
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE);
+
+out:
+ vput(ap->a_dvp);
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+
+ return (error);
+}
+
+int
+fusefs_mknod(void *v)
+{
+ struct vop_mknod_args *ap = v;
+
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE);
+ vput(ap->a_dvp);
+ return (EINVAL);
+}
+
+int
+fusefs_read(void *v)
+{
+ struct vop_read_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct fuse_in_header hdr;
+ struct fuse_read_in fri;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error=0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_read\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+#ifdef FUSE_DEBUG_VNOP
+ printf("read inode=%i, offset=%p, resid=%p\n", ip->i_mnt,
+ uio->uio_offset, uio->uio_resid);
+#endif
+
+ if (uio->uio_resid == 0)
+ return (error);
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+
+ while (uio->uio_resid > 0) {
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fri);
+ msg.data = &fri;
+ msg.type = msg_buff;
+ msg.rep.buff.len = 0;
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fri.fh = ip->fufh[FUFH_RDONLY].fh_id;
+ fri.offset = uio->uio_offset;
+ fri.size = MIN(uio->uio_resid, fmp->max_write);
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_READ,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse read", 0)))
+ break;
+
+ if ((error = uiomove(msg.rep.buff.data_rcv, MIN(fri.size,
msg.rep.buff.len), uio))) {
+ break;
+ }
+
+ if (msg.rep.buff.len < fri.size)
+ break;
+
+ if (msg.rep.buff.data_rcv) {
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ msg.rep.buff.data_rcv = NULL;
+ }
+ }
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_write(void *v)
+{
+ struct vop_write_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ struct fuse_in_header hdr;
+ struct fuse_write_in fwi;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ size_t len, diff;
+ int error=0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_write\n");
+#endif
+ ip = VTOI(vp);
+ fmp = ip->i_mnt;
+#ifdef FUSE_DEBUG_VNOP
+ printf("write inode=%i, offset=%x, resid=%x\n", ip->i_mnt,
+ uio->uio_offset, uio->uio_resid);
+#endif
+
+ if (!uio->uio_resid)
+ return (error);
+
+ while (uio->uio_resid > 0) {
+ len = MIN(uio->uio_resid, fmp->max_write);
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fwi) + len;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_write_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ fwi.fh = ip->fufh[FUFH_WRONLY].fh_id;
+ fwi.offset = uio->uio_offset;
+ fwi.size = len;
+
+ memcpy(msg.data, &fwi, sizeof(fwi));
+ if ((error = uiomove((char *)msg.data + sizeof(fwi), len, uio)))
+ break;
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_WRITE,
ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse write", 0)))
+ break;
+
+ diff = len - ((struct fuse_write_out *)msg.rep.buff.data_rcv)->size;
+ if (diff < 0) {
+ error = EINVAL;
+ break;
+ }
+
+ uio->uio_resid += diff;
+ uio->uio_offset -= diff;
+
+ if (msg.rep.buff.data_rcv) {
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ msg.rep.buff.data_rcv = NULL;
+ }
+ }
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+ return (error);
+}
+
+int
+fusefs_poll(void *v)
+{
+ struct vop_poll_args *ap = v;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_poll\n");
+#endif
+
+ /*
+ * We should really check to see if I/O is possible.
+ */
+ return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
+}
+
+int
+fusefs_fsync(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_fsync\n");
+#endif
+ return 0;
+}
+
+int
+fusefs_rename(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_rename\n");
+#endif
+ return 0;
+}
+
+int
+fusefs_mkdir(void *v)
+{
+ struct vop_mkdir_args *ap = v;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct vattr *vap = ap->a_vap;
+ struct fuse_mkdir_in fmdi;
+ struct vnode *tdp = NULL;
+ struct fuse_in_header hdr;
+ struct fuse_entry_out *feo;
+ struct fuse_node *ip;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_mkdir %s\n", cnp->cn_nameptr);
+#endif
+ ip = VTOI(dvp);
+ fmp = ip->i_mnt;
+ fmdi.mode = MAKEIMODE(vap->va_type, vap->va_mode);
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_MKDIR)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = sizeof(fmdi) + cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_buff;
+ msg.rep.buff.len = sizeof(struct fuse_entry_out);
+ msg.rep.buff.data_rcv = NULL;
+ msg.cb = &fuse_sync_resp;
+
+ memcpy(msg.data, &fmdi, sizeof(fmdi));
+ memcpy((char *)msg.data + sizeof(fmdi), cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[sizeof(fmdi) + cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_MKDIR, ip->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse mkdir", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS) {
+ fmp->undef_op |= UNDEF_MKDIR;
+ }
+ goto out;
+ }
+
+ feo = (struct fuse_entry_out *)msg.rep.buff.data_rcv;
+
+ if ((error = VFS_VGET(fmp->mp, feo->nodeid, &tdp)))
+ goto out;
+
+ tdp->v_type = IFTOVT(feo->attr.mode);
+ VTOI(tdp)->vtype = tdp->v_type;
+
+ if (dvp != NULL && dvp->v_type == VDIR)
+ VTOI(tdp)->parent = ip->i_number;
+
+ *vpp = tdp;
+ VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK);
+
+out:
+ vput(dvp);
+
+ if (msg.rep.buff.data_rcv)
+ free(msg.rep.buff.data_rcv, M_FUSEFS);
+
+ return (error);
+}
+
+int
+fusefs_rmdir(void *v)
+{
+ struct vop_rmdir_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ struct fuse_node *ip, *dp;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_rmdir\n");
+ printf("len :%i, cnp: %c %c %c\n", cnp->cn_namelen,
cnp->cn_nameptr[0], cnp->cn_nameptr[1], cnp->cn_nameptr[2]);
+#endif
+ ip = VTOI(vp);
+ dp = VTOI(dvp);
+ fmp = ip->i_mnt;
+
+ /*
+ * No rmdir "." please.
+ */
+ if (dp == ip) {
+ vrele(dvp);
+ vput(vp);
+ return (EINVAL);
+ }
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_RMDIR)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_intr;
+ msg.cb = &fuse_sync_it;
+
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_RMDIR, dp->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+ if ((error = tsleep(&msg, PWAIT, "fuse rmdir", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS)
+ fmp->undef_op |= UNDEF_RMDIR;
+ if (error != ENOTEMPTY)
+ VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
+ goto out;
+ }
+
+ VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
+
+ cache_purge(dvp);
+ vput(dvp);
+ dvp = NULL;
+
+ cache_purge(ITOV(ip));
+out:
+ if (dvp)
+ vput(dvp);
+ VN_KNOTE(vp, NOTE_DELETE);
+ vput(vp);
+ return (error);
+}
+
+int
+fusefs_remove(void *v)
+{
+ struct vop_remove_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ struct fuse_node *ip;
+ struct fuse_node *dp;
+ struct fuse_in_header hdr;
+ struct fuse_mnt *fmp;
+ struct fuse_msg msg;
+ int error = 0;
+
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_remove\n");
+ printf("len :%i, cnp: %c %c %c\n", cnp->cn_namelen,
cnp->cn_nameptr[0], cnp->cn_nameptr[1], cnp->cn_nameptr[2]);
+#endif
+ ip = VTOI(vp);
+ dp = VTOI(dvp);
+ fmp = ip->i_mnt;
+
+ if (!fmp->sess_init || (fmp->undef_op & UNDEF_REMOVE)) {
+ error = ENOSYS;
+ goto out;
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.hdr = &hdr;
+ msg.len = cnp->cn_namelen + 1;
+ msg.data = malloc(msg.len, M_FUSEFS, M_WAITOK | M_ZERO);
+ msg.type = msg_intr;
+ msg.cb = &fuse_sync_it;
+
+ memcpy(msg.data, cnp->cn_nameptr, cnp->cn_namelen);
+ ((char *)msg.data)[cnp->cn_namelen] = '\0';
+
+ fuse_make_in(fmp->mp, msg.hdr, msg.len, FUSE_UNLINK,
dp->i_number, curproc);
+
+ TAILQ_INSERT_TAIL(&fmq_in, &msg, node);
+ wakeup(&fmq_in);
+
+
+ if ((error = tsleep(&msg, PWAIT, "fuse remove", 0)))
+ goto out;
+
+ if (msg.error) {
+ error = msg.error;
+
+ if (error == ENOSYS)
+ fmp->undef_op |= UNDEF_REMOVE;
+ goto out;
+ }
+
+
+ VN_KNOTE(vp, NOTE_DELETE);
+ VN_KNOTE(dvp, NOTE_WRITE);
+out:
+ if (dvp == vp)
+ vrele(vp);
+ else
+ vput(vp);
+ vput(dvp);
+ return (error);
+}
+
+int
+fusefs_strategy(void *v)
+{
+#ifdef FUSE_DEBUG_VNOP
+ printf("fusefs_strategy\n");
+#endif
+ return 0;
+}
+
+int
+fusefs_lock(void *v)
+{
+ struct vop_lock_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+#ifdef FUSE_LOCK
+ printf("fuse_lock\n");
+#endif
+ return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, NULL));
+}
+
+int
+fusefs_unlock(void *v)
+{
+ struct vop_unlock_args *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+#ifdef FUSE_LOCK
+ printf("fuse_unlock\n");
+#endif
+ return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, NULL));
+}
+
+int
+fusefs_islocked(void *v)
+{
+ struct vop_islocked_args *ap = v;
+
+#ifdef FUSE_LOCK
+ printf("fuse_islock\n");
+#endif
+ return (lockstatus(&VTOI(ap->a_vp)->i_lock));
+}
+
+int
+fusefs_advlock(void *v)
+{
+ struct vop_advlock_args *ap = v;
+ struct fuse_node *ip = VTOI(ap->a_vp);
+
+#ifdef FUSE_LOCK
+ printf("fuse_advlock\n");
+#endif
+ return (lf_advlock(&ip->i_lockf, ip->filesize, ap->a_id, ap->a_op,
+ ap->a_fl, ap->a_flags));
+}
Index: miscfs/fuse/fusefs.h
===================================================================
RCS file: miscfs/fuse/fusefs.h
diff -N miscfs/fuse/fusefs.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ miscfs/fuse/fusefs.h 5 Mar 2013 15:16:09 -0000
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012-2013 Sylvestre Gallon <
ccna...@gmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __FUSEFS_H__
+#define __FUSEFS_H__
+
+struct fuse_msg;
+
+struct fuse_mnt {
+ struct mount *mp;
+ uint32_t undef_op;
+ uint32_t max_write;
+ int sess_init;
+ int unique;
+ int fd;
+};
+
+#define UNDEF_ACCESS 1<<0
+#define UNDEF_MKDIR 1<<1
+#define UNDEF_CREATE 1<<2
+#define UNDEF_LINK 1<<3
+#define UNDEF_READLINK 1<<4
+#define UNDEF_RMDIR 1<<5
+#define UNDEF_REMOVE 1<<6
+
+typedef void (*fuse_cb)(struct fuse_msg *msg,struct fuse_out_header
*hdr, void *buf);
+
+struct rcv_buf {
+ void *data_rcv;
+ size_t len;
+};
+
+enum msg_type {
+ msg_intr,
+ msg_buff,
+ msg_buff_async,
+};
+
+struct fuse_msg {
+ struct fuse_in_header *hdr;
+ struct fuse_mnt *fmp;
+ void *data;
+ int len;
+ int error;
+
+ enum msg_type type;
+ union {
+ struct rcv_buf buff;
+ uint32_t it_res;
+ } rep;
+
+ fuse_cb cb;
+ TAILQ_ENTRY(fuse_msg) node;
+};
+
+extern struct vops fusefs_vops;
+
+/*
+ * In and Out fifo for fuse communication
+ */
+TAILQ_HEAD(fuse_msg_head, fuse_msg);
+
+extern struct fuse_msg_head fmq_in;
+extern struct fuse_msg_head fmq_wait;
+
+/*
+ * fuse helpers
+ */
+void fuse_make_in(struct mount *, struct fuse_in_header *, int,
+ enum fuse_opcode, ino_t, struct proc *);
+void fuse_init_resp(struct fuse_msg *, struct fuse_out_header *, void *);
+void fuse_sync_resp(struct fuse_msg *, struct fuse_out_header *, void *);
+void fuse_sync_it(struct fuse_msg *msg, struct fuse_out_header *hdr,
void *data);
+
+/*
+ * files helpers.
+ */
+
+int fuse_file_open(struct fuse_mnt *, struct fuse_node *, enum
fufh_type, int, int);
+int fuse_file_close(struct fuse_mnt *, struct fuse_node *, enum
fufh_type, int, int);
+
+void fuse_internal_attr_fat2vat(struct mount *, struct fuse_attr *,
struct vattr *);
+
+/*
+ * The root inode is the root of the file system. Inode 0 can't be used for
+ * normal purposes and bad blocks are normally linked to inode 1, thus
+ * the root inode is 2.
+ */
+#define FUSE_ROOTINO ((ino_t)1)
+#define VFSTOFUSEFS(mp) ((struct fuse_mnt *)((mp)->mnt_data))
+
+#define MAX_FUSE_DEV 4
+/*
+#define FUSE_DEBUG_VNOP 42
+#define FUSE_DEBUG_VFS 42
+#define FUSE_DEBUG 42
+#define FUSE_DEV_DEBUG 42
+#define FUSE_DEBUG_MSG 42
+*/
+/*
+ * Helpers
+ */
+
+#endif /* __FUSEFS_H__ */
Index: sys/conf.h
===================================================================
RCS file: /cvs/src/sys/sys/conf.h,v
retrieving revision 1.119
diff -u -p -u -p -r1.119 conf.h
--- sys/conf.h 23 Aug 2012 06:12:49 -0000 1.119
+++ sys/conf.h 5 Mar 2013 15:16:09 -0000
@@ -509,6 +509,13 @@ extern struct cdevsw cdevsw[];
(dev_type_stop((*))) enodev, 0, selfalse, \
(dev_type_mmap((*))) enodev }
+/* open, close, read, write, poll, ioctl */
+#define cdev_fuse_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), dev_init(c,n,ioctl), \
+ (dev_type_stop((*))) enodev, 0, dev_init(c,n,poll), \
+ (dev_type_mmap((*))) enodev }
+
#endif
/*
@@ -657,6 +664,7 @@ cdev_decl(urio);
cdev_decl(hotplug);
cdev_decl(gpio);
cdev_decl(amdmsr);
+cdev_decl(fuse);
#endif
Index: sys/malloc.h
===================================================================
RCS file: /cvs/src/sys/sys/malloc.h,v
retrieving revision 1.101
diff -u -p -u -p -r1.101 malloc.h
--- sys/malloc.h 7 Feb 2013 11:06:42 -0000 1.101
+++ sys/malloc.h 5 Mar 2013 15:16:09 -0000
@@ -118,7 +118,8 @@
#define M_TTYS 62 /* allocated tty structures */
#define M_EXEC 63 /* argument lists & other mem used by exec */
#define M_MISCFSMNT 64 /* miscfs mount structures */
-/* 65-73 - free */
+#define M_FUSEFS 65 /* fusefs mount structures */
+/* 66-73 - free */
#define M_PFKEY 74 /* pfkey data */
#define M_TDB 75 /* Transforms database */
#define M_XDATA 76 /* IPsec data */
@@ -247,7 +248,7 @@
"ttys", /* 62 M_TTYS */ \
"exec", /* 63 M_EXEC */ \
"miscfs mount", /* 64 M_MISCFSMNT */ \
- NULL, \
+ "fusefs mount", /* 65 M_FUSEFS */ \
NULL, \
NULL, \
NULL, \
Index: sys/mount.h
===================================================================
RCS file: /cvs/src/sys/sys/mount.h,v
retrieving revision 1.108
diff -u -p -u -p -r1.108 mount.h
--- sys/mount.h 5 Sep 2012 17:01:06 -0000 1.108
+++ sys/mount.h 5 Mar 2013 15:16:09 -0000
@@ -258,6 +258,15 @@ struct procfs_args {
#define PROCFS_ARGSVERSION 1
#define PROCFSMNT_LINUXCOMPAT 0x01
+/*
+ * Arguments to mount fusefs filesystems
+ */
+struct fusefs_args {
+ char *name;
+ char *url;
+ int fd;
+ int flags;
+};
/*
* file system statistics
@@ -325,6 +334,7 @@ struct statfs {
#define MOUNT_NCPFS "ncpfs" /* NetWare Network File System */
#define MOUNT_NTFS "ntfs" /* NTFS */
#define MOUNT_UDF "udf" /* UDF */
+#define MOUNT_FUSEFS "fuse" /* FUSE */
/*
* Structure per mounted file system. Each mounted file system has an
Index: sys/vnode.h
===================================================================
RCS file: /cvs/src/sys/sys/vnode.h,v
retrieving revision 1.113
diff -u -p -u -p -r1.113 vnode.h
--- sys/vnode.h 8 Oct 2012 15:43:08 -0000 1.113
+++ sys/vnode.h 5 Mar 2013 15:16:09 -0000
@@ -71,13 +71,13 @@ enum vtype { VNON, VREG, VDIR, VBLK, VCH
enum vtagtype {
VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_MSDOSFS,
VT_PORTAL, VT_PROCFS, VT_AFS, VT_ISOFS, VT_ADOSFS,
- VT_EXT2FS, VT_VFS, VT_NTFS, VT_UDF,
+ VT_EXT2FS, VT_VFS, VT_NTFS, VT_UDF, VT_FUSEFS
};
#define VTAG_NAMES \
"NON", "UFS", "NFS", "MFS", "MSDOSFS", \
"PORTAL", "PROCFS", "AFS", "ISOFS", "ADOSFS", \
- "EXT2FS", "VFS", "NTFS", "UDF"
+ "EXT2FS", "VFS", "NTFS", "UDF", "FUSEFS"
/*
* Each underlying filesystem allocates its own private area and hangs