-static inline unsigned
-ufs_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 int
-ufs_readdir(struct file *filp, void *dirent, filldir_t filldir)
-{
- loff_t pos = filp->f_pos;
- struct inode *inode = filp->f_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_SECTOR_SIZE - 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, __FUNCTION__,
- "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, __FUNCTION__,
- "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);
- }