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