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 if (dir->i_nlink > 250) {
308 iput(dir);
309 return -EMLINK;
310 }
311 inode = minix_new_inode(dir);
312 if (!inode) {
313 iput(dir);
314 return -ENOSPC;
315 }
316 inode->i_op = &minix_dir_inode_operations;
317 inode->i_size = 2 * sizeof (struct minix_dir_entry);
318 inode->i_mtime = inode->i_atime = CURRENT_TIME;
319 dir_block = minix_bread(inode,0,1);
320 if (!dir_block) {
321 iput(dir);
322 inode->i_nlink--;
323 inode->i_dirt = 1;
324 iput(inode);
325 return -ENOSPC;
326 }
327 de = (struct minix_dir_entry *) dir_block->b_data;
328 de->inode=inode->i_ino;
329 strcpy(de->name,".");
330 de++;
331 de->inode = dir->i_ino;
332 strcpy(de->name,"..");
333 inode->i_nlink = 2;
334 dir_block->b_dirt = 1;
335 brelse(dir_block);
336 inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
337 if (dir->i_mode & S_ISGID)
338 inode->i_mode |= S_ISGID;
339 inode->i_dirt = 1;
340 bh = minix_add_entry(dir,name,len,&de);
341 if (!bh) {
342 iput(dir);
343 inode->i_nlink=0;
344 iput(inode);
345 return -ENOSPC;
346 }
347 de->inode = inode->i_ino;
348 bh->b_dirt = 1;
349 dir->i_nlink++;
350 dir->i_dirt = 1;
351 iput(dir);
352 iput(inode);
353 brelse(bh);
354 return 0;
355 }
356
357
358
359
360 static int empty_dir(struct inode * inode)
361 {
362 int nr, len;
363 struct buffer_head * bh;
364 struct minix_dir_entry * de;
365
366 len = inode->i_size / sizeof (struct minix_dir_entry);
367 if (len<2 || !(bh = minix_bread(inode,0,0))) {
368 printk("warning - bad directory on dev %04x\n",inode->i_dev);
369 return 1;
370 }
371 de = (struct minix_dir_entry *) bh->b_data;
372 if (de[0].inode != inode->i_ino || !de[1].inode ||
373 strcmp(".",de[0].name) || strcmp("..",de[1].name)) {
374 printk("warning - bad directory on dev %04x\n",inode->i_dev);
375 return 1;
376 }
377 nr = 2;
378 de += 2;
379 while (nr<len) {
380 if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
381 brelse(bh);
382 bh = minix_bread(inode,nr/MINIX_DIR_ENTRIES_PER_BLOCK,0);
383 if (!bh) {
384 nr += MINIX_DIR_ENTRIES_PER_BLOCK;
385 continue;
386 }
387 de = (struct minix_dir_entry *) bh->b_data;
388 }
389 if (de->inode) {
390 brelse(bh);
391 return 0;
392 }
393 de++;
394 nr++;
395 }
396 brelse(bh);
397 return 1;
398 }
399
400 int minix_rmdir(struct inode * dir, const char * name, int len)
401 {
402 int retval;
403 struct inode * inode;
404 struct buffer_head * bh;
405 struct minix_dir_entry * de;
406
407 inode = NULL;
408 bh = minix_find_entry(dir,name,len,&de);
409 retval = -ENOENT;
410 if (!bh)
411 goto end_rmdir;
412 retval = -EPERM;
413 if (!(inode = iget(dir->i_sb, de->inode)))
414 goto end_rmdir;
415 if ((dir->i_mode & S_ISVTX) && current->euid &&
416 inode->i_uid != current->euid)
417 goto end_rmdir;
418 if (inode->i_dev != dir->i_dev)
419 goto end_rmdir;
420 if (inode == dir)
421 goto end_rmdir;
422 if (!S_ISDIR(inode->i_mode)) {
423 retval = -ENOTDIR;
424 goto end_rmdir;
425 }
426 if (!empty_dir(inode)) {
427 retval = -ENOTEMPTY;
428 goto end_rmdir;
429 }
430 if (inode->i_count > 1) {
431 retval = -EBUSY;
432 goto end_rmdir;
433 }
434 if (inode->i_nlink != 2)
435 printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
436 de->inode = 0;
437 bh->b_dirt = 1;
438 inode->i_nlink=0;
439 inode->i_dirt=1;
440 dir->i_nlink--;
441 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
442 dir->i_dirt=1;
443 retval = 0;
444 end_rmdir:
445 iput(dir);
446 iput(inode);
447 brelse(bh);
448 return retval;
449 }
450
451 int minix_unlink(struct inode * dir, const char * name, int len)
452 {
453 int retval;
454 struct inode * inode;
455 struct buffer_head * bh;
456 struct minix_dir_entry * de;
457
458 repeat:
459 retval = -ENOENT;
460 inode = NULL;
461 bh = minix_find_entry(dir,name,len,&de);
462 if (!bh)
463 goto end_unlink;
464 if (!(inode = iget(dir->i_sb, de->inode)))
465 goto end_unlink;
466 if (de->inode != inode->i_ino) {
467 iput(inode);
468 brelse(bh);
469 current->counter = 0;
470 schedule();
471 goto repeat;
472 }
473 retval = -EPERM;
474 if ((dir->i_mode & S_ISVTX) && !suser() &&
475 current->euid != inode->i_uid &&
476 current->euid != dir->i_uid)
477 goto end_unlink;
478 if (S_ISDIR(inode->i_mode))
479 goto end_unlink;
480 if (!inode->i_nlink) {
481 printk("Deleting nonexistent file (%04x:%d), %d\n",
482 inode->i_dev,inode->i_ino,inode->i_nlink);
483 inode->i_nlink=1;
484 }
485 de->inode = 0;
486 bh->b_dirt = 1;
487 dir->i_ctime = dir->i_mtime = CURRENT_TIME;
488 dir->i_dirt = 1;
489 inode->i_nlink--;
490 inode->i_ctime = CURRENT_TIME;
491 inode->i_dirt = 1;
492 retval = 0;
493 end_unlink:
494 brelse(bh);
495 iput(inode);
496 iput(dir);
497 return retval;
498 }
499
500 int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
501 {
502 struct minix_dir_entry * de;
503 struct inode * inode = NULL;
504 struct buffer_head * bh = NULL, * name_block = NULL;
505 int i;
506 char c;
507
508 if (!(inode = minix_new_inode(dir))) {
509 iput(dir);
510 return -ENOSPC;
511 }
512 inode->i_mode = S_IFLNK | 0777;
513 inode->i_op = &minix_symlink_inode_operations;
514 name_block = minix_bread(inode,0,1);
515 if (!name_block) {
516 iput(dir);
517 inode->i_nlink--;
518 inode->i_dirt = 1;
519 iput(inode);
520 return -ENOSPC;
521 }
522 i = 0;
523 while (i < 1023 && (c=get_fs_byte(symname++)))
524 name_block->b_data[i++] = c;
525 name_block->b_data[i] = 0;
526 name_block->b_dirt = 1;
527 brelse(name_block);
528 inode->i_size = i;
529 inode->i_dirt = 1;
530 bh = minix_find_entry(dir,name,len,&de);
531 if (bh) {
532 inode->i_nlink--;
533 inode->i_dirt = 1;
534 iput(inode);
535 brelse(bh);
536 iput(dir);
537 return -EEXIST;
538 }
539 bh = minix_add_entry(dir,name,len,&de);
540 if (!bh) {
541 inode->i_nlink--;
542 inode->i_dirt = 1;
543 iput(inode);
544 iput(dir);
545 return -ENOSPC;
546 }
547 de->inode = inode->i_ino;
548 bh->b_dirt = 1;
549 brelse(bh);
550 iput(dir);
551 iput(inode);
552 return 0;
553 }
554
555 int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
556 {
557 struct minix_dir_entry * de;
558 struct buffer_head * bh;
559
560 if (S_ISDIR(oldinode->i_mode)) {
561 iput(oldinode);
562 iput(dir);
563 return -EPERM;
564 }
565 if (oldinode->i_nlink > 126) {
566 iput(oldinode);
567 iput(dir);
568 return -EMLINK;
569 }
570 bh = minix_find_entry(dir,name,len,&de);
571 if (bh) {
572 brelse(bh);
573 iput(dir);
574 iput(oldinode);
575 return -EEXIST;
576 }
577 bh = minix_add_entry(dir,name,len,&de);
578 if (!bh) {
579 iput(dir);
580 iput(oldinode);
581 return -ENOSPC;
582 }
583 de->inode = oldinode->i_ino;
584 bh->b_dirt = 1;
585 brelse(bh);
586 iput(dir);
587 oldinode->i_nlink++;
588 oldinode->i_ctime = CURRENT_TIME;
589 oldinode->i_dirt = 1;
590 iput(oldinode);
591 return 0;
592 }
593
594 static int subdir(struct inode * new, struct inode * old)
595 {
596 unsigned short fs;
597 int ino;
598 int result;
599
600 __asm__("mov %%fs,%0":"=r" (fs));
601 __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
602 new->i_count++;
603 result = 0;
604 for (;;) {
605 if (new == old) {
606 result = 1;
607 break;
608 }
609 if (new->i_dev != old->i_dev)
610 break;
611 ino = new->i_ino;
612 if (minix_lookup(new,"..",2,&new))
613 break;
614 if (new->i_ino == ino)
615 break;
616 }
617 iput(new);
618 __asm__("mov %0,%%fs"::"r" (fs));
619 return result;
620 }
621
622 #define PARENT_INO(buffer) \
623 (((struct minix_dir_entry *) (buffer))[1].inode)
624
625 #define PARENT_NAME(buffer) \
626 (((struct minix_dir_entry *) (buffer))[1].name)
627
628
629
630
631
632
633
634
635
636
637
638 static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
639 struct inode * new_dir, const char * new_name, int new_len)
640 {
641 struct inode * old_inode, * new_inode;
642 struct buffer_head * old_bh, * new_bh, * dir_bh;
643 struct minix_dir_entry * old_de, * new_de;
644 int retval;
645
646 goto start_up;
647 try_again:
648 brelse(old_bh);
649 brelse(new_bh);
650 brelse(dir_bh);
651 iput(old_inode);
652 iput(new_inode);
653 current->counter = 0;
654 schedule();
655 start_up:
656 old_inode = new_inode = NULL;
657 old_bh = new_bh = dir_bh = NULL;
658 old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
659 retval = -ENOENT;
660 if (!old_bh)
661 goto end_rename;
662 old_inode = iget(old_dir->i_sb, old_de->inode);
663 if (!old_inode)
664 goto end_rename;
665 retval = -EPERM;
666 if ((old_dir->i_mode & S_ISVTX) &&
667 current->euid != old_inode->i_uid &&
668 current->euid != old_dir->i_uid && !suser())
669 goto end_rename;
670 new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
671 if (new_bh) {
672 new_inode = iget(new_dir->i_sb, new_de->inode);
673 if (!new_inode) {
674 brelse(new_bh);
675 new_bh = NULL;
676 }
677 }
678 if (new_inode == old_inode) {
679 retval = 0;
680 goto end_rename;
681 }
682 if (new_inode && S_ISDIR(new_inode->i_mode)) {
683 retval = -EEXIST;
684 goto end_rename;
685 }
686 retval = -EPERM;
687 if (new_inode && (new_dir->i_mode & S_ISVTX) &&
688 current->euid != new_inode->i_uid &&
689 current->euid != new_dir->i_uid && !suser())
690 goto end_rename;
691 if (S_ISDIR(old_inode->i_mode)) {
692 retval = -EEXIST;
693 if (new_bh)
694 goto end_rename;
695 retval = -EACCES;
696 if (!permission(old_inode, MAY_WRITE))
697 goto end_rename;
698 retval = -EINVAL;
699 if (subdir(new_dir, old_inode))
700 goto end_rename;
701 retval = -EIO;
702 dir_bh = minix_bread(old_inode,0,0);
703 if (!dir_bh)
704 goto end_rename;
705 if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
706 goto end_rename;
707 retval = -EMLINK;
708 if (new_dir->i_nlink > 250)
709 goto end_rename;
710 }
711 if (!new_bh)
712 new_bh = minix_add_entry(new_dir,new_name,new_len,&new_de);
713 retval = -ENOSPC;
714 if (!new_bh)
715 goto end_rename;
716
717 if (new_inode && (new_de->inode != new_inode->i_ino))
718 goto try_again;
719 if (new_de->inode && !new_inode)
720 goto try_again;
721 if (old_de->inode != old_inode->i_ino)
722 goto try_again;
723
724 old_de->inode = 0;
725 new_de->inode = old_inode->i_ino;
726 if (new_inode) {
727 new_inode->i_nlink--;
728 new_inode->i_dirt = 1;
729 }
730 old_bh->b_dirt = 1;
731 new_bh->b_dirt = 1;
732 if (dir_bh) {
733 PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
734 dir_bh->b_dirt = 1;
735 old_dir->i_nlink--;
736 new_dir->i_nlink++;
737 old_dir->i_dirt = 1;
738 new_dir->i_dirt = 1;
739 }
740 retval = 0;
741 end_rename:
742 brelse(dir_bh);
743 brelse(old_bh);
744 brelse(new_bh);
745 iput(old_inode);
746 iput(new_inode);
747 iput(old_dir);
748 iput(new_dir);
749 return retval;
750 }
751
752
753
754
755
756
757
758
759
760
761 int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
762 struct inode * new_dir, const char * new_name, int new_len)
763 {
764 static struct wait_queue * wait = NULL;
765 static int lock = 0;
766 int result;
767
768 while (lock)
769 sleep_on(&wait);
770 lock = 1;
771 result = do_minix_rename(old_dir, old_name, old_len,
772 new_dir, new_name, new_len);
773 lock = 0;
774 wake_up(&wait);
775 return result;
776 }