Import 2.1.118
[davej-history.git] / fs / affs / dir.c
blob51e45b682be0f39cec3680b9ea875dd760b2ce39
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, /* readpage */
61 NULL, /* writepage */
62 NULL, /* bmap */
63 NULL, /* truncate */
64 NULL, /* permissions */
65 NULL, /* smap */
66 NULL, /* updatepage */
67 NULL /* revalidate */
70 static ssize_t
71 affs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
73 return -EISDIR;
76 static int
77 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
79 int j, namelen;
80 s32 i;
81 int hash_pos;
82 int chain_pos;
83 unsigned long ino;
84 int stored;
85 unsigned char *name;
86 struct buffer_head *dir_bh;
87 struct buffer_head *fh_bh;
88 struct inode *dir;
89 struct inode *inode = filp->f_dentry->d_inode;
91 pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
93 if (!inode || !S_ISDIR(inode->i_mode))
94 return -EBADF;
96 stored = 0;
97 dir_bh = NULL;
98 fh_bh = NULL;
99 dir = NULL;
100 ino = inode->i_ino;
102 if (filp->f_pos == 0) {
103 filp->private_data = (void *)0;
104 if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
105 return 0;
107 ++filp->f_pos;
108 stored++;
110 if (filp->f_pos == 1) {
111 if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
112 return stored;
114 filp->f_pos = 2;
115 stored++;
117 chain_pos = (filp->f_pos - 2) & 0xffff;
118 hash_pos = (filp->f_pos - 2) >> 16;
119 if (chain_pos == 0xffff) {
120 affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
121 chain_pos = 0;
122 hash_pos++;
123 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
125 if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
126 AFFS_I2BSIZE(inode))))
127 goto readdir_done;
129 while (1) {
130 while (hash_pos < AFFS_I2HSIZE(inode) &&
131 !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
132 hash_pos++;
133 if (hash_pos >= AFFS_I2HSIZE(inode))
134 break;
136 i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
137 j = chain_pos;
139 /* If the directory hasn't changed since the last call to readdir(),
140 * we can jump directly to where we left off.
142 if (filp->private_data && filp->f_version == inode->i_version) {
143 i = (s32)filp->private_data;
144 j = 0;
145 pr_debug("AFFS: readdir() left off=%d\n",i);
147 filp->f_version = inode->i_version;
148 pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
149 while (i) {
150 if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
151 affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
152 goto readdir_done;
154 ino = i;
155 i = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
156 if (j == 0)
157 break;
158 affs_brelse(fh_bh);
159 fh_bh = NULL;
160 j--;
162 if (fh_bh) {
163 namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
164 pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
165 namelen,name,ino,i);
166 filp->private_data = (void *)ino;
167 if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
168 goto readdir_done;
169 filp->private_data = (void *)i;
170 affs_brelse(fh_bh);
171 fh_bh = NULL;
172 stored++;
174 if (i == 0) {
175 hash_pos++;
176 chain_pos = 0;
177 } else
178 chain_pos++;
179 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
182 readdir_done:
183 affs_brelse(dir_bh);
184 affs_brelse(fh_bh);
185 pr_debug("AFFS: readdir()=%d\n",stored);
186 return stored;