This source file includes following definitions.
- get_max_filename
- getname
- putname
- permission
- lookup
- follow_link
- dir_namei
- _namei
- lnamei
- namei
- open_namei
- do_mknod
- sys_mknod
- do_mkdir
- sys_mkdir
- do_rmdir
- sys_rmdir
- do_unlink
- sys_unlink
- do_symlink
- sys_symlink
- do_link
- sys_link
- do_rename
- sys_rename
1
2
3
4
5
6
7
8
9
10
11 #include <asm/segment.h>
12
13 #include <linux/errno.h>
14 #include <linux/sched.h>
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/fcntl.h>
18 #include <linux/stat.h>
19
20 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
21
22
23
24
25
26
27
28 static inline int get_max_filename(unsigned long address)
29 {
30 struct vm_area_struct * vma;
31
32 if (get_fs() == KERNEL_DS)
33 return 0;
34 for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
35 if (!vma)
36 return -EFAULT;
37 if (vma->vm_end > address)
38 break;
39 }
40 if (vma->vm_start > address || !(vma->vm_page_prot & PAGE_USER))
41 return -EFAULT;
42 address = vma->vm_end - address;
43 if (address > PAGE_SIZE)
44 return 0;
45 if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
46 (vma->vm_next->vm_page_prot & PAGE_USER))
47 return 0;
48 return address;
49 }
50
51
52
53
54
55
56
57
58 int getname(const char * filename, char **result)
59 {
60 int i, error;
61 unsigned long page;
62 char * tmp, c;
63
64 i = get_max_filename((unsigned long) filename);
65 if (i < 0)
66 return i;
67 error = -EFAULT;
68 if (!i) {
69 error = -ENAMETOOLONG;
70 i = PAGE_SIZE;
71 }
72 c = get_fs_byte(filename++);
73 if (!c)
74 return -ENOENT;
75 if(!(page = __get_free_page(GFP_KERNEL)))
76 return -ENOMEM;
77 *result = tmp = (char *) page;
78 while (--i) {
79 *(tmp++) = c;
80 c = get_fs_byte(filename++);
81 if (!c) {
82 *tmp = '\0';
83 return 0;
84 }
85 }
86 free_page(page);
87 return error;
88 }
89
90 void putname(char * name)
91 {
92 free_page((unsigned long) name);
93 }
94
95
96
97
98
99
100
101
102
103 int permission(struct inode * inode,int mask)
104 {
105 int mode = inode->i_mode;
106
107 if (inode->i_op && inode->i_op->permission)
108 return inode->i_op->permission(inode, mask);
109 else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
110 return 0;
111 else if (current->fsuid == inode->i_uid)
112 mode >>= 6;
113 else if (in_group_p(inode->i_gid))
114 mode >>= 3;
115 if (((mode & mask & 0007) == mask) || fsuser())
116 return 1;
117 return 0;
118 }
119
120
121
122
123
124
125 int lookup(struct inode * dir,const char * name, int len,
126 struct inode ** result)
127 {
128 struct super_block * sb;
129 int perm;
130
131 *result = NULL;
132 if (!dir)
133 return -ENOENT;
134
135 perm = permission(dir,MAY_EXEC);
136 if (len==2 && name[0] == '.' && name[1] == '.') {
137 if (dir == current->fs->root) {
138 *result = dir;
139 return 0;
140 } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
141 sb = dir->i_sb;
142 iput(dir);
143 dir = sb->s_covered;
144 if (!dir)
145 return -ENOENT;
146 dir->i_count++;
147 }
148 }
149 if (!dir->i_op || !dir->i_op->lookup) {
150 iput(dir);
151 return -ENOTDIR;
152 }
153 if (!perm) {
154 iput(dir);
155 return -EACCES;
156 }
157 if (!len) {
158 *result = dir;
159 return 0;
160 }
161 return dir->i_op->lookup(dir,name,len,result);
162 }
163
164 int follow_link(struct inode * dir, struct inode * inode,
165 int flag, int mode, struct inode ** res_inode)
166 {
167 if (!dir || !inode) {
168 iput(dir);
169 iput(inode);
170 *res_inode = NULL;
171 return -ENOENT;
172 }
173 if (!inode->i_op || !inode->i_op->follow_link) {
174 iput(dir);
175 *res_inode = inode;
176 return 0;
177 }
178 return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
179 }
180
181
182
183
184
185
186
187 static int dir_namei(const char * pathname, int * namelen, const char ** name,
188 struct inode * base, struct inode ** res_inode)
189 {
190 char c;
191 const char * thisname;
192 int len,error;
193 struct inode * inode;
194
195 *res_inode = NULL;
196 if (!base) {
197 base = current->fs->pwd;
198 base->i_count++;
199 }
200 if ((c = *pathname) == '/') {
201 iput(base);
202 base = current->fs->root;
203 pathname++;
204 base->i_count++;
205 }
206 while (1) {
207 thisname = pathname;
208 for(len=0;(c = *(pathname++))&&(c != '/');len++)
209 ;
210 if (!c)
211 break;
212 base->i_count++;
213 error = lookup(base,thisname,len,&inode);
214 if (error) {
215 iput(base);
216 return error;
217 }
218 error = follow_link(base,inode,0,0,&base);
219 if (error)
220 return error;
221 }
222 if (!base->i_op || !base->i_op->lookup) {
223 iput(base);
224 return -ENOTDIR;
225 }
226 *name = thisname;
227 *namelen = len;
228 *res_inode = base;
229 return 0;
230 }
231
232 static int _namei(const char * pathname, struct inode * base,
233 int follow_links, struct inode ** res_inode)
234 {
235 const char * basename;
236 int namelen,error;
237 struct inode * inode;
238
239 *res_inode = NULL;
240 error = dir_namei(pathname,&namelen,&basename,base,&base);
241 if (error)
242 return error;
243 base->i_count++;
244 error = lookup(base,basename,namelen,&inode);
245 if (error) {
246 iput(base);
247 return error;
248 }
249 if (follow_links) {
250 error = follow_link(base,inode,0,0,&inode);
251 if (error)
252 return error;
253 } else
254 iput(base);
255 *res_inode = inode;
256 return 0;
257 }
258
259 int lnamei(const char * pathname, struct inode ** res_inode)
260 {
261 int error;
262 char * tmp;
263
264 error = getname(pathname,&tmp);
265 if (!error) {
266 error = _namei(tmp,NULL,0,res_inode);
267 putname(tmp);
268 }
269 return error;
270 }
271
272
273
274
275
276
277
278
279 int namei(const char * pathname, struct inode ** res_inode)
280 {
281 int error;
282 char * tmp;
283
284 error = getname(pathname,&tmp);
285 if (!error) {
286 error = _namei(tmp,NULL,1,res_inode);
287 putname(tmp);
288 }
289 return error;
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 int open_namei(const char * pathname, int flag, int mode,
306 struct inode ** res_inode, struct inode * base)
307 {
308 const char * basename;
309 int namelen,error;
310 struct inode * dir, *inode;
311 struct task_struct ** p;
312
313 mode &= S_IALLUGO & ~current->fs->umask;
314 mode |= S_IFREG;
315 error = dir_namei(pathname,&namelen,&basename,base,&dir);
316 if (error)
317 return error;
318 if (!namelen) {
319 if (flag & 2) {
320 iput(dir);
321 return -EISDIR;
322 }
323
324 if (!permission(dir,ACC_MODE(flag))) {
325 iput(dir);
326 return -EACCES;
327 }
328 *res_inode=dir;
329 return 0;
330 }
331 dir->i_count++;
332 if (flag & O_CREAT) {
333 down(&dir->i_sem);
334 error = lookup(dir,basename,namelen,&inode);
335 if (!error) {
336 if (flag & O_EXCL) {
337 iput(inode);
338 error = -EEXIST;
339 }
340 } else if (!permission(dir,MAY_WRITE | MAY_EXEC))
341 error = -EACCES;
342 else if (!dir->i_op || !dir->i_op->create)
343 error = -EACCES;
344 else if (IS_RDONLY(dir))
345 error = -EROFS;
346 else {
347 dir->i_count++;
348 error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
349 up(&dir->i_sem);
350 iput(dir);
351 return error;
352 }
353 up(&dir->i_sem);
354 } else
355 error = lookup(dir,basename,namelen,&inode);
356 if (error) {
357 iput(dir);
358 return error;
359 }
360 error = follow_link(dir,inode,flag,mode,&inode);
361 if (error)
362 return error;
363 if (S_ISDIR(inode->i_mode) && (flag & 2)) {
364 iput(inode);
365 return -EISDIR;
366 }
367 if (!permission(inode,ACC_MODE(flag))) {
368 iput(inode);
369 return -EACCES;
370 }
371 if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
372 if (IS_NODEV(inode)) {
373 iput(inode);
374 return -EACCES;
375 }
376 } else {
377 if (IS_RDONLY(inode) && (flag & 2)) {
378 iput(inode);
379 return -EROFS;
380 }
381 }
382 if ((inode->i_count > 1) && (flag & 2)) {
383 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
384 struct vm_area_struct * mpnt;
385 if (!*p)
386 continue;
387 for(mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
388 if (inode != mpnt->vm_inode)
389 continue;
390 if (mpnt->vm_page_prot & PAGE_RW)
391 continue;
392 if (mpnt->vm_flags & VM_DENYWRITE) {
393 iput(inode);
394 return -ETXTBSY;
395 }
396 }
397 }
398 }
399
400
401
402 if (IS_APPEND(inode) && ((flag & 2) && !(flag & O_APPEND))) {
403 iput(inode);
404 return -EPERM;
405 }
406 if (flag & O_TRUNC) {
407 inode->i_size = 0;
408 if (inode->i_op && inode->i_op->truncate)
409 inode->i_op->truncate(inode);
410 if ((error = notify_change(NOTIFY_SIZE, inode))) {
411 iput(inode);
412 return error;
413 }
414 inode->i_dirt = 1;
415 }
416 *res_inode = inode;
417 return 0;
418 }
419
420 int do_mknod(const char * filename, int mode, dev_t dev)
421 {
422 const char * basename;
423 int namelen, error;
424 struct inode * dir;
425
426 mode &= ~current->fs->umask;
427 error = dir_namei(filename,&namelen,&basename, NULL, &dir);
428 if (error)
429 return error;
430 if (!namelen) {
431 iput(dir);
432 return -ENOENT;
433 }
434 if (IS_RDONLY(dir)) {
435 iput(dir);
436 return -EROFS;
437 }
438 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
439 iput(dir);
440 return -EACCES;
441 }
442 if (!dir->i_op || !dir->i_op->mknod) {
443 iput(dir);
444 return -EPERM;
445 }
446 dir->i_count++;
447 down(&dir->i_sem);
448 error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
449 up(&dir->i_sem);
450 iput(dir);
451 return error;
452 }
453
454 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
455 {
456 int error;
457 char * tmp;
458
459 if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
460 return -EPERM;
461 switch (mode & S_IFMT) {
462 case 0:
463 mode |= S_IFREG;
464 break;
465 case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO:
466 break;
467 default:
468 return -EINVAL;
469 }
470 error = getname(filename,&tmp);
471 if (!error) {
472 error = do_mknod(tmp,mode,dev);
473 putname(tmp);
474 }
475 return error;
476 }
477
478 static int do_mkdir(const char * pathname, int mode)
479 {
480 const char * basename;
481 int namelen, error;
482 struct inode * dir;
483
484 error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
485 if (error)
486 return error;
487 if (!namelen) {
488 iput(dir);
489 return -ENOENT;
490 }
491 if (IS_RDONLY(dir)) {
492 iput(dir);
493 return -EROFS;
494 }
495 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
496 iput(dir);
497 return -EACCES;
498 }
499 if (!dir->i_op || !dir->i_op->mkdir) {
500 iput(dir);
501 return -EPERM;
502 }
503 dir->i_count++;
504 down(&dir->i_sem);
505 error = dir->i_op->mkdir(dir,basename,namelen,mode);
506 up(&dir->i_sem);
507 iput(dir);
508 return error;
509 }
510
511 asmlinkage int sys_mkdir(const char * pathname, int mode)
512 {
513 int error;
514 char * tmp;
515
516 error = getname(pathname,&tmp);
517 if (!error) {
518 error = do_mkdir(tmp,mode);
519 putname(tmp);
520 }
521 return error;
522 }
523
524 static int do_rmdir(const char * name)
525 {
526 const char * basename;
527 int namelen, error;
528 struct inode * dir;
529
530 error = dir_namei(name,&namelen,&basename,NULL,&dir);
531 if (error)
532 return error;
533 if (!namelen) {
534 iput(dir);
535 return -ENOENT;
536 }
537 if (IS_RDONLY(dir)) {
538 iput(dir);
539 return -EROFS;
540 }
541 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
542 iput(dir);
543 return -EACCES;
544 }
545
546
547
548 if (IS_APPEND(dir)) {
549 iput(dir);
550 return -EPERM;
551 }
552 if (!dir->i_op || !dir->i_op->rmdir) {
553 iput(dir);
554 return -EPERM;
555 }
556 return dir->i_op->rmdir(dir,basename,namelen);
557 }
558
559 asmlinkage int sys_rmdir(const char * pathname)
560 {
561 int error;
562 char * tmp;
563
564 error = getname(pathname,&tmp);
565 if (!error) {
566 error = do_rmdir(tmp);
567 putname(tmp);
568 }
569 return error;
570 }
571
572 static int do_unlink(const char * name)
573 {
574 const char * basename;
575 int namelen, error;
576 struct inode * dir;
577
578 error = dir_namei(name,&namelen,&basename,NULL,&dir);
579 if (error)
580 return error;
581 if (!namelen) {
582 iput(dir);
583 return -EPERM;
584 }
585 if (IS_RDONLY(dir)) {
586 iput(dir);
587 return -EROFS;
588 }
589 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
590 iput(dir);
591 return -EACCES;
592 }
593
594
595
596 if (IS_APPEND(dir)) {
597 iput(dir);
598 return -EPERM;
599 }
600 if (!dir->i_op || !dir->i_op->unlink) {
601 iput(dir);
602 return -EPERM;
603 }
604 return dir->i_op->unlink(dir,basename,namelen);
605 }
606
607 asmlinkage int sys_unlink(const char * pathname)
608 {
609 int error;
610 char * tmp;
611
612 error = getname(pathname,&tmp);
613 if (!error) {
614 error = do_unlink(tmp);
615 putname(tmp);
616 }
617 return error;
618 }
619
620 static int do_symlink(const char * oldname, const char * newname)
621 {
622 struct inode * dir;
623 const char * basename;
624 int namelen, error;
625
626 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
627 if (error)
628 return error;
629 if (!namelen) {
630 iput(dir);
631 return -ENOENT;
632 }
633 if (IS_RDONLY(dir)) {
634 iput(dir);
635 return -EROFS;
636 }
637 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
638 iput(dir);
639 return -EACCES;
640 }
641 if (!dir->i_op || !dir->i_op->symlink) {
642 iput(dir);
643 return -EPERM;
644 }
645 dir->i_count++;
646 down(&dir->i_sem);
647 error = dir->i_op->symlink(dir,basename,namelen,oldname);
648 up(&dir->i_sem);
649 iput(dir);
650 return error;
651 }
652
653 asmlinkage int sys_symlink(const char * oldname, const char * newname)
654 {
655 int error;
656 char * from, * to;
657
658 error = getname(oldname,&from);
659 if (!error) {
660 error = getname(newname,&to);
661 if (!error) {
662 error = do_symlink(from,to);
663 putname(to);
664 }
665 putname(from);
666 }
667 return error;
668 }
669
670 static int do_link(struct inode * oldinode, const char * newname)
671 {
672 struct inode * dir;
673 const char * basename;
674 int namelen, error;
675
676 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
677 if (error) {
678 iput(oldinode);
679 return error;
680 }
681 if (!namelen) {
682 iput(oldinode);
683 iput(dir);
684 return -EPERM;
685 }
686 if (IS_RDONLY(dir)) {
687 iput(oldinode);
688 iput(dir);
689 return -EROFS;
690 }
691 if (dir->i_dev != oldinode->i_dev) {
692 iput(dir);
693 iput(oldinode);
694 return -EXDEV;
695 }
696 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
697 iput(dir);
698 iput(oldinode);
699 return -EACCES;
700 }
701
702
703
704 if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
705 iput(dir);
706 iput(oldinode);
707 return -EPERM;
708 }
709 if (!dir->i_op || !dir->i_op->link) {
710 iput(dir);
711 iput(oldinode);
712 return -EPERM;
713 }
714 dir->i_count++;
715 down(&dir->i_sem);
716 error = dir->i_op->link(oldinode, dir, basename, namelen);
717 up(&dir->i_sem);
718 iput(dir);
719 return error;
720 }
721
722 asmlinkage int sys_link(const char * oldname, const char * newname)
723 {
724 int error;
725 char * to;
726 struct inode * oldinode;
727
728 error = namei(oldname, &oldinode);
729 if (error)
730 return error;
731 error = getname(newname,&to);
732 if (error) {
733 iput(oldinode);
734 return error;
735 }
736 error = do_link(oldinode,to);
737 putname(to);
738 return error;
739 }
740
741 static int do_rename(const char * oldname, const char * newname)
742 {
743 struct inode * old_dir, * new_dir;
744 const char * old_base, * new_base;
745 int old_len, new_len, error;
746
747 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
748 if (error)
749 return error;
750 if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
751 iput(old_dir);
752 return -EACCES;
753 }
754 if (!old_len || (old_base[0] == '.' &&
755 (old_len == 1 || (old_base[1] == '.' &&
756 old_len == 2)))) {
757 iput(old_dir);
758 return -EPERM;
759 }
760 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
761 if (error) {
762 iput(old_dir);
763 return error;
764 }
765 if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
766 iput(old_dir);
767 iput(new_dir);
768 return -EACCES;
769 }
770 if (!new_len || (new_base[0] == '.' &&
771 (new_len == 1 || (new_base[1] == '.' &&
772 new_len == 2)))) {
773 iput(old_dir);
774 iput(new_dir);
775 return -EPERM;
776 }
777 if (new_dir->i_dev != old_dir->i_dev) {
778 iput(old_dir);
779 iput(new_dir);
780 return -EXDEV;
781 }
782 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
783 iput(old_dir);
784 iput(new_dir);
785 return -EROFS;
786 }
787
788
789
790 if (IS_APPEND(old_dir)) {
791 iput(old_dir);
792 iput(new_dir);
793 return -EPERM;
794 }
795 if (!old_dir->i_op || !old_dir->i_op->rename) {
796 iput(old_dir);
797 iput(new_dir);
798 return -EPERM;
799 }
800 new_dir->i_count++;
801 down(&new_dir->i_sem);
802 error = old_dir->i_op->rename(old_dir, old_base, old_len,
803 new_dir, new_base, new_len);
804 up(&new_dir->i_sem);
805 iput(new_dir);
806 return error;
807 }
808
809 asmlinkage int sys_rename(const char * oldname, const char * newname)
810 {
811 int error;
812 char * from, * to;
813
814 error = getname(oldname,&from);
815 if (!error) {
816 error = getname(newname,&to);
817 if (!error) {
818 error = do_rename(from,to);
819 putname(to);
820 }
821 putname(from);
822 }
823 return error;
824 }