From: Miklos Szeredi Date: Mon, 29 Oct 2001 14:57:57 +0000 (+0000) Subject: x X-Git-Tag: fuse_0_9~12 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=b483c93623dd64eb5f1dcf23f32adb32f616ee0e;p=qemu-gpiodev%2Flibfuse.git x --- diff --git a/.cvsignore b/.cvsignore index be4407b..26633aa 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1 +1 @@ -fusemount +fusepro diff --git a/fusepro.c b/fusepro.c index 4c0582c..cbe80aa 100644 --- a/fusepro.c +++ b/fusepro.c @@ -64,6 +64,50 @@ static int pro_mknod(const char *path, int mode, int rdev) return 0; } +static int pro_symlink(const char *from, const char *to) +{ + int res; + + res = symlink(from, to); + if(res == -1) + return -errno; + + return 0; +} + +static int pro_mkdir(const char *path, int mode) +{ + int res; + + res = mkdir(path, mode); + if(res == -1) + return -errno; + + return 0; +} + +static int pro_unlink(const char *path) +{ + int res; + + res = unlink(path); + if(res == -1) + return -errno; + + return 0; +} + +static int pro_rmdir(const char *path) +{ + int res; + + res = rmdir(path); + if(res == -1) + return -errno; + + return 0; +} + static void exit_handler() { exit(0); @@ -104,6 +148,10 @@ static struct fuse_operations pro_oper = { readlink: pro_readlink, getdir: pro_getdir, mknod: pro_mknod, + mkdir: pro_mkdir, + symlink: pro_symlink, + unlink: pro_unlink, + rmdir: pro_rmdir, }; int main(int argc, char *argv[]) diff --git a/include/fuse.h b/include/fuse.h index 6b1a151..6837b9e 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -20,8 +20,12 @@ typedef int (*dirfiller_t) (struct fuse_dh *, const char *, int type); struct fuse_operations { int (*getattr) (const char *path, struct stat *stbuf); int (*readlink) (const char *path, char *buf, size_t size); - int (*mknod) (const char *path, int mode, int rdev); int (*getdir) (const char *path, struct fuse_dh *h, dirfiller_t filler); + int (*mknod) (const char *path, int mode, int rdev); + int (*mkdir) (const char *path, int mode); + int (*symlink) (const char *from, const char *to); + int (*unlink) (const char *path); + int (*rmdir) (const char *path); }; struct fuse *fuse_new(); diff --git a/include/linux/fuse.h b/include/linux/fuse.h index fb3aca0..b519a8d 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -39,6 +39,11 @@ enum fuse_opcode { FUSE_READLINK, FUSE_GETDIR, FUSE_MKNOD, + FUSE_MKDIR, + FUSE_SYMLINK, + FUSE_UNLINK, + FUSE_RMDIR, + FUSE_RENAME, }; /* Conservative buffer size for the client */ @@ -69,10 +74,21 @@ struct fuse_mknod_out { struct fuse_attr attr; }; +struct fuse_mkdir_in { + unsigned short mode; + char name[1]; +}; + + +struct fuse_rename_in { + unsigned long newdir; + char names[2]; +}; + struct fuse_in_header { int unique; enum fuse_opcode opcode; - unsigned long ino; + unsigned long ino; }; struct fuse_out_header { diff --git a/kernel/dir.c b/kernel/dir.c index 92ddc55..065ac01 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -14,6 +14,15 @@ #include #include +static struct inode_operations fuse_dir_inode_operations; +static struct inode_operations fuse_file_inode_operations; +static struct inode_operations fuse_symlink_inode_operations; +static struct inode_operations fuse_special_inode_operations; + +static struct file_operations fuse_dir_operations; +static struct file_operations fuse_file_operations; + + static void change_attributes(struct inode *inode, struct fuse_attr *attr) { inode->i_mode = attr->mode; @@ -28,18 +37,22 @@ static void change_attributes(struct inode *inode, struct fuse_attr *attr) inode->i_ctime = attr->ctime; } -static void init_inode(struct inode *inode, struct fuse_attr *attr) +void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) { change_attributes(inode, attr); - if(S_ISREG(inode->i_mode)) - fuse_file_init(inode); - else if(S_ISDIR(inode->i_mode)) - fuse_dir_init(inode); + if(S_ISREG(inode->i_mode)) { + inode->i_op = &fuse_file_inode_operations; + inode->i_fop = &fuse_file_operations; + } + else if(S_ISDIR(inode->i_mode)) { + inode->i_op = &fuse_dir_inode_operations; + inode->i_fop = &fuse_dir_operations; + } else if(S_ISLNK(inode->i_mode)) - fuse_symlink_init(inode); + inode->i_op = &fuse_symlink_inode_operations; else { - fuse_special_init(inode); + inode->i_op = &fuse_special_inode_operations; init_special_inode(inode, inode->i_mode, attr->rdev); } } @@ -73,11 +86,12 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) if(!inode) return ERR_PTR(-ENOMEM); - init_inode(inode, &arg.attr); + fuse_init_inode(inode, &arg.attr); d_add(entry, inode); return NULL; } +/* create needs to return a positive entry, so this also does a lookup */ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, int rdev) { @@ -106,26 +120,142 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, out.arg = &outarg; request_send(fc, &in, &out); kfree(inarg); - if(out.h.result) + + if(out.h.result) return out.h.result; inode = iget(dir->i_sb, outarg.ino); if(!inode) return -ENOMEM; - - init_inode(inode, &outarg.attr); + + fuse_init_inode(inode, &outarg.attr); d_add(entry, inode); + return 0; } + static int fuse_create(struct inode *dir, struct dentry *entry, int mode) { return fuse_mknod(dir, entry, mode, 0); } -static int fuse_permission(struct inode *inode, int mask) +static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) +{ + struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_mkdir_in *inarg; + unsigned int insize; + + insize = offsetof(struct fuse_mkdir_in, name) + entry->d_name.len + 1; + inarg = kmalloc(insize, GFP_KERNEL); + if(!inarg) + return -ENOMEM; + + inarg->mode = mode; + strcpy(inarg->name, entry->d_name.name); + + in.h.opcode = FUSE_MKDIR; + in.h.ino = dir->i_ino; + in.argsize = insize; + in.arg = inarg; + request_send(fc, &in, &out); + kfree(inarg); + + return out.h.result; +} + +static int fuse_symlink(struct inode *dir, struct dentry *entry, + const char *link) +{ + struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + char *inarg; + unsigned int insize; + + insize = entry->d_name.len + 1 + strlen(link) + 1; + inarg = kmalloc(insize, GFP_KERNEL); + if(!inarg) + return -ENOMEM; + + strcpy(inarg, entry->d_name.name); + strcpy(inarg + entry->d_name.len + 1, link); + + in.h.opcode = FUSE_SYMLINK; + in.h.ino = dir->i_ino; + in.argsize = insize; + in.arg = inarg; + request_send(fc, &in, &out); + kfree(inarg); + + return out.h.result; +} + +static int fuse_remove(struct inode *dir, struct dentry *entry, + enum fuse_opcode op) { + struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + in.h.opcode = op; + in.h.ino = dir->i_ino; + in.argsize = entry->d_name.len + 1; + in.arg = entry->d_name.name; + request_send(fc, &in, &out); + if(!out.h.result) { + d_drop(entry); + entry->d_inode->i_nlink = 0; + } + + return out.h.result; +} + +static int fuse_unlink(struct inode *dir, struct dentry *entry) +{ + return fuse_remove(dir, entry, FUSE_UNLINK); +} + +static int fuse_rmdir(struct inode *dir, struct dentry *entry) +{ + return fuse_remove(dir, entry, FUSE_RMDIR); +} + +static int fuse_rename(struct inode *olddir, struct dentry *oldent, + struct inode *newdir, struct dentry *newent) +{ + struct fuse_conn *fc = olddir->i_sb->u.generic_sbp; + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_rename_in *inarg; + unsigned int oldnamsize = oldent->d_name.len + 1; + unsigned int newnamsize = newent->d_name.len + 1; + unsigned int insize; + + insize = offsetof(struct fuse_rename_in, names) + oldnamsize + + newnamsize; + inarg = kmalloc(insize, GFP_KERNEL); + if(!inarg) + return -ENOMEM; + + inarg->newdir = newdir->i_ino; + strcpy(inarg->names, oldent->d_name.name); + strcpy(inarg->names + oldnamsize, newent->d_name.name); + + in.h.opcode = FUSE_RENAME; + in.h.ino = olddir->i_ino; + in.argsize = insize; + in.arg = inarg; + request_send(fc, &in, &out); + kfree(inarg); + + return out.h.result; +} + +static int fuse_permission(struct inode *inode, int mask) +{ return 0; } @@ -145,41 +275,22 @@ static int fuse_revalidate(struct dentry *dentry) if(out.h.result == 0) change_attributes(inode, &arg.attr); + else + d_drop(dentry); return out.h.result; } - -#define DIR_BUFSIZE 2048 - -static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) +static int parse_dirfile(char *buf, size_t nbytes, struct file *file, + void *dstbuf, filldir_t filldir) { - struct file *cfile = file->private_data; - char *buf; - char *p; - int ret; - size_t nbytes; - - buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL); - if(!buf) - return -ENOMEM; - - ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE); - if(ret < 0) { - printk("fuse_readdir: failed to read container file\n"); - goto out; - } - nbytes = ret; - p = buf; - ret = 0; while(nbytes >= FUSE_NAME_OFFSET) { - struct fuse_dirent *dirent = (struct fuse_dirent *) p; + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; size_t reclen = FUSE_DIRENT_SIZE(dirent); int over; if(dirent->namelen > NAME_MAX) { printk("fuse_readdir: name too long\n"); - ret = -EPROTO; - goto out; + return -EPROTO; } if(reclen > nbytes) break; @@ -189,17 +300,34 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) if(over) break; - p += reclen; + buf += reclen; file->f_pos += reclen; nbytes -= reclen; } - out: - kfree(buf); - return ret; + return 0; } +#define DIR_BUFSIZE 2048 +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) +{ + struct file *cfile = file->private_data; + char *buf; + int ret; + + buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL); + if(!buf) + return -ENOMEM; + ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE); + if(ret < 0) + printk("fuse_readdir: failed to read container file\n"); + else + ret = parse_dirfile(buf, ret, file, dstbuf, filldir); + + kfree(buf); + return ret; +} static int read_link(struct dentry *dentry, char **bufp) { @@ -314,14 +442,14 @@ static struct inode_operations fuse_dir_inode_operations = lookup: fuse_lookup, create: fuse_create, mknod: fuse_mknod, -#if 0 - - link: fuse_link, - unlink: fuse_unlink, - symlink: fuse_symlink, mkdir: fuse_mkdir, + symlink: fuse_symlink, + unlink: fuse_unlink, rmdir: fuse_rmdir, rename: fuse_rename, +#if 0 + link: fuse_link, + setattr: fuse_setattr, #endif permission: fuse_permission, revalidate: fuse_revalidate, @@ -354,28 +482,6 @@ static struct inode_operations fuse_symlink_inode_operations = revalidate: fuse_revalidate, }; -void fuse_dir_init(struct inode *inode) -{ - inode->i_op = &fuse_dir_inode_operations; - inode->i_fop = &fuse_dir_operations; -} - -void fuse_file_init(struct inode *inode) -{ - inode->i_op = &fuse_file_inode_operations; - inode->i_fop = &fuse_file_operations; -} - -void fuse_symlink_init(struct inode *inode) -{ - inode->i_op = &fuse_symlink_inode_operations; -} - -void fuse_special_init(struct inode *inode) -{ - inode->i_op = &fuse_special_inode_operations; -} - /* * Local Variables: * indent-tabs-mode: t diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 1eb0bb4..de0a9e6 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -109,25 +109,11 @@ extern struct proc_dir_entry *proc_fuse_dev; */ extern spinlock_t fuse_lock; -/** - * Fill in the directory operations - */ -void fuse_dir_init(struct inode *inode); - -/** - * Fill in the file operations - */ -void fuse_file_init(struct inode *inode); - -/** - * Fill in the symlink operations - */ -void fuse_symlink_init(struct inode *inode); /** - * Fill in the special inode operaions + * Initialize inode */ -void fuse_special_init(struct inode *inode); +void fuse_init_inode(struct inode *inode, struct fuse_attr *attr); /** * Check if the connection can be released, and if yes, then free the diff --git a/kernel/inode.c b/kernel/inode.c index ac2d6be..b59a146 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -139,21 +139,14 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d) static struct inode *get_root_inode(struct super_block *sb) { - struct inode *root ; + struct inode *root; root = iget(sb, 1); if(root) { - root->i_mode = S_IFDIR; - root->i_uid = 0; - root->i_gid = 0; - root->i_nlink = 2; - root->i_size = 0; - root->i_blksize = 1024; - root->i_blocks = 0; - root->i_atime = CURRENT_TIME; - root->i_mtime = CURRENT_TIME; - root->i_ctime = CURRENT_TIME; - fuse_dir_init(root); + struct fuse_attr attr; + memset(&attr, 0, sizeof(attr)); + attr.mode = S_IFDIR; + fuse_init_inode(root, &attr); } return root; diff --git a/lib/fuse.c b/lib/fuse.c index f846f74..62695f0 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -43,15 +43,14 @@ static int free_node(struct node *node) static inline struct node *get_node(fino_t ino) { - return (struct node *) ino; + return (struct node *) ((ino << 3) + 0x8000000); } static inline fino_t get_ino(struct node *node) { - return (fino_t) node; + return (((fino_t) node) - 0x8000000) >> 3; } - static fino_t find_node(struct fuse *f, fino_t parent, char *name, int create) { struct node *node; @@ -95,6 +94,14 @@ static char *get_path(fino_t ino) return ss; } +static char *get_path_name(fino_t ino, const char *name) +{ + char *path = get_path(ino); + char *path2 = g_strconcat(path, "/", name, NULL); + g_free(path); + return path2; +} + static void remove_node(struct fuse *f, fino_t ino) { struct node *node = get_node(ino); @@ -102,7 +109,6 @@ static void remove_node(struct fuse *f, fino_t ino) free_node(node); } - static void convert_stat(struct stat *stbuf, struct fuse_attr *attr) { attr->mode = stbuf->st_mode; @@ -124,11 +130,10 @@ static int get_attributes(struct fuse *f, fino_t ino, struct fuse_attr *attr) struct stat buf; int res; - if(f->op.getattr == NULL) - return -ENOSYS; - path = get_path(ino); - res = f->op.getattr(path, &buf); + res = -ENOSYS; + if(f->op.getattr) + res = f->op.getattr(path, &buf); g_free(path); if(res == 0) convert_stat(&buf, attr); @@ -136,21 +141,6 @@ static int get_attributes(struct fuse *f, fino_t ino, struct fuse_attr *attr) return res; } -static int read_link(struct fuse *f, fino_t ino, char *buf, size_t size) -{ - char *path; - int res; - - if(f->op.readlink == NULL) - return -ENOSYS; - - path = get_path(ino); - res = f->op.readlink(path, buf, size); - g_free(path); - - return res; -} - static int fill_dir(struct fuse_dh *dh, char *name, int type) { struct fuse_dirent dirent; @@ -170,27 +160,6 @@ static int fill_dir(struct fuse_dh *dh, char *name, int type) return 0; } -static int get_dir(struct fuse *f, fino_t ino, FILE *fp) -{ - char *path; - int res; - struct fuse_dh dh; - - if(f->op.getdir == NULL) - return -ENOSYS; - - dh.fuse = f; - dh.fp = fp; - dh.dir = ino; - - path = get_path(ino); - res = f->op.getdir(path, &dh, (dirfiller_t) fill_dir); - g_free(path); - - return res; -} - - static void send_reply(struct fuse *f, struct fuse_in_header *in, int result, void *arg, size_t argsize) { @@ -237,7 +206,6 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name) send_reply(f, in, res, &arg, sizeof(arg)); } - static void do_forget(struct fuse *f, unsigned long *inos, size_t num) { size_t i; @@ -259,50 +227,112 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in) { int res; char link[PATH_MAX + 1]; + char *path; + + path = get_path(in->ino); + res = -ENOSYS; + if(f->op.readlink) + res = f->op.readlink(path, link, sizeof(link)); + g_free(path); - res = read_link(f, in->ino, link, PATH_MAX + 1); send_reply(f, in, res, link, res == 0 ? strlen(link) : 0); } +static void do_getdir(struct fuse *f, struct fuse_in_header *in) +{ + int res; + struct fuse_getdir_out arg; + struct fuse_dh dh; + char *path; + + dh.fuse = f; + dh.fp = tmpfile(); + dh.dir = in->ino; + + path = get_path(in->ino); + res = -ENOSYS; + if(f->op.getdir) + res = f->op.getdir(path, &dh, (dirfiller_t) fill_dir); + g_free(path); + + fflush(dh.fp); + arg.fd = fileno(dh.fp); + send_reply(f, in, res, &arg, sizeof(arg)); + fclose(dh.fp); +} + static void do_mknod(struct fuse *f, struct fuse_in_header *in, struct fuse_mknod_in *inarg) { int res; + char *path; struct fuse_mknod_out outarg; - - res = -ENOSYS; - if(f->op.mknod != NULL && f->op.getattr != NULL) { - char *path; - struct stat buf; + struct stat buf; - outarg.ino = find_node(f, in->ino, inarg->name, 1); - path = get_path(outarg.ino); + outarg.ino = find_node(f, in->ino, inarg->name, 1); + path = get_path(outarg.ino); + res = -ENOSYS; + if(f->op.mknod && f->op.getattr) { res = f->op.mknod(path, inarg->mode, inarg->rdev); if(res == 0) res = f->op.getattr(path, &buf); - g_free(path); - - if(res == 0) - convert_stat(&buf, &outarg.attr); - else - remove_node(f, outarg.ino); } + g_free(path); + + if(res == 0) + convert_stat(&buf, &outarg.attr); + send_reply(f, in, res, &outarg, sizeof(outarg)); } -static void do_getdir(struct fuse *f, struct fuse_in_header *in) +static void do_mkdir(struct fuse *f, struct fuse_in_header *in, + struct fuse_mkdir_in *inarg) { int res; - struct fuse_getdir_out arg; - FILE *fp = tmpfile(); + char *path; - res = get_dir(f, in->ino, fp); - fflush(fp); - arg.fd = fileno(fp); - send_reply(f, in, res, &arg, sizeof(arg)); - fclose(fp); + path = get_path_name(in->ino, inarg->name); + res = -ENOSYS; + if(f->op.mkdir) + res = f->op.mkdir(path, inarg->mode); + g_free(path); + send_reply(f, in, res, NULL, 0); +} + +static void do_remove(struct fuse *f, struct fuse_in_header *in, char *name) +{ + int res; + char *path; + + path = get_path_name(in->ino, name); + res = -ENOSYS; + if(in->opcode == FUSE_UNLINK) { + if(f->op.unlink) + res = f->op.unlink(path); + } + else { + if(f->op.rmdir) + res = f->op.rmdir(path); + } + g_free(path); + send_reply(f, in, res, NULL, 0); +} + +static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name, + char *link) +{ + int res; + char *path; + + path = get_path_name(in->ino, name); + res = -ENOSYS; + if(f->op.symlink) + res = f->op.symlink(link, path); + g_free(path); + send_reply(f, in, res, NULL, 0); } + void fuse_loop(struct fuse *f) { int res; @@ -355,6 +385,20 @@ void fuse_loop(struct fuse *f) case FUSE_MKNOD: do_mknod(f, in, (struct fuse_mknod_in *) inarg); break; + + case FUSE_MKDIR: + do_mkdir(f, in, (struct fuse_mkdir_in *) inarg); + break; + + case FUSE_UNLINK: + case FUSE_RMDIR: + do_remove(f, in, (char *) inarg); + break; + + case FUSE_SYMLINK: + do_symlink(f, in, (char *) inarg, + ((char *) inarg) + strlen((char *) inarg) + 1); + break; default: fprintf(stderr, "Operation %i not implemented\n", in->opcode); @@ -377,7 +421,6 @@ struct fuse *fuse_new() return f; } - void fuse_set_operations(struct fuse *f, const struct fuse_operations *op) { f->op = *op; @@ -390,4 +433,3 @@ void fuse_destroy(struct fuse *f) g_hash_table_destroy(f->nametab); g_free(f); } -