Commit 92a8780e authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Linus Torvalds

[PATCH] FUSE - extended attribute operations

This patch adds the extended attribute operations to FUSE.

The following operations are added:

 o getxattr
 o setxattr
 o listxattr
 o removexattr
Signed-off-by: default avatarMiklos Szeredi <miklos@szeredi.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1e9a4ed9
......@@ -744,6 +744,177 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
return d_splice_alias(inode, entry);
}
static int fuse_setxattr(struct dentry *entry, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_setxattr_in inarg;
int err;
if (size > FUSE_XATTR_SIZE_MAX)
return -E2BIG;
if (fc->no_setxattr)
return -EOPNOTSUPP;
req = fuse_get_request(fc);
if (!req)
return -ERESTARTNOINTR;
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
inarg.flags = flags;
req->in.h.opcode = FUSE_SETXATTR;
req->in.h.nodeid = get_node_id(inode);
req->inode = inode;
req->in.numargs = 3;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
req->in.args[1].size = strlen(name) + 1;
req->in.args[1].value = name;
req->in.args[2].size = size;
req->in.args[2].value = value;
request_send(fc, req);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err == -ENOSYS) {
fc->no_setxattr = 1;
err = -EOPNOTSUPP;
}
return err;
}
static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
void *value, size_t size)
{
struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
ssize_t ret;
if (fc->no_getxattr)
return -EOPNOTSUPP;
req = fuse_get_request(fc);
if (!req)
return -ERESTARTNOINTR;
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
req->in.h.opcode = FUSE_GETXATTR;
req->in.h.nodeid = get_node_id(inode);
req->inode = inode;
req->in.numargs = 2;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
req->in.args[1].size = strlen(name) + 1;
req->in.args[1].value = name;
/* This is really two different operations rolled into one */
req->out.numargs = 1;
if (size) {
req->out.argvar = 1;
req->out.args[0].size = size;
req->out.args[0].value = value;
} else {
req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg;
}
request_send(fc, req);
ret = req->out.h.error;
if (!ret)
ret = size ? req->out.args[0].size : outarg.size;
else {
if (ret == -ENOSYS) {
fc->no_getxattr = 1;
ret = -EOPNOTSUPP;
}
}
fuse_put_request(fc, req);
return ret;
}
static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
{
struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
ssize_t ret;
if (fc->no_listxattr)
return -EOPNOTSUPP;
req = fuse_get_request(fc);
if (!req)
return -ERESTARTNOINTR;
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
req->in.h.opcode = FUSE_LISTXATTR;
req->in.h.nodeid = get_node_id(inode);
req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = sizeof(inarg);
req->in.args[0].value = &inarg;
/* This is really two different operations rolled into one */
req->out.numargs = 1;
if (size) {
req->out.argvar = 1;
req->out.args[0].size = size;
req->out.args[0].value = list;
} else {
req->out.args[0].size = sizeof(outarg);
req->out.args[0].value = &outarg;
}
request_send(fc, req);
ret = req->out.h.error;
if (!ret)
ret = size ? req->out.args[0].size : outarg.size;
else {
if (ret == -ENOSYS) {
fc->no_listxattr = 1;
ret = -EOPNOTSUPP;
}
}
fuse_put_request(fc, req);
return ret;
}
static int fuse_removexattr(struct dentry *entry, const char *name)
{
struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
int err;
if (fc->no_removexattr)
return -EOPNOTSUPP;
req = fuse_get_request(fc);
if (!req)
return -ERESTARTNOINTR;
req->in.h.opcode = FUSE_REMOVEXATTR;
req->in.h.nodeid = get_node_id(inode);
req->inode = inode;
req->in.numargs = 1;
req->in.args[0].size = strlen(name) + 1;
req->in.args[0].value = name;
request_send(fc, req);
err = req->out.h.error;
fuse_put_request(fc, req);
if (err == -ENOSYS) {
fc->no_removexattr = 1;
err = -EOPNOTSUPP;
}
return err;
}
static struct inode_operations fuse_dir_inode_operations = {
.lookup = fuse_lookup,
.mkdir = fuse_mkdir,
......@@ -757,6 +928,10 @@ static struct inode_operations fuse_dir_inode_operations = {
.mknod = fuse_mknod,
.permission = fuse_permission,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
.getxattr = fuse_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
};
static struct file_operations fuse_dir_operations = {
......@@ -771,6 +946,10 @@ static struct inode_operations fuse_common_inode_operations = {
.setattr = fuse_setattr,
.permission = fuse_permission,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
.getxattr = fuse_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
};
static struct inode_operations fuse_symlink_inode_operations = {
......@@ -779,6 +958,10 @@ static struct inode_operations fuse_symlink_inode_operations = {
.put_link = fuse_put_link,
.readlink = generic_readlink,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
.getxattr = fuse_getxattr,
.listxattr = fuse_listxattr,
.removexattr = fuse_removexattr,
};
void fuse_init_common(struct inode *inode)
......
......@@ -245,6 +245,18 @@ struct fuse_conn {
/** Is flush not implemented by fs? */
unsigned no_flush : 1;
/** Is setxattr not implemented by fs? */
unsigned no_setxattr : 1;
/** Is getxattr not implemented by fs? */
unsigned no_getxattr : 1;
/** Is listxattr not implemented by fs? */
unsigned no_listxattr : 1;
/** Is removexattr not implemented by fs? */
unsigned no_removexattr : 1;
/** Backing dev info */
struct backing_dev_info bdi;
};
......
......@@ -80,6 +80,10 @@ enum fuse_opcode {
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
};
......@@ -89,6 +93,7 @@ enum fuse_opcode {
#define FUSE_NAME_MAX 1024
#define FUSE_SYMLINK_MAX 4096
#define FUSE_XATTR_SIZE_MAX 4096
struct fuse_entry_out {
__u64 nodeid; /* Inode ID */
......@@ -183,6 +188,19 @@ struct fuse_fsync_in {
__u32 fsync_flags;
};
struct fuse_setxattr_in {
__u32 size;
__u32 flags;
};
struct fuse_getxattr_in {
__u32 size;
};
struct fuse_getxattr_out {
__u32 size;
};
struct fuse_init_in_out {
__u32 major;
__u32 minor;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment