This source file includes following definitions.
- namecompare
- minix_match
- minix_find_entry
- minix_lookup
- minix_add_entry
- minix_create
- minix_mknod
- minix_mkdir
- empty_dir
- minix_rmdir
- minix_unlink
- minix_symlink
- minix_link
- subdir
- do_minix_rename
- minix_rename
1
2
3
4
5
6
7 #include <linux/sched.h>
8 #include <linux/minix_fs.h>
9 #include <linux/kernel.h>
10 #include <linux/string.h>
11 #include <linux/stat.h>
12 #include <linux/fcntl.h>
13 #include <linux/errno.h>
14
15 #include <asm/segment.h>
16
17
18
19
20
21
22
23 static inline int namecompare(int len, int maxlen,
24 const char * name, const char * buffer)
25 {
26 if (len >= maxlen || !buffer[len]) {
27 unsigned char same;
28 __asm__("repe ; cmpsb ; setz %0"
29 :"=q" (same)
30 :"S" ((long) name),"D" ((long) buffer),"c" (len)
31 :"cx","di","si");
32 return same;
33 }
34 return 0;
35 }
36
37
38
39
40
41
42
43
44 static int minix_match(int len, const char * name,
45 struct buffer_head * bh, unsigned long * offset,
46 struct minix_sb_info * info)
47 {
48 struct minix_dir_entry * de;
49
50 de = (struct minix_dir_entry *) (bh->b_data + *offset);
51 *offset += info->s_dirsize;
52 if (!de->inode || len > info->s_namelen)
53 return 0;
54
55 if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
56 return 1;
57 return namecompare(len,info->s_namelen,name,de->name);
58 }
59
60
61
62
63
64
65
66
67
68 static struct buffer_head * minix_find_entry(struct inode * dir,
69 const char * name, int namelen, struct minix_dir_entry ** res_dir)
70 {
71 unsigned long block, offset;
72 struct buffer_head * bh;
73 struct minix_sb_info * info;
74
75 *res_dir = NULL;
76 if (!dir || !dir->i_sb)
77 return NULL;
78 info = &dir->i_sb->u.minix_sb;
79 if (namelen > info->s_namelen) {
80 #ifdef NO_TRUNCATE
81 return NULL;
82 #else
83 namelen = info->s_namelen;
84 #endif
85 }
86 bh = NULL;
87 block = offset = 0;
88 while (block*BLOCK_SIZE+offset < dir->i_size) {
89 if (!bh) {
90 bh = minix_bread(dir,block,0);
91 if (!bh) {
92 block++;
93 continue;
94 }
95 }
96 *res_dir = (struct minix_dir_entry *) (bh->b_data + offset);
97 if (minix_match(namelen,name,bh,&offset,info))
98 return bh;
99 if (offset < bh->b_size)
100 continue;
101 brelse(bh);
102 bh = NULL;
103 offset = 0;
104 block++;
105 }
106 brelse(bh);
107 *res_dir = NULL;
108 return NULL;
109 }
110
111 int minix_lookup(struct inode * dir,const char * name, int len,
112 struct inode ** result)
113 {
114 int ino;
115 struct minix_dir_entry * de;
116 struct buffer_head * bh;
117
118 *result = NULL;
119 if (!dir)
120 return -ENOENT;
121 if (!S_ISDIR(dir->i_mode)) {
122 iput(dir);
123 return -ENOENT;
124 }
125 if (!(bh = minix_find_entry(dir,name,len,&de))) {
126 iput(dir);
127 return -ENOENT;
128 }
129 ino = de->inode;
130 brelse(bh);
131 if (!(*result = iget(dir->i_sb,ino))) {
132 iput(dir);
133 return -EACCES;
134 }
135 iput(dir);
136 return 0;
137 }
138
139
140
141
142
143
144
145
146
147
148
149 static int minix_add_entry(struct inode * dir,
150 const char * name, int namelen,
151 struct buffer_head ** res_buf,
152 struct minix_dir_entry ** res_dir)
153 {
154 int i;
155 unsigned long block, offset;
156 struct buffer_head * bh;
157 struct minix_dir_entry * de;
158 struct minix_sb_info * info;
159
160 *res_buf = NULL;
161 *res_dir = NULL;
162 if (!dir || !dir->i_sb)
163 return -ENOENT;
164 info = &dir->i_sb->u.minix_sb;
165 if (namelen > info->s_namelen) {
166 #ifdef NO_TRUNCATE
167 return -ENAMETOOLONG;
168 #else
169 namelen = info->s_namelen;
170 #endif
171 }
172 if (!namelen)
173 return -ENOENT;
174 bh = NULL;
175 block = offset = 0;
176 while (1) {
177 if (!bh) {
178 bh = minix_bread(dir,block,1);
179 if (!bh)
180 return -ENOSPC;
181 }
182 de = (struct minix_dir_entry *) (bh->b_data + offset);
183 offset += info->s_dirsize;
184 if (block*bh->b_size + offset > dir->i_size) {
185 de->inode = 0;
186 dir->i_size = block*bh->b_size + offset;
187 dir->i_dirt = 1;
188 dir->i_ctime = CURRENT_TIME;
189 }
190 if (de->inode) {
191 if (namecompare(namelen, info->s_namelen, name, de->name)) {
192 brelse(bh);
193 return -EEXIST;
194 }
195 } else {
196 dir->i_mtime = dir->i_ctime = CURRENT_TIME;
197 for (i = 0; i < info->s_namelen ; i++)
198 de->name[i] = (i < namelen) ? name[i] : 0;
199 bh->b_dirt = 1;
200 *res_dir = de;
201 break;
202 }
203 if (offset < bh->b_size)
204 continue;
205 brelse(bh);
206 bh = NULL;
207 offset = 0;
208 block++;
209 }
210 *res_buf = bh;
211 return 0;
212 }
213
214 int minix_create(struct inode * dir,const char * name, int len, int mode,
215 struct inode ** result)
216 {
217 int error;
218 struct inode * inode;
219 struct buffer_head * bh;
220 struct minix_dir_entry * de;
221
222 *result = NULL;
223 if (!dir)
224 return -ENOENT;
225 inode = minix_new_inode(dir);
226 if (!inode) {
227 iput(dir);
228 return -ENOSPC;
229 }
230 inode->i_op = &minix_file_inode_operations;
231 inode->i_mode = mode;
232 inode->i_dirt = 1;
233 error = minix_add_entry(dir,name,len, &bh ,&de);
234 if (error) {
235 inode->i_nlink--;
236 inode->i_dirt = 1;
237 iput(inode);
238 iput(dir);
239 return error;
240 }
241 de->inode = inode->i_ino;
242 bh->b_dirt = 1;
243 brelse(bh);
244 iput(dir);
245 *result = inode;
246 return 0;
247 }
248
249 int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
250 {
251 int error;
252 struct inode * inode;
253 struct buffer_head * bh;
254 struct minix_dir_entry * de;
255
256 if (!dir)
257 return -ENOENT;
258 bh = minix_find_entry(dir,name,len,&de);
259 if (bh) {
260 brelse(bh);
261 iput(dir);
262 return -EEXIST;
263 }
264 inode = minix_new_inode(dir);
265 if (!inode) {
266 iput(dir);
267 return -ENOSPC;
268 }
269 inode->i_uid = current->euid;
270 inode->i_mode = mode;
271 inode->i_op = NULL;
272 if (S_ISREG(inode->i_mode))
273 inode->i_op = &minix_file_inode_operations;
274 else if (S_ISDIR(inode->i_mode)) {
275 inode->i_op = &minix_dir_inode_operations;
276 if (dir->i_mode & S_ISGID)
277 inode->i_mode |= S_ISGID;
278 }
279 else if (S_ISLNK(inode->i_mode))
280 inode->i_op = &minix_symlink_inode_operations;
281 else if (S_ISCHR(inode->i_mode))
282 inode->i_op = &chrdev_inode_operations;
283 else if (S_ISBLK(inode->i_mode))
284 inode->i_op = &blkdev_inode_operations;
285 else if (S_ISFIFO(inode->i_mode))
286 init_fifo(inode);
287 if (S_ISBLK(mode) || S_ISCHR(mode))
288 inode->i_rdev = rdev;
289 inode->i_mtime = inode->i_atime = CURRENT_TIME;
290 inode->i_dirt = 1;
291 error = minix_add_entry(dir, name, len, &bh, &de);
292 if (error) {
293 inode->i_nlink--;
294 inode->i_dirt = 1;
295 iput(inode);
296 iput(dir);
297 return error;
298 }
299 de->inode = inode->i_ino;
300 bh->b_dirt = 1;
301 brelse(bh);
302 iput(dir);
303 iput(inode);
304 return 0;
305 }
306
307 int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
308 {
309 int error;
310 struct inode * inode;
311 struct buffer_head * bh, *dir_block;
312 struct minix_dir_entry * de;
313 struct minix_sb_info * info;
314
315 if (!dir || !dir->i_sb) {
316 iput(dir);
317 return -EINVAL;
318 }
319 info = &dir->i_sb->u.minix_sb;
320 bh = minix_find_entry(dir,name,len,&de);
321 if (bh) {
322 brelse(bh);
323 iput(dir);
324 return -EEXIST;
325 }
326 if (dir->i_nlink >= MINIX_LINK_MAX) {
327 iput(dir);
328 return -EMLINK;
329 }
330 inode = minix_new_inode(dir);
331 if (!inode) {
332 iput(dir);
333 return -ENOSPC;
334 }
335 inode->i_op = &minix_dir_inode_operations;
336 inode->i_size = 2 * info->s_dirsize;
337 inode->i_mtime = inode->i_atime = CURRENT_TIME;
338 dir_block = minix_bread(inode,0,1);
339 if (!dir_block) {
340 iput(dir);
341 inode->i_nlink--;
342 inode->i_dirt = 1;
343 iput(inode);
344 return -ENOSPC;
345 }
346 de = (struct minix_dir_entry *) dir_block->b_data;
347 de->inode=inode->i_ino;
348 strcpy(de->name,".");
349 de = (struct minix_dir_entry *) (dir_block->b_data + info->s_dirsize);
350 de->inode = dir->i_ino;
351 strcpy(de->name,"..");
352 inode->i_nlink = 2;
353 dir_block->b_dirt = 1;
354 brelse(dir_block);
355 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
356 if (dir->i_mode & S_ISGID)
357 inode->i_mode |= S_ISGID;
358 inode->i_dirt = 1;
359 error = minix_add_entry(dir, name, len, &bh, &de);
360 if (error) {
361 iput(dir);
362 inode->i_nlink=0;
363 iput(inode);
364 return error;
365 }
366 de->inode = inode->i_ino;
367 bh->b_dirt = 1;
368 dir->i_nlink++;
369 dir->i_dirt = 1;
370 iput(dir);
371 iput(inode);
372 brelse(bh);
373 return 0;
374 }
375
376
377
378
379 static int empty_dir(struct inode * inode)
380 {
381 unsigned int block, offset;
382 struct buffer_head * bh;
383 struct minix_dir_entry * de;
384 struct minix_sb_info * info;
385
386 if (!inode || !inode->i_sb)
387 return 1;
388 info = &inode->i_sb->u.minix_sb;
389 block = 0;
390 bh = NULL;
391 offset = 2*info->s_dirsize;
392 if (inode->i_size & (info->s_dirsize-1))
393 goto bad_dir;
394 if (inode->i_size < offset)
395 goto bad_dir;
396 bh = minix_bread(inode,0,0);
397 if (!bh)
398 goto bad_dir;
399 de = (struct minix_dir_entry *) bh->b_data;
400 if (!de->inode || strcmp(de->name,"."))
401 goto bad_dir;
402 de = (struct minix_dir_entry *) (bh->b_data + info->s_dirsize);
403 if (!de->inode || strcmp(de->name,".."))
404 goto bad_dir;
405 while (block*BLOCK_SIZE+offset < inode->i_size) {
406 if (!bh) {
407 bh = minix_bread(inode,block,0);
408 if (!bh) {
409 block++;
410 continue;
411 }
412 }
413 de = (struct minix_dir_entry *) (bh->b_data + offset);
414 offset += info->s_dirsize;
415 if (de->inode) {
416 brelse(bh);
417 return 0;
418 }
419 if (offset < bh->b_size)
420 continue;
421 brelse(bh);
422 bh = NULL;
423 offset = 0;
424 block++;
425 }
426 brelse(bh);
427 return 1;
428 bad_dir:
429 brelse(bh);
430 printk("Bad directory on device %04x\n",inode->i_dev);
431 return 1;
432 }
433
434 int minix_rmdir(struct inode * dir, const char * name, int len)
435 {
436 int retval;
437 struct inode * inode;
438 struct buffer_head * bh;
439 struct minix_dir_entry * de;
440
441 inode = NULL;
442 bh = minix_find_entry(dir,name,len,&de);
443 retval = -ENOENT;
444 if (!bh)
445 goto end_rmdir;
446 retval = -EPERM;
447 if (!(inode = iget(dir->i_sb, de->inode)))
448 goto end_rmdir;
449 if ((dir->i_mode & S_ISVTX) && current->euid &&
450 inode->i_uid != current->euid)
451 goto end_rmdir;
452 if (inode->i_dev != dir->i_dev)
453 goto end_rmdir;
454 if (inode == dir)
455 goto end_rmdir;
456 if (!S_ISDIR(inode->i_mode)) {
457 retval = -ENOTDIR;
458 goto end_rmdir;
459 }
460 if (!empty_dir(inode)) {
461 retval = -ENOTEMPTY;
462 goto end_rmdir;
463 }
464 if (inode->i_count > 1) {
465 retval = -EBUSY;
466 goto end_rmdir;
467 }
468 if (inode->i_nlink != 2)
469 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
470 de->inode = 0;
471 bh->b_dirt = 1;
472 inode->i_nlink=0;
473 inode->i_dirt=1;
474 dir->i_nlink--;
475 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
476 dir->i_dirt=1;
477 retval = 0;
478 end_rmdir:
479 iput(dir);
480 iput(inode);
481 brelse(bh);
482 return retval;
483 }
484
485 int minix_unlink(struct inode * dir, const char * name, int len)
486 {
487 int retval;
488 struct inode * inode;
489 struct buffer_head * bh;
490 struct minix_dir_entry * de;
491
492 repeat:
493 retval = -ENOENT;
494 inode = NULL;
495 bh = minix_find_entry(dir,name,len,&de);
496 if (!bh)
497 goto end_unlink;
498 if (!(inode = iget(dir->i_sb, de->inode)))
499 goto end_unlink;
500 if (de->inode != inode->i_ino) {
501 iput(inode);
502 brelse(bh);
503 current->counter = 0;
504 schedule();
505 goto repeat;
506 }
507 retval = -EPERM;
508 if ((dir->i_mode & S_ISVTX) && !suser() &&
509 current->euid != inode->i_uid &&
510 current->euid != dir->i_uid)
511 goto end_unlink;
512 if (S_ISDIR(inode->i_mode))
513 goto end_unlink;
514 if (!inode->i_nlink) {
515 printk("Deleting nonexistent file (%04x:%d), %d\n",
516 inode->i_dev,inode->i_ino,inode->i_nlink);
517 inode->i_nlink=1;
518 }
519 de->inode = 0;
520 bh->b_dirt = 1;
521 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
522 dir->i_dirt = 1;
523 inode->i_nlink--;
524 inode->i_ctime = CURRENT_TIME;
525 inode->i_dirt = 1;
526 retval = 0;
527 end_unlink:
528 brelse(bh);
529 iput(inode);
530 iput(dir);
531 return retval;
532 }
533
534 int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
535 {
536 struct minix_dir_entry * de;
537 struct inode * inode = NULL;
538 struct buffer_head * bh = NULL, * name_block = NULL;
539 int i;
540 char c;
541
542 if (!(inode = minix_new_inode(dir))) {
543 iput(dir);
544 return -ENOSPC;
545 }
546 inode->i_mode = S_IFLNK | 0777;
547 inode->i_op = &minix_symlink_inode_operations;
548 name_block = minix_bread(inode,0,1);
549 if (!name_block) {
550 iput(dir);
551 inode->i_nlink--;
552 inode->i_dirt = 1;
553 iput(inode);
554 return -ENOSPC;
555 }
556 i = 0;
557 while (i < 1023 && (c=*(symname++)))
558 name_block->b_data[i++] = c;
559 name_block->b_data[i] = 0;
560 name_block->b_dirt = 1;
561 brelse(name_block);
562 inode->i_size = i;
563 inode->i_dirt = 1;
564 bh = minix_find_entry(dir,name,len,&de);
565 if (bh) {
566 inode->i_nlink--;
567 inode->i_dirt = 1;
568 iput(inode);
569 brelse(bh);
570 iput(dir);
571 return -EEXIST;
572 }
573 i = minix_add_entry(dir, name, len, &bh, &de);
574 if (i) {
575 inode->i_nlink--;
576 inode->i_dirt = 1;
577 iput(inode);
578 iput(dir);
579 return i;
580 }
581 de->inode = inode->i_ino;
582 bh->b_dirt = 1;
583 brelse(bh);
584 iput(dir);
585 iput(inode);
586 return 0;
587 }
588
589 int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
590 {
591 int error;
592 struct minix_dir_entry * de;
593 struct buffer_head * bh;
594
595 if (S_ISDIR(oldinode->i_mode)) {
596 iput(oldinode);
597 iput(dir);
598 return -EPERM;
599 }
600 if (oldinode->i_nlink >= MINIX_LINK_MAX) {
601 iput(oldinode);
602 iput(dir);
603 return -EMLINK;
604 }
605 bh = minix_find_entry(dir,name,len,&de);
606 if (bh) {
607 brelse(bh);
608 iput(dir);
609 iput(oldinode);
610 return -EEXIST;
611 }
612 error = minix_add_entry(dir, name, len, &bh, &de);
613 if (error) {
614 iput(dir);
615 iput(oldinode);
616 return error;
617 }
618 de->inode = oldinode->i_ino;
619 bh->b_dirt = 1;
620 brelse(bh);
621 iput(dir);
622 oldinode->i_nlink++;
623 oldinode->i_ctime = CURRENT_TIME;
624 oldinode->i_dirt = 1;
625 iput(oldinode);
626 return 0;
627 }
628
629 static int subdir(struct inode * new, struct inode * old)
630 {
631 int ino;
632 int result;
633
634 new->i_count++;
635 result = 0;
636 for (;;) {
637 if (new == old) {
638 result = 1;
639 break;
640 }
641 if (new->i_dev != old->i_dev)
642 break;
643 ino = new->i_ino;
644 if (minix_lookup(new,"..",2,&new))
645 break;
646 if (new->i_ino == ino)
647 break;
648 }
649 iput(new);
650 return result;
651 }
652
653 #define PARENT_INO(buffer) \
654 (((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode)
655
656
657
658
659
660
661
662
663
664
665
666 static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
667 struct inode * new_dir, const char * new_name, int new_len)
668 {
669 struct inode * old_inode, * new_inode;
670 struct buffer_head * old_bh, * new_bh, * dir_bh;
671 struct minix_dir_entry * old_de, * new_de;
672 struct minix_sb_info * info;
673 int retval;
674
675 info = &old_dir->i_sb->u.minix_sb;
676 goto start_up;
677 try_again:
678 brelse(old_bh);
679 brelse(new_bh);
680 brelse(dir_bh);
681 iput(old_inode);
682 iput(new_inode);
683 current->counter = 0;
684 schedule();
685 start_up:
686 old_inode = new_inode = NULL;
687 old_bh = new_bh = dir_bh = NULL;
688 old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
689 retval = -ENOENT;
690 if (!old_bh)
691 goto end_rename;
692 old_inode = iget(old_dir->i_sb, old_de->inode);
693 if (!old_inode)
694 goto end_rename;
695 retval = -EPERM;
696 if ((old_dir->i_mode & S_ISVTX) &&
697 current->euid != old_inode->i_uid &&
698 current->euid != old_dir->i_uid && !suser())
699 goto end_rename;
700 new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
701 if (new_bh) {
702 new_inode = iget(new_dir->i_sb, new_de->inode);
703 if (!new_inode) {
704 brelse(new_bh);
705 new_bh = NULL;
706 }
707 }
708 if (new_inode == old_inode) {
709 retval = 0;
710 goto end_rename;
711 }
712 if (new_inode && S_ISDIR(new_inode->i_mode)) {
713 retval = -EISDIR;
714 if (!S_ISDIR(old_inode->i_mode))
715 goto end_rename;
716 retval = -EINVAL;
717 if (subdir(new_dir, old_inode))
718 goto end_rename;
719 retval = -ENOTEMPTY;
720 if (!empty_dir(new_inode))
721 goto end_rename;
722 retval = -EBUSY;
723 if (new_inode->i_count > 1)
724 goto end_rename;
725 }
726 retval = -EPERM;
727 if (new_inode && (new_dir->i_mode & S_ISVTX) &&
728 current->euid != new_inode->i_uid &&
729 current->euid != new_dir->i_uid && !suser())
730 goto end_rename;
731 if (S_ISDIR(old_inode->i_mode)) {
732 retval = -ENOTDIR;
733 if (new_inode && !S_ISDIR(new_inode->i_mode))
734 goto end_rename;
735 retval = -EINVAL;
736 if (subdir(new_dir, old_inode))
737 goto end_rename;
738 retval = -EIO;
739 dir_bh = minix_bread(old_inode,0,0);
740 if (!dir_bh)
741 goto end_rename;
742 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
743 goto end_rename;
744 retval = -EMLINK;
745 if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
746 goto end_rename;
747 }
748 if (!new_bh) {
749 retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
750 if (retval)
751 goto end_rename;
752 }
753
754 if (new_inode && (new_de->inode != new_inode->i_ino))
755 goto try_again;
756 if (new_de->inode && !new_inode)
757 goto try_again;
758 if (old_de->inode != old_inode->i_ino)
759 goto try_again;
760
761 old_de->inode = 0;
762 new_de->inode = old_inode->i_ino;
763 if (new_inode) {
764 new_inode->i_nlink--;
765 new_inode->i_dirt = 1;
766 }
767 old_bh->b_dirt = 1;
768 new_bh->b_dirt = 1;
769 if (dir_bh) {
770 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
771 dir_bh->b_dirt = 1;
772 old_dir->i_nlink--;
773 old_dir->i_dirt = 1;
774 if (new_inode) {
775 new_inode->i_nlink--;
776 new_inode->i_dirt = 1;
777 } else {
778 new_dir->i_nlink++;
779 new_dir->i_dirt = 1;
780 }
781 }
782 retval = 0;
783 end_rename:
784 brelse(dir_bh);
785 brelse(old_bh);
786 brelse(new_bh);
787 iput(old_inode);
788 iput(new_inode);
789 iput(old_dir);
790 iput(new_dir);
791 return retval;
792 }
793
794
795
796
797
798
799
800
801
802
803 int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
804 struct inode * new_dir, const char * new_name, int new_len)
805 {
806 static struct wait_queue * wait = NULL;
807 static int lock = 0;
808 int result;
809
810 while (lock)
811 sleep_on(&wait);
812 lock = 1;
813 result = do_minix_rename(old_dir, old_name, old_len,
814 new_dir, new_name, new_len);
815 lock = 0;
816 wake_up(&wait);
817 return result;
818 }