2 * linux/fs/affs/namei.c
4 * (c) 1996 Hans-Joachim Widmaier - Rewritten
6 * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
8 * (C) 1991 Linus Torvalds - minix filesystem
11 #include <linux/time.h>
12 #include <linux/affs_fs.h>
13 #include <linux/kernel.h>
14 #include <linux/string.h>
15 #include <linux/stat.h>
16 #include <linux/fcntl.h>
17 #include <linux/amigaffs.h>
18 #include <linux/smp_lock.h>
19 #include <linux/buffer_head.h>
20 #include <asm/uaccess.h>
22 #include <linux/errno.h>
24 typedef int (*toupper_t)(int);
26 extern struct inode_operations affs_symlink_inode_operations;
28 static int affs_toupper(int ch);
29 static int affs_hash_dentry(struct dentry *, struct qstr *);
30 static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
31 static int affs_intl_toupper(int ch);
32 static int affs_intl_hash_dentry(struct dentry *, struct qstr *);
33 static int affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
35 struct dentry_operations affs_dentry_operations = {
36 .d_hash = affs_hash_dentry,
37 .d_compare = affs_compare_dentry,
40 struct dentry_operations affs_intl_dentry_operations = {
41 .d_hash = affs_intl_hash_dentry,
42 .d_compare = affs_intl_compare_dentry,
46 /* Simple toupper() for DOS\1 */
51 return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
54 /* International toupper() for DOS\3 ("international") */
57 affs_intl_toupper(int ch)
59 return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
60 && ch <= 0xFE && ch != 0xF7) ?
61 ch - ('a' - 'A') : ch;
64 static inline toupper_t
65 affs_get_toupper(struct super_block *sb)
67 return AFFS_SB(sb)->s_flags & SF_INTL ? affs_intl_toupper : affs_toupper;
71 * Note: the dentry argument is the parent dentry.
74 __affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper)
76 const u8 *name = qstr->name;
80 i = affs_check_name(qstr->name,qstr->len);
84 hash = init_name_hash();
85 i = min(qstr->len, 30u);
86 for (; i > 0; name++, i--)
87 hash = partial_name_hash(toupper(*name), hash);
88 qstr->hash = end_name_hash(hash);
94 affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
96 return __affs_hash_dentry(dentry, qstr, affs_toupper);
99 affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr)
101 return __affs_hash_dentry(dentry, qstr, affs_intl_toupper);
105 __affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper)
107 const u8 *aname = a->name;
108 const u8 *bname = b->name;
111 /* 'a' is the qstr of an already existing dentry, so the name
112 * must be valid. 'b' must be validated first.
115 if (affs_check_name(b->name,b->len))
118 /* If the names are longer than the allowed 30 chars,
119 * the excess is ignored, so their length may differ.
126 } else if (len != b->len)
129 for (; len > 0; len--)
130 if (toupper(*aname++) != toupper(*bname++))
137 affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
139 return __affs_compare_dentry(dentry, a, b, affs_toupper);
142 affs_intl_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
144 return __affs_compare_dentry(dentry, a, b, affs_intl_toupper);
148 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
152 affs_match(struct dentry *dentry, const u8 *name2, toupper_t toupper)
154 const u8 *name = dentry->d_name.name;
155 int len = dentry->d_name.len;
161 } else if (len != *name2)
164 for (name2++; len > 0; len--)
165 if (toupper(*name++) != toupper(*name2++))
171 affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len)
173 toupper_t toupper = affs_get_toupper(sb);
176 hash = len = min(len, 30u);
177 for (; len > 0; len--)
178 hash = (hash * 13 + toupper(*name++)) & 0x7ff;
180 return hash % AFFS_SB(sb)->s_hashsize;
183 static struct buffer_head *
184 affs_find_entry(struct inode *dir, struct dentry *dentry)
186 struct super_block *sb = dir->i_sb;
187 struct buffer_head *bh;
188 toupper_t toupper = affs_get_toupper(sb);
191 pr_debug("AFFS: find_entry(\"%.*s\")\n", (int)dentry->d_name.len, dentry->d_name.name);
193 bh = affs_bread(sb, dir->i_ino);
195 return ERR_PTR(-EIO);
197 key = be32_to_cpu(AFFS_HEAD(bh)->table[affs_hash_name(sb, dentry->d_name.name, dentry->d_name.len)]);
203 bh = affs_bread(sb, key);
205 return ERR_PTR(-EIO);
206 if (affs_match(dentry, AFFS_TAIL(sb, bh)->name, toupper))
208 key = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
213 affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
215 struct super_block *sb = dir->i_sb;
216 struct buffer_head *bh;
217 struct inode *inode = NULL;
219 pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
222 bh = affs_find_entry(dir, dentry);
223 affs_unlock_dir(dir);
225 return ERR_PTR(PTR_ERR(bh));
228 u32 ino = bh->b_blocknr;
230 /* store the real header ino in d_fsdata for faster lookups */
231 dentry->d_fsdata = (void *)(long)ino;
232 switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
233 //link to dirs disabled
236 ino = be32_to_cpu(AFFS_TAIL(sb, bh)->original);
239 inode = iget(sb, ino);
241 return ERR_PTR(-EACCES);
244 dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations;
245 d_add(dentry, inode);
250 affs_unlink(struct inode *dir, struct dentry *dentry)
252 pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
253 (int)dentry->d_name.len, dentry->d_name.name);
255 return affs_remove_header(dentry);
259 affs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
261 struct super_block *sb = dir->i_sb;
265 pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
266 dentry->d_name.name,mode);
268 inode = affs_new_inode(dir);
272 inode->i_mode = mode;
274 mark_inode_dirty(inode);
276 inode->i_op = &affs_file_inode_operations;
277 inode->i_fop = &affs_file_operations;
278 inode->i_mapping->a_ops = (AFFS_SB(sb)->s_flags & SF_OFS) ? &affs_aops_ofs : &affs_aops;
279 error = affs_add_entry(dir, inode, dentry, ST_FILE);
289 affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
294 pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
295 (int)dentry->d_name.len,dentry->d_name.name,mode);
297 inode = affs_new_inode(dir);
301 inode->i_mode = S_IFDIR | mode;
304 inode->i_op = &affs_dir_inode_operations;
305 inode->i_fop = &affs_dir_operations;
307 error = affs_add_entry(dir, inode, dentry, ST_USERDIR);
310 mark_inode_dirty(inode);
318 affs_rmdir(struct inode *dir, struct dentry *dentry)
320 pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino,
321 (int)dentry->d_name.len, dentry->d_name.name);
323 return affs_remove_header(dentry);
327 affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
329 struct super_block *sb = dir->i_sb;
330 struct buffer_head *bh;
333 int i, maxlen, error;
336 pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
337 (int)dentry->d_name.len,dentry->d_name.name,symname);
339 maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
340 inode = affs_new_inode(dir);
344 inode->i_op = &affs_symlink_inode_operations;
345 inode->i_data.a_ops = &affs_symlink_aops;
346 inode->i_mode = S_IFLNK | 0777;
350 bh = affs_bread(sb, inode->i_ino);
354 p = (char *)AFFS_HEAD(bh)->table;
356 if (*symname == '/') {
357 while (*symname == '/')
359 while (AFFS_SB(sb)->s_volume[i]) /* Cannot overflow */
360 *p++ = AFFS_SB(sb)->s_volume[i++];
362 while (i < maxlen && (c = *symname++)) {
363 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
368 } else if (c == '.' && lc == '/' && *symname == '/') {
377 while (*symname == '/')
381 mark_buffer_dirty_inode(bh, inode);
383 mark_inode_dirty(inode);
385 error = affs_add_entry(dir, inode, dentry, ST_SOFTLINK);
393 mark_inode_dirty(inode);
399 affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
401 struct inode *inode = old_dentry->d_inode;
403 pr_debug("AFFS: link(%u, %u, \"%.*s\")\n", (u32)inode->i_ino, (u32)dir->i_ino,
404 (int)dentry->d_name.len,dentry->d_name.name);
406 return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
410 affs_rename(struct inode *old_dir, struct dentry *old_dentry,
411 struct inode *new_dir, struct dentry *new_dentry)
413 struct super_block *sb = old_dir->i_sb;
414 struct buffer_head *bh = NULL;
417 pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
418 (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
419 (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
421 retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len);
425 /* Unlink destination if it already exists */
426 if (new_dentry->d_inode) {
427 retval = affs_remove_header(new_dentry);
433 bh = affs_bread(sb, old_dentry->d_inode->i_ino);
437 /* Remove header from its parent directory. */
438 affs_lock_dir(old_dir);
439 retval = affs_remove_hash(old_dir, bh);
440 affs_unlock_dir(old_dir);
444 /* And insert it into the new directory with the new name. */
445 affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
446 affs_fix_checksum(sb, bh);
447 affs_lock_dir(new_dir);
448 retval = affs_insert_hash(new_dir, bh);
449 affs_unlock_dir(new_dir);
450 /* TODO: move it back to old_dir, if error? */
453 mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);