Import 2.4.0-test2pre6
[davej-history.git] / fs / affs / dir.c
blob3fc8409b0bd9b319ec7ddfb3ce4e0ad40bd24771
1 /*
2 * linux/fs/affs/dir.c
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
8 * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
10 * (C) 1991 Linus Torvalds - minix filesystem
12 * affs directory handling functions
16 #define DEBUG 0
17 #include <asm/uaccess.h>
18 #include <linux/errno.h>
19 #include <linux/fs.h>
20 #include <linux/kernel.h>
21 #include <linux/affs_fs.h>
22 #include <linux/stat.h>
23 #include <linux/string.h>
24 #include <linux/mm.h>
25 #include <linux/amigaffs.h>
27 static int affs_readdir(struct file *, void *, filldir_t);
29 struct file_operations affs_dir_operations = {
30 read: generic_read_dir,
31 readdir: affs_readdir,
32 fsync: file_fsync,
36 * directories can handle most operations...
38 struct inode_operations affs_dir_inode_operations = {
39 create: affs_create,
40 lookup: affs_lookup,
41 link: affs_link,
42 unlink: affs_unlink,
43 symlink: affs_symlink,
44 mkdir: affs_mkdir,
45 rmdir: affs_rmdir,
46 rename: affs_rename,
47 setattr: affs_notify_change,
50 static int
51 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
53 int j, namelen;
54 s32 i;
55 int hash_pos;
56 int chain_pos;
57 unsigned long ino;
58 int stored;
59 unsigned char *name;
60 struct buffer_head *dir_bh;
61 struct buffer_head *fh_bh;
62 struct inode *dir;
63 struct inode *inode = filp->f_dentry->d_inode;
65 pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
67 stored = 0;
68 dir_bh = NULL;
69 fh_bh = NULL;
70 dir = NULL;
71 ino = inode->i_ino;
73 if (filp->f_pos == 0) {
74 filp->private_data = (void *)0;
75 if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
76 return 0;
78 ++filp->f_pos;
79 stored++;
81 if (filp->f_pos == 1) {
82 if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
83 return stored;
85 filp->f_pos = 2;
86 stored++;
88 chain_pos = (filp->f_pos - 2) & 0xffff;
89 hash_pos = (filp->f_pos - 2) >> 16;
90 if (chain_pos == 0xffff) {
91 affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
92 chain_pos = 0;
93 hash_pos++;
94 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
96 if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
97 AFFS_I2BSIZE(inode))))
98 goto readdir_done;
100 while (1) {
101 while (hash_pos < AFFS_I2HSIZE(inode) &&
102 !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
103 hash_pos++;
104 if (hash_pos >= AFFS_I2HSIZE(inode))
105 break;
107 i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
108 j = chain_pos;
110 /* If the directory hasn't changed since the last call to readdir(),
111 * we can jump directly to where we left off.
113 if (filp->private_data && filp->f_version == inode->i_version) {
114 i = (s32)filp->private_data;
115 j = 0;
116 pr_debug("AFFS: readdir() left off=%d\n",i);
118 filp->f_version = inode->i_version;
119 pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
120 while (i) {
121 if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
122 affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
123 goto readdir_done;
125 ino = i;
126 i = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
127 if (j == 0)
128 break;
129 affs_brelse(fh_bh);
130 fh_bh = NULL;
131 j--;
133 if (fh_bh) {
134 namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
135 pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
136 namelen,name,ino,i);
137 filp->private_data = (void *)ino;
138 if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
139 goto readdir_done;
140 filp->private_data = (void *)i;
141 affs_brelse(fh_bh);
142 fh_bh = NULL;
143 stored++;
145 if (i == 0) {
146 hash_pos++;
147 chain_pos = 0;
148 } else
149 chain_pos++;
150 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
153 readdir_done:
154 affs_brelse(dir_bh);
155 affs_brelse(fh_bh);
156 pr_debug("AFFS: readdir()=%d\n",stored);
157 return stored;