1 /*
2  * dir.c
3  *
4  * Copyright (c) 1999 Al Smith
5  */
6 
7 #include <linux/efs_fs.h>
8 
9 static int efs_readdir(struct file *, void *, filldir_t);
10 
11 struct file_operations efs_dir_operations = {
12 	read:		generic_read_dir,
13 	readdir:	efs_readdir,
14 };
15 
16 struct inode_operations efs_dir_inode_operations = {
17 	lookup:		efs_lookup,
18 };
19 
efs_readdir(struct file * filp,void * dirent,filldir_t filldir)20 static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
21 	struct inode *inode = filp->f_dentry->d_inode;
22 	struct buffer_head *bh;
23 
24 	struct efs_dir		*dirblock;
25 	struct efs_dentry	*dirslot;
26 	efs_ino_t		inodenum;
27 	efs_block_t		block;
28 	int			slot, namelen;
29 	char			*nameptr;
30 
31 	if (inode->i_size & (EFS_DIRBSIZE-1))
32 		printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n");
33 
34 	/* work out where this entry can be found */
35 	block = filp->f_pos >> EFS_DIRBSIZE_BITS;
36 
37 	/* each block contains at most 256 slots */
38 	slot  = filp->f_pos & 0xff;
39 
40 	/* look at all blocks */
41 	while (block < inode->i_blocks) {
42 		/* read the dir block */
43 		bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
44 
45 		if (!bh) {
46 			printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block);
47 			break;
48 		}
49 
50 		dirblock = (struct efs_dir *) bh->b_data;
51 
52 		if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
53 			printk(KERN_ERR "EFS: readdir(): invalid directory block\n");
54 			brelse(bh);
55 			break;
56 		}
57 
58 		while (slot < dirblock->slots) {
59 			if (dirblock->space[slot] == 0) {
60 				slot++;
61 				continue;
62 			}
63 
64 			dirslot  = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
65 
66 			inodenum = be32_to_cpu(dirslot->inode);
67 			namelen  = dirslot->namelen;
68 			nameptr  = dirslot->name;
69 
70 #ifdef DEBUG
71 			printk(KERN_DEBUG "EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots-1, inodenum, nameptr, namelen);
72 #endif
73 			if (namelen > 0) {
74 				/* found the next entry */
75 				filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
76 
77 				/* copy filename and data in dirslot */
78 				filldir(dirent, nameptr, namelen, filp->f_pos, inodenum, DT_UNKNOWN);
79 
80 				/* sanity check */
81 				if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
82 					printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot);
83 					slot++;
84 					continue;
85 				}
86 
87 				/* store position of next slot */
88 				if (++slot == dirblock->slots) {
89 					slot = 0;
90 					block++;
91 				}
92 				brelse(bh);
93 				filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
94 				return 0;
95 			}
96 			slot++;
97 		}
98 		brelse(bh);
99 
100 		slot = 0;
101 		block++;
102 	}
103 
104 	filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot;
105 	return 0;
106 }
107 
108