cleanup
[linux-2.4.git] / fs / affs / dir.c
1 /*
2  *  linux/fs/affs/dir.c
3  *
4  *  (c) 1996  Hans-Joachim Widmaier - Rewritten
5  *
6  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
7  *
8  *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
9  *
10  *  (C) 1991  Linus Torvalds - minix filesystem
11  *
12  *  affs directory handling functions
13  *
14  */
15
16 #include <asm/uaccess.h>
17 #include <linux/errno.h>
18 #include <linux/fs.h>
19 #include <linux/kernel.h>
20 #include <linux/affs_fs.h>
21 #include <linux/stat.h>
22 #include <linux/string.h>
23 #include <linux/mm.h>
24 #include <linux/amigaffs.h>
25
26 static int affs_readdir(struct file *, void *, filldir_t);
27
28 struct file_operations affs_dir_operations = {
29         read:           generic_read_dir,
30         readdir:        affs_readdir,
31         fsync:          file_fsync,
32 };
33
34 /*
35  * directories can handle most operations...
36  */
37 struct inode_operations affs_dir_inode_operations = {
38         create:         affs_create,
39         lookup:         affs_lookup,
40         link:           affs_link,
41         unlink:         affs_unlink,
42         symlink:        affs_symlink,
43         mkdir:          affs_mkdir,
44         rmdir:          affs_rmdir,
45         rename:         affs_rename,
46         setattr:        affs_notify_change,
47 };
48
49 static int
50 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
51 {
52         struct inode            *inode = filp->f_dentry->d_inode;
53         struct super_block      *sb = inode->i_sb;
54         struct buffer_head      *dir_bh;
55         struct buffer_head      *fh_bh;
56         unsigned char           *name;
57         int                      namelen;
58         u32                      i;
59         int                      hash_pos;
60         int                      chain_pos;
61         u32                      f_pos;
62         u32                      ino;
63         int                      stored;
64         int                      res;
65
66         pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
67
68         stored = 0;
69         res    = -EIO;
70         dir_bh = NULL;
71         fh_bh  = NULL;
72         f_pos  = filp->f_pos;
73
74         if (f_pos == 0) {
75                 filp->private_data = (void *)0;
76                 if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0)
77                         return 0;
78                 filp->f_pos = f_pos = 1;
79                 stored++;
80         }
81         if (f_pos == 1) {
82                 if (filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
83                         return stored;
84                 filp->f_pos = f_pos = 2;
85                 stored++;
86         }
87
88         affs_lock_dir(inode);
89         chain_pos = (f_pos - 2) & 0xffff;
90         hash_pos  = (f_pos - 2) >> 16;
91         if (chain_pos == 0xffff) {
92                 affs_warning(sb, "readdir", "More than 65535 entries in chain");
93                 chain_pos = 0;
94                 hash_pos++;
95                 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
96         }
97         dir_bh = affs_bread(sb, inode->i_ino);
98         if (!dir_bh)
99                 goto readdir_out;
100
101         /* If the directory hasn't changed since the last call to readdir(),
102          * we can jump directly to where we left off.
103          */
104         ino = (u32)(long)filp->private_data;
105         if (ino && filp->f_version == inode->i_version) {
106                 pr_debug("AFFS: readdir() left off=%d\n", ino);
107                 goto inside;
108         }
109
110         ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
111         for (i = 0; ino && i < chain_pos; i++) {
112                 fh_bh = affs_bread(sb, ino);
113                 if (!fh_bh) {
114                         affs_error(sb, "readdir","Cannot read block %d", i);
115                         goto readdir_out;
116                 }
117                 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
118                 affs_brelse(fh_bh);
119                 fh_bh = NULL;
120         }
121         if (ino)
122                 goto inside;
123         hash_pos++;
124
125         for (; hash_pos < AFFS_SB->s_hashsize; hash_pos++) {
126                 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
127                 if (!ino)
128                         continue;
129                 f_pos = (hash_pos << 16) + 2;
130 inside:
131                 do {
132                         fh_bh = affs_bread(sb, ino);
133                         if (!fh_bh) {
134                                 affs_error(sb, "readdir","Cannot read block %d", ino);
135                                 goto readdir_done;
136                         }
137
138                         namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
139                         name = AFFS_TAIL(sb, fh_bh)->name + 1;
140                         pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
141                                  namelen, name, ino, hash_pos, f_pos);
142                         if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
143                                 goto readdir_done;
144                         stored++;
145                         f_pos++;
146                         ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
147                         affs_brelse(fh_bh);
148                         fh_bh = NULL;
149                 } while (ino);
150         }
151 readdir_done:
152         filp->f_pos = f_pos;
153         filp->f_version = inode->i_version;
154         filp->private_data = (void *)(long)ino;
155         res = stored;
156
157 readdir_out:
158         affs_brelse(dir_bh);
159         affs_brelse(fh_bh);
160         affs_unlock_dir(inode);
161         pr_debug("AFFS: readdir()=%d\n", stored);
162         return res;
163 }