+2002-12-05 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * 64 bit file offset fixes in the fuse kernel module
+
+ * Added function 'fuse_exit()' which can be used to exit the main
+ loop
+
2002-12-03 Miklos Szeredi <mszeredi@inf.bme.hu>
* Added _FILE_OFFSET_BITS=64 define to fuse.h. Note, that this is
*/
int fuse_mount(const char *mountpoint, const char *args[]);
+/*
+ * Umount a FUSE mountpoint
+ *
+ * @param mountpoint the mount point path
+ */
+void fuse_unmount(const char *mountpoint);
+
/**
* Create a new FUSE filesystem.
*
*/
struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op);
+/**
+ * Destroy the FUSE handle.
+ *
+ * The filesystem is not unmounted.
+ *
+ * @param f the FUSE handle
+ */
+void fuse_destroy(struct fuse *f);
+
/**
* FUSE event loop.
*
*/
void fuse_loop(struct fuse *f);
+
+/**
+ * Exit from event loop
+ *
+ * @param f the FUSE handle
+ */
+void fuse_exit(struct fuse *f);
+
/**
* FUSE event loop with multiple threads
*
*/
void fuse_loop_mt(struct fuse *f);
-/**
- * Destroy the FUSE handle.
- *
- * The filesystem is not unmounted.
- *
- * @param f the FUSE handle
- */
-void fuse_destroy(struct fuse *f);
-
/**
* Get the current context
*
if(fc->sb == NULL)
return -ENODEV;
if(req == NULL)
- return -ERESTARTSYS;
+ return -EINTR;
ret = copy_in_args(req->in, buf, nbytes);
spin_lock(&fuse_lock);
buffer = kmap(page);
memset(&inarg, 0, sizeof(inarg));
- inarg.offset = page->index << PAGE_CACHE_SHIFT;
+ inarg.offset = (unsigned long long) page->index << PAGE_CACHE_SHIFT;
inarg.size = PAGE_CACHE_SIZE;
in.h.opcode = FUSE_READ;
buffer = kmap(page);
memset(&inarg, 0, sizeof(inarg));
- inarg.offset = (page->index << PAGE_CACHE_SHIFT) + offset;
+ inarg.offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) +
+ offset;
inarg.size = count;
in.h.opcode = FUSE_WRITE;
fuse.c \
fuse_mt.c \
helper.c \
+ mount.c
fuse_i.h
size_t outsize;
struct fuse_out_header *out;
- if(error > 0) {
- fprintf(stderr, "fuse: positive error code: %i\n", error);
+ if(error <= -512 || error > 0) {
+ fprintf(stderr, "fuse: bad error value: %i\n", error);
error = -ERANGE;
}
outsize = sizeof(struct fuse_out_header) + argsize;
outbuf = (char *) malloc(outsize);
out = (struct fuse_out_header *) outbuf;
+ memset(out, 0, sizeof(struct fuse_out_header));
out->unique = in->unique;
out->error = error;
if(argsize != 0)
res = f->op.getattr(path, &buf);
free(path);
}
+
if(res == 0) {
+ memset(&arg, 0, sizeof(struct fuse_lookup_out));
convert_stat(&buf, &arg.attr);
arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique);
if(f->flags & FUSE_DEBUG) {
res = f->op.getattr(path, &buf);
free(path);
}
- if(res == 0)
+
+ if(res == 0) {
+ memset(&arg, 0, sizeof(struct fuse_getattr_out));
convert_stat(&buf, &arg.attr);
+ }
send_reply(f, in, res, &arg, sizeof(arg));
}
if(!res) {
struct stat buf;
res = f->op.getattr(path, &buf);
- if(!res)
+ if(!res) {
+ memset(&outarg, 0, sizeof(struct fuse_setattr_out));
convert_stat(&buf, &outarg.attr);
+ }
}
}
free(path);
free(path);
}
fflush(dh.fp);
+
+ memset(&arg, 0, sizeof(struct fuse_getdir_out));
arg.fd = fileno(dh.fp);
send_reply(f, in, res, &arg, sizeof(arg));
fclose(dh.fp);
free(path);
}
if(res == 0) {
+ memset(&outarg, 0, sizeof(struct fuse_mknod_out));
convert_stat(&buf, &outarg.attr);
outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr,
in->unique);
fflush(stdout);
}
}
+ memset(out, 0, sizeof(struct fuse_out_header));
out->unique = in->unique;
out->error = res;
outsize = sizeof(struct fuse_out_header) + size;
struct fuse_statfs_out arg;
res = -ENOSYS;
- if(f->op.statfs)
+ if(f->op.statfs) {
+ memset(&arg, 0, sizeof(struct fuse_statfs_out));
res = f->op.statfs((struct fuse_statfs *) &arg.st);
+ }
send_reply(f, in, res, &arg, sizeof(arg));
}
do {
res = read(f->fd, cmd->buf, FUSE_MAX_IN);
if(res == -1) {
+ free_cmd(cmd);
+ if(errno == EINTR)
+ return NULL;
+
/* ENODEV means we got unmounted, so we silenty return failure */
if(errno != ENODEV) {
- perror("fuse: reading device");
/* BAD... This will happen again */
+ perror("fuse: reading device");
}
- free_cmd(cmd);
+
+ fuse_exit(f);
return NULL;
}
if((size_t) res < sizeof(struct fuse_in_header)) {
- fprintf(stderr, "short read on fuse device\n");
- /* Cannot happen */
free_cmd(cmd);
+ /* Cannot happen */
+ fprintf(stderr, "short read on fuse device\n");
+ fuse_exit(f);
return NULL;
}
cmd->buflen = res;
return cmd;
}
-
void fuse_loop(struct fuse *f)
{
while(1) {
- struct fuse_cmd *cmd = __fuse_read_cmd(f);
+ struct fuse_cmd *cmd;
+
+ if(f->exited)
+ return;
+
+ cmd = __fuse_read_cmd(f);
if(cmd == NULL)
- exit(1);
+ continue;
__fuse_process_cmd(f, cmd);
}
}
+void fuse_exit(struct fuse *f)
+{
+ f->exited = 1;
+}
+
struct fuse_context *fuse_get_context(struct fuse *f)
{
if(f->getcontext)
f->getcontext = NULL;
f->context.uid = 0;
f->context.gid = 0;
+ f->exited = 0;
root = (struct node *) calloc(1, sizeof(struct node));
root->mode = 0;
struct fuse_context *(*getcontext)(struct fuse *);
struct fuse_context context;
pthread_key_t context_key;
+ volatile int exited;
};
struct fuse_dirhandle {
struct fuse *f = w->f;
while(1) {
- struct fuse_cmd *cmd = __fuse_read_cmd(w->f);
+ struct fuse_cmd *cmd;
+
+ if(f->exited)
+ break;
+
+ cmd = __fuse_read_cmd(w->f);
if(cmd == NULL)
- pthread_exit(NULL);
+ continue;
if(f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) {
pthread_mutex_lock(&f->lock);
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <unistd.h>
+#include <string.h>
#include <limits.h>
#include <signal.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <fcntl.h>
-#include <sys/wait.h>
#define FUSE_MOUNTED_ENV "_FUSE_MOUNTED"
#define FUSE_UMOUNT_CMD_ENV "_FUSE_UNMOUNT_CMD"
-#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
-#define FUSERMOUNT_PROG "fusermount"
+static struct fuse *fuse;
static void usage(char *progname)
{
exit(1);
}
-static char umount_cmd[1024];
-static int fuse_fd;
-
-static void fuse_unmount()
-{
- close(fuse_fd);
- if(umount_cmd[0] != '\0')
- system(umount_cmd);
-}
-
-/* return value:
- * >= 0 => fd
- * -1 => error
- */
-static int receive_fd(int fd)
-{
- struct msghdr msg;
- struct iovec iov;
- char buf[1];
- int rv;
- int connfd = -1;
- char ccmsg[CMSG_SPACE(sizeof(connfd))];
- struct cmsghdr *cmsg;
-
- iov.iov_base = buf;
- iov.iov_len = 1;
-
- msg.msg_name = 0;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- /* old BSD implementations should use msg_accrights instead of
- * msg_control; the interface is different. */
- msg.msg_control = ccmsg;
- msg.msg_controllen = sizeof(ccmsg);
-
- while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
- if (rv == -1) {
- perror("recvmsg");
- return -1;
- }
- if(!rv) {
- /* EOF */
- fprintf(stderr, "got EOF\n");
- return -1;
- }
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg->cmsg_type == SCM_RIGHTS) {
- fprintf(stderr, "got control message of unknown type %d\n",
- cmsg->cmsg_type);
- return -1;
- }
- return *(int*)CMSG_DATA(cmsg);
-}
-
-int fuse_mount(const char *mountpoint, const char *args[])
-{
- const char *mountprog = FUSERMOUNT_PROG;
- int fds[2], pid;
- int res;
- int rv;
-
- snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u %s", mountprog,
- mountpoint);
-
- res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
- if(res == -1) {
- perror("fuse: socketpair() failed");
- return -1;
- }
-
- pid = fork();
- if(pid == -1) {
- perror("fuse: fork() failed");
- close(fds[0]);
- close(fds[1]);
- return -1;
- }
-
- if(pid == 0) {
- char env[10];
- char **newargv;
- int numargs = 0;
- int actr;
- int i;
-
- if(args != NULL)
- while(args[numargs] != NULL)
- numargs ++;
-
- newargv = (char **) malloc((1 + numargs + 2) * sizeof(char *));
- actr = 0;
- newargv[actr++] = strdup(mountprog);
- for(i = 0; i < numargs; i++)
- newargv[actr++] = strdup(args[i]);
- newargv[actr++] = strdup(mountpoint);
- newargv[actr++] = NULL;
-
- close(fds[1]);
- fcntl(fds[0], F_SETFD, 0);
- snprintf(env, sizeof(env), "%i", fds[0]);
- setenv(FUSE_COMMFD_ENV, env, 1);
- execvp(mountprog, newargv);
- perror("fuse: failed to exec fusermount");
- exit(1);
- }
-
- close(fds[0]);
- rv = receive_fd(fds[1]);
- close(fds[1]);
- waitpid(pid, NULL, 0); /* bury zombie */
-
- return rv;
-}
-
static void exit_handler()
{
- exit(0);
+ if(fuse != NULL)
+ fuse_exit(fuse);
}
static void set_signal_handlers()
int argctr = 1;
int flags;
int multithreaded;
- struct fuse *fuse;
char *isreexec = getenv(FUSE_MOUNTED_ENV);
+ int fuse_fd;
+ char *fuse_mountpoint = NULL;
+ char umount_cmd[1024] = "";
if(isreexec == NULL) {
if(argc < 2 || argv[1][0] == '-')
usage(argv[0]);
- fuse_fd = fuse_mount(argv[1], NULL);
+ fuse_mountpoint = strdup(argv[1]);
+ fuse_fd = fuse_mount(fuse_mountpoint, NULL);
if(fuse_fd == -1)
exit(1);
strncpy(umount_cmd, tmpstr, sizeof(umount_cmd) - 1);
}
- atexit(fuse_unmount);
set_signal_handlers();
flags = 0;
fuse_loop_mt(fuse);
else
fuse_loop(fuse);
+
+ close(fuse_fd);
+ if(fuse_mountpoint != NULL)
+ fuse_unmount(fuse_mountpoint);
+ else if(umount_cmd[0] != '\0')
+ system(umount_cmd);
}
--- /dev/null
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
+
+ This program can be distributed under the terms of the GNU LGPL.
+ See the file COPYING.LIB.
+*/
+
+#include "fuse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#define FUSERMOUNT_PROG "fusermount"
+#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
+
+
+/* return value:
+ * >= 0 => fd
+ * -1 => error
+ */
+static int receive_fd(int fd)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ char buf[1];
+ int rv;
+ int connfd = -1;
+ char ccmsg[CMSG_SPACE(sizeof(connfd))];
+ struct cmsghdr *cmsg;
+
+ iov.iov_base = buf;
+ iov.iov_len = 1;
+
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ /* old BSD implementations should use msg_accrights instead of
+ * msg_control; the interface is different. */
+ msg.msg_control = ccmsg;
+ msg.msg_controllen = sizeof(ccmsg);
+
+ while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+ if (rv == -1) {
+ perror("recvmsg");
+ return -1;
+ }
+ if(!rv) {
+ /* EOF */
+ return -1;
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg->cmsg_type == SCM_RIGHTS) {
+ fprintf(stderr, "got control message of unknown type %d\n",
+ cmsg->cmsg_type);
+ return -1;
+ }
+ return *(int*)CMSG_DATA(cmsg);
+}
+
+void fuse_unmount(const char *mountpoint)
+{
+ const char *mountprog = FUSERMOUNT_PROG;
+ char umount_cmd[1024];
+
+ snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u %s", mountprog,
+ mountpoint);
+
+ umount_cmd[sizeof(umount_cmd) - 1] = '\0';
+ system(umount_cmd);
+}
+
+int fuse_mount(const char *mountpoint, const char *args[])
+{
+ const char *mountprog = FUSERMOUNT_PROG;
+ int fds[2], pid;
+ int res;
+ int rv;
+
+ res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
+ if(res == -1) {
+ perror("fuse: socketpair() failed");
+ return -1;
+ }
+
+ pid = fork();
+ if(pid == -1) {
+ perror("fuse: fork() failed");
+ close(fds[0]);
+ close(fds[1]);
+ return -1;
+ }
+
+ if(pid == 0) {
+ char env[10];
+ char **newargv;
+ int numargs = 0;
+ int actr;
+ int i;
+
+ if(args != NULL)
+ while(args[numargs] != NULL)
+ numargs ++;
+
+ newargv = (char **) malloc((1 + numargs + 2) * sizeof(char *));
+ actr = 0;
+ newargv[actr++] = strdup(mountprog);
+ for(i = 0; i < numargs; i++)
+ newargv[actr++] = strdup(args[i]);
+ newargv[actr++] = strdup(mountpoint);
+ newargv[actr++] = NULL;
+
+ close(fds[1]);
+ fcntl(fds[0], F_SETFD, 0);
+ snprintf(env, sizeof(env), "%i", fds[0]);
+ setenv(FUSE_COMMFD_ENV, env, 1);
+ execvp(mountprog, newargv);
+ perror("fuse: failed to exec fusermount");
+ exit(1);
+ }
+
+ close(fds[0]);
+ rv = receive_fd(fds[1]);
+ close(fds[1]);
+ waitpid(pid, NULL, 0); /* bury zombie */
+
+ return rv;
+}