Import 2.4.0-test2pre6
[davej-history.git] / fs / affs / namei.c
blob8ad7b07a2e7ac72a324a4182a0a4cf42b01611a8
1 /*
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
9 */
11 #define DEBUG 0
12 #include <linux/sched.h>
13 #include <linux/affs_fs.h>
14 #include <linux/kernel.h>
15 #include <linux/string.h>
16 #include <linux/stat.h>
17 #include <linux/fcntl.h>
18 #include <linux/locks.h>
19 #include <linux/amigaffs.h>
20 #include <asm/uaccess.h>
22 #include <linux/errno.h>
24 extern struct inode_operations affs_symlink_inode_operations;
26 /* Simple toupper() for DOS\1 */
28 static unsigned int
29 affs_toupper(unsigned int ch)
31 return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
34 /* International toupper() for DOS\3 ("international") */
36 static unsigned int
37 affs_intl_toupper(unsigned int ch)
39 return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
40 && ch <= 0xFE && ch != 0xF7) ?
41 ch - ('a' - 'A') : ch;
44 static int affs_hash_dentry(struct dentry *, struct qstr *);
45 static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
46 struct dentry_operations affs_dentry_operations = {
47 d_hash: affs_hash_dentry,
48 d_compare: affs_compare_dentry,
52 * Note: the dentry argument is the parent dentry.
54 static int
55 affs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
57 unsigned int (*toupper)(unsigned int) = affs_toupper;
58 unsigned long hash;
59 int i;
61 if ((i = affs_check_name(qstr->name,qstr->len)))
62 return i;
64 /* Check whether to use the international 'toupper' routine */
65 if (AFFS_I2FSTYPE(dentry->d_inode))
66 toupper = affs_intl_toupper;
67 hash = init_name_hash();
68 for (i = 0; i < qstr->len && i < 30; i++)
69 hash = partial_name_hash(toupper(qstr->name[i]), hash);
70 qstr->hash = end_name_hash(hash);
72 return 0;
75 static int
76 affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
78 unsigned int (*toupper)(unsigned int) = affs_toupper;
79 int alen = a->len;
80 int blen = b->len;
81 int i;
83 /* 'a' is the qstr of an already existing dentry, so the name
84 * must be valid. 'b' must be validated first.
87 if (affs_check_name(b->name,b->len))
88 return 1;
90 /* If the names are longer than the allowed 30 chars,
91 * the excess is ignored, so their length may differ.
93 if (alen > 30)
94 alen = 30;
95 if (blen > 30)
96 blen = 30;
97 if (alen != blen)
98 return 1;
100 /* Check whether to use the international 'toupper' routine */
101 if (AFFS_I2FSTYPE(dentry->d_inode))
102 toupper = affs_intl_toupper;
104 for (i = 0; i < alen; i++)
105 if (toupper(a->name[i]) != toupper(b->name[i]))
106 return 1;
108 return 0;
112 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
115 static int
116 affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl)
118 unsigned int (*toupper)(unsigned int) = intl ? affs_intl_toupper : affs_toupper;
119 int i;
121 if (!compare)
122 return 0;
124 if (len > 30)
125 len = 30;
126 if (dlen > 30)
127 dlen = 30;
129 /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
130 if (!len && dlen == 1 && compare[0] == '.')
131 return 1;
132 if (dlen != len)
133 return 0;
134 for (i = 0; i < len; i++)
135 if (toupper(name[i]) != toupper(compare[i]))
136 return 0;
137 return 1;
141 affs_hash_name(const unsigned char *name, int len, int intl, int hashsize)
143 unsigned int i, x;
145 if (len > 30)
146 len = 30;
148 x = len;
149 for (i = 0; i < len; i++)
150 if (intl)
151 x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
152 else
153 x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
155 return x % hashsize;
158 static struct buffer_head *
159 affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
161 struct buffer_head *bh;
162 int intl = AFFS_I2FSTYPE(dir);
163 s32 key;
164 const char *name = dentry->d_name.name;
165 int namelen = dentry->d_name.len;
167 pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name);
169 bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
170 if (!bh)
171 return NULL;
173 if (namelen == 1 && name[0] == '.') {
174 *ino = dir->i_ino;
175 return bh;
177 if (namelen == 2 && name[0] == '.' && name[1] == '.') {
178 *ino = affs_parent_ino(dir);
179 return bh;
182 key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
184 for (;;) {
185 unsigned char *cname;
186 int cnamelen;
188 affs_brelse(bh);
189 bh = NULL;
190 if (key == 0)
191 break;
192 bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
193 if (!bh)
194 break;
195 cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
196 if (affs_match(name,namelen,cname,cnamelen,intl))
197 break;
198 key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain);
200 *ino = key;
201 return bh;
204 struct dentry *
205 affs_lookup(struct inode *dir, struct dentry *dentry)
207 unsigned long ino;
208 struct buffer_head *bh;
209 struct inode *inode;
211 pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name);
213 inode = NULL;
214 bh = affs_find_entry(dir,dentry,&ino);
215 if (bh) {
216 if (FILE_END(bh->b_data,dir)->original)
217 ino = be32_to_cpu(FILE_END(bh->b_data,dir)->original);
218 affs_brelse(bh);
219 inode = iget(dir->i_sb,ino);
220 if (!inode)
221 return ERR_PTR(-EACCES);
223 dentry->d_op = &affs_dentry_operations;
224 d_add(dentry,inode);
225 return NULL;
229 affs_unlink(struct inode *dir, struct dentry *dentry)
231 int retval;
232 struct buffer_head *bh;
233 unsigned long ino;
234 struct inode *inode;
236 pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,
237 (int)dentry->d_name.len,dentry->d_name.name);
239 retval = -ENOENT;
240 if (!(bh = affs_find_entry(dir,dentry,&ino)))
241 goto unlink_done;
243 inode = dentry->d_inode;
245 if ((retval = affs_remove_header(bh,inode)) < 0)
246 goto unlink_done;
248 inode->i_nlink = retval;
249 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
250 dir->i_version = ++event;
251 mark_inode_dirty(inode);
252 mark_inode_dirty(dir);
253 retval = 0;
255 unlink_done:
256 affs_brelse(bh);
257 return retval;
261 affs_create(struct inode *dir, struct dentry *dentry, int mode)
263 struct inode *inode;
264 int error;
266 pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len,
267 dentry->d_name.name,mode);
269 error = -ENOSPC;
270 inode = affs_new_inode(dir);
271 if (!inode)
272 goto out;
274 pr_debug("AFFS: ino=%lu\n",inode->i_ino);
275 if (dir->i_sb->u.affs_sb.s_flags & SF_OFS) {
276 inode->i_op = &affs_file_inode_operations;
277 inode->i_fop = &affs_file_operations_ofs;
278 } else {
279 inode->i_op = &affs_file_inode_operations;
280 inode->i_fop = &affs_file_operations;
281 inode->i_mapping->a_ops = &affs_aops;
282 inode->u.affs_i.mmu_private = inode->i_size;
284 error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE);
285 if (error)
286 goto out_iput;
287 inode->i_mode = mode;
288 inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
289 d_instantiate(dentry,inode);
290 mark_inode_dirty(inode);
291 dir->i_version = ++event;
292 mark_inode_dirty(dir);
293 out:
294 return error;
296 out_iput:
297 inode->i_nlink = 0;
298 mark_inode_dirty(inode);
299 iput(inode);
300 goto out;
304 affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
306 struct inode *inode;
307 int error;
309 pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,
310 (int)dentry->d_name.len,dentry->d_name.name,mode);
312 error = -ENOSPC;
313 inode = affs_new_inode(dir);
314 if (!inode)
315 goto out;
317 inode->i_op = &affs_dir_inode_operations;
318 inode->i_fop = &affs_dir_operations;
319 error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR);
320 if (error)
321 goto out_iput;
322 inode->i_mode = S_IFDIR | S_ISVTX | mode;
323 inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
324 d_instantiate(dentry,inode);
325 mark_inode_dirty(inode);
326 dir->i_version = ++event;
327 mark_inode_dirty(dir);
328 out:
329 return error;
331 out_iput:
332 inode->i_nlink = 0;
333 mark_inode_dirty(inode);
334 iput(inode);
335 goto out;
338 static int
339 empty_dir(struct buffer_head *bh, int hashsize)
341 while (--hashsize >= 0) {
342 if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
343 return 0;
345 return 1;
349 affs_rmdir(struct inode *dir, struct dentry *dentry)
351 struct inode *inode = dentry->d_inode;
352 int retval;
353 unsigned long ino;
354 struct buffer_head *bh;
356 pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,
357 (int)dentry->d_name.len,dentry->d_name.name);
359 retval = -ENOENT;
360 if (!(bh = affs_find_entry(dir,dentry,&ino)))
361 goto rmdir_done;
364 * Make sure the directory is empty and the dentry isn't busy.
366 retval = -ENOTEMPTY;
367 if (!empty_dir(bh,AFFS_I2HSIZE(inode)))
368 goto rmdir_done;
369 retval = -EBUSY;
370 if (!d_unhashed(dentry))
371 goto rmdir_done;
373 if ((retval = affs_remove_header(bh,inode)) < 0)
374 goto rmdir_done;
376 inode->i_nlink = retval;
377 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
378 retval = 0;
379 dir->i_version = ++event;
380 mark_inode_dirty(dir);
381 mark_inode_dirty(inode);
383 rmdir_done:
384 affs_brelse(bh);
385 return retval;
389 affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
391 struct buffer_head *bh;
392 struct inode *inode;
393 char *p;
394 unsigned long tmp;
395 int i, maxlen, error;
396 char c, lc;
398 pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,
399 (int)dentry->d_name.len,dentry->d_name.name,symname);
401 maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
402 error = -ENOSPC;
403 inode = affs_new_inode(dir);
404 if (!inode)
405 goto out;
407 inode->i_op = &affs_symlink_inode_operations;
408 inode->i_data.a_ops = &affs_symlink_aops;
409 inode->i_mode = S_IFLNK | 0777;
410 inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
411 error = -EIO;
412 bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
413 if (!bh)
414 goto out_iput;
415 i = 0;
416 p = ((struct slink_front *)bh->b_data)->symname;
417 lc = '/';
418 if (*symname == '/') {
419 while (*symname == '/')
420 symname++;
421 while (inode->i_sb->u.affs_sb.s_volume[i]) /* Cannot overflow */
422 *p++ = inode->i_sb->u.affs_sb.s_volume[i++];
424 while (i < maxlen && (c = *symname++)) {
425 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
426 *p++ = '/';
427 i++;
428 symname += 2;
429 lc = '/';
430 } else if (c == '.' && lc == '/' && *symname == '/') {
431 symname++;
432 lc = '/';
433 } else {
434 *p++ = c;
435 lc = c;
436 i++;
438 if (lc == '/')
439 while (*symname == '/')
440 symname++;
442 *p = 0;
443 mark_buffer_dirty(bh,1);
444 affs_brelse(bh);
445 mark_inode_dirty(inode);
447 /* N.B. This test shouldn't be necessary ... dentry must be negative */
448 error = -EEXIST;
449 bh = affs_find_entry(dir,dentry,&tmp);
450 if (bh)
451 goto out_release;
452 /* N.B. Shouldn't we add the entry before dirtying the buffer? */
453 error = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK);
454 if (error)
455 goto out_release;
456 d_instantiate(dentry,inode);
457 dir->i_version = ++event;
458 mark_inode_dirty(dir);
460 out:
461 return error;
463 out_release:
464 affs_brelse(bh);
465 out_iput:
466 inode->i_nlink = 0;
467 mark_inode_dirty(inode);
468 iput(inode);
469 goto out;
473 affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
475 struct inode *oldinode = old_dentry->d_inode;
476 struct inode *inode;
477 struct buffer_head *bh;
478 unsigned long i;
479 int error;
481 pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,
482 (int)dentry->d_name.len,dentry->d_name.name);
484 /* N.B. Do we need this test? The dentry must be negative ... */
485 bh = affs_find_entry(dir,dentry,&i);
486 if (bh) {
487 affs_brelse(bh);
488 return -EEXIST;
490 if (oldinode->u.affs_i.i_hlink) { /* Cannot happen */
491 affs_warning(dir->i_sb,"link","Impossible link to link");
492 return -EINVAL;
494 error = -ENOSPC;
495 if (!(inode = affs_new_inode(dir)))
496 goto out;
498 inode->i_op = oldinode->i_op;
499 inode->i_fop = oldinode->i_fop;
500 inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode);
501 inode->u.affs_i.i_original = oldinode->i_ino;
502 inode->u.affs_i.i_hlink = 1;
503 inode->i_mtime = oldinode->i_mtime;
505 if (S_ISDIR(oldinode->i_mode))
506 error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR);
507 else
508 error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE);
509 if (error)
510 inode->i_nlink = 0;
511 else {
512 dir->i_version = ++event;
513 mark_inode_dirty(dir);
514 mark_inode_dirty(oldinode);
515 atomic_inc(&oldinode->i_count);
516 d_instantiate(dentry,oldinode);
518 mark_inode_dirty(inode);
519 iput(inode);
521 out:
522 return error;
526 affs_rename(struct inode *old_dir, struct dentry *old_dentry,
527 struct inode *new_dir, struct dentry *new_dentry)
529 struct inode *old_inode = old_dentry->d_inode;
530 struct inode *new_inode = new_dentry->d_inode;
531 struct buffer_head *old_bh;
532 struct buffer_head *new_bh;
533 unsigned long old_ino;
534 unsigned long new_ino;
535 int retval;
537 pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p))\n",
538 old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode,
539 new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode);
541 if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len)))
542 goto out;
544 new_bh = NULL;
545 retval = -ENOENT;
546 old_bh = affs_find_entry(old_dir,old_dentry,&old_ino);
547 if (!old_bh)
548 goto end_rename;
550 new_bh = affs_find_entry(new_dir,new_dentry,&new_ino);
551 if (new_bh && !new_inode) {
552 affs_error(old_inode->i_sb,"affs_rename",
553 "No inode for entry found (key=%lu)\n",new_ino);
554 goto end_rename;
556 if (S_ISDIR(old_inode->i_mode)) {
557 if (new_inode) {
558 retval = -EBUSY;
559 if (!d_unhashed(new_dentry))
560 goto end_rename;
561 retval = -ENOTEMPTY;
562 if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
563 goto end_rename;
566 retval = -ENOENT;
567 if (affs_parent_ino(old_inode) != old_dir->i_ino)
568 goto end_rename;
570 /* Unlink destination if it already exists */
571 if (new_inode) {
572 if ((retval = affs_remove_header(new_bh,new_dir)) < 0)
573 goto end_rename;
574 new_inode->i_nlink = retval;
575 mark_inode_dirty(new_inode);
576 if (new_inode->i_ino == new_ino)
577 new_inode->i_nlink = 0;
579 /* Remove header from its parent directory. */
580 if ((retval = affs_remove_hash(old_bh,old_dir)))
581 goto end_rename;
582 /* And insert it into the new directory with the new name. */
583 affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name);
584 if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir)))
585 goto end_rename;
586 affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5);
588 new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime
589 = old_dir->i_mtime = CURRENT_TIME;
590 new_dir->i_version = ++event;
591 old_dir->i_version = ++event;
592 retval = 0;
593 mark_inode_dirty(new_dir);
594 mark_inode_dirty(old_dir);
595 mark_buffer_dirty(old_bh,1);
597 end_rename:
598 affs_brelse(old_bh);
599 affs_brelse(new_bh);
600 out:
601 return retval;