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