static int ext2_readdir (struct inode * inode, struct file * filp, struct dirent * dirent, int count) { unsigned long offset, blk; int i, num; struct buffer_head * bh, * tmp, * bha[16]; struct ext2_dir_entry * de; struct super_block * sb; int err; if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; sb = inode->i_sb; while (filp->f_pos < inode->i_size) { offset = filp->f_pos & (sb->s_blocksize - 1); blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb); bh = ext2_bread (inode, blk, 0, &err); if (!bh) { filp->f_pos += sb->s_blocksize - offset; continue; } /* * Do the readahead */ if (!offset) { for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0; i > 0; i--) { tmp = ext2_getblk (inode, ++blk, 0, &err); if (tmp && !tmp->b_uptodate && !tmp->b_lock) bha[num++] = tmp; else brelse (tmp); } if (num) { ll_rw_block (READA, num, bha); for (i = 0; i < num; i++) brelse (bha[i]); } } de = (struct ext2_dir_entry *) (offset + bh->b_data); while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) { if (!ext2_check_dir_entry ("ext2_readdir", inode, de, bh, offset)) { brelse (bh); return 0; } offset += de->rec_len; filp->f_pos += de->rec_len; if (de->inode) { memcpy_tofs (dirent->d_name, de->name, de->name_len); put_fs_long (de->inode, &dirent->d_ino); put_fs_byte (0, de->name_len + dirent->d_name); put_fs_word (de->name_len, &dirent->d_reclen); dcache_add(inode, de->name, de->name_len, de->inode); i = de->name_len; brelse (bh); if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; } return i; } de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); } brelse (bh); } if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; } return 0; }
static int ext2_readdir (struct inode * inode, struct file * filp, struct dirent * dirent, int count) { unsigned long offset, blk; int i, num, stored, dlen; struct buffer_head * bh, * tmp, * bha[16]; struct ext2_dir_entry * de; struct super_block * sb; int err, version; if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; sb = inode->i_sb; stored = 0; bh = NULL; offset = filp->f_pos & (sb->s_blocksize - 1); while (count > 0 && !stored && filp->f_pos < inode->i_size) { blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb); bh = ext2_bread (inode, blk, 0, &err); if (!bh) { filp->f_pos += sb->s_blocksize - offset; continue; } /* * Do the readahead */ if (!offset) { for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0; i > 0; i--) { tmp = ext2_getblk (inode, ++blk, 0, &err); if (tmp && !tmp->b_uptodate && !tmp->b_lock) bha[num++] = tmp; else brelse (tmp); } if (num) { ll_rw_block (READA, num, bha); for (i = 0; i < num; i++) brelse (bha[i]); } } revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { de = (struct ext2_dir_entry *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ if (de->rec_len < EXT2_DIR_REC_LEN(1)) break; i += de->rec_len; } offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset; filp->f_version = inode->i_version; } while (count > 0 && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext2_dir_entry *) (bh->b_data + offset); if (!ext2_check_dir_entry ("ext2_readdir", inode, de, bh, offset)) { /* On error, skip the f_pos to the next block. */ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse (bh); return stored; } if (de->inode) { dlen = ROUND_UP(NAME_OFFSET(dirent) + de->name_len + 1); /* Old libc libraries always use a count of 1. */ if (count == 1 && !stored) count = dlen; if (count < dlen) { count = 0; break; } /* We might block in the next section * if the data destination is * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ version = inode->i_version; i = de->name_len; memcpy_tofs (dirent->d_name, de->name, i); put_fs_long (de->inode, &dirent->d_ino); put_fs_byte (0, dirent->d_name + i); put_fs_word (i, &dirent->d_reclen); put_fs_long (dlen, &dirent->d_off); if (version != inode->i_version) goto revalidate; dcache_add(inode, de->name, de->name_len, de->inode); stored += dlen; count -= dlen; ((char *) dirent) += dlen; } offset += de->rec_len; filp->f_pos += de->rec_len; } offset = 0; brelse (bh); } if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; } return stored; }
static int ext2_readdir(struct file * filp, void * dirent, filldir_t filldir) { int error = 0; unsigned long offset, blk; int i, num, stored; struct buffer_head * bh, * tmp, * bha[16]; struct ext2_dir_entry_2 * de; struct super_block * sb; int err; struct inode *inode = filp->f_dentry->d_inode; if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; sb = inode->i_sb; stored = 0; bh = NULL; offset = filp->f_pos & (sb->s_blocksize - 1); while (!error && !stored && filp->f_pos < inode->i_size) { blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb); bh = ext2_bread (inode, blk, 0, &err); if (!bh) { ext2_error (sb, "ext2_readdir", "directory #%lu contains a hole at offset %lu", inode->i_ino, (unsigned long)filp->f_pos); filp->f_pos += sb->s_blocksize - offset; continue; } /* * Do the readahead */ if (!offset) { for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0; i > 0; i--) { tmp = ext2_getblk (inode, ++blk, 0, &err); if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) bha[num++] = tmp; else brelse (tmp); } if (num) { ll_rw_block (READA, num, bha); for (i = 0; i < num; i++) brelse (bha[i]); } } revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { de = (struct ext2_dir_entry_2 *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1)) break; i += le16_to_cpu(de->rec_len); } offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset; filp->f_version = inode->i_version; } while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ext2_dir_entry_2 *) (bh->b_data + offset); if (!ext2_check_dir_entry ("ext2_readdir", inode, de, bh, offset)) { /* On error, skip the f_pos to the next block. */ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse (bh); return stored; } offset += le16_to_cpu(de->rec_len); if (le32_to_cpu(de->inode)) { /* We might block in the next section * if the data destination is * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ unsigned long version = inode->i_version; error = filldir(dirent, de->name, de->name_len, filp->f_pos, le32_to_cpu(de->inode)); if (error) break; if (version != inode->i_version) goto revalidate; stored ++; } filp->f_pos += le16_to_cpu(de->rec_len); } offset = 0; brelse (bh); } UPDATE_ATIME(inode); return 0; }
/* * This is blatantly stolen from ext2fs */ static int ufs_readdir (struct inode * inode, struct file * filp, void * dirent, filldir_t filldir) { int error = 0; unsigned long offset, lblk, blk; int i, stored; struct buffer_head * bh; struct ufs_direct * de; struct super_block * sb; if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; sb = inode->i_sb; if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_readdir: ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos); ufs_print_inode(inode); } stored = 0; bh = NULL; offset = filp->f_pos & (sb->s_blocksize - 1); while (!error && !stored && filp->f_pos < inode->i_size) { lblk = (filp->f_pos) >> sb->s_blocksize_bits; blk = ufs_bmap(inode, lblk); /* XXX - ufs_bmap() call needs error checking */ blk = ufs_bmap(inode, lblk); bh = bread (sb->s_dev, blk, sb->s_blocksize); if (!bh) { /* XXX - error - skip to the next block */ printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n", inode->i_ino, (unsigned long int)filp->f_pos); filp->f_pos += sb->s_blocksize - offset; continue; } revalidate: /* If the dir block has changed since the last call to * readdir(2), then we might be pointing to an invalid * dirent right now. Scan from the start of the block * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { de = (struct ufs_direct *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this * loop, but we do have to test at * least that it is non-zero. A * failure will be detected in the * dirent test below. */ if (de->d_reclen < 1) break; i += de->d_reclen; } offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset; filp->f_version = inode->i_version; } while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ufs_direct *) (bh->b_data + offset); /* XXX - put in a real ufs_check_dir_entry() */ if ((de->d_reclen == 0) || (de->d_namlen == 0)) { filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse(bh); return stored; } #if 0 if (!ext2_check_dir_entry ("ext2_readdir", inode, de, bh, offset)) { /* On error, skip the f_pos to the next block. */ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse (bh); return stored; } #endif /* XXX */ offset += de->d_reclen; if (de->d_ino) { /* We might block in the next section * if the data destination is * currently swapped out. So, use a * version stamp to detect whether or * not the directory has been modified * during the copy operation. */ unsigned long version; dcache_add(inode, de->d_name, de->d_namlen, de->d_ino); version = inode->i_version; if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_readdir: filldir(%s,%u)\n", de->d_name, de->d_ino); } error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino); if (error) break; if (version != inode->i_version) goto revalidate; stored ++; } filp->f_pos += de->d_reclen; } offset = 0; brelse (bh); } #if 0 /* XXX */ if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; } #endif /* XXX */ return 0; }