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