fuse_lowlevel.c

来自「FUSE文件系统开发工具,将内核层面的文件系统开发过程平移到应用层面上来。」· C语言 代码 · 共 1,449 行 · 第 1/3 页

C
1,449
字号
	size_t bufsize = fuse_chan_bufsize(req->ch);	(void) nodeid;	if (f->debug) {		fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor);		if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {			fprintf(stderr, "flags=0x%08x\n", arg->flags);			fprintf(stderr, "max_readahead=0x%08x\n",				arg->max_readahead);		}	}	f->conn.proto_major = arg->major;	f->conn.proto_minor = arg->minor;	if (arg->major < 7) {		fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",			arg->major, arg->minor);		fuse_reply_err(req, EPROTO);		return;	}	if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {		if (f->conn.async_read)			f->conn.async_read = arg->flags & FUSE_ASYNC_READ;		if (arg->max_readahead < f->conn.max_readahead)			f->conn.max_readahead = arg->max_readahead;	} else {		f->conn.async_read = 0;		f->conn.max_readahead = 0;	}	if (bufsize < FUSE_MIN_READ_BUFFER) {		fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",			bufsize);		bufsize = FUSE_MIN_READ_BUFFER;	}	bufsize -= 4096;	if (bufsize < f->conn.max_write)		f->conn.max_write = bufsize;	f->got_init = 1;	if (f->op.init)		f->op.init(f->userdata, &f->conn);	memset(&outarg, 0, sizeof(outarg));	outarg.major = FUSE_KERNEL_VERSION;	outarg.minor = FUSE_KERNEL_MINOR_VERSION;	if (f->conn.async_read)		outarg.flags |= FUSE_ASYNC_READ;	if (f->op.getlk && f->op.setlk)		outarg.flags |= FUSE_POSIX_LOCKS;	outarg.max_readahead = f->conn.max_readahead;	outarg.max_write = f->conn.max_write;	if (f->debug) {		fprintf(stderr, "   INIT: %u.%u\n", outarg.major, outarg.minor);		fprintf(stderr, "   flags=0x%08x\n", outarg.flags);		fprintf(stderr, "   max_readahead=0x%08x\n",			outarg.max_readahead);		fprintf(stderr, "   max_write=0x%08x\n", outarg.max_write);	}	send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));}static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){	struct fuse_ll *f = req->f;	(void) nodeid;	(void) inarg;	f->got_destroy = 1;	if (f->op.destroy)		f->op.destroy(f->userdata);	send_reply_ok(req, NULL, 0);}void *fuse_req_userdata(fuse_req_t req){	return req->f->userdata;}const struct fuse_ctx *fuse_req_ctx(fuse_req_t req){	return &req->ctx;}void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,			     void *data){	pthread_mutex_lock(&req->lock);	req->u.ni.func = func;	req->u.ni.data = data;	if (req->interrupted && func)		func(req, data);	pthread_mutex_unlock(&req->lock);}int fuse_req_interrupted(fuse_req_t req){	int interrupted;	pthread_mutex_lock(&req->f->lock);	interrupted = req->interrupted;	pthread_mutex_unlock(&req->f->lock);	return interrupted;}static struct {	void (*func)(fuse_req_t, fuse_ino_t, const void *);	const char *name;} fuse_ll_ops[] = {	[FUSE_LOOKUP]	   = { do_lookup,      "LOOKUP"	     },	[FUSE_FORGET]	   = { do_forget,      "FORGET"	     },	[FUSE_GETATTR]	   = { do_getattr,     "GETATTR"     },	[FUSE_SETATTR]	   = { do_setattr,     "SETATTR"     },	[FUSE_READLINK]	   = { do_readlink,    "READLINK"    },	[FUSE_SYMLINK]	   = { do_symlink,     "SYMLINK"     },	[FUSE_MKNOD]	   = { do_mknod,       "MKNOD"	     },	[FUSE_MKDIR]	   = { do_mkdir,       "MKDIR"	     },	[FUSE_UNLINK]	   = { do_unlink,      "UNLINK"	     },	[FUSE_RMDIR]	   = { do_rmdir,       "RMDIR"	     },	[FUSE_RENAME]	   = { do_rename,      "RENAME"	     },	[FUSE_LINK]	   = { do_link,	       "LINK"	     },	[FUSE_OPEN]	   = { do_open,	       "OPEN"	     },	[FUSE_READ]	   = { do_read,	       "READ"	     },	[FUSE_WRITE]	   = { do_write,       "WRITE"	     },	[FUSE_STATFS]	   = { do_statfs,      "STATFS"	     },	[FUSE_RELEASE]	   = { do_release,     "RELEASE"     },	[FUSE_FSYNC]	   = { do_fsync,       "FSYNC"	     },	[FUSE_SETXATTR]	   = { do_setxattr,    "SETXATTR"    },	[FUSE_GETXATTR]	   = { do_getxattr,    "GETXATTR"    },	[FUSE_LISTXATTR]   = { do_listxattr,   "LISTXATTR"   },	[FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },	[FUSE_FLUSH]	   = { do_flush,       "FLUSH"	     },	[FUSE_INIT]	   = { do_init,	       "INIT"	     },	[FUSE_OPENDIR]	   = { do_opendir,     "OPENDIR"     },	[FUSE_READDIR]	   = { do_readdir,     "READDIR"     },	[FUSE_RELEASEDIR]  = { do_releasedir,  "RELEASEDIR"  },	[FUSE_FSYNCDIR]	   = { do_fsyncdir,    "FSYNCDIR"    },	[FUSE_GETLK]	   = { do_getlk,       "GETLK"	     },	[FUSE_SETLK]	   = { do_setlk,       "SETLK"	     },	[FUSE_SETLKW]	   = { do_setlkw,      "SETLKW"	     },	[FUSE_ACCESS]	   = { do_access,      "ACCESS"	     },	[FUSE_CREATE]	   = { do_create,      "CREATE"	     },	[FUSE_INTERRUPT]   = { do_interrupt,   "INTERRUPT"   },	[FUSE_BMAP]	   = { do_bmap,	       "BMAP"	     },	[FUSE_DESTROY]	   = { do_destroy,     "DESTROY"     },};#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))static const char *opname(enum fuse_opcode opcode){	if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)		return "???";	else		return fuse_ll_ops[opcode].name;}static void fuse_ll_process(void *data, const char *buf, size_t len,			    struct fuse_chan *ch){	struct fuse_ll *f = (struct fuse_ll *) data;	struct fuse_in_header *in = (struct fuse_in_header *) buf;	const void *inarg = buf + sizeof(struct fuse_in_header);	struct fuse_req *req;	if (f->debug)		fprintf(stderr,			"unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n",			(unsigned long long) in->unique,			opname((enum fuse_opcode) in->opcode), in->opcode,			(unsigned long) in->nodeid, len);	req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));	if (req == NULL) {		fprintf(stderr, "fuse: failed to allocate request\n");		return;	}	req->f = f;	req->unique = in->unique;	req->ctx.uid = in->uid;	req->ctx.gid = in->gid;	req->ctx.pid = in->pid;	req->ch = ch;	req->ctr = 1;	list_init_req(req);	fuse_mutex_init(&req->lock);	if (!f->got_init && in->opcode != FUSE_INIT)		fuse_reply_err(req, EIO);	else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&		 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&		 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&		 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&		 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {		fuse_reply_err(req, EACCES);	} else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)		fuse_reply_err(req, ENOSYS);	else {		if (in->opcode != FUSE_INTERRUPT) {			struct fuse_req *intr;			pthread_mutex_lock(&f->lock);			intr = check_interrupt(f, req);			list_add_req(req, &f->list);			pthread_mutex_unlock(&f->lock);			if (intr)				fuse_reply_err(intr, EAGAIN);		}		fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);	}}enum {	KEY_HELP,	KEY_VERSION,};static struct fuse_opt fuse_ll_opts[] = {	{ "debug", offsetof(struct fuse_ll, debug), 1 },	{ "-d", offsetof(struct fuse_ll, debug), 1 },	{ "allow_root", offsetof(struct fuse_ll, allow_root), 1 },	{ "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },	{ "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },	{ "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },	{ "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },	FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),	FUSE_OPT_KEY("-h", KEY_HELP),	FUSE_OPT_KEY("--help", KEY_HELP),	FUSE_OPT_KEY("-V", KEY_VERSION),	FUSE_OPT_KEY("--version", KEY_VERSION),	FUSE_OPT_END};static void fuse_ll_version(void){	fprintf(stderr, "using FUSE kernel interface version %i.%i\n",		FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);}static void fuse_ll_help(void){	fprintf(stderr,"    -o max_write=N         set maximum size of write requests\n""    -o max_readahead=N     set maximum readahead\n""    -o async_read          perform reads asynchronously (default)\n""    -o sync_read           perform reads synchronously\n""    -o atomic_o_trunc      enable atomic open+truncate support\n");}static int fuse_ll_opt_proc(void *data, const char *arg, int key,			    struct fuse_args *outargs){	(void) data; (void) outargs;	switch (key) {	case KEY_HELP:		fuse_ll_help();		break;	case KEY_VERSION:		fuse_ll_version();		break;	default:		fprintf(stderr, "fuse: unknown option `%s'\n", arg);	}	return -1;}int fuse_lowlevel_is_lib_option(const char *opt){	return fuse_opt_match(fuse_ll_opts, opt);}static void fuse_ll_destroy(void *data){	struct fuse_ll *f = (struct fuse_ll *) data;	if (f->got_init && !f->got_destroy) {		if (f->op.destroy)			f->op.destroy(f->userdata);	}	pthread_mutex_destroy(&f->lock);	free(f);}/* * always call fuse_lowlevel_new_common() internally, to work around a * misfeature in the FreeBSD runtime linker, which links the old * version of a symbol to internal references. */struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,					      const struct fuse_lowlevel_ops *op,					      size_t op_size, void *userdata){	struct fuse_ll *f;	struct fuse_session *se;	struct fuse_session_ops sop = {		.process = fuse_ll_process,		.destroy = fuse_ll_destroy,	};	if (sizeof(struct fuse_lowlevel_ops) < op_size) {		fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");		op_size = sizeof(struct fuse_lowlevel_ops);	}	f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));	if (f == NULL) {		fprintf(stderr, "fuse: failed to allocate fuse object\n");		goto out;	}	f->conn.async_read = 1;	f->conn.max_write = UINT_MAX;	f->conn.max_readahead = UINT_MAX;	list_init_req(&f->list);	list_init_req(&f->interrupts);	fuse_mutex_init(&f->lock);	if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)		goto out_free;	memcpy(&f->op, op, op_size);	f->owner = getuid();	f->userdata = userdata;	se = fuse_session_new(&sop, f);	if (!se)		goto out_free;	return se;out_free:	free(f);out:	return NULL;}struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,				       const struct fuse_lowlevel_ops *op,				       size_t op_size, void *userdata){	return fuse_lowlevel_new_common(args, op, op_size, userdata);}#ifndef __FreeBSD__static void fill_open_compat(struct fuse_open_out *arg,			     const struct fuse_file_info_compat *f){	arg->fh = f->fh;	if (f->direct_io)		arg->open_flags |= FOPEN_DIRECT_IO;	if (f->keep_cache)		arg->open_flags |= FOPEN_KEEP_CACHE;}static void convert_statfs_compat(const struct statfs *compatbuf,				  struct statvfs *buf){	buf->f_bsize	= compatbuf->f_bsize;	buf->f_blocks	= compatbuf->f_blocks;	buf->f_bfree	= compatbuf->f_bfree;	buf->f_bavail	= compatbuf->f_bavail;	buf->f_files	= compatbuf->f_files;	buf->f_ffree	= compatbuf->f_ffree;	buf->f_namemax	= compatbuf->f_namelen;}int fuse_reply_open_compat(fuse_req_t req,			   const struct fuse_file_info_compat *f){	struct fuse_open_out arg;	memset(&arg, 0, sizeof(arg));	fill_open_compat(&arg, f);	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf){	struct statvfs newbuf;	memset(&newbuf, 0, sizeof(newbuf));	convert_statfs_compat(stbuf, &newbuf);	return fuse_reply_statfs(req, &newbuf);}struct fuse_session *fuse_lowlevel_new_compat(const char *opts,				const struct fuse_lowlevel_ops_compat *op,				size_t op_size, void *userdata){	struct fuse_session *se;	struct fuse_args args = FUSE_ARGS_INIT(0, NULL);	if (opts &&	    (fuse_opt_add_arg(&args, "") == -1 ||	     fuse_opt_add_arg(&args, "-o") == -1 ||	     fuse_opt_add_arg(&args, opts) == -1)) {		fuse_opt_free_args(&args);		return NULL;	}	se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op,			       op_size, userdata);	fuse_opt_free_args(&args);	return se;}struct fuse_ll_compat_conf {	unsigned max_read;	int set_max_read;};static const struct fuse_opt fuse_ll_opts_compat[] = {	{ "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 },	{ "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 },	FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),	FUSE_OPT_END};int fuse_sync_compat_args(struct fuse_args *args){	struct fuse_ll_compat_conf conf;	memset(&conf, 0, sizeof(conf));	if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1)		return -1;	if (fuse_opt_insert_arg(args, 1, "-osync_read"))		return -1;	if (conf.set_max_read) {		char tmpbuf[64];		sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read);		if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1)			return -1;	}	return 0;}FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");FUSE_SYMVER(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");#else /* __FreeBSD__ */int fuse_sync_compat_args(struct fuse_args *args){	(void) args;	return 0;}#endif /* __FreeBSD__ */struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,				const struct fuse_lowlevel_ops_compat25 *op,				size_t op_size, void *userdata){	if (fuse_sync_compat_args(args) == -1)		return NULL;	return fuse_lowlevel_new_common(args,					(const struct fuse_lowlevel_ops *) op,					op_size, userdata);}FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?