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

📄 dir.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct page *page;	struct inode *inode = file->f_path.dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_req *req;	if (is_bad_inode(inode))		return -EIO;	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	page = alloc_page(GFP_KERNEL);	if (!page) {		fuse_put_request(fc, req);		return -ENOMEM;	}	req->num_pages = 1;	req->pages[0] = page;	fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);	request_send(fc, req);	nbytes = req->out.args[0].size;	err = req->out.h.error;	fuse_put_request(fc, req);	if (!err)		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,				    filldir);	__free_page(page);	fuse_invalidate_attr(inode); /* atime changed */	return err;}static char *read_link(struct dentry *dentry){	struct inode *inode = dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_req *req = fuse_get_req(fc);	char *link;	if (IS_ERR(req))		return ERR_PTR(PTR_ERR(req));	link = (char *) __get_free_page(GFP_KERNEL);	if (!link) {		link = ERR_PTR(-ENOMEM);		goto out;	}	req->in.h.opcode = FUSE_READLINK;	req->in.h.nodeid = get_node_id(inode);	req->out.argvar = 1;	req->out.numargs = 1;	req->out.args[0].size = PAGE_SIZE - 1;	req->out.args[0].value = link;	request_send(fc, req);	if (req->out.h.error) {		free_page((unsigned long) link);		link = ERR_PTR(req->out.h.error);	} else		link[req->out.args[0].size] = '\0'; out:	fuse_put_request(fc, req);	fuse_invalidate_attr(inode); /* atime changed */	return link;}static void free_link(char *link){	if (!IS_ERR(link))		free_page((unsigned long) link);}static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd){	nd_set_link(nd, read_link(dentry));	return NULL;}static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c){	free_link(nd_get_link(nd));}static int fuse_dir_open(struct inode *inode, struct file *file){	return fuse_open_common(inode, file, 1);}static int fuse_dir_release(struct inode *inode, struct file *file){	return fuse_release_common(inode, file, 1);}static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync){	/* nfsd can call this with no file */	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;}static bool update_mtime(unsigned ivalid){	/* Always update if mtime is explicitly set  */	if (ivalid & ATTR_MTIME_SET)		return true;	/* If it's an open(O_TRUNC) or an ftruncate(), don't update */	if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))		return false;	/* In all other cases update */	return true;}static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg){	unsigned ivalid = iattr->ia_valid;	if (ivalid & ATTR_MODE)		arg->valid |= FATTR_MODE,   arg->mode = iattr->ia_mode;	if (ivalid & ATTR_UID)		arg->valid |= FATTR_UID,    arg->uid = iattr->ia_uid;	if (ivalid & ATTR_GID)		arg->valid |= FATTR_GID,    arg->gid = iattr->ia_gid;	if (ivalid & ATTR_SIZE)		arg->valid |= FATTR_SIZE,   arg->size = iattr->ia_size;	if (ivalid & ATTR_ATIME) {		arg->valid |= FATTR_ATIME;		arg->atime = iattr->ia_atime.tv_sec;		arg->atimensec = iattr->ia_atime.tv_nsec;		if (!(ivalid & ATTR_ATIME_SET))			arg->valid |= FATTR_ATIME_NOW;	}	if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {		arg->valid |= FATTR_MTIME;		arg->mtime = iattr->ia_mtime.tv_sec;		arg->mtimensec = iattr->ia_mtime.tv_nsec;		if (!(ivalid & ATTR_MTIME_SET))			arg->valid |= FATTR_MTIME_NOW;	}}/* * Set attributes, and at the same time refresh them. * * Truncation is slightly complicated, because the 'truncate' request * may fail, in which case we don't want to touch the mapping. * vmtruncate() doesn't allow for this case, so do the rlimit checking * and the actual truncation by hand. */static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,			   struct file *file){	struct inode *inode = entry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_req *req;	struct fuse_setattr_in inarg;	struct fuse_attr_out outarg;	int err;	if (!fuse_allow_task(fc, current))		return -EACCES;	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {		err = inode_change_ok(inode, attr);		if (err)			return err;	}	if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)		return 0;	if (attr->ia_valid & ATTR_SIZE) {		unsigned long limit;		if (IS_SWAPFILE(inode))			return -ETXTBSY;		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {			send_sig(SIGXFSZ, current, 0);			return -EFBIG;		}	}	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	memset(&inarg, 0, sizeof(inarg));	memset(&outarg, 0, sizeof(outarg));	iattr_to_fattr(attr, &inarg);	if (file) {		struct fuse_file *ff = file->private_data;		inarg.valid |= FATTR_FH;		inarg.fh = ff->fh;	}	if (attr->ia_valid & ATTR_SIZE) {		/* For mandatory locking in truncate */		inarg.valid |= FATTR_LOCKOWNER;		inarg.lock_owner = fuse_lock_owner_id(fc, current->files);	}	req->in.h.opcode = FUSE_SETATTR;	req->in.h.nodeid = get_node_id(inode);	req->in.numargs = 1;	req->in.args[0].size = sizeof(inarg);	req->in.args[0].value = &inarg;	req->out.numargs = 1;	if (fc->minor < 9)		req->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;	else		req->out.args[0].size = sizeof(outarg);	req->out.args[0].value = &outarg;	request_send(fc, req);	err = req->out.h.error;	fuse_put_request(fc, req);	if (err) {		if (err == -EINTR)			fuse_invalidate_attr(inode);		return err;	}	if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {		make_bad_inode(inode);		return -EIO;	}	fuse_change_attributes(inode, &outarg.attr, attr_timeout(&outarg), 0);	return 0;}static int fuse_setattr(struct dentry *entry, struct iattr *attr){	if (attr->ia_valid & ATTR_FILE)		return fuse_do_setattr(entry, attr, attr->ia_file);	else		return fuse_do_setattr(entry, attr, NULL);}static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,			struct kstat *stat){	struct inode *inode = entry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	if (!fuse_allow_task(fc, current))		return -EACCES;	return fuse_update_attributes(inode, stat, NULL, NULL);}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 (fc->no_setxattr)		return -EOPNOTSUPP;	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	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->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_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	memset(&inarg, 0, sizeof(inarg));	inarg.size = size;	req->in.h.opcode = FUSE_GETXATTR;	req->in.h.nodeid = get_node_id(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 (!fuse_allow_task(fc, current))		return -EACCES;	if (fc->no_listxattr)		return -EOPNOTSUPP;	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	memset(&inarg, 0, sizeof(inarg));	inarg.size = size;	req->in.h.opcode = FUSE_LISTXATTR;	req->in.h.nodeid = get_node_id(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_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	req->in.h.opcode = FUSE_REMOVEXATTR;	req->in.h.nodeid = get_node_id(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 const struct inode_operations fuse_dir_inode_operations = {	.lookup		= fuse_lookup,	.mkdir		= fuse_mkdir,	.symlink	= fuse_symlink,	.unlink		= fuse_unlink,	.rmdir		= fuse_rmdir,	.rename		= fuse_rename,	.link		= fuse_link,	.setattr	= fuse_setattr,	.create		= fuse_create,	.mknod		= fuse_mknod,	.permission	= fuse_permission,	.getattr	= fuse_getattr,	.setxattr	= fuse_setxattr,	.getxattr	= fuse_getxattr,	.listxattr	= fuse_listxattr,	.removexattr	= fuse_removexattr,};static const struct file_operations fuse_dir_operations = {	.llseek		= generic_file_llseek,	.read		= generic_read_dir,	.readdir	= fuse_readdir,	.open		= fuse_dir_open,	.release	= fuse_dir_release,	.fsync		= fuse_dir_fsync,};static const 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 const struct inode_operations fuse_symlink_inode_operations = {	.setattr	= fuse_setattr,	.follow_link	= fuse_follow_link,	.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){	inode->i_op = &fuse_common_inode_operations;}void fuse_init_dir(struct inode *inode){	inode->i_op = &fuse_dir_inode_operations;	inode->i_fop = &fuse_dir_operations;}void fuse_init_symlink(struct inode *inode){	inode->i_op = &fuse_symlink_inode_operations;}

⌨️ 快捷键说明

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