cleanups
diff --git a/.cvsignore b/.cvsignore
index 5743e9b..d6dac71 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,2 +1,2 @@
-fusepro
+fusexmp
avfsd
diff --git a/Makefile b/Makefile
index 97d19d4..92d91ad 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,12 @@
CC = gcc
CFLAGS = -Wall -g `glib-config --cflags`
-LDFLAGS = `glib-config --libs` -ldl -L ../avfs/libneon/
+LDFLAGS = `glib-config --libs` -ldl -L ../avfs/libneon/ -L lib
#LIBXML = -lxml
LIBXML = -lxmltok -lxmlparse
-LDLIBS = -lneon $(LIBXML) -lpthread
+LDLIBS = -lneon $(LIBXML) -lfuse -lpthread
CPPFLAGS = -Iinclude -I ../avfs/include
-
-
-all: kernel/fuse.o fusepro avfsd
+all: kernel/fuse.o fusexmp avfsd
kernel/fuse.o: FORCE
make -C kernel fuse.o
@@ -16,15 +14,21 @@
lib/libfuse.a: FORCE
make -C lib libfuse.a
-fusepro: fusepro.o lib/libfuse.a
+lib/libfuse.so: FORCE
+ make -C lib libfuse.so
-avfsd: usermux.o avfsd.o ../avfs/lib/avfs.o lib/libfuse.a
+fusexmp: fusexmp.o lib/libfuse.so
+ gcc $(CFLAGS) $(LDFLAGS) -o fusexmp fusexmp.o $(LDLIBS)
+
+avfsd_objs = usermux.o avfsd.o ../avfs/lib/avfs.o
+avfsd: $(avfsd_objs) lib/libfuse.so
+ gcc $(CFLAGS) $(LDFLAGS) -o avfsd $(avfsd_objs) $(LDLIBS)
clean:
make -C kernel clean
make -C lib clean
rm -f *.o
- rm -f fusepro avfsd
+ rm -f fusexmp avfsd
rm -f *~
FORCE:
diff --git a/fusepro.c b/fusepro.c
deleted file mode 100644
index ce32000..0000000
--- a/fusepro.c
+++ /dev/null
@@ -1,314 +0,0 @@
-#ifdef linux
-/* For pread()/pwrite() */
-#define _XOPEN_SOURCE 500
-#endif
-
-#include <fuse.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <signal.h>
-#include <utime.h>
-#include <fcntl.h>
-
-static struct fuse *pro_fuse;
-
-static int pro_getattr(struct fuse_cred *cred, const char *path,
- struct stat *stbuf)
-{
- int res;
-
- res = lstat(path, stbuf);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_readlink(struct fuse_cred *cred, const char *path, char *buf,
- size_t size)
-{
- int res;
-
- res = readlink(path, buf, size - 1);
- if(res == -1)
- return -errno;
-
- buf[res] = '\0';
- return 0;
-}
-
-
-static int pro_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
- fuse_dirfil_t filler)
-{
- DIR *dp;
- struct dirent *de;
- int res;
-
- dp = opendir(path);
- if(dp == NULL)
- return -errno;
-
- while((de = readdir(dp)) != NULL) {
- res = filler(h, de->d_name, de->d_type);
- if(res != 0)
- break;
- }
-
- closedir(dp);
- return res;
-}
-
-static int pro_mknod(struct fuse_cred *cred, const char *path, mode_t mode,
- dev_t rdev)
-{
- int res;
-
- res = mknod(path, mode, rdev);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_mkdir(struct fuse_cred *cred, const char *path, mode_t mode)
-{
- int res;
-
- res = mkdir(path, mode);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_unlink(struct fuse_cred *cred, const char *path)
-{
- int res;
-
- res = unlink(path);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_rmdir(struct fuse_cred *cred, const char *path)
-{
- int res;
-
- res = rmdir(path);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_symlink(struct fuse_cred *cred, const char *from,
- const char *to)
-{
- int res;
-
- res = symlink(from, to);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_rename(struct fuse_cred *cred, const char *from, const char *to)
-{
- int res;
-
- res = rename(from, to);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_link(struct fuse_cred *cred, const char *from, const char *to)
-{
- int res;
-
- res = link(from, to);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_chmod(struct fuse_cred *cred, const char *path, mode_t mode)
-{
- int res;
-
- res = chmod(path, mode);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_chown(struct fuse_cred *cred, const char *path, uid_t uid,
- gid_t gid)
-{
- int res;
-
- res = lchown(path, uid, gid);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_truncate(struct fuse_cred *cred, const char *path, off_t size)
-{
- int res;
-
- res = truncate(path, size);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-static int pro_utime(struct fuse_cred *cred, const char *path,
- struct utimbuf *buf)
-{
- int res;
-
- res = utime(path, buf);
- if(res == -1)
- return -errno;
-
- return 0;
-}
-
-
-static int pro_open(struct fuse_cred *cred, const char *path, int flags)
-{
- int res;
-
- res = open(path, flags);
- if(res == -1)
- return -errno;
-
- close(res);
- return 0;
-}
-
-static int pro_read(struct fuse_cred *cred, const char *path, char *buf,
- size_t size, off_t offset)
-{
- int fd;
- int res;
-
- fd = open(path, O_RDONLY);
- if(fd == -1)
- return -errno;
-
- res = pread(fd, buf, size, offset);
- if(res == -1)
- res = -errno;
-
- close(fd);
- return res;
-}
-
-static int pro_write(struct fuse_cred *cred, const char *path, const char *buf,
- size_t size, off_t offset)
-{
- int fd;
- int res;
-
- fd = open(path, O_WRONLY);
- if(fd == -1)
- return -errno;
-
- res = pwrite(fd, buf, size, offset);
- if(res == -1)
- res = -errno;
-
- close(fd);
- return res;
-}
-
-static void exit_handler()
-{
- exit(0);
-}
-
-static void set_signal_handlers()
-{
- struct sigaction sa;
-
- sa.sa_handler = exit_handler;
- sigemptyset(&(sa.sa_mask));
- sa.sa_flags = 0;
-
- if (sigaction(SIGHUP, &sa, NULL) == -1 ||
- sigaction(SIGINT, &sa, NULL) == -1 ||
- sigaction(SIGTERM, &sa, NULL) == -1) {
-
- perror("Cannot set exit signal handlers");
- exit(1);
- }
-
- sa.sa_handler = SIG_IGN;
-
- if(sigaction(SIGPIPE, &sa, NULL) == -1) {
- perror("Cannot set ignored signals");
- exit(1);
- }
-}
-
-static void cleanup()
-{
- fuse_unmount(pro_fuse);
- fuse_destroy(pro_fuse);
-}
-
-static struct fuse_operations pro_oper = {
- getattr: pro_getattr,
- readlink: pro_readlink,
- getdir: pro_getdir,
- mknod: pro_mknod,
- mkdir: pro_mkdir,
- symlink: pro_symlink,
- unlink: pro_unlink,
- rmdir: pro_rmdir,
- rename: pro_rename,
- link: pro_link,
- chmod: pro_chmod,
- chown: pro_chown,
- truncate: pro_truncate,
- utime: pro_utime,
- open: pro_open,
- read: pro_read,
- write: pro_write,
-};
-
-int main(int argc, char *argv[])
-{
- int res;
- if(argc != 2) {
- fprintf(stderr, "usage: %s mount_dir\n", argv[0]);
- exit(1);
- }
-
- set_signal_handlers();
- atexit(cleanup);
-
- pro_fuse = fuse_new(0);
- res = fuse_mount(pro_fuse, argv[1]);
- if(res == -1)
- exit(1);
-
- fuse_set_operations(pro_fuse, &pro_oper);
- fuse_loop(pro_fuse);
-
- return 0;
-}
diff --git a/fusexmp.c b/fusexmp.c
new file mode 100644
index 0000000..b00039d
--- /dev/null
+++ b/fusexmp.c
@@ -0,0 +1,410 @@
+#ifdef linux
+/* For pread()/pwrite() */
+#define _XOPEN_SOURCE 500
+#endif
+
+/* For setgroups() */
+#define _BSD_SOURCE
+
+#include <fuse.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <sys/fsuid.h>
+
+static struct fuse *xmp_fuse;
+
+static int set_creds(struct fuse_cred *cred)
+{
+ int res;
+
+ res = setfsuid(cred->uid);
+ if(res == -1)
+ return -errno;
+
+ res = setfsgid(cred->gid);
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static void restore_creds()
+{
+ setfsuid(getuid());
+ setfsgid(getgid());
+}
+
+static int xmp_getattr(struct fuse_cred *cred, const char *path,
+ struct stat *stbuf)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = lstat(path, stbuf);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_readlink(struct fuse_cred *cred, const char *path, char *buf,
+ size_t size)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = readlink(path, buf, size - 1);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ buf[res] = '\0';
+ return 0;
+}
+
+
+static int xmp_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h,
+ fuse_dirfil_t filler)
+{
+ DIR *dp;
+ struct dirent *de;
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ dp = opendir(path);
+ restore_creds();
+ if(dp == NULL)
+ return -errno;
+
+ while((de = readdir(dp)) != NULL) {
+ res = filler(h, de->d_name, de->d_type);
+ if(res != 0)
+ break;
+ }
+
+ closedir(dp);
+ return res;
+}
+
+static int xmp_mknod(struct fuse_cred *cred, const char *path, mode_t mode,
+ dev_t rdev)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = mknod(path, mode, rdev);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_mkdir(struct fuse_cred *cred, const char *path, mode_t mode)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = mkdir(path, mode);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_unlink(struct fuse_cred *cred, const char *path)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = unlink(path);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_rmdir(struct fuse_cred *cred, const char *path)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = rmdir(path);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_symlink(struct fuse_cred *cred, const char *from,
+ const char *to)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = symlink(from, to);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_rename(struct fuse_cred *cred, const char *from, const char *to)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = rename(from, to);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_link(struct fuse_cred *cred, const char *from, const char *to)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = link(from, to);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_chmod(struct fuse_cred *cred, const char *path, mode_t mode)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = chmod(path, mode);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_chown(struct fuse_cred *cred, const char *path, uid_t uid,
+ gid_t gid)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = lchown(path, uid, gid);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_truncate(struct fuse_cred *cred, const char *path, off_t size)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = truncate(path, size);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+static int xmp_utime(struct fuse_cred *cred, const char *path,
+ struct utimbuf *buf)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = utime(path, buf);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ return 0;
+}
+
+
+static int xmp_open(struct fuse_cred *cred, const char *path, int flags)
+{
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ res = open(path, flags);
+ restore_creds();
+ if(res == -1)
+ return -errno;
+
+ close(res);
+ return 0;
+}
+
+static int xmp_read(struct fuse_cred *cred, const char *path, char *buf,
+ size_t size, off_t offset)
+{
+ int fd;
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ fd = open(path, O_RDONLY);
+ restore_creds();
+ if(fd == -1)
+ return -errno;
+
+ res = pread(fd, buf, size, offset);
+ if(res == -1)
+ res = -errno;
+
+ close(fd);
+ return res;
+}
+
+static int xmp_write(struct fuse_cred *cred, const char *path, const char *buf,
+ size_t size, off_t offset)
+{
+ int fd;
+ int res;
+
+ res = set_creds(cred);
+ if(res)
+ return res;
+ fd = open(path, O_WRONLY);
+ restore_creds();
+ if(fd == -1)
+ return -errno;
+
+ res = pwrite(fd, buf, size, offset);
+ if(res == -1)
+ res = -errno;
+
+ close(fd);
+ return res;
+}
+
+static void exit_handler()
+{
+ exit(0);
+}
+
+static void set_signal_handlers()
+{
+ struct sigaction sa;
+
+ sa.sa_handler = exit_handler;
+ sigemptyset(&(sa.sa_mask));
+ sa.sa_flags = 0;
+
+ if (sigaction(SIGHUP, &sa, NULL) == -1 ||
+ sigaction(SIGINT, &sa, NULL) == -1 ||
+ sigaction(SIGTERM, &sa, NULL) == -1) {
+
+ perror("Cannot set exit signal handlers");
+ exit(1);
+ }
+
+ sa.sa_handler = SIG_IGN;
+
+ if(sigaction(SIGPIPE, &sa, NULL) == -1) {
+ perror("Cannot set ignored signals");
+ exit(1);
+ }
+}
+
+static void cleanup()
+{
+ fuse_unmount(xmp_fuse);
+ fuse_destroy(xmp_fuse);
+}
+
+static struct fuse_operations xmp_oper = {
+ getattr: xmp_getattr,
+ readlink: xmp_readlink,
+ getdir: xmp_getdir,
+ mknod: xmp_mknod,
+ mkdir: xmp_mkdir,
+ symlink: xmp_symlink,
+ unlink: xmp_unlink,
+ rmdir: xmp_rmdir,
+ rename: xmp_rename,
+ link: xmp_link,
+ chmod: xmp_chmod,
+ chown: xmp_chown,
+ truncate: xmp_truncate,
+ utime: xmp_utime,
+ open: xmp_open,
+ read: xmp_read,
+ write: xmp_write,
+};
+
+int main(int argc, char *argv[])
+{
+ int res;
+ if(argc != 2) {
+ fprintf(stderr, "usage: %s mount_dir\n", argv[0]);
+ exit(1);
+ }
+
+ set_signal_handlers();
+ atexit(cleanup);
+ setgroups(0, NULL);
+
+ xmp_fuse = fuse_new(0,0);
+ res = fuse_mount(xmp_fuse, argv[1]);
+ if(res == -1)
+ exit(1);
+
+ fuse_set_operations(xmp_fuse, &xmp_oper);
+
+ fuse_loop(xmp_fuse);
+
+ return 0;
+}
diff --git a/include/fuse.h b/include/fuse.h
index 4edb0c7..4cddaaf 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -12,16 +12,56 @@
#include <sys/stat.h>
#include <utime.h>
+/** Handle for a FUSE filesystem */
struct fuse;
+
+/** Handle for a getdir() operation */
typedef struct fuse_dirhandle *fuse_dirh_t;
+/** Function to add an entry in a getdir() operation */
typedef int (*fuse_dirfil_t) (fuse_dirh_t, const char *, int type);
+/** Credentials for an operation, these are determined by the fsuid
+ and fsgid of the calling process */
struct fuse_cred {
uid_t uid;
gid_t gid;
+ /* FIXME: supplementary groups should also be included */
};
+/**
+ * The file system operations:
+ *
+ * Most of these should work very similarly to the well known UNIX
+ * file system operations. Exceptions are:
+ *
+ * - All operations get a fuse_cred structure by which the filesystem
+ * implementation can check, whether the operation is permitted or
+ * not.
+ *
+ * - All operations should return the negated error value (-errno) on
+ * error.
+ *
+ * - readlink() should fill the buffer with a null terminated string.
+ * The buffer size argument includes the space for the terminating
+ * null character. If the linkname is too long to fit in the buffer,
+ * it should be truncated. The return value should be 0 for success.
+ *
+ * - getdir() is the opendir(), readdir(), ..., closedir() sequence
+ * in one call. For each directory entry the filldir parameter should
+ * be called.
+ *
+ * - There is no create() operation, mknod() will be called for
+ * creation of all non directory, non symlink nodes.
+ *
+ * - open() should not return a filehandle, but 0 on success. No
+ * creation, or trunctation flags (O_CREAT, O_EXCL, O_TRUNC) will be
+ * passed to open(). Open should only check if the operation is
+ * permitted for the given flags.
+ *
+ * - read(), write() are not passed a filehandle, but rather a
+ * pathname. The offset of the read and write is passed as the last
+ * argument, like the pread() and pwrite() system calls. */
struct fuse_operations {
int (*getattr) (struct fuse_cred *, const char *, struct stat *);
int (*readlink) (struct fuse_cred *, const char *, char *, size_t);
@@ -42,16 +82,64 @@
int (*write) (struct fuse_cred *, const char *, const char *, size_t, off_t);
};
+/* FUSE flags: */
#define FUSE_MULTITHREAD (1 << 0)
-struct fuse *fuse_new(int flags);
+/**
+ * Create a new FUSE filesystem. The filesystem is not yet mounted
+ *
+ * @param flags any combination of the FUSE flags defined above, or 0
+ * @param root the file type of the root node. 0 is the default (directory).
+ * @return the created FUSE handle
+ */
+struct fuse *fuse_new(int flags, mode_t root);
-int fuse_mount(struct fuse *f, const char *dir);
+/**
+ * Connect to the kernel and mount the filesystem.
+ *
+ * @param f the FUSE handle
+ * @param mnt the mount point
+ * @return 0 on success -1 on failure
+ */
+int fuse_mount(struct fuse *f, const char *mnt);
+/**
+ * Set the filesystem operations.
+ *
+ * Operations which are initialised to NULL will return ENOSYS to the
+ * calling process. This function can be called anytime after
+ * fuse_new() and before fuse_loop().
+ *
+ * @param f the FUSE handle
+ * @param op the operations
+ */
void fuse_set_operations(struct fuse *f, const struct fuse_operations *op);
+/**
+ * FUSE event loop.
+ *
+ * Requests from the kernel are processed, and the apropriate
+ * operations are called.
+ *
+ * @param f the FUSE handle
+ */
void fuse_loop(struct fuse *f);
+/**
+ * Disconnect from the kernel and unmount the filesystem
+ *
+ * @param f the FUSE handle
+ */
int fuse_unmount(struct fuse *f);
+/**
+ * Destroy the filesystem.
+ *
+ * The filesystem is not unmounted (call fuse_unmount() for that).
+ * After a fork() system call it is possible to call fuse_destroy() in
+ * one process, and leave the other process to service the filesystem
+ * requests.
+ *
+ * @param f the FUSE handle
+ */
void fuse_destroy(struct fuse *f);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index a6e74df..22897d4 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -9,11 +9,12 @@
/* This file defines the kernel interface of FUSE */
-#define FUSE_MOUNT_VERSION 1
+#define FUSE_KERNEL_VERSION 1
struct fuse_mount_data {
int version;
int fd;
+ unsigned int rootmode;
};
#define FUSE_ROOT_INO 1
diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h
index b738bed..b3f3a9c 100644
--- a/kernel/fuse_i.h
+++ b/kernel/fuse_i.h
@@ -12,8 +12,6 @@
#include <linux/spinlock.h>
#include <linux/rwsem.h>
-#define FUSE_VERSION "0.1"
-
#define MAX_CLEARED 256
/**
diff --git a/kernel/inode.c b/kernel/inode.c
index 77e8469..5fb4a66 100644
--- a/kernel/inode.c
+++ b/kernel/inode.c
@@ -66,8 +66,8 @@
return NULL;
}
- if(d->version != FUSE_MOUNT_VERSION) {
- printk("fuse_read_super: Bad mount version: %i\n", d->version);
+ if(d->version != FUSE_KERNEL_VERSION) {
+ printk("fuse_read_super: Bad version: %i\n", d->version);
return NULL;
}
@@ -89,12 +89,12 @@
}
-static struct inode *get_root_inode(struct super_block *sb)
+static struct inode *get_root_inode(struct super_block *sb, unsigned int mode)
{
struct fuse_attr attr;
memset(&attr, 0, sizeof(attr));
- attr.mode = S_IFDIR;
+ attr.mode = mode;
return fuse_iget(sb, 1, &attr, 0);
}
@@ -103,20 +103,21 @@
{
struct fuse_conn *fc;
struct inode *root;
+ struct fuse_mount_data *d = data;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = FUSE_SUPER_MAGIC;
sb->s_op = &fuse_super_operations;
- root = get_root_inode(sb);
+ root = get_root_inode(sb, d->rootmode);
if(root == NULL) {
printk("fuse_read_super: failed to get root inode\n");
return NULL;
}
spin_lock(&fuse_lock);
- fc = get_conn(data);
+ fc = get_conn(d);
if(fc == NULL)
goto err;
diff --git a/kernel/util.c b/kernel/util.c
index 57b1a90..9b7bec1 100644
--- a/kernel/util.c
+++ b/kernel/util.c
@@ -12,8 +12,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
-#define FUSE_VERSION "0.1"
-
spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED;
/* Must be called with the fuse lock held */
@@ -28,7 +26,7 @@
{
int res;
- printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION);
+ printk(KERN_DEBUG "fuse init (version %i)\n", FUSE_KERNEL_VERSION);
res = fuse_fs_init();
if(res)
diff --git a/lib/Makefile b/lib/Makefile
index e72a39d..88b087a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,16 +1,18 @@
CC = gcc
-CFLAGS = -Wall -W -g `glib-config --cflags`
+CFLAGS = -Wall -W -g `glib-config --cflags` -fPIC
LDFLAGS = `glib-config --libs`
CPPFLAGS = -I../include
-
-all: libfuse.a
+all: libfuse.a libfuse.so
libfuse_objs = mount.o fuse.o
libfuse.a: $(libfuse_objs)
ar cr libfuse.a $(libfuse_objs)
+libfuse.so: $(libfuse_objs)
+ gcc -shared -o libfuse.so $(libfuse_objs)
+
clean:
rm -f *.o *.a
rm -f *~
diff --git a/lib/fuse.c b/lib/fuse.c
index 137b5ef..b12c58d 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -407,6 +407,7 @@
res = f->op.readlink(&cred, path, link, sizeof(link));
g_free(path);
}
+ link[PATH_MAX] = '\0';
send_reply(f, in, res, link, !res ? strlen(link) : 0);
}
@@ -756,6 +757,17 @@
return NULL;
}
+/* This hack makes it possible to link FUSE with or without the
+ pthread library */
+__attribute__((weak))
+int pthread_create(pthread_t *thrid __attribute__((unused)),
+ const pthread_attr_t *attr __attribute__((unused)),
+ void *(*func)(void *) __attribute__((unused)),
+ void *arg __attribute__((unused)))
+{
+ return ENOSYS;
+}
+
void fuse_loop(struct fuse *f)
{
int res;
@@ -787,24 +799,35 @@
if(f->flags & FUSE_MULTITHREAD) {
res = pthread_create(&thrid, &attr, do_command, cmd);
- if(res != 0) {
- fprintf(stderr, "Error creating thread: %s\n",
- strerror(errno));
- exit(1);
- }
+ if(res == 0)
+ continue;
+
+ fprintf(stderr, "Error creating thread: %s\n", strerror(res));
+ fprintf(stderr, "Will run in single thread mode\n");
+ f->flags &= ~FUSE_MULTITHREAD;
}
- else
- do_command(cmd);
+
+ do_command(cmd);
}
}
-struct fuse *fuse_new(int flags)
+struct fuse *fuse_new(int flags, mode_t root)
{
struct fuse *f = g_new0(struct fuse, 1);
+ if(!root)
+ root = S_IFDIR;
+
+ if(!S_ISDIR(root) && !S_ISREG(root)) {
+ fprintf(stderr, "Invalid mode for root: 0%o\n", root);
+ root = S_IFDIR;
+ }
+ root &= S_IFMT;
+
f->flags = flags;
+ f->rootmode = root;
f->fd = -1;
- f->dir = NULL;
+ f->mnt = NULL;
f->nametab = g_hash_table_new((GHashFunc) name_hash,
(GCompareFunc) name_compare);
pthread_mutex_init(&f->lock, NULL);
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index c28e2e8..6f363d8 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -25,7 +25,8 @@
struct fuse {
int flags;
- char *dir;
+ char *mnt;
+ mode_t rootmode;
int fd;
struct fuse_operations op;
GHashTable *nametab;
diff --git a/lib/mount.c b/lib/mount.c
index 48d9d45..98d9e59 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -16,13 +16,15 @@
#include <sys/mount.h>
#include <mntent.h>
-static int do_mount(const char *dev, const char *dir, const char *type, int fd)
+static int do_mount(const char *dev, const char *dir, const char *type,
+ mode_t rootmode, int fd)
{
int res;
struct fuse_mount_data data;
- data.version = FUSE_MOUNT_VERSION;
+ data.version = FUSE_KERNEL_VERSION;
data.fd = fd;
+ data.rootmode = rootmode;
res = mount(dev, dir, type, MS_MGC_VAL | MS_NOSUID | MS_NODEV, &data);
if(res == -1) {
@@ -100,7 +102,7 @@
const char *dev = FUSE_DEV;
const char *type = "fuse";
- if(f->dir != NULL)
+ if(f->mnt != NULL)
return 0;
f->fd = open(dev, O_RDWR);
@@ -109,12 +111,12 @@
return -1;
}
- res = do_mount(dev, dir, type, f->fd);
+ res = do_mount(dev, dir, type, f->rootmode, f->fd);
if(res == -1)
return -1;
add_mntent(dev, dir, type);
- f->dir = g_strdup(dir);
+ f->mnt = g_strdup(dir);
return 0;
}
@@ -123,20 +125,20 @@
{
int res;
- if(f->dir == NULL)
+ if(f->mnt == NULL)
return 0;
close(f->fd);
f->fd = -1;
- res = umount(f->dir);
+ res = umount(f->mnt);
if(res == -1)
perror("umount failed");
else
- remove_mntent(f->dir);
+ remove_mntent(f->mnt);
- g_free(f->dir);
- f->dir = NULL;
+ g_free(f->mnt);
+ f->mnt = NULL;
return res;
}
diff --git a/usermux.c b/usermux.c
index 4caacb9..f2f11f3 100644
--- a/usermux.c
+++ b/usermux.c
@@ -50,7 +50,7 @@
if(pw == NULL)
return;
- user_fuse = fuse_new(0);
+ user_fuse = fuse_new(FUSE_MULTITHREAD, 0);
userdir = g_strdup_printf("%s/%010u", MOUNTDIR, uid);
mkdir(userdir, 0755);
@@ -240,7 +240,7 @@
set_signal_handlers();
atexit(cleanup);
- um_fuse = fuse_new(0);
+ um_fuse = fuse_new(FUSE_MULTITHREAD, 0);
res = fuse_mount(um_fuse, um_dir);
if(res == -1)
exit(1);