This source file includes following definitions.
- affs_toupper
- affs_intl_toupper
- affs_match
- affs_hash_name
- affs_find_entry
- affs_lookup
- affs_unlink
- affs_create
- affs_mkdir
- empty_dir
- affs_rmdir
- affs_symlink
- affs_link
- subdir
- affs_rename
- affs_fixup
1
2
3
4
5
6
7
8
9
10
11 #include <linux/sched.h>
12 #include <linux/affs_fs.h>
13 #include <linux/amigaffs.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 <asm/segment.h>
20
21 #include <linux/errno.h>
22
23
24
25 static inline unsigned int
26 affs_toupper(unsigned int ch)
27 {
28 return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
29 }
30
31
32
33 static inline unsigned int
34 affs_intl_toupper(unsigned int ch)
35 {
36 return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
37 && ch <= 0xFE && ch != 0xF7) ?
38 ch - ('a' - 'A') : ch;
39 }
40
41
42
43
44
45 static int
46 affs_match(const char *name, int len, const char *compare, int dlen, int intl)
47 {
48 if (!compare)
49 return 0;
50
51 if (len > 30)
52 len = 30;
53 if (dlen > 30)
54 dlen = 30;
55
56
57 if (!len && dlen == 1 && compare[0] == '.')
58 return 1;
59 if (dlen != len)
60 return 0;
61 if (intl) {
62 while (dlen--) {
63 if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF))
64 return 0;
65 name++;
66 compare++;
67 }
68 } else {
69 while (dlen--) {
70 if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF))
71 return 0;
72 name++;
73 compare++;
74 }
75 }
76 return 1;
77 }
78
79 int
80 affs_hash_name(const char *name, int len, int intl, int hashsize)
81 {
82 unsigned int i, x;
83
84 if (len > 30)
85 len = 30;
86
87 x = len;
88 for (i = 0; i < len; i++)
89 if (intl)
90 x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
91 else
92 x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
93
94 return x % hashsize;
95 }
96
97 static struct buffer_head *
98 affs_find_entry(struct inode *dir, const char *name, int namelen,
99 unsigned long *ino)
100 {
101 struct buffer_head *bh;
102 int intl;
103 ULONG key;
104
105 pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
106
107 intl = AFFS_I2FSTYPE(dir);
108 bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
109 if (!bh)
110 return NULL;
111
112 if (affs_match(name,namelen,".",1,intl)) {
113 *ino = dir->i_ino;
114 return bh;
115 }
116 if (affs_match(name,namelen,"..",2,intl)) {
117 *ino = affs_parent_ino(dir);
118 return bh;
119 }
120
121 key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
122
123 for (;;) {
124 char *cname;
125 int cnamelen;
126
127 affs_brelse(bh);
128 if (key == 0) {
129 bh = NULL;
130 break;
131 }
132 bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
133 if (!bh)
134 break;
135 cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
136 if (affs_match(name,namelen,cname,cnamelen,intl))
137 break;
138 key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
139 }
140 pr_debug("%lu\n",key);
141 *ino = key;
142 return bh;
143 }
144
145 int
146 affs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
147 {
148 int res;
149 unsigned long ino;
150 struct buffer_head *bh;
151
152 pr_debug("AFFS: lookup(%.*s)\n",len,name);
153
154 *result = NULL;
155 if (!dir)
156 return -ENOENT;
157
158 res = -ENOENT;
159 if (S_ISDIR(dir->i_mode)) {
160 if ((bh = affs_find_entry(dir,name,len,&ino))) {
161 if (FILE_END(bh->b_data,dir)->original)
162 ino = htonl(FILE_END(bh->b_data,dir)->original);
163 affs_brelse(bh);
164 if ((*result = iget(dir->i_sb,ino)))
165 res = 0;
166 else
167 res = -EACCES;
168 }
169 }
170 iput(dir);
171 return res;
172 }
173
174 int
175 affs_unlink(struct inode *dir, const char *name, int len)
176 {
177 int retval;
178 struct buffer_head *bh;
179 unsigned long ino;
180 struct inode *inode;
181
182 pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name);
183
184 bh = NULL;
185 inode = NULL;
186 retval = -ENOENT;
187 if (!(bh = affs_find_entry(dir,name,len,&ino))) {
188 goto unlink_done;
189 }
190 if (!(inode = iget(dir->i_sb,ino))) {
191 goto unlink_done;
192 }
193 if (S_ISDIR(inode->i_mode)) {
194 retval = -EPERM;
195 goto unlink_done;
196 }
197
198 if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
199 AFFS_I2HSIZE(dir)) + 6,ino,
200 FILE_END(bh->b_data,dir)->hash_chain)))
201 goto unlink_done;
202
203 if ((retval = affs_fixup(bh,inode)))
204 goto unlink_done;
205
206 inode->i_nlink=0;
207 inode->i_dirt=1;
208 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
209 dir->i_version = ++event;
210 dir->i_dirt=1;
211 unlink_done:
212 affs_brelse(bh);
213 iput(inode);
214 iput(dir);
215 return retval;
216 }
217
218 int
219 affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result)
220 {
221 struct inode *inode;
222 int error;
223
224 pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
225
226
227 *result = NULL;
228
229 if (!dir || !dir->i_sb) {
230 iput(dir);
231 return -EINVAL;
232 }
233 inode = affs_new_inode(dir);
234 if (!inode) {
235 iput (dir);
236 return -ENOSPC;
237 }
238 inode->i_op = &affs_file_inode_operations;
239 inode->i_mode = mode;
240 error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
241 if (error) {
242 iput(dir);
243 inode->i_nlink = 0;
244 inode->i_dirt = 1;
245 iput(inode);
246 return -ENOSPC;
247 }
248 inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
249
250 iput(dir);
251 *result = inode;
252
253 return 0;
254 }
255
256 int
257 affs_mkdir(struct inode *dir, const char *name, int len, int mode)
258 {
259 struct inode *inode;
260 struct buffer_head *bh;
261 unsigned long i;
262 int error;
263
264 pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
265
266 if (!dir || !dir->i_sb) {
267 iput(dir);
268 return -EINVAL;
269 }
270 bh = affs_find_entry(dir,name,len,&i);
271 if (bh) {
272 affs_brelse(bh);
273 iput(dir);
274 return -EEXIST;
275 }
276 inode = affs_new_inode(dir);
277 if (!inode) {
278 iput (dir);
279 return -ENOSPC;
280 }
281 inode->i_op = &affs_dir_inode_operations;
282 error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR);
283 if (error) {
284 iput(dir);
285 inode->i_nlink = 0;
286 inode->i_dirt = 1;
287 iput(inode);
288 return error;
289 }
290 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
291 inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
292
293 iput(dir);
294 iput(inode);
295
296 return 0;
297 }
298
299 static int
300 empty_dir(struct buffer_head *bh, int hashsize)
301 {
302 while (--hashsize >= 0) {
303 if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
304 return 0;
305 }
306 return 1;
307 }
308
309 int
310 affs_rmdir(struct inode *dir, const char *name, int len)
311 {
312 int retval;
313 unsigned long ino;
314 struct inode *inode;
315 struct buffer_head *bh;
316
317 pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name);
318
319 inode = NULL;
320 retval = -ENOENT;
321 if (!(bh = affs_find_entry(dir,name,len,&ino))) {
322 goto rmdir_done;
323 }
324 if (!(inode = iget(dir->i_sb,ino))) {
325 goto rmdir_done;
326 }
327 retval = -EPERM;
328 if (!fsuser() && current->fsuid != inode->i_uid &&
329 current->fsuid != dir->i_uid)
330 goto rmdir_done;
331 if (inode->i_dev != dir->i_dev)
332 goto rmdir_done;
333 if (inode == dir)
334 goto rmdir_done;
335 if (!S_ISDIR(inode->i_mode)) {
336 retval = -ENOTDIR;
337 goto rmdir_done;
338 }
339 if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
340 retval = -ENOTEMPTY;
341 goto rmdir_done;
342 }
343 if (inode->i_count > 1) {
344 retval = -EBUSY;
345 goto rmdir_done;
346 }
347 if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
348 AFFS_I2HSIZE(dir)) + 6,ino,
349 FILE_END(bh->b_data,dir)->hash_chain)))
350 goto rmdir_done;
351
352 if ((retval = affs_fixup(bh,inode)))
353 goto rmdir_done;
354
355 inode->i_nlink=0;
356 inode->i_dirt=1;
357 inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
358 dir->i_version = ++event;
359 dir->i_dirt=1;
360 rmdir_done:
361 iput(dir);
362 iput(inode);
363 affs_brelse(bh);
364 return retval;
365 }
366
367 int
368 affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
369 {
370 struct buffer_head *bh;
371 struct inode *inode;
372 char *p;
373 unsigned long tmp;
374 int i, maxlen;
375 char c, lc;
376
377 pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
378 printk("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
379
380 maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
381 inode = affs_new_inode(dir);
382 if (!inode) {
383 iput(dir);
384 return -ENOSPC;
385 }
386 inode->i_op = &affs_symlink_inode_operations;
387 inode->i_mode = S_IFLNK | 0777;
388 inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
389 bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
390 if (!bh) {
391 iput(dir);
392 inode->i_nlink = 0;
393 inode->i_dirt = 1;
394 iput(inode);
395 return -EIO;
396 }
397 i = 0;
398 p = ((struct slink_front *)bh->b_data)->symname;
399 lc = '/';
400 if (*symname == '/') {
401 while (*symname == '/')
402 symname++;
403 while (inode->i_sb->u.affs_sb.s_volume[i])
404 *p++ = inode->i_sb->u.affs_sb.s_volume[i++];
405 }
406 while (i < maxlen && (c = *symname++)) {
407 if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
408 *p++ = '/';
409 i++;
410 symname += 2;
411 lc = '/';
412 } else if (c == '.' && lc == '/' && *symname == '/') {
413 symname++;
414 lc = '/';
415 } else {
416 *p++ = c;
417 lc = c;
418 i++;
419 }
420 if (lc == '/')
421 while (*symname == '/')
422 symname++;
423 }
424 *p = 0;
425 mark_buffer_dirty(bh,1);
426 affs_brelse(bh);
427 inode->i_dirt = 1;
428 bh = affs_find_entry(dir,name,len,&tmp);
429 if (bh) {
430 inode->i_nlink = 0;
431 iput(inode);
432 affs_brelse(bh);
433 iput(dir);
434 return -EEXIST;
435 }
436 i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
437 if (i) {
438 inode->i_nlink = 0;
439 inode->i_dirt = 1;
440 iput(inode);
441 affs_brelse(bh);
442 iput(dir);
443 return i;
444 }
445 iput(dir);
446 iput(inode);
447
448 return 0;
449 }
450
451 int
452 affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
453 {
454 struct inode *inode;
455 struct buffer_head *bh;
456 unsigned long i;
457 int error;
458
459 pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name);
460
461 bh = affs_find_entry(dir,name,len,&i);
462 if (bh) {
463 affs_brelse(bh);
464 iput(oldinode);
465 iput(dir);
466 return -EEXIST;
467 }
468 if (oldinode->u.affs_i.i_hlink) {
469 i = oldinode->u.affs_i.i_original;
470 iput(oldinode);
471 oldinode = iget(dir->i_sb,i);
472 if (!oldinode) {
473 printk("AFFS: link(): original does not exist.\n");
474 iput(dir);
475 return -ENOENT;
476 }
477 }
478 inode = affs_new_inode(dir);
479 if (!inode) {
480 iput(oldinode);
481 iput(dir);
482 return -ENOSPC;
483 }
484 inode->i_op = oldinode->i_op;
485 inode->i_mode = oldinode->i_mode;
486 inode->i_uid = oldinode->i_uid;
487 inode->i_gid = oldinode->i_gid;
488 inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
489 inode->u.affs_i.i_original = oldinode->i_ino;
490 inode->u.affs_i.i_hlink = 1;
491
492 if (S_ISDIR(oldinode->i_mode))
493 error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR);
494 else
495 error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
496 if (error) {
497 inode->i_nlink = 0;
498 inode->i_dirt = 1;
499 }
500 iput(dir);
501 iput(inode);
502 iput(oldinode);
503
504 return error;
505 }
506
507 static int
508 subdir(struct inode * new_inode, struct inode * old_inode)
509 {
510 int ino;
511 int result;
512
513 new_inode->i_count++;
514 result = 0;
515 for (;;) {
516 if (new_inode == old_inode) {
517 result = 1;
518 break;
519 }
520 if (new_inode->i_dev != old_inode->i_dev)
521 break;
522 ino = new_inode->i_ino;
523 if (affs_lookup(new_inode,"..",2,&new_inode))
524 break;
525 if (new_inode->i_ino == ino)
526 break;
527 }
528 iput(new_inode);
529 return result;
530 }
531
532
533
534 int
535 affs_rename(struct inode *old_dir, const char *old_name, int old_len,
536 struct inode *new_dir, const char *new_name, int new_len)
537 {
538 struct inode *old_inode;
539 struct inode *new_inode;
540 struct buffer_head *old_bh;
541 struct buffer_head *new_bh;
542 unsigned long old_ino;
543 unsigned long new_ino;
544 int retval;
545
546 pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
547 new_dir->i_ino,new_len,new_name);
548
549 if (new_len > 30)
550 new_len = 30;
551 goto start_up;
552 retry:
553 affs_brelse(old_bh);
554 affs_brelse(new_bh);
555 iput(new_inode);
556 iput(old_inode);
557 current->counter = 0;
558 schedule();
559 start_up:
560 old_inode = new_inode = NULL;
561 old_bh = new_bh = NULL;
562 retval = -ENOENT;
563
564 old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
565 if (!old_bh)
566 goto end_rename;
567 old_inode = __iget(old_dir->i_sb,old_ino,0);
568 if (!old_inode)
569 goto end_rename;
570 new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
571 if (new_bh) {
572 new_inode = __iget(new_dir->i_sb,new_ino,0);
573 if (!new_inode) {
574 affs_brelse(new_bh);
575 new_bh = NULL;
576 }
577 }
578 if (new_inode == old_inode) {
579 retval = 0;
580 goto end_rename;
581 }
582 if (new_inode && S_ISDIR(new_inode->i_mode)) {
583 retval = -EISDIR;
584 if (!S_ISDIR(old_inode->i_mode))
585 goto end_rename;
586 retval = -EINVAL;
587 if (subdir(new_dir,old_inode))
588 goto end_rename;
589 retval = -ENOTEMPTY;
590 if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
591 goto end_rename;
592 retval = -EBUSY;
593 if (new_inode->i_count > 1)
594 goto end_rename;
595 }
596 if (S_ISDIR(old_inode->i_mode)) {
597 retval = -ENOTDIR;
598 if (new_inode && !S_ISDIR(new_inode->i_mode))
599 goto end_rename;
600 retval = -EINVAL;
601 if (subdir(new_dir,old_inode))
602 goto end_rename;
603 if (affs_parent_ino(old_inode) != old_dir->i_ino)
604 goto end_rename;
605 }
606
607 if (new_inode) {
608 if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
609 AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
610 new_ino,
611 FILE_END(new_bh->b_data,new_dir)->hash_chain)))
612 goto retry;
613 if ((retval = affs_fixup(new_bh,new_inode)))
614 goto retry;
615 mark_buffer_dirty(new_bh,1);
616 new_dir->i_version = ++event;
617 new_dir->i_dirt = 1;
618 new_inode->i_nlink = 0;
619 new_inode->i_dirt = 1;
620 }
621 retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
622 AFFS_I2HSIZE(old_dir)) + 6,old_ino,
623 FILE_END(old_bh->b_data,old_dir)->hash_chain);
624 if (retval)
625 goto retry;
626
627 retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len,
628 htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type));
629
630 new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
631 new_dir->i_version = ++event;
632 old_dir->i_version = ++event;
633 new_dir->i_dirt = 1;
634 old_dir->i_dirt = 1;
635 mark_buffer_dirty(old_bh,1);
636
637 end_rename:
638 affs_brelse(old_bh);
639 affs_brelse(new_bh);
640 iput(new_inode);
641 iput(old_inode);
642 iput(old_dir);
643 iput(new_dir);
644
645 return retval;
646 }
647
648 int
649 affs_fixup(struct buffer_head *bh, struct inode *inode)
650 {
651 ULONG key, link_key;
652 LONG type;
653 struct buffer_head *nbh;
654 struct inode *ofinode;
655
656 type = htonl(FILE_END(bh->b_data,inode)->secondary_type);
657 if (type == ST_LINKFILE || type == ST_LINKDIR) {
658 key = htonl(LINK_END(bh->b_data,inode)->original);
659 LINK_END(bh->b_data,inode)->original = 0;
660 if (!key) {
661 printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino);
662 return -ENOENT;
663 }
664 if (!(ofinode = iget(inode->i_sb,key)))
665 return -ENOENT;
666 type = affs_fix_link_pred(ofinode,inode->i_ino,
667 FILE_END(bh->b_data,inode)->link_chain);
668 iput(ofinode);
669 return type;
670 } else if (type == ST_FILE || type == ST_USERDIR) {
671 if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
672
673 if (!(ofinode = iget(inode->i_sb,key))) {
674 printk("AFFS: fixup(): cannot read inode %u\n",key);
675 return -ENOENT;
676 }
677 if (!ofinode->u.affs_i.i_hlink) {
678 printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n",
679 inode->i_ino,key);
680 iput(ofinode);
681 return -ENOENT;
682 }
683 if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
684 printk("AFFS: fixup(): cannot read block %u\n",key);
685 iput(ofinode);
686 return -ENOENT;
687 }
688 lock_super(inode->i_sb);
689 memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208);
690 FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)->
691 byte_size;
692 FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)->
693 extension;
694 FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)->
695 secondary_type;
696 FILE_END(nbh->b_data,inode)->original = 0;
697
698 ofinode->u.affs_i.i_original = 0;
699 ofinode->u.affs_i.i_hlink = 0;
700 ofinode->i_size = inode->i_size;
701 ofinode->i_uid = inode->i_uid;
702 ofinode->i_gid = inode->i_gid;
703 ofinode->i_dirt = 1;
704 link_key = ofinode->i_ino;
705
706
707 while (1) {
708 affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5);
709 mark_buffer_dirty(nbh,1);
710 key = htonl(FILE_END(nbh->b_data,inode)->link_chain);
711 affs_brelse(nbh);
712 iput(ofinode);
713 if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode))))
714 break;
715 if ((ofinode = iget(inode->i_sb,key))) {
716 if (!ofinode->u.affs_i.i_hlink)
717 printk("AFFS: fixup() inode %u in link chain is "
718 "not a link\n",key);
719 ofinode->u.affs_i.i_original = link_key;
720 ofinode->i_dirt = 1;
721 FILE_END(nbh->b_data,inode)->original = htonl(link_key);
722 } else
723 printk("AFFS: fixup(): cannot get inode %u\n",key);
724 }
725
726 inode->u.affs_i.i_hlink = 1;
727 unlock_super(inode->i_sb);
728 }
729 return 0;
730 } else if (type == ST_SOFTLINK) {
731 return 0;
732 } else {
733 printk("AFFS: fixup(): secondary type=%d\n",type);
734 return -EBADF;
735 }
736 }