📄 dir.c
字号:
__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);}#ifdef KERNEL_2_6_13_PLUSstatic 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));}#elsestatic int fuse_follow_link(struct dentry *dentry, struct nameidata *nd){ nd_set_link(nd, read_link(dentry)); return 0;}static void fuse_put_link(struct dentry *dentry, struct nameidata *nd){ free_link(nd_get_link(nd));}#endifstatic 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 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; /* You can only _set_ these together (they may change by themselves) */ if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { arg->valid |= FATTR_ATIME | FATTR_MTIME; arg->atime = iattr->ia_atime.tv_sec; arg->mtime = iattr->ia_mtime.tv_sec; }#ifdef ATTR_FILE if (ivalid & ATTR_FILE) { struct fuse_file *ff = iattr->ia_file->private_data; arg->valid |= FATTR_FH; arg->fh = ff->fh; }#endif}static void fuse_vmtruncate(struct inode *inode, loff_t offset){ struct fuse_conn *fc = get_fuse_conn(inode); int need_trunc; spin_lock(&fc->lock); need_trunc = inode->i_size > offset; i_size_write(inode, offset); spin_unlock(&fc->lock); if (need_trunc) { struct address_space *mapping = inode->i_mapping; unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); truncate_inode_pages(mapping, offset); }}/* * 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_setattr(struct dentry *entry, struct iattr *attr){ struct inode *inode = entry->d_inode; struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_inode *fi = get_fuse_inode(inode); struct fuse_req *req; struct fuse_setattr_in inarg; struct fuse_attr_out outarg; int err; int is_truncate = 0; if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { err = inode_change_ok(inode, attr); if (err) return err; } if (attr->ia_valid & ATTR_SIZE) { unsigned long limit; is_truncate = 1; if (IS_SWAPFILE(inode)) return -ETXTBSY;#ifdef KERNEL_2_6_10_PLUS limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;#else limit = current->rlim[RLIMIT_FSIZE].rlim_cur;#endif 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)); iattr_to_fattr(attr, &inarg); /* Defend against future expansion of ATTR_FILE use */ if (S_ISDIR(inode->i_mode)) inarg.valid &= ~FATTR_FH; 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; 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 ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {#ifndef KERNEL_2_6_12_PLUS if (get_node_id(inode) != FUSE_ROOT_ID) make_bad_inode(inode);#else make_bad_inode(inode);#endif err = -EIO; } else { if (is_truncate) fuse_vmtruncate(inode, outarg.attr.size); fuse_change_attributes(inode, &outarg.attr); fi->i_time = time_to_jiffies(outarg.attr_valid, outarg.attr_valid_nsec); } } else if (err == -EINTR) fuse_invalidate_attr(inode); return err;}static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, struct kstat *stat){ struct inode *inode = entry->d_inode; int err = fuse_revalidate(entry); if (!err) /* FIXME: may want specialized function because of st_blksize on block devices on 2.6.19+ */ generic_fillattr(inode, stat); return err;}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 (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 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 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 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 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 + -