📄 inode.c
字号:
if (!check_parent(hidden_dir_dentry, hidden_dentry)) goto out; err = vfs_mknod(hidden_dir_dentry->d_inode, hidden_dentry, mode, dev); if (err) goto out; err = wrapfs_interpose(hidden_dentry, dentry, dir->i_sb, 0); if (err) goto out; fist_copy_attr_timesizes(dir, hidden_dir_dentry->d_inode); out: unlock_dir(hidden_dir_dentry); fist_checkinode(dir, "post wrapfs_mknod-dir"); print_exit_status(err); return err;}STATIC intwrapfs_rename(inode_t *old_dir, dentry_t *old_dentry, inode_t *new_dir, dentry_t *new_dentry){ int err; dentry_t *hidden_old_dentry = wrapfs_hidden_dentry(old_dentry); dentry_t *hidden_new_dentry = wrapfs_hidden_dentry(new_dentry); dentry_t *hidden_old_dir_dentry; dentry_t *hidden_new_dir_dentry; print_entry_location(); fist_checkinode(old_dir, "wrapfs_rename-old_dir"); fist_checkinode(new_dir, "wrapfs_rename-new_dir"); dget(hidden_old_dentry); dget(hidden_new_dentry); hidden_old_dir_dentry = get_parent(hidden_old_dentry); hidden_new_dir_dentry = get_parent(hidden_new_dentry); double_lock(hidden_old_dir_dentry, hidden_new_dir_dentry); err = -ENOENT;#ifdef FIST_FILTER_SCA /* Also rename the index file */ if (old_dentry->d_inode && S_ISREG(old_dentry->d_inode->i_mode)) { /* These must be in the same directory as the main file */ dentry_t *idx_old_dentry = dtopd(old_dentry)->idx_dentry; dentry_t *idx_new_dentry = dtopd(new_dentry)->idx_dentry; if (check_parent(hidden_old_dir_dentry, idx_old_dentry) && check_parent(hidden_new_dir_dentry, idx_new_dentry)) err = vfs_rename(hidden_old_dir_dentry->d_inode, idx_old_dentry, hidden_new_dir_dentry->d_inode, idx_new_dentry); if (err) goto out_lock; }#endif if (check_parent(hidden_old_dir_dentry, hidden_old_dentry) && check_parent(hidden_new_dir_dentry, hidden_new_dentry)) err = vfs_rename(hidden_old_dir_dentry->d_inode, hidden_old_dentry, hidden_new_dir_dentry->d_inode, hidden_new_dentry); if (err) goto out_lock; fist_copy_attr_all(new_dir, hidden_new_dir_dentry->d_inode); if (new_dir != old_dir) fist_copy_attr_all(old_dir, hidden_old_dir_dentry->d_inode); out_lock: // double_unlock will dput the new/old parent dentries whose refcnts // were incremented via get_parent above. double_unlock(hidden_old_dir_dentry, hidden_new_dir_dentry); dput(hidden_new_dentry); dput(hidden_old_dentry); fist_checkinode(new_dir, "post wrapfs_rename-new_dir"); print_exit_status(err); return err;}STATIC intwrapfs_readlink(dentry_t *dentry, char *buf, int bufsiz){ int err; dentry_t *hidden_dentry = wrapfs_hidden_dentry(dentry);#ifdef FIST_FILTER_NAME char *decoded_name, *hidden_buf; mm_segment_t old_fs;#endif /* FIST_FILTER_NAME */ print_entry_location(); fist_print_dentry("wrapfs_readlink IN", dentry); if (!hidden_dentry->d_inode->i_op || !hidden_dentry->d_inode->i_op->readlink) { err = -EINVAL; goto out; }#ifndef FIST_FILTER_NAME err = hidden_dentry->d_inode->i_op->readlink(hidden_dentry, buf, bufsiz); if (err > 0) fist_copy_attr_atime(dentry->d_inode, hidden_dentry->d_inode);#else /* FIST_FILTER_NAME */ hidden_buf = kmalloc(bufsiz, GFP_KERNEL); if (hidden_buf == NULL) { printk("Out of memory.\n"); err = -ENOMEM; goto out; } old_fs = get_fs(); set_fs(KERNEL_DS); err = hidden_dentry->d_inode->i_op->readlink(hidden_dentry, hidden_buf, bufsiz); set_fs(old_fs); if (err >= 0) { // don't do this, it's not zero-terminated!!! // fist_dprint(7, "READLINK: link \"%s\", length %d\n", hidden_buf, err); err = wrapfs_decode_filename(hidden_buf, err, &decoded_name, DO_DOTS, dentry->d_inode, dentry->d_sb); if (err > 0) { if (copy_to_user(buf, decoded_name, err)) err = -EFAULT; kfree_s(decoded_name, err); } fist_copy_attr_atime(dentry->d_inode, hidden_dentry->d_inode); } kfree_s(hidden_buf, bufsiz);#endif /* FIST_FILTER_NAME */ out: print_exit_status(err); return err;}STATIC intwrapfs_follow_link(dentry_t *dentry, struct nameidata *nd){ char *buf; int len = PAGE_SIZE, err; mm_segment_t old_fs; print_entry_location(); // fist_print_dentry("wrapfs_follow_link dentry IN", dentry); buf = kmalloc(len, GFP_KERNEL); if (!buf) { err = -ENOMEM; goto out; } /* read the symlink, and then we will follow it */ old_fs = get_fs(); set_fs(KERNEL_DS); err = dentry->d_inode->i_op->readlink(dentry, buf, len); set_fs(old_fs); if (err < 0) goto out_free; buf[err] = 0; // terminate the buffer -- XXX still needed? // XXX: FIXME w/ wrapfs_encode_filename() /* * vfs_follow_link will increase the nd's mnt refcnt * we assume that some other VFS code decrements it. */ err = vfs_follow_link(nd, buf); out_free: kfree_s(buf, len); out:#if 0 if (err < 0) { dput(nd->dentry); printk("EZK follow_link() mnt_cnt %d\n", atomic_read(&nd->mnt->mnt_count)); mntput(nd->mnt); }#endif print_exit_status(err); return err;}#ifdef FIST_FILTER_SCASTATIC intwrapfs_truncate_and_enlarge(dentry_t *dentry){ dentry_t *hidden_dentry = dtohd(dentry); inode_t *hidden_inode = hidden_dentry->d_inode; inode_t *inode = dentry->d_inode; int err = 0; page_t *page = NULL; int index, new_index; unsigned offset, new_offset, real_size; struct encoded_page *ep = NULL, *next_ep, **cur_ep; struct scafs_header *hdr = &itopd(inode)->hdr; void *opaque; file_t *hidden_file; struct iattr attr; off_t abs_offset; int need_to_call = 1; file_t fake_file; /* needed b/c notify change doesn't get a struct file */ print_entry_location(); if (dentry->d_inode->i_size == hdr->real_size) goto out; down(&hidden_inode->i_sem); // calculate page index and page offset (offset) new_index = inode->i_size >> PAGE_CACHE_SHIFT; new_offset = inode->i_size & ~PAGE_CACHE_MASK; if (inode->i_size > hdr->real_size) { /* enlarge */ index = hdr->real_size >> PAGE_CACHE_SHIFT; offset = hdr->real_size & ~PAGE_CACHE_MASK; /* abs_offset is the absolute offset within the hidden_file * where the encoded representation of the current page begins. * Whee... */ abs_offset = HIDDEN_PAGE_STARTING_OFFSET(index, inode); } else { /* shrink */ index = new_index; offset = new_offset; abs_offset = HIDDEN_PAGE_STARTING_OFFSET(new_index, inode); } real_size = 0; if (offset == 0 || IS_HOLE(index, inode)) goto page_boundary; if (index == new_index) offset = new_offset; else offset = PAGE_CACHE_SIZE; /* * get our page at offset inode->i_size * this is either the page within which we're truncating, * if we are shrinking, * or the former last page, if we are enlarging */ /* * XXX: set up fake file. A hack b/c address_ops need a struct file * but notify_change only gets a dentry. */ memset(&fake_file, 0, sizeof(file_t)); // XXX: may need to initialize other fields! fake_file.f_dentry = dentry; page = wrapfs_get1page(&fake_file, index); if (IS_ERR(page)) { err = PTR_ERR(page); goto out_unlock; } /* re-encode our page from 0 to "offset" within page */ kmap(page); cur_ep = &ep; while (need_to_call) { *cur_ep = kmalloc(sizeof(struct encoded_page), GFP_KERNEL); (*cur_ep)->data = (char *) __get_free_page(GFP_KERNEL);#ifdef FIST_FAST_TAILS if (CAN_BE_FASTTAIL_PAGE(offset, inode)) { memcpy((*cur_ep)->data, (char *) page_address(page), offset); need_to_call = 0; err = offset; hdr->flags |= SCA_FLAG_FASTTAIL; } else#endif /* FIST_FAST_TAILS */ { err = wrapfs_encode_buffers((*cur_ep)->data, (char *) page_address(page), &need_to_call, offset, inode, inode->i_sb, &opaque); if (page->index + 1 >= hdr->num_chunks) hdr->flags &= ~SCA_FLAG_FASTTAIL; } cur_ep = &(*cur_ep)->next; *cur_ep = NULL; if (err < 0) goto out_free; real_size += err; } wrapfs_idx_set_entry(hdr, index, abs_offset + real_size); // write new bytes dget(hidden_dentry); /* * dentry_open will decrement mnt refcnt if err. * otherwise fput() will do an mntput() for us upon file close. */ mntget(stopd(inode->i_sb)->hidden_mnt); hidden_file = dentry_open(hidden_dentry, stopd(inode->i_sb)->hidden_mnt, FMODE_WRITE, O_WRONLY); if (IS_ERR(hidden_file)) { err = PTR_ERR(hidden_file); goto out_free; } err = wrapfs_copy_encoded_data(hidden_file, abs_offset, ep, real_size); fput(hidden_file); if (err < 0) goto out_free; page_boundary: index = new_index; offset = new_offset; abs_offset = HIDDEN_PAGE_STARTING_OFFSET(new_index, inode); if (index >= hdr->num_chunks) real_size = 0; /* hole, even though imcomplete */ // call notify change on lower data file w/ new size attr.ia_size = abs_offset + real_size; attr.ia_valid = ATTR_SIZE; err = notify_change(hidden_dentry, &attr); if (err < 0) goto out_free; // update IT for the new encoded bytes hdr->real_size = inode->i_size; if (offset == 0) { if (index > 0) err = wrapfs_idx_set_entry(hdr, index - 1, attr.ia_size); hdr->num_chunks = index; } else { err = wrapfs_idx_set_entry(hdr, index, attr.ia_size); hdr->num_chunks = index + 1; } if (err < 0) goto out_free; mark_inode_dirty(inode); /* so it'll write the index table */ /* all is ok */ out_free: /* free encoded_pages */ while (ep) { next_ep = ep->next; free_page((unsigned long) ep->data); kfree_s(ep, sizeof(encoded_pages_t)); ep = next_ep; } kunmap(page); if (page) page_cache_release(page); out_unlock: up(&hidden_inode->i_sem); out: print_exit_location(); return err;}#endif /* not FIST_FILTER_SCA */STATIC intwrapfs_permission(inode_t *inode, int mask){ inode_t *hidden_inode = itohi(inode); int mode = inode->i_mode; int err; print_entry_location(); if ((mask & S_IWOTH) && IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) { err = -EROFS; /* Nobody gets write access to a read-only fs */ goto out; } err = permission(hidden_inode, mask); out: print_exit_status(err); return err;}STATIC intwrapfs_inode_revalidate(dentry_t *dentry){ int err = 0; dentry_t *hidden_dentry = wrapfs_hidden_dentry(dentry); inode_t *hidden_inode = hidden_dentry->d_inode; print_entry_location(); // fist_print_dentry("inode_revalidate IN", dentry); if (hidden_inode->i_op && hidden_inode->i_op->revalidate) { err = hidden_inode->i_op->revalidate(hidden_dentry); if (!err) fist_copy_attr_all(dentry->d_inode, hidden_inode); } // fist_print_dentry("inode_revalidate OUT", dentry); print_exit_status(err); return err;}STATIC intwrapfs_setattr(dentry_t *dentry, struct iattr *ia){ int err = 0; dentry_t *hidden_dentry = wrapfs_hidden_dentry(dentry); inode_t *inode = dentry->d_inode; inode_t *hidden_inode = itohi(inode); print_entry_location(); fist_checkinode(inode, "wrapfs_setattr");#ifdef FIST_FILTER_SCA if (ia->ia_valid & ATTR_SIZE) { dentry->d_inode->i_size = ia->ia_size; err = wrapfs_truncate_and_enlarge(dentry); if (err < 0) goto out; ia->ia_valid &= ~ATTR_SIZE; /* b/c we handled it */ }#endif /* FIST_FILTER_SCA */ err = notify_change(hidden_dentry, ia);#ifdef FIST_FILTER_SCA out:#endif /* FIST_FILTER_SCA */ /* * The lower file system might has changed the attributes, even if * notify_change above resulted in an error(!) so we copy the * hidden_inode's attributes (and a few more) to our inode. */ fist_copy_attr_all(inode, hidden_inode); fist_checkinode(inode, "post wrapfs_setattr"); print_exit_status(err); return err;}#if NOT_USED_YETSTATIC intwrapfs_getattr(dentry_t *dentry, struct iattr *ia){ return -ENOSYS;}#endif /* NOT_USED_YET */struct inode_operations wrapfs_iops_symlink ={ create: wrapfs_create, lookup: wrapfs_lookup, link: wrapfs_link, unlink: wrapfs_unlink, symlink: wrapfs_symlink, mkdir: wrapfs_mkdir, rmdir: wrapfs_rmdir, mknod: wrapfs_mknod, rename: wrapfs_rename, readlink: wrapfs_readlink, follow_link: wrapfs_follow_link, // off because we have setattr // truncate: wrapfs_truncate, permission: wrapfs_permission, revalidate: wrapfs_inode_revalidate, setattr: wrapfs_setattr,#if 0 // XXX: off, b/c the VFS doesn't call getattr yet getattr: wrapfs_getattr,#endif};struct inode_operations wrapfs_iops ={ create: wrapfs_create, lookup: wrapfs_lookup, link: wrapfs_link, unlink: wrapfs_unlink, symlink: wrapfs_symlink, mkdir: wrapfs_mkdir, rmdir: wrapfs_rmdir, mknod: wrapfs_mknod, rename: wrapfs_rename, //readlink: wrapfs_readlink, //follow_link: wrapfs_follow_link, // off because we have setattr // truncate: wrapfs_truncate, permission: wrapfs_permission, revalidate: wrapfs_inode_revalidate, setattr: wrapfs_setattr,#if 0 // XXX: off, b/c the VFS doesn't call getattr yet getattr: wrapfs_getattr,#endif};/* * Local variables: * c-basic-offset: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -