- It is allowed to mount a directory on a non-directory.
-- When a non-directory is mounted the root inode is not filled in, only at
- the first getattr
-
- I want really low priority for my cached pages. Can they start out
'old' so they will be thrown out on the first oportunity?
-2001-11-09 Miklos Szeredi <mszeredi@inf.bme.hu>
+2001-12-20 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Added function fuse_get_context() to library API (inspired by
+ patch from Matt Ryan)
+
+ * Added flags to fusermount and to kernel interface to control
+ permission checking
- * Started ChangeLog
+ * Integrated fuse_set_operations() into fuse_new()
+
+2001-12-08 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Applied header protection + extern "C" patch by Roland
+ Bauerschmidt
+
+2001-12-02 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Added perl bindings by Mark Glines
+
+2001-11-21 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Cleaned up way of mounting simple filesystems.
+
+ * fuse_main() helper function added
+
+2001-11-18 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Optimized read/write operations, so that minimal copying of data
+ is done
+
+2001-11-14 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Python bindings by Jeff Epler added
2001-11-13 Miklos Szeredi <mszeredi@inf.bme.hu>
* FS blocksize is set to PAGE_CACHE_SIZE, blksize attribute from
userspace is ignored
-2001-11-14 Miklos Szeredi <mszeredi@inf.bme.hu>
-
- * Python bindings by Jeff Epler added
+2001-11-09 Miklos Szeredi <mszeredi@inf.bme.hu>
+ * Started ChangeLog
- Better (but not too complex) library interface for open/read/write/close
- - Permission checking for users other then the owner of the mount
-
- Integrate (parts of) fusermount into mount(8)
- Statfs operation
/* This file defines the kernel interface of FUSE */
/** Version number of this interface */
-#define FUSE_KERNEL_VERSION 1
+#define FUSE_KERNEL_VERSION 2
/** The inode number of the root indode */
#define FUSE_ROOT_INO 1
unsigned int flags;
};
+/* FUSE mount flags: */
+
+/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
+module will check permissions based on the file mode. Otherwise no
+permission checking is done in the kernel */
+#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
+
+/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
+ doing the mount will be allowed to access the filesystem */
+#define FUSE_ALLOW_OTHER (1 << 1)
+
struct fuse_attr {
unsigned int mode;
unsigned int nlink;
int unique;
enum fuse_opcode opcode;
unsigned long ino;
+ unsigned int uid;
+ unsigned int gid;
};
struct fuse_out_header {
return out.h.error;
}
-static int fuse_permission(struct inode *inode, int mask)
-{
- struct fuse_conn *fc = INO_FC(inode);
-
- /* (too) simple protection */
- if(current->fsuid == fc->uid)
- return 0;
- else
- return -EACCES;
-}
-static int fuse_revalidate(struct dentry *entry)
+int fuse_getattr(struct inode *inode)
{
- struct inode *inode = entry->d_inode;
struct fuse_conn *fc = INO_FC(inode);
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_getattr_out arg;
- if(inode->i_ino != FUSE_ROOT_INO &&
- time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
- return 0;
-
in.h.opcode = FUSE_GETATTR;
in.h.ino = inode->i_ino;
out.numargs = 1;
return out.h.error;
}
+static int fuse_revalidate(struct dentry *entry)
+{
+ struct inode *inode = entry->d_inode;
+ struct fuse_conn *fc = INO_FC(inode);
+
+ if(inode->i_ino == FUSE_ROOT_INO) {
+ if(!(fc->flags & FUSE_ALLOW_OTHER)
+ && current->fsuid != fc->uid)
+ return -EACCES;
+ }
+ else if(time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
+ return 0;
+
+ return fuse_getattr(inode);
+}
+
+static int fuse_permission(struct inode *inode, int mask)
+{
+ struct fuse_conn *fc = INO_FC(inode);
+
+ if(!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
+ return -EACCES;
+ else if(fc->flags & FUSE_DEFAULT_PERMISSIONS) {
+ int err = vfs_permission(inode, mask);
+
+ /* If permission is denied, try to refresh file
+ attributes. This is also needed, because the root
+ node will at first have no permissions */
+
+ if(err == -EACCES) {
+ err = fuse_getattr(inode);
+ if(!err)
+ err = vfs_permission(inode, mask);
+ }
+
+ /* FIXME: Need some mechanism to revoke permissions:
+ currently if the filesystem suddenly changes the
+ file mode, we will not be informed abot that, and
+ continue to allow access to the file/directory.
+
+ This is actually not so grave, since the user can
+ simply keep access to the file/directory anyway by
+ keeping it open... */
+
+ return err;
+ }
+ else
+ return 0;
+}
+
+
static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
void *dstbuf, filldir_t filldir)
{
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_open_in inarg;
+ /* If opening the root node, no lookup has been performed on
+ it, so the attributes must be refreshed */
+ if(inode->i_ino == FUSE_ROOT_INO) {
+ int err = fuse_getattr(inode);
+ if(err)
+ return err;
+ }
+
memset(&inarg, 0, sizeof(inarg));
inarg.flags = file->f_flags & ~O_EXCL;
struct fuse_out_arg args[3];
};
-#define FUSE_IN_INIT { {0, 0, 0}, 0}
+#define FUSE_IN_INIT { {0, 0, 0, current->fsuid, current->fsgid}, 0}
#define FUSE_OUT_INIT { {0, 0}, 0, 0}
/**
*/
int request_send_noreply(struct fuse_conn *fc, struct fuse_in *in);
+/**
+ * Get the attributes of a file
+ */
+int fuse_getattr(struct inode *inode);
+
/*
* Local Variables:
* indent-tabs-mode: t
in = kmalloc(sizeof(struct fuse_in), GFP_NOFS);
if(!in)
return;
+ memset(in, 0, sizeof(struct fuse_in));
inarg = kmalloc(sizeof(struct fuse_forget_in), GFP_NOFS);
if(!inarg)
struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
void *inarg = cmd->buf + sizeof(struct fuse_in_header);
size_t argsize;
+ struct fuse_context *ctx = fuse_get_context(f);
dec_avail(f);
in->opcode, in->ino, cmd->buflen);
fflush(stdout);
}
+
+ ctx->uid = in->uid;
+ ctx->gid = in->gid;
argsize = cmd->buflen - sizeof(struct fuse_in_header);
int numavail;
struct fuse_context *(*getcontext)(struct fuse *);
struct fuse_context context;
+ pthread_key_t context_key;
};
struct fuse_dirhandle {
pthread_detach(thrid);
}
+static struct fuse_context *mt_getcontext(struct fuse *f)
+{
+ struct fuse_context *ctx;
+
+ ctx = (struct fuse_context *) pthread_getspecific(f->context_key);
+ if(ctx == NULL) {
+ ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context));
+ pthread_setspecific(f->context_key, ctx);
+ }
+
+ return ctx;
+}
+
+static void mt_freecontext(void *data)
+{
+ free(data);
+}
+
void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data)
{
struct fuse_worker *w;
+ int res;
w = malloc(sizeof(struct fuse_worker));
w->f = f;
w->proc = proc;
f->numworker = 1;
+ res = pthread_key_create(&f->context_key, mt_freecontext);
+ if(res != 0) {
+ fprintf(stderr, "Failed to create thread specific key\n");
+ exit(1);
+ }
+ f->getcontext = mt_getcontext;
do_work(w);
}
}
static int do_mount(const char *dev, const char *mnt, const char *type,
- mode_t rootmode, int fd)
+ mode_t rootmode, int fd, int fuseflags)
{
int res;
struct fuse_mount_data data;
data.fd = fd;
data.rootmode = rootmode;
data.uid = getuid();
- data.flags = 0;
+ data.flags = fuseflags;
res = mount(dev, mnt, type, flags, &data);
if(res == -1)
return 0;
}
-static int mount_fuse(const char *mnt)
+static int mount_fuse(const char *mnt, int flags)
{
int res;
int fd;
return -1;
}
- res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd);
+ res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd, flags);
if(res == -1)
return -1;
"%s: [options] mountpoint [program [args ...]]\n"
"Options:\n"
" -h print help\n"
- " -u unmount\n",
+ " -u unmount\n"
+ " -p check default permissions on files\n"
+ " -x allow other users to access the files (only for root)\n",
progname);
exit(1);
}
char mypath[PATH_MAX];
char *unmount_cmd;
char verstr[128];
+ int flags = 0;
progname = argv[0];
unmount = 1;
break;
+ case 'p':
+ flags |= FUSE_DEFAULT_PERMISSIONS;
+ break;
+
+ case 'x':
+ if(getuid() != 0) {
+ fprintf(stderr, "%s: option %s is allowed only for root\n",
+ progname, argv[a]);
+ exit(1);
+ }
+ flags |= FUSE_ALLOW_OTHER;
+ break;
+
default:
fprintf(stderr, "%s: Unknown option %s\n", progname, argv[a]);
exit(1);
userprog = argv + a;
numargs = argc - a;
- fd = mount_fuse(mnt);
+ fd = mount_fuse(mnt, flags);
if(fd == -1)
exit(1);