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