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