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
affs_readdir(struct file * filp,void * dirent,filldir_t filldir)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 }
164