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