📄 dir.c
字号:
for (n = 0; n <= npages; n++) { char *dir_end; page = ufs_get_page(dir, n); err = PTR_ERR(page); if (IS_ERR(page)) goto out; lock_page(page); kaddr = page_address(page); dir_end = kaddr + ufs_last_byte(dir, n); de = (struct ufs_dir_entry *)kaddr; kaddr += PAGE_CACHE_SIZE - reclen; while ((char *)de <= kaddr) { if ((char *)de == dir_end) { /* We hit i_size */ name_len = 0; rec_len = chunk_size; de->d_reclen = cpu_to_fs16(sb, chunk_size); de->d_ino = 0; goto got_it; } if (de->d_reclen == 0) { ufs_error(dir->i_sb, __func__, "zero-length directory entry"); err = -EIO; goto out_unlock; } err = -EEXIST; if (ufs_match(sb, namelen, name, de)) goto out_unlock; name_len = UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)); rec_len = fs16_to_cpu(sb, de->d_reclen); if (!de->d_ino && rec_len >= reclen) goto got_it; if (rec_len >= name_len + reclen) goto got_it; de = (struct ufs_dir_entry *) ((char *) de + rec_len); } unlock_page(page); ufs_put_page(page); } BUG(); return -EINVAL;got_it: pos = page_offset(page) + (char*)de - (char*)page_address(page); err = __ufs_write_begin(NULL, page->mapping, pos, rec_len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) goto out_unlock; if (de->d_ino) { struct ufs_dir_entry *de1 = (struct ufs_dir_entry *) ((char *) de + name_len); de1->d_reclen = cpu_to_fs16(sb, rec_len - name_len); de->d_reclen = cpu_to_fs16(sb, name_len); de = de1; } ufs_set_de_namlen(sb, de, namelen); memcpy(de->d_name, name, namelen + 1); de->d_ino = cpu_to_fs32(sb, inode->i_ino); ufs_set_de_type(sb, de, inode->i_mode); err = ufs_commit_chunk(page, pos, rec_len); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); /* OFFSET_CACHE */out_put: ufs_put_page(page);out: return err;out_unlock: unlock_page(page); goto out_put;}static inline unsignedufs_validate_entry(struct super_block *sb, char *base, unsigned offset, unsigned mask){ struct ufs_dir_entry *de = (struct ufs_dir_entry*)(base + offset); struct ufs_dir_entry *p = (struct ufs_dir_entry*)(base + (offset&mask)); while ((char*)p < (char*)de) { if (p->d_reclen == 0) break; p = ufs_next_entry(sb, p); } return (char *)p - base;}/* * This is blatantly stolen from ext2fs */static intufs_readdir(struct file *filp, void *dirent, filldir_t filldir){ loff_t pos = filp->f_pos; struct inode *inode = filp->f_path.dentry->d_inode; struct super_block *sb = inode->i_sb; unsigned int offset = pos & ~PAGE_CACHE_MASK; unsigned long n = pos >> PAGE_CACHE_SHIFT; unsigned long npages = ufs_dir_pages(inode); unsigned chunk_mask = ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); int need_revalidate = filp->f_version != inode->i_version; unsigned flags = UFS_SB(sb)->s_flags; UFSD("BEGIN\n"); if (pos > inode->i_size - UFS_DIR_REC_LEN(1)) return 0; for ( ; n < npages; n++, offset = 0) { char *kaddr, *limit; struct ufs_dir_entry *de; struct page *page = ufs_get_page(inode, n); if (IS_ERR(page)) { ufs_error(sb, __func__, "bad page in #%lu", inode->i_ino); filp->f_pos += PAGE_CACHE_SIZE - offset; return -EIO; } kaddr = page_address(page); if (unlikely(need_revalidate)) { if (offset) { offset = ufs_validate_entry(sb, kaddr, offset, chunk_mask); filp->f_pos = (n<<PAGE_CACHE_SHIFT) + offset; } filp->f_version = inode->i_version; need_revalidate = 0; } de = (struct ufs_dir_entry *)(kaddr+offset); limit = kaddr + ufs_last_byte(inode, n) - UFS_DIR_REC_LEN(1); for ( ;(char*)de <= limit; de = ufs_next_entry(sb, de)) { if (de->d_reclen == 0) { ufs_error(sb, __func__, "zero-length directory entry"); ufs_put_page(page); return -EIO; } if (de->d_ino) { int over; unsigned char d_type = DT_UNKNOWN; offset = (char *)de - kaddr; UFSD("filldir(%s,%u)\n", de->d_name, fs32_to_cpu(sb, de->d_ino)); UFSD("namlen %u\n", ufs_get_de_namlen(sb, de)); if ((flags & UFS_DE_MASK) == UFS_DE_44BSD) d_type = de->d_u.d_44.d_type; over = filldir(dirent, de->d_name, ufs_get_de_namlen(sb, de), (n<<PAGE_CACHE_SHIFT) | offset, fs32_to_cpu(sb, de->d_ino), d_type); if (over) { ufs_put_page(page); return 0; } } filp->f_pos += fs16_to_cpu(sb, de->d_reclen); } ufs_put_page(page); } return 0;}/* * ufs_delete_entry deletes a directory entry by merging it with the * previous entry. */int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, struct page * page){ struct super_block *sb = inode->i_sb; struct address_space *mapping = page->mapping; char *kaddr = page_address(page); unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen); loff_t pos; struct ufs_dir_entry *pde = NULL; struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from); int err; UFSD("ENTER\n"); UFSD("ino %u, reclen %u, namlen %u, name %s\n", fs32_to_cpu(sb, de->d_ino), fs16_to_cpu(sb, de->d_reclen), ufs_get_de_namlen(sb, de), de->d_name); while ((char*)de < (char*)dir) { if (de->d_reclen == 0) { ufs_error(inode->i_sb, __func__, "zero-length directory entry"); err = -EIO; goto out; } pde = de; de = ufs_next_entry(sb, de); } if (pde) from = (char*)pde - (char*)page_address(page); pos = page_offset(page) + from; lock_page(page); err = __ufs_write_begin(NULL, mapping, pos, to - from, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); BUG_ON(err); if (pde) pde->d_reclen = cpu_to_fs16(sb, to - from); dir->d_ino = 0; err = ufs_commit_chunk(page, pos, to - from); inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(inode);out: ufs_put_page(page); UFSD("EXIT\n"); return err;}int ufs_make_empty(struct inode * inode, struct inode *dir){ struct super_block * sb = dir->i_sb; struct address_space *mapping = inode->i_mapping; struct page *page = grab_cache_page(mapping, 0); const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize; struct ufs_dir_entry * de; char *base; int err; if (!page) return -ENOMEM; err = __ufs_write_begin(NULL, mapping, 0, chunk_size, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); if (err) { unlock_page(page); goto fail; } kmap(page); base = (char*)page_address(page); memset(base, 0, PAGE_CACHE_SIZE); de = (struct ufs_dir_entry *) base; de->d_ino = cpu_to_fs32(sb, inode->i_ino); ufs_set_de_type(sb, de, inode->i_mode); ufs_set_de_namlen(sb, de, 1); de->d_reclen = cpu_to_fs16(sb, UFS_DIR_REC_LEN(1)); strcpy (de->d_name, "."); de = (struct ufs_dir_entry *) ((char *)de + fs16_to_cpu(sb, de->d_reclen)); de->d_ino = cpu_to_fs32(sb, dir->i_ino); ufs_set_de_type(sb, de, dir->i_mode); de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1)); ufs_set_de_namlen(sb, de, 2); strcpy (de->d_name, ".."); kunmap(page); err = ufs_commit_chunk(page, 0, chunk_size);fail: page_cache_release(page); return err;}/* * routine to check that the specified directory is empty (for rmdir) */int ufs_empty_dir(struct inode * inode){ struct super_block *sb = inode->i_sb; struct page *page = NULL; unsigned long i, npages = ufs_dir_pages(inode); for (i = 0; i < npages; i++) { char *kaddr; struct ufs_dir_entry *de; page = ufs_get_page(inode, i); if (IS_ERR(page)) continue; kaddr = page_address(page); de = (struct ufs_dir_entry *)kaddr; kaddr += ufs_last_byte(inode, i) - UFS_DIR_REC_LEN(1); while ((char *)de <= kaddr) { if (de->d_reclen == 0) { ufs_error(inode->i_sb, __func__, "zero-length directory entry: " "kaddr=%p, de=%p\n", kaddr, de); goto not_empty; } if (de->d_ino) { u16 namelen=ufs_get_de_namlen(sb, de); /* check for . and .. */ if (de->d_name[0] != '.') goto not_empty; if (namelen > 2) goto not_empty; if (namelen < 2) { if (inode->i_ino != fs32_to_cpu(sb, de->d_ino)) goto not_empty; } else if (de->d_name[1] != '.') goto not_empty; } de = ufs_next_entry(sb, de); } ufs_put_page(page); } return 1;not_empty: ufs_put_page(page); return 0;}const struct file_operations ufs_dir_operations = { .read = generic_read_dir, .readdir = ufs_readdir, .fsync = file_fsync, .llseek = generic_file_llseek,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -