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