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_writecount++;
140 return 0;
141 }
142
143 void put_write_access(struct inode * inode)
144 {
145 inode->i_writecount--;
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 if (dir->i_sb && dir->i_sb->dq_op)
375 dir->i_sb->dq_op->initialize(dir, -1);
376 error = dir->i_op->create(dir, basename, namelen, mode, res_inode);
377 up(&dir->i_sem);
378 iput(dir);
379 return error;
380 }
381 up(&dir->i_sem);
382 } else
383 error = lookup(dir, basename, namelen, &inode);
384 if (error) {
385 iput(dir);
386 return error;
387 }
388 error = follow_link(dir,inode,flag,mode,&inode);
389 if (error)
390 return error;
391 if (S_ISDIR(inode->i_mode) && (flag & 2)) {
392 iput(inode);
393 return -EISDIR;
394 }
395 if ((error = permission(inode,ACC_MODE(flag))) != 0) {
396 iput(inode);
397 return error;
398 }
399 if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
400
401
402
403
404
405
406
407
408 }
409 else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
410 if (IS_NODEV(inode)) {
411 iput(inode);
412 return -EACCES;
413 }
414 flag &= ~O_TRUNC;
415 } else {
416 if (IS_RDONLY(inode) && (flag & 2)) {
417 iput(inode);
418 return -EROFS;
419 }
420 }
421
422
423
424 if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) {
425 iput(inode);
426 return -EPERM;
427 }
428 if (flag & O_TRUNC) {
429 if ((error = get_write_access(inode))) {
430 iput(inode);
431 return error;
432 }
433
434
435
436 error = locks_verify_locked(inode);
437 if (error) {
438 iput(inode);
439 return error;
440 }
441 if (inode->i_sb && inode->i_sb->dq_op)
442 inode->i_sb->dq_op->initialize(inode, -1);
443
444 error = do_truncate(inode, 0);
445 put_write_access(inode);
446 if (error) {
447 iput(inode);
448 return error;
449 }
450 } else
451 if (flag & FMODE_WRITE)
452 if (inode->i_sb && inode->i_sb->dq_op)
453 inode->i_sb->dq_op->initialize(inode, -1);
454 *res_inode = inode;
455 return 0;
456 }
457
458 int do_mknod(const char * filename, int mode, dev_t dev)
459 {
460 const char * basename;
461 int namelen, error;
462 struct inode * dir;
463
464 mode &= ~current->fs->umask;
465 error = dir_namei(filename, &namelen, &basename, NULL, &dir);
466 if (error)
467 return error;
468 if (!namelen) {
469 iput(dir);
470 return -ENOENT;
471 }
472 if (IS_RDONLY(dir)) {
473 iput(dir);
474 return -EROFS;
475 }
476 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
477 iput(dir);
478 return error;
479 }
480 if (!dir->i_op || !dir->i_op->mknod) {
481 iput(dir);
482 return -EPERM;
483 }
484 dir->i_count++;
485 if (dir->i_sb && dir->i_sb->dq_op)
486 dir->i_sb->dq_op->initialize(dir, -1);
487 down(&dir->i_sem);
488 error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
489 up(&dir->i_sem);
490 iput(dir);
491 return error;
492 }
493
494 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
495 {
496 int error;
497 char * tmp;
498
499 if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
500 return -EPERM;
501 switch (mode & S_IFMT) {
502 case 0:
503 mode |= S_IFREG;
504 break;
505 case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
506 break;
507 default:
508 return -EINVAL;
509 }
510 error = getname(filename,&tmp);
511 if (!error) {
512 error = do_mknod(tmp,mode,dev);
513 putname(tmp);
514 }
515 return error;
516 }
517
518 static int do_mkdir(const char * pathname, int mode)
519 {
520 const char * basename;
521 int namelen, error;
522 struct inode * dir;
523
524 error = dir_namei(pathname, &namelen, &basename, NULL, &dir);
525 if (error)
526 return error;
527 if (!namelen) {
528 iput(dir);
529 return -ENOENT;
530 }
531 if (IS_RDONLY(dir)) {
532 iput(dir);
533 return -EROFS;
534 }
535 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
536 iput(dir);
537 return error;
538 }
539 if (!dir->i_op || !dir->i_op->mkdir) {
540 iput(dir);
541 return -EPERM;
542 }
543 dir->i_count++;
544 if (dir->i_sb && dir->i_sb->dq_op)
545 dir->i_sb->dq_op->initialize(dir, -1);
546 down(&dir->i_sem);
547 error = dir->i_op->mkdir(dir, basename, namelen, mode & 0777 & ~current->fs->umask);
548 up(&dir->i_sem);
549 iput(dir);
550 return error;
551 }
552
553 asmlinkage int sys_mkdir(const char * pathname, int mode)
554 {
555 int error;
556 char * tmp;
557
558 error = getname(pathname,&tmp);
559 if (!error) {
560 error = do_mkdir(tmp,mode);
561 putname(tmp);
562 }
563 return error;
564 }
565
566 static int do_rmdir(const char * name)
567 {
568 const char * basename;
569 int namelen, error;
570 struct inode * dir;
571
572 error = dir_namei(name, &namelen, &basename, NULL, &dir);
573 if (error)
574 return error;
575 if (!namelen) {
576 iput(dir);
577 return -ENOENT;
578 }
579 if (IS_RDONLY(dir)) {
580 iput(dir);
581 return -EROFS;
582 }
583 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
584 iput(dir);
585 return error;
586 }
587
588
589
590 if (IS_APPEND(dir)) {
591 iput(dir);
592 return -EPERM;
593 }
594 if (!dir->i_op || !dir->i_op->rmdir) {
595 iput(dir);
596 return -EPERM;
597 }
598 if (dir->i_sb && dir->i_sb->dq_op)
599 dir->i_sb->dq_op->initialize(dir, -1);
600 return dir->i_op->rmdir(dir,basename,namelen);
601 }
602
603 asmlinkage int sys_rmdir(const char * pathname)
604 {
605 int error;
606 char * tmp;
607
608 error = getname(pathname,&tmp);
609 if (!error) {
610 error = do_rmdir(tmp);
611 putname(tmp);
612 }
613 return error;
614 }
615
616 static int do_unlink(const char * name)
617 {
618 const char * basename;
619 int namelen, error;
620 struct inode * dir;
621
622 error = dir_namei(name, &namelen, &basename, NULL, &dir);
623 if (error)
624 return error;
625 if (!namelen) {
626 iput(dir);
627 return -EPERM;
628 }
629 if (IS_RDONLY(dir)) {
630 iput(dir);
631 return -EROFS;
632 }
633 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
634 iput(dir);
635 return error;
636 }
637
638
639
640 if (IS_APPEND(dir)) {
641 iput(dir);
642 return -EPERM;
643 }
644 if (!dir->i_op || !dir->i_op->unlink) {
645 iput(dir);
646 return -EPERM;
647 }
648 if (dir->i_sb && dir->i_sb->dq_op)
649 dir->i_sb->dq_op->initialize(dir, -1);
650 return dir->i_op->unlink(dir,basename,namelen);
651 }
652
653 asmlinkage int sys_unlink(const char * pathname)
654 {
655 int error;
656 char * tmp;
657
658 error = getname(pathname,&tmp);
659 if (!error) {
660 error = do_unlink(tmp);
661 putname(tmp);
662 }
663 return error;
664 }
665
666 static int do_symlink(const char * oldname, const char * newname)
667 {
668 struct inode * dir;
669 const char * basename;
670 int namelen, error;
671
672 error = dir_namei(newname, &namelen, &basename, NULL, &dir);
673 if (error)
674 return error;
675 if (!namelen) {
676 iput(dir);
677 return -ENOENT;
678 }
679 if (IS_RDONLY(dir)) {
680 iput(dir);
681 return -EROFS;
682 }
683 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
684 iput(dir);
685 return error;
686 }
687 if (!dir->i_op || !dir->i_op->symlink) {
688 iput(dir);
689 return -EPERM;
690 }
691 dir->i_count++;
692 if (dir->i_sb && dir->i_sb->dq_op)
693 dir->i_sb->dq_op->initialize(dir, -1);
694 down(&dir->i_sem);
695 error = dir->i_op->symlink(dir,basename,namelen,oldname);
696 up(&dir->i_sem);
697 iput(dir);
698 return error;
699 }
700
701 asmlinkage int sys_symlink(const char * oldname, const char * newname)
702 {
703 int error;
704 char * from, * to;
705
706 error = getname(oldname,&from);
707 if (!error) {
708 error = getname(newname,&to);
709 if (!error) {
710 error = do_symlink(from,to);
711 putname(to);
712 }
713 putname(from);
714 }
715 return error;
716 }
717
718 static int do_link(struct inode * oldinode, const char * newname)
719 {
720 struct inode * dir;
721 const char * basename;
722 int namelen, error;
723
724 error = dir_namei(newname, &namelen, &basename, NULL, &dir);
725 if (error) {
726 iput(oldinode);
727 return error;
728 }
729 if (!namelen) {
730 iput(oldinode);
731 iput(dir);
732 return -EPERM;
733 }
734 if (IS_RDONLY(dir)) {
735 iput(oldinode);
736 iput(dir);
737 return -EROFS;
738 }
739 if (dir->i_dev != oldinode->i_dev) {
740 iput(dir);
741 iput(oldinode);
742 return -EXDEV;
743 }
744 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
745 iput(dir);
746 iput(oldinode);
747 return error;
748 }
749
750
751
752 if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
753 iput(dir);
754 iput(oldinode);
755 return -EPERM;
756 }
757 if (!dir->i_op || !dir->i_op->link) {
758 iput(dir);
759 iput(oldinode);
760 return -EPERM;
761 }
762 dir->i_count++;
763 if (dir->i_sb && dir->i_sb->dq_op)
764 dir->i_sb->dq_op->initialize(dir, -1);
765 down(&dir->i_sem);
766 error = dir->i_op->link(oldinode, dir, basename, namelen);
767 up(&dir->i_sem);
768 iput(dir);
769 return error;
770 }
771
772 asmlinkage int sys_link(const char * oldname, const char * newname)
773 {
774 int error;
775 char * to;
776 struct inode * oldinode;
777
778 error = lnamei(oldname, &oldinode);
779 if (error)
780 return error;
781 error = getname(newname,&to);
782 if (error) {
783 iput(oldinode);
784 return error;
785 }
786 error = do_link(oldinode,to);
787 putname(to);
788 return error;
789 }
790
791 static int do_rename(const char * oldname, const char * newname)
792 {
793 struct inode * old_dir, * new_dir;
794 const char * old_base, * new_base;
795 int old_len, new_len, error;
796
797 error = dir_namei(oldname, &old_len, &old_base, NULL, &old_dir);
798 if (error)
799 return error;
800 if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) {
801 iput(old_dir);
802 return error;
803 }
804 if (!old_len || (old_base[0] == '.' &&
805 (old_len == 1 || (old_base[1] == '.' &&
806 old_len == 2)))) {
807 iput(old_dir);
808 return -EPERM;
809 }
810 error = dir_namei(newname, &new_len, &new_base, NULL, &new_dir);
811 if (error) {
812 iput(old_dir);
813 return error;
814 }
815 if ((error = permission(new_dir,MAY_WRITE | MAY_EXEC)) != 0){
816 iput(old_dir);
817 iput(new_dir);
818 return error;
819 }
820 if (!new_len || (new_base[0] == '.' &&
821 (new_len == 1 || (new_base[1] == '.' &&
822 new_len == 2)))) {
823 iput(old_dir);
824 iput(new_dir);
825 return -EPERM;
826 }
827 if (new_dir->i_dev != old_dir->i_dev) {
828 iput(old_dir);
829 iput(new_dir);
830 return -EXDEV;
831 }
832 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
833 iput(old_dir);
834 iput(new_dir);
835 return -EROFS;
836 }
837
838
839
840 if (IS_APPEND(old_dir)) {
841 iput(old_dir);
842 iput(new_dir);
843 return -EPERM;
844 }
845 if (!old_dir->i_op || !old_dir->i_op->rename) {
846 iput(old_dir);
847 iput(new_dir);
848 return -EPERM;
849 }
850 new_dir->i_count++;
851 if (new_dir->i_sb && new_dir->i_sb->dq_op)
852 new_dir->i_sb->dq_op->initialize(new_dir, -1);
853 down(&new_dir->i_sem);
854 error = old_dir->i_op->rename(old_dir, old_base, old_len,
855 new_dir, new_base, new_len);
856 up(&new_dir->i_sem);
857 iput(new_dir);
858 return error;
859 }
860
861 asmlinkage int sys_rename(const char * oldname, const char * newname)
862 {
863 int error;
864 char * from, * to;
865
866 error = getname(oldname,&from);
867 if (!error) {
868 error = getname(newname,&to);
869 if (!error) {
870 error = do_rename(from,to);
871 putname(to);
872 }
873 putname(from);
874 }
875 return error;
876 }