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