From: Miklos Szeredi Date: Tue, 18 Jan 2005 21:23:41 +0000 (+0000) Subject: fix X-Git-Tag: fuse_2_2_pre5~2 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=3ead28e7b1d08517f91f70d5ec144313b0f646a9;p=qemu-gpiodev%2Flibfuse.git fix --- diff --git a/kernel/dir.c b/kernel/dir.c index 076d966..38611c5 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -534,9 +534,9 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) struct page *page; struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_req *req = fuse_get_request(fc); + struct fuse_req *req = fuse_get_request_nonint(fc); if (!req) - return -ERESTARTNOINTR; + return -EINTR; page = alloc_page(GFP_KERNEL); if (!page) { diff --git a/kernel/file.c b/kernel/file.c index 41e8d47..0405f7b 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -411,7 +411,7 @@ static int fuse_file_bigread(struct file *file, struct inode *inode, #endif /* KERNEL_2_6 */ static size_t fuse_send_write(struct fuse_req *req, struct file *file, - struct inode *inode, loff_t pos, size_t count) + struct inode *inode, loff_t pos, size_t count) { struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_file *ff = file->private_data; diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 92fb703..e4d9588 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -321,11 +321,6 @@ struct fuse_conn { #endif }; -struct fuse_getdir_out_i { - int fd; - void *file; /* Used by kernel only */ -}; - static inline struct fuse_conn **get_fuse_conn_super_p(struct super_block *sb) { #ifdef KERNEL_2_6 @@ -384,6 +379,23 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, unsigned long nodeid, int version); +/** + * Send READ or READDIR request + */ +size_t fuse_send_read_common(struct fuse_req *req, struct file *file, + struct inode *inode, loff_t pos, size_t count, + int isdir); + +/** + * Send OPEN or OPENDIR request + */ +int fuse_open_common(struct inode *inode, struct file *file, int isdir); + +/** + * Send RELEASE or RELEASEDIR request + */ +int fuse_release_common(struct inode *inode, struct file *file, int isdir); + /** * Initialise file operations on a regular file */ diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index 378791b..cd8f46f 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -67,7 +67,6 @@ enum fuse_opcode { FUSE_SETATTR = 4, FUSE_READLINK = 5, FUSE_SYMLINK = 6, - FUSE_GETDIR = 7, FUSE_MKNOD = 8, FUSE_MKDIR = 9, FUSE_UNLINK = 10, @@ -85,7 +84,10 @@ enum fuse_opcode { FUSE_LISTXATTR = 23, FUSE_REMOVEXATTR = 24, FUSE_FLUSH = 25, - FUSE_INIT = 26 + FUSE_INIT = 26, + FUSE_OPENDIR = 27, + FUSE_READDIR = 28, + FUSE_RELEASEDIR = 29 }; /* Conservative buffer size for the client */ @@ -117,10 +119,6 @@ struct fuse_attr_out { struct fuse_attr attr; }; -struct fuse_getdir_out { - __u32 fd; -}; - struct fuse_mknod_in { __u32 mode; __u32 rdev; diff --git a/lib/fuse.c b/lib/fuse.c index 25b62a0..8154feb 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -60,8 +60,8 @@ struct node { struct fuse_dirhandle { struct fuse *fuse; - nodeid_t dir; FILE *fp; + int filled; }; struct fuse_cmd { @@ -72,6 +72,13 @@ struct fuse_cmd { static struct fuse_context *(*fuse_getcontext)(void) = NULL; +/* Compatibility with kernel ABI version 5.1 */ +struct fuse_getdir_out { + __u32 fd; +}; + +#define FUSE_GETDIR 7 + static const char *opname(enum fuse_opcode opcode) { switch (opcode) { @@ -100,6 +107,9 @@ static const char *opname(enum fuse_opcode opcode) case FUSE_LISTXATTR: return "LISTXATTR"; case FUSE_REMOVEXATTR: return "REMOVEXATTR"; case FUSE_INIT: return "INIT"; + case FUSE_OPENDIR: return "OPENDIR"; + case FUSE_READDIR: return "READDIR"; + case FUSE_RELEASEDIR: return "RELEASEDIR"; default: return "???"; } } @@ -805,29 +815,37 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in) send_reply(f, in, res, link, res == 0 ? strlen(link) : 0); } +static int common_getdir(struct fuse *f, struct fuse_in_header *in, + struct fuse_dirhandle *dh) +{ + int res; + char *path; + + res = -ENOENT; + path = get_path(f, in->nodeid); + if (path != NULL) { + res = -ENOSYS; + if (f->op.getdir) + res = f->op.getdir(path, dh, fill_dir); + free(path); + } + return res; +} + static void do_getdir(struct fuse *f, struct fuse_in_header *in) { int res; struct fuse_getdir_out arg; struct fuse_dirhandle dh; - char *path; dh.fuse = f; dh.fp = tmpfile(); - dh.dir = in->nodeid; res = -EIO; if (dh.fp == NULL) perror("fuse: failed to create temporary file"); else { - res = -ENOENT; - path = get_path(f, in->nodeid); - if (path != NULL) { - res = -ENOSYS; - if (f->op.getdir) - res = f->op.getdir(path, &dh, fill_dir); - free(path); - } + res = common_getdir(f, in, &dh); fflush(dh.fp); } memset(&arg, 0, sizeof(struct fuse_getdir_out)); @@ -1520,6 +1538,88 @@ static void do_init(struct fuse *f, struct fuse_in_header *in, send_reply(f, in, 0, &outarg, sizeof(outarg)); } +static struct fuse_dirhandle *get_dirhandle(unsigned long fh) +{ + return (struct fuse_dirhandle *) fh; +} + +static void do_opendir(struct fuse *f, struct fuse_in_header *in, + struct fuse_open_in *arg) +{ + int res; + struct fuse_open_out outarg; + struct fuse_dirhandle *dh; + + (void) arg; + + res = -ENOMEM; + dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle)); + if (dh != NULL) { + dh->fuse = f; + dh->fp = tmpfile(); + dh->filled = 0; + + res = -EIO; + if (dh->fp == NULL) { + perror("fuse: failed to create temporary file"); + free(dh); + } else { + outarg.fh = (unsigned long) dh; + res = 0; + } + } + send_reply(f, in, res, &outarg, sizeof(outarg)); +} + +static void do_readdir(struct fuse *f, struct fuse_in_header *in, + struct fuse_read_in *arg) +{ + int res; + char *outbuf; + struct fuse_dirhandle *dh = get_dirhandle(arg->fh); + + if (!dh->filled) { + res = common_getdir(f, in, dh); + if (res) + send_reply(f, in, res, NULL, 0); + dh->filled = 1; + } + outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size); + if (outbuf == NULL) + send_reply(f, in, -ENOMEM, NULL, 0); + else { + struct fuse_out_header *out = (struct fuse_out_header *) outbuf; + char *buf = outbuf + sizeof(struct fuse_out_header); + size_t size = 0; + size_t outsize; + fseek(dh->fp, arg->offset, SEEK_SET); + res = fread(buf, 1, arg->size, dh->fp); + if (res == 0 && ferror(dh->fp)) + res = -EIO; + else { + size = res; + res = 0; + } + memset(out, 0, sizeof(struct fuse_out_header)); + out->unique = in->unique; + out->error = res; + outsize = sizeof(struct fuse_out_header) + size; + + send_reply_raw(f, outbuf, outsize); + free(outbuf); + } +} + +static void do_releasedir(struct fuse *f, struct fuse_in_header *in, + struct fuse_release_in *arg) +{ + struct fuse_dirhandle *dh = get_dirhandle(arg->fh); + fclose(dh->fp); + free(dh); + send_reply(f, in, 0, NULL, 0); +} + + static void free_cmd(struct fuse_cmd *cmd) { free(cmd->buf); @@ -1653,6 +1753,18 @@ void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) do_init(f, in, (struct fuse_init_in_out *) inarg); break; + case FUSE_OPENDIR: + do_opendir(f, in, (struct fuse_open_in *) inarg); + break; + + case FUSE_READDIR: + do_readdir(f, in, (struct fuse_read_in *) inarg); + break; + + case FUSE_RELEASEDIR: + do_releasedir(f, in, (struct fuse_release_in *) inarg); + break; + default: send_reply(f, in, -ENOSYS, NULL, 0); } diff --git a/lib/helper.c b/lib/helper.c index 2b15628..365b813 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -395,7 +395,7 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, #undef fuse_main int fuse_main() { - fprintf(stderr, "This function does not exist\n"); + fprintf(stderr, "fuse_main(): This function does not exist\n"); return -1; }