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