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