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