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