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