⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fuse_lowlevel.c

📁 FUSE文件系统开发工具,将内核层面的文件系统开发过程平移到应用层面上来。
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  FUSE: Filesystem in Userspace  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>  This program can be distributed under the terms of the GNU LGPLv2.  See the file COPYING.LIB*/#include "fuse_lowlevel.h"#include "fuse_kernel.h"#include "fuse_opt.h"#include "fuse_i.h"#include "fuse_misc.h"#include "fuse_common_compat.h"#include "fuse_lowlevel_compat.h"#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <string.h>#include <unistd.h>#include <limits.h>#include <errno.h>#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))#define OFFSET_MAX 0x7fffffffffffffffLLstruct fuse_ll;struct fuse_req {	struct fuse_ll *f;	uint64_t unique;	int ctr;	pthread_mutex_t lock;	struct fuse_ctx ctx;	struct fuse_chan *ch;	int interrupted;	union {		struct {			uint64_t unique;		} i;		struct {			fuse_interrupt_func_t func;			void *data;		} ni;	} u;	struct fuse_req *next;	struct fuse_req *prev;};struct fuse_ll {	int debug;	int allow_root;	struct fuse_lowlevel_ops op;	int got_init;	void *userdata;	uid_t owner;	struct fuse_conn_info conn;	struct fuse_req list;	struct fuse_req interrupts;	pthread_mutex_t lock;	int got_destroy;};static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr){	attr->ino	= stbuf->st_ino;	attr->mode	= stbuf->st_mode;	attr->nlink	= stbuf->st_nlink;	attr->uid	= stbuf->st_uid;	attr->gid	= stbuf->st_gid;	attr->rdev	= stbuf->st_rdev;	attr->size	= stbuf->st_size;	attr->blocks	= stbuf->st_blocks;	attr->atime	= stbuf->st_atime;	attr->mtime	= stbuf->st_mtime;	attr->ctime	= stbuf->st_ctime;	attr->atimensec = ST_ATIM_NSEC(stbuf);	attr->mtimensec = ST_MTIM_NSEC(stbuf);	attr->ctimensec = ST_CTIM_NSEC(stbuf);}static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf){	stbuf->st_mode	       = attr->mode;	stbuf->st_uid	       = attr->uid;	stbuf->st_gid	       = attr->gid;	stbuf->st_size	       = attr->size;	stbuf->st_atime	       = attr->atime;	stbuf->st_mtime	       = attr->mtime;	ST_ATIM_NSEC_SET(stbuf, attr->atimensec);	ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);}static	size_t iov_length(const struct iovec *iov, size_t count){	size_t seg;	size_t ret = 0;	for (seg = 0; seg < count; seg++)		ret += iov[seg].iov_len;	return ret;}static void list_init_req(struct fuse_req *req){	req->next = req;	req->prev = req;}static void list_del_req(struct fuse_req *req){	struct fuse_req *prev = req->prev;	struct fuse_req *next = req->next;	prev->next = next;	next->prev = prev;}static void list_add_req(struct fuse_req *req, struct fuse_req *next){	struct fuse_req *prev = next->prev;	req->next = next;	req->prev = prev;	prev->next = req;	next->prev = req;}static void destroy_req(fuse_req_t req){	pthread_mutex_destroy(&req->lock);	free(req);}static void free_req(fuse_req_t req){	int ctr;	struct fuse_ll *f = req->f;	pthread_mutex_lock(&req->lock);	req->u.ni.func = NULL;	req->u.ni.data = NULL;	pthread_mutex_unlock(&req->lock);	pthread_mutex_lock(&f->lock);	list_del_req(req);	ctr = --req->ctr;	pthread_mutex_unlock(&f->lock);	if (!ctr)		destroy_req(req);}static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,			  int count){	struct fuse_out_header out;	int res;	if (error <= -1000 || error > 0) {		fprintf(stderr, "fuse: bad error value: %i\n",	error);		error = -ERANGE;	}	out.unique = req->unique;	out.error = error;	iov[0].iov_base = &out;	iov[0].iov_len = sizeof(struct fuse_out_header);	out.len = iov_length(iov, count);	if (req->f->debug)		fprintf(stderr,			"   unique: %llu, error: %i (%s), outsize: %i\n",			(unsigned long long) out.unique, out.error,			strerror(-out.error), out.len);	res = fuse_chan_send(req->ch, iov, count);	free_req(req);	return res;}static int send_reply(fuse_req_t req, int error, const void *arg,		      size_t argsize){	struct iovec iov[2];	int count = 1;	if (argsize) {		iov[1].iov_base = (void *) arg;		iov[1].iov_len = argsize;		count++;	}	return send_reply_iov(req, error, iov, count);}int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count){	int res;	struct iovec *padded_iov;	padded_iov = malloc((count + 1) * sizeof(struct iovec));	if (padded_iov == NULL)		return fuse_reply_err(req, -ENOMEM);	memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));	count++;	res = send_reply_iov(req, 0, padded_iov, count);	free(padded_iov);	return res;}size_t fuse_dirent_size(size_t namelen){	return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);}char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,		      off_t off){	unsigned namelen = strlen(name);	unsigned entlen = FUSE_NAME_OFFSET + namelen;	unsigned entsize = fuse_dirent_size(namelen);	unsigned padlen = entsize - entlen;	struct fuse_dirent *dirent = (struct fuse_dirent *) buf;	dirent->ino = stbuf->st_ino;	dirent->off = off;	dirent->namelen = namelen;	dirent->type = (stbuf->st_mode & 0170000) >> 12;	strncpy(dirent->name, name, namelen);	if (padlen)		memset(buf + entlen, 0, padlen);	return buf + entsize;}size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,			 const char *name, const struct stat *stbuf, off_t off){	size_t entsize;	(void) req;	entsize = fuse_dirent_size(strlen(name));	if (entsize <= bufsize && buf)		fuse_add_dirent(buf, name, stbuf, off);	return entsize;}static void convert_statfs(const struct statvfs *stbuf,			   struct fuse_kstatfs *kstatfs){	kstatfs->bsize	 = stbuf->f_bsize;	kstatfs->frsize	 = stbuf->f_frsize;	kstatfs->blocks	 = stbuf->f_blocks;	kstatfs->bfree	 = stbuf->f_bfree;	kstatfs->bavail	 = stbuf->f_bavail;	kstatfs->files	 = stbuf->f_files;	kstatfs->ffree	 = stbuf->f_ffree;	kstatfs->namelen = stbuf->f_namemax;}static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize){	return send_reply(req, 0, arg, argsize);}int fuse_reply_err(fuse_req_t req, int err){	return send_reply(req, -err, NULL, 0);}void fuse_reply_none(fuse_req_t req){	fuse_chan_send(req->ch, NULL, 0);	free_req(req);}static unsigned long calc_timeout_sec(double t){	if (t > (double) ULONG_MAX)		return ULONG_MAX;	else if (t < 0.0)		return 0;	else		return (unsigned long) t;}static unsigned int calc_timeout_nsec(double t){	double f = t - (double) calc_timeout_sec(t);	if (f < 0.0)		return 0;	else if (f >= 0.999999999)		return 999999999;	else		return (unsigned int) (f * 1.0e9);}static void fill_entry(struct fuse_entry_out *arg,		       const struct fuse_entry_param *e){	arg->nodeid = e->ino;	arg->generation = e->generation;	arg->entry_valid = calc_timeout_sec(e->entry_timeout);	arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);	arg->attr_valid = calc_timeout_sec(e->attr_timeout);	arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);	convert_stat(&e->attr, &arg->attr);}static void fill_open(struct fuse_open_out *arg,		      const struct fuse_file_info *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;}int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e){	struct fuse_entry_out arg;	/* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant	   negative entry */	if (!e->ino && req->f->conn.proto_minor < 4)		return fuse_reply_err(req, ENOENT);	memset(&arg, 0, sizeof(arg));	fill_entry(&arg, e);	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,		      const struct fuse_file_info *f){	struct {		struct fuse_entry_out e;		struct fuse_open_out o;	} arg;	memset(&arg, 0, sizeof(arg));	fill_entry(&arg.e, e);	fill_open(&arg.o, f);	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_attr(fuse_req_t req, const struct stat *attr,		    double attr_timeout){	struct fuse_attr_out arg;	memset(&arg, 0, sizeof(arg));	arg.attr_valid = calc_timeout_sec(attr_timeout);	arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);	convert_stat(attr, &arg.attr);	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_readlink(fuse_req_t req, const char *linkname){	return send_reply_ok(req, linkname, strlen(linkname));}int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f){	struct fuse_open_out arg;	memset(&arg, 0, sizeof(arg));	fill_open(&arg, f);	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_write(fuse_req_t req, size_t count){	struct fuse_write_out arg;	memset(&arg, 0, sizeof(arg));	arg.size = count;	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size){	return send_reply_ok(req, buf, size);}int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf){	struct fuse_statfs_out arg;	size_t size = req->f->conn.proto_minor < 4 ?		FUSE_COMPAT_STATFS_SIZE : sizeof(arg);	memset(&arg, 0, sizeof(arg));	convert_statfs(stbuf, &arg.st);	return send_reply_ok(req, &arg, size);}int fuse_reply_xattr(fuse_req_t req, size_t count){	struct fuse_getxattr_out arg;	memset(&arg, 0, sizeof(arg));	arg.size = count;	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_lock(fuse_req_t req, struct flock *lock){	struct fuse_lk_out arg;	memset(&arg, 0, sizeof(arg));	arg.lk.type = lock->l_type;	if (lock->l_type != F_UNLCK) {		arg.lk.start = lock->l_start;		if (lock->l_len == 0)			arg.lk.end = OFFSET_MAX;		else			arg.lk.end = lock->l_start + lock->l_len - 1;	}	arg.lk.pid = lock->l_pid;	return send_reply_ok(req, &arg, sizeof(arg));}int fuse_reply_bmap(fuse_req_t req, uint64_t idx){	struct fuse_bmap_out arg;	memset(&arg, 0, sizeof(arg));	arg.block = idx;	return send_reply_ok(req, &arg, sizeof(arg));}static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){	char *name = (char *) inarg;	if (req->f->op.lookup)		req->f->op.lookup(req, nodeid, name);	else		fuse_reply_err(req, ENOSYS);}static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){	struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;	if (req->f->op.forget)		req->f->op.forget(req, nodeid, arg->nlookup);	else		fuse_reply_none(req);}static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){	(void) inarg;	if (req->f->op.getattr)		req->f->op.getattr(req, nodeid, NULL);	else		fuse_reply_err(req, ENOSYS);}static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg){	struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;	if (req->f->op.setattr) {		struct fuse_file_info *fi = NULL;		struct fuse_file_info fi_store;		struct stat stbuf;		memset(&stbuf, 0, sizeof(stbuf));		convert_attr(arg, &stbuf);		if (arg->valid & FATTR_FH) {			arg->valid &= ~FATTR_FH;			memset(&fi_store, 0, sizeof(fi_store));			fi = &fi_store;			fi->fh = arg->fh;

⌨️ 快捷键说明

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