Import 2.3.30pre7
[davej-history.git] / fs / affs / dir.c
blobf126dcbb80308f75761a49e194e59a6b288b0db1
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);
28 static ssize_t affs_dir_read(struct file *, char *, size_t, loff_t *);
30 static struct file_operations affs_dir_operations = {
31 NULL, /* lseek - default */
32 affs_dir_read, /* read */
33 NULL, /* write - bad */
34 affs_readdir, /* readdir */
35 NULL, /* poll - default */
36 NULL, /* ioctl - default */
37 NULL, /* mmap */
38 NULL, /* no special open code */
39 NULL, /* flush */
40 NULL, /* no special release code */
41 file_fsync /* default fsync */
45 * directories can handle most operations...
47 struct inode_operations affs_dir_inode_operations = {
48 &affs_dir_operations, /* default directory file-ops */
49 affs_create, /* create */
50 affs_lookup, /* lookup */
51 affs_link, /* link */
52 affs_unlink, /* unlink */
53 affs_symlink, /* symlink */
54 affs_mkdir, /* mkdir */
55 affs_rmdir, /* rmdir */
56 NULL, /* mknod */
57 affs_rename, /* rename */
58 NULL, /* readlink */
59 NULL, /* follow_link */
60 NULL, /* get_block */
61 NULL, /* readpage */
62 NULL, /* writepage */
63 NULL, /* truncate */
64 NULL, /* permissions */
65 NULL /* revalidate */
68 static ssize_t
69 affs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
71 return -EISDIR;
74 static int
75 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
77 int j, namelen;
78 s32 i;
79 int hash_pos;
80 int chain_pos;
81 unsigned long ino;
82 int stored;
83 unsigned char *name;
84 struct buffer_head *dir_bh;
85 struct buffer_head *fh_bh;
86 struct inode *dir;
87 struct inode *inode = filp->f_dentry->d_inode;
89 pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
91 stored = 0;
92 dir_bh = NULL;
93 fh_bh = NULL;
94 dir = NULL;
95 ino = inode->i_ino;
97 if (filp->f_pos == 0) {
98 filp->private_data = (void *)0;
99 if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
100 return 0;
102 ++filp->f_pos;
103 stored++;
105 if (filp->f_pos == 1) {
106 if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
107 return stored;
109 filp->f_pos = 2;
110 stored++;
112 chain_pos = (filp->f_pos - 2) & 0xffff;
113 hash_pos = (filp->f_pos - 2) >> 16;
114 if (chain_pos == 0xffff) {
115 affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
116 chain_pos = 0;
117 hash_pos++;
118 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
120 if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
121 AFFS_I2BSIZE(inode))))
122 goto readdir_done;
124 while (1) {
125 while (hash_pos < AFFS_I2HSIZE(inode) &&
126 !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
127 hash_pos++;
128 if (hash_pos >= AFFS_I2HSIZE(inode))
129 break;
131 i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
132 j = chain_pos;
134 /* If the directory hasn't changed since the last call to readdir(),
135 * we can jump directly to where we left off.
137 if (filp->private_data && filp->f_version == inode->i_version) {
138 i = (s32)filp->private_data;
139 j = 0;
140 pr_debug("AFFS: readdir() left off=%d\n",i);
142 filp->f_version = inode->i_version;
143 pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
144 while (i) {
145 if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
146 affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
147 goto readdir_done;
149 ino = i;
150 i = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
151 if (j == 0)
152 break;
153 affs_brelse(fh_bh);
154 fh_bh = NULL;
155 j--;
157 if (fh_bh) {
158 namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
159 pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
160 namelen,name,ino,i);
161 filp->private_data = (void *)ino;
162 if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
163 goto readdir_done;
164 filp->private_data = (void *)i;
165 affs_brelse(fh_bh);
166 fh_bh = NULL;
167 stored++;
169 if (i == 0) {
170 hash_pos++;
171 chain_pos = 0;
172 } else
173 chain_pos++;
174 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
177 readdir_done:
178 affs_brelse(dir_bh);
179 affs_brelse(fh_bh);
180 pr_debug("AFFS: readdir()=%d\n",stored);
181 return stored;