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
20 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
21
22
23
24
25
26
27
28 static inline int get_max_filename(unsigned long address)
29 {
30 struct vm_area_struct * vma;
31
32 if (get_fs() == KERNEL_DS)
33 return 0;
34 for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
35 if (!vma)
36 return -EFAULT;
37 if (vma->vm_end > address)
38 break;
39 }
40 if (vma->vm_start > address || !(vma->vm_page_prot & PAGE_USER))
41 return -EFAULT;
42 address = vma->vm_end - address;
43 if (address > PAGE_SIZE)
44 return 0;
45 if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
46 (vma->vm_next->vm_page_prot & PAGE_USER))
47 return 0;
48 return address;
49 }
50
51
52
53
54
55
56
57
58 int getname(const char * filename, char **result)
59 {
60 int i, error;
61 unsigned long page;
62 char * tmp, c;
63
64 i = get_max_filename((unsigned long) filename);
65 if (i < 0)
66 return i;
67 error = -EFAULT;
68 if (!i) {
69 error = -ENAMETOOLONG;
70 i = PAGE_SIZE;
71 }
72 c = get_fs_byte(filename++);
73 if (!c)
74 return -ENOENT;
75 if(!(page = __get_free_page(GFP_KERNEL)))
76 return -ENOMEM;
77 *result = tmp = (char *) page;
78 while (--i) {
79 *(tmp++) = c;
80 c = get_fs_byte(filename++);
81 if (!c) {
82 *tmp = '\0';
83 return 0;
84 }
85 }
86 free_page(page);
87 return error;
88 }
89
90 void putname(char * name)
91 {
92 free_page((unsigned long) name);
93 }
94
95
96
97
98
99
100
101
102
103 int permission(struct inode * inode,int mask)
104 {
105 int mode = inode->i_mode;
106
107 if (inode->i_op && inode->i_op->permission)
108 return inode->i_op->permission(inode, mask);
109 else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
110 return 0;
111 else if (current->fsuid == inode->i_uid)
112 mode >>= 6;
113 else if (in_group_p(inode->i_gid))
114 mode >>= 3;
115 if (((mode & mask & 0007) == mask) || fsuser())
116 return 1;
117 return 0;
118 }
119
120
121
122
123
124
125
126
127 int get_write_access(struct inode * inode)
128 {
129 struct task_struct ** p;
130
131 if ((inode->i_count > 1) && S_ISREG(inode->i_mode))
132 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
133 struct vm_area_struct * mpnt;
134 if (!*p)
135 continue;
136 for(mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
137 if (inode != mpnt->vm_inode)
138 continue;
139 if (mpnt->vm_flags & VM_DENYWRITE)
140 return -ETXTBSY;
141 }
142 }
143 inode->i_wcount++;
144 return 0;
145 }
146
147 void put_write_access(struct inode * inode)
148 {
149 inode->i_wcount--;
150 }
151
152
153
154
155
156
157 int lookup(struct inode * dir,const char * name, int len,
158 struct inode ** result)
159 {
160 struct super_block * sb;
161 int perm;
162
163 *result = NULL;
164 if (!dir)
165 return -ENOENT;
166
167 perm = permission(dir,MAY_EXEC);
168 if (len==2 && name[0] == '.' && name[1] == '.') {
169 if (dir == current->fs->root) {
170 *result = dir;
171 return 0;
172 } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
173 sb = dir->i_sb;
174 iput(dir);
175 dir = sb->s_covered;
176 if (!dir)
177 return -ENOENT;
178 dir->i_count++;
179 }
180 }
181 if (!dir->i_op || !dir->i_op->lookup) {
182 iput(dir);
183 return -ENOTDIR;
184 }
185 if (!perm) {
186 iput(dir);
187 return -EACCES;
188 }
189 if (!len) {
190 *result = dir;
191 return 0;
192 }
193 return dir->i_op->lookup(dir,name,len,result);
194 }
195
196 int follow_link(struct inode * dir, struct inode * inode,
197 int flag, int mode, struct inode ** res_inode)
198 {
199 if (!dir || !inode) {
200 iput(dir);
201 iput(inode);
202 *res_inode = NULL;
203 return -ENOENT;
204 }
205 if (!inode->i_op || !inode->i_op->follow_link) {
206 iput(dir);
207 *res_inode = inode;
208 return 0;
209 }
210 return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
211 }
212
213
214
215
216
217
218
219 static int dir_namei(const char * pathname, int * namelen, const char ** name,
220 struct inode * base, struct inode ** res_inode)
221 {
222 char c;
223 const char * thisname;
224 int len,error;
225 struct inode * inode;
226
227 *res_inode = NULL;
228 if (!base) {
229 base = current->fs->pwd;
230 base->i_count++;
231 }
232 if ((c = *pathname) == '/') {
233 iput(base);
234 base = current->fs->root;
235 pathname++;
236 base->i_count++;
237 }
238 while (1) {
239 thisname = pathname;
240 for(len=0;(c = *(pathname++))&&(c != '/');len++)
241 ;
242 if (!c)
243 break;
244 base->i_count++;
245 error = lookup(base,thisname,len,&inode);
246 if (error) {
247 iput(base);
248 return error;
249 }
250 error = follow_link(base,inode,0,0,&base);
251 if (error)
252 return error;
253 }
254 if (!base->i_op || !base->i_op->lookup) {
255 iput(base);
256 return -ENOTDIR;
257 }
258 *name = thisname;
259 *namelen = len;
260 *res_inode = base;
261 return 0;
262 }
263
264 static int _namei(const char * pathname, struct inode * base,
265 int follow_links, struct inode ** res_inode)
266 {
267 const char * basename;
268 int namelen,error;
269 struct inode * inode;
270
271 *res_inode = NULL;
272 error = dir_namei(pathname,&namelen,&basename,base,&base);
273 if (error)
274 return error;
275 base->i_count++;
276 error = lookup(base,basename,namelen,&inode);
277 if (error) {
278 iput(base);
279 return error;
280 }
281 if (follow_links) {
282 error = follow_link(base,inode,0,0,&inode);
283 if (error)
284 return error;
285 } else
286 iput(base);
287 *res_inode = inode;
288 return 0;
289 }
290
291 int lnamei(const char * pathname, struct inode ** res_inode)
292 {
293 int error;
294 char * tmp;
295
296 error = getname(pathname,&tmp);
297 if (!error) {
298 error = _namei(tmp,NULL,0,res_inode);
299 putname(tmp);
300 }
301 return error;
302 }
303
304
305
306
307
308
309
310
311 int namei(const char * pathname, struct inode ** res_inode)
312 {
313 int error;
314 char * tmp;
315
316 error = getname(pathname,&tmp);
317 if (!error) {
318 error = _namei(tmp,NULL,1,res_inode);
319 putname(tmp);
320 }
321 return error;
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 int open_namei(const char * pathname, int flag, int mode,
338 struct inode ** res_inode, struct inode * base)
339 {
340 const char * basename;
341 int namelen,error;
342 struct inode * dir, *inode;
343
344 mode &= S_IALLUGO & ~current->fs->umask;
345 mode |= S_IFREG;
346 error = dir_namei(pathname,&namelen,&basename,base,&dir);
347 if (error)
348 return error;
349 if (!namelen) {
350 if (flag & 2) {
351 iput(dir);
352 return -EISDIR;
353 }
354
355 if (!permission(dir,ACC_MODE(flag))) {
356 iput(dir);
357 return -EACCES;
358 }
359 *res_inode=dir;
360 return 0;
361 }
362 dir->i_count++;
363 if (flag & O_CREAT) {
364 down(&dir->i_sem);
365 error = lookup(dir,basename,namelen,&inode);
366 if (!error) {
367 if (flag & O_EXCL) {
368 iput(inode);
369 error = -EEXIST;
370 }
371 } else if (!permission(dir,MAY_WRITE | MAY_EXEC))
372 error = -EACCES;
373 else if (!dir->i_op || !dir->i_op->create)
374 error = -EACCES;
375 else if (IS_RDONLY(dir))
376 error = -EROFS;
377 else {
378 dir->i_count++;
379 error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
380 up(&dir->i_sem);
381 iput(dir);
382 return error;
383 }
384 up(&dir->i_sem);
385 } else
386 error = lookup(dir,basename,namelen,&inode);
387 if (error) {
388 iput(dir);
389 return error;
390 }
391 error = follow_link(dir,inode,flag,mode,&inode);
392 if (error)
393 return error;
394 if (S_ISDIR(inode->i_mode) && (flag & 2)) {
395 iput(inode);
396 return -EISDIR;
397 }
398 if (!permission(inode,ACC_MODE(flag))) {
399 iput(inode);
400 return -EACCES;
401 }
402 if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
403 if (IS_NODEV(inode)) {
404 iput(inode);
405 return -EACCES;
406 }
407 flag &= ~O_TRUNC;
408 } else {
409 if (IS_RDONLY(inode) && (flag & 2)) {
410 iput(inode);
411 return -EROFS;
412 }
413 }
414
415
416
417 if (IS_APPEND(inode) && ((flag & 2) && !(flag & O_APPEND))) {
418 iput(inode);
419 return -EPERM;
420 }
421 if (flag & O_TRUNC) {
422 struct iattr newattrs;
423
424 if ((error = get_write_access(inode))) {
425 iput(inode);
426 return error;
427 }
428 newattrs.ia_size = 0;
429 newattrs.ia_valid = ATTR_SIZE;
430 if ((error = notify_change(inode, &newattrs))) {
431 put_write_access(inode);
432 iput(inode);
433 return error;
434 }
435 inode->i_size = 0;
436 if (inode->i_op && inode->i_op->truncate)
437 inode->i_op->truncate(inode);
438 inode->i_dirt = 1;
439 put_write_access(inode);
440 }
441 *res_inode = inode;
442 return 0;
443 }
444
445 int do_mknod(const char * filename, int mode, dev_t dev)
446 {
447 const char * basename;
448 int namelen, error;
449 struct inode * dir;
450
451 mode &= ~current->fs->umask;
452 error = dir_namei(filename,&namelen,&basename, NULL, &dir);
453 if (error)
454 return error;
455 if (!namelen) {
456 iput(dir);
457 return -ENOENT;
458 }
459 if (IS_RDONLY(dir)) {
460 iput(dir);
461 return -EROFS;
462 }
463 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
464 iput(dir);
465 return -EACCES;
466 }
467 if (!dir->i_op || !dir->i_op->mknod) {
468 iput(dir);
469 return -EPERM;
470 }
471 dir->i_count++;
472 down(&dir->i_sem);
473 error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
474 up(&dir->i_sem);
475 iput(dir);
476 return error;
477 }
478
479 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
480 {
481 int error;
482 char * tmp;
483
484 if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
485 return -EPERM;
486 switch (mode & S_IFMT) {
487 case 0:
488 mode |= S_IFREG;
489 break;
490 case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO:
491 break;
492 default:
493 return -EINVAL;
494 }
495 error = getname(filename,&tmp);
496 if (!error) {
497 error = do_mknod(tmp,mode,dev);
498 putname(tmp);
499 }
500 return error;
501 }
502
503 static int do_mkdir(const char * pathname, int mode)
504 {
505 const char * basename;
506 int namelen, error;
507 struct inode * dir;
508
509 error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
510 if (error)
511 return error;
512 if (!namelen) {
513 iput(dir);
514 return -ENOENT;
515 }
516 if (IS_RDONLY(dir)) {
517 iput(dir);
518 return -EROFS;
519 }
520 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
521 iput(dir);
522 return -EACCES;
523 }
524 if (!dir->i_op || !dir->i_op->mkdir) {
525 iput(dir);
526 return -EPERM;
527 }
528 dir->i_count++;
529 down(&dir->i_sem);
530 error = dir->i_op->mkdir(dir, basename, namelen, mode & 0777 & ~current->fs->umask);
531 up(&dir->i_sem);
532 iput(dir);
533 return error;
534 }
535
536 asmlinkage int sys_mkdir(const char * pathname, int mode)
537 {
538 int error;
539 char * tmp;
540
541 error = getname(pathname,&tmp);
542 if (!error) {
543 error = do_mkdir(tmp,mode);
544 putname(tmp);
545 }
546 return error;
547 }
548
549 static int do_rmdir(const char * name)
550 {
551 const char * basename;
552 int namelen, error;
553 struct inode * dir;
554
555 error = dir_namei(name,&namelen,&basename,NULL,&dir);
556 if (error)
557 return error;
558 if (!namelen) {
559 iput(dir);
560 return -ENOENT;
561 }
562 if (IS_RDONLY(dir)) {
563 iput(dir);
564 return -EROFS;
565 }
566 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
567 iput(dir);
568 return -EACCES;
569 }
570
571
572
573 if (IS_APPEND(dir)) {
574 iput(dir);
575 return -EPERM;
576 }
577 if (!dir->i_op || !dir->i_op->rmdir) {
578 iput(dir);
579 return -EPERM;
580 }
581 return dir->i_op->rmdir(dir,basename,namelen);
582 }
583
584 asmlinkage int sys_rmdir(const char * pathname)
585 {
586 int error;
587 char * tmp;
588
589 error = getname(pathname,&tmp);
590 if (!error) {
591 error = do_rmdir(tmp);
592 putname(tmp);
593 }
594 return error;
595 }
596
597 static int do_unlink(const char * name)
598 {
599 const char * basename;
600 int namelen, error;
601 struct inode * dir;
602
603 error = dir_namei(name,&namelen,&basename,NULL,&dir);
604 if (error)
605 return error;
606 if (!namelen) {
607 iput(dir);
608 return -EPERM;
609 }
610 if (IS_RDONLY(dir)) {
611 iput(dir);
612 return -EROFS;
613 }
614 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
615 iput(dir);
616 return -EACCES;
617 }
618
619
620
621 if (IS_APPEND(dir)) {
622 iput(dir);
623 return -EPERM;
624 }
625 if (!dir->i_op || !dir->i_op->unlink) {
626 iput(dir);
627 return -EPERM;
628 }
629 return dir->i_op->unlink(dir,basename,namelen);
630 }
631
632 asmlinkage int sys_unlink(const char * pathname)
633 {
634 int error;
635 char * tmp;
636
637 error = getname(pathname,&tmp);
638 if (!error) {
639 error = do_unlink(tmp);
640 putname(tmp);
641 }
642 return error;
643 }
644
645 static int do_symlink(const char * oldname, const char * newname)
646 {
647 struct inode * dir;
648 const char * basename;
649 int namelen, error;
650
651 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
652 if (error)
653 return error;
654 if (!namelen) {
655 iput(dir);
656 return -ENOENT;
657 }
658 if (IS_RDONLY(dir)) {
659 iput(dir);
660 return -EROFS;
661 }
662 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
663 iput(dir);
664 return -EACCES;
665 }
666 if (!dir->i_op || !dir->i_op->symlink) {
667 iput(dir);
668 return -EPERM;
669 }
670 dir->i_count++;
671 down(&dir->i_sem);
672 error = dir->i_op->symlink(dir,basename,namelen,oldname);
673 up(&dir->i_sem);
674 iput(dir);
675 return error;
676 }
677
678 asmlinkage int sys_symlink(const char * oldname, const char * newname)
679 {
680 int error;
681 char * from, * to;
682
683 error = getname(oldname,&from);
684 if (!error) {
685 error = getname(newname,&to);
686 if (!error) {
687 error = do_symlink(from,to);
688 putname(to);
689 }
690 putname(from);
691 }
692 return error;
693 }
694
695 static int do_link(struct inode * oldinode, const char * newname)
696 {
697 struct inode * dir;
698 const char * basename;
699 int namelen, error;
700
701 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
702 if (error) {
703 iput(oldinode);
704 return error;
705 }
706 if (!namelen) {
707 iput(oldinode);
708 iput(dir);
709 return -EPERM;
710 }
711 if (IS_RDONLY(dir)) {
712 iput(oldinode);
713 iput(dir);
714 return -EROFS;
715 }
716 if (dir->i_dev != oldinode->i_dev) {
717 iput(dir);
718 iput(oldinode);
719 return -EXDEV;
720 }
721 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
722 iput(dir);
723 iput(oldinode);
724 return -EACCES;
725 }
726
727
728
729 if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
730 iput(dir);
731 iput(oldinode);
732 return -EPERM;
733 }
734 if (!dir->i_op || !dir->i_op->link) {
735 iput(dir);
736 iput(oldinode);
737 return -EPERM;
738 }
739 dir->i_count++;
740 down(&dir->i_sem);
741 error = dir->i_op->link(oldinode, dir, basename, namelen);
742 up(&dir->i_sem);
743 iput(dir);
744 return error;
745 }
746
747 asmlinkage int sys_link(const char * oldname, const char * newname)
748 {
749 int error;
750 char * to;
751 struct inode * oldinode;
752
753 error = namei(oldname, &oldinode);
754 if (error)
755 return error;
756 error = getname(newname,&to);
757 if (error) {
758 iput(oldinode);
759 return error;
760 }
761 error = do_link(oldinode,to);
762 putname(to);
763 return error;
764 }
765
766 static int do_rename(const char * oldname, const char * newname)
767 {
768 struct inode * old_dir, * new_dir;
769 const char * old_base, * new_base;
770 int old_len, new_len, error;
771
772 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
773 if (error)
774 return error;
775 if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
776 iput(old_dir);
777 return -EACCES;
778 }
779 if (!old_len || (old_base[0] == '.' &&
780 (old_len == 1 || (old_base[1] == '.' &&
781 old_len == 2)))) {
782 iput(old_dir);
783 return -EPERM;
784 }
785 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
786 if (error) {
787 iput(old_dir);
788 return error;
789 }
790 if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
791 iput(old_dir);
792 iput(new_dir);
793 return -EACCES;
794 }
795 if (!new_len || (new_base[0] == '.' &&
796 (new_len == 1 || (new_base[1] == '.' &&
797 new_len == 2)))) {
798 iput(old_dir);
799 iput(new_dir);
800 return -EPERM;
801 }
802 if (new_dir->i_dev != old_dir->i_dev) {
803 iput(old_dir);
804 iput(new_dir);
805 return -EXDEV;
806 }
807 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
808 iput(old_dir);
809 iput(new_dir);
810 return -EROFS;
811 }
812
813
814
815 if (IS_APPEND(old_dir)) {
816 iput(old_dir);
817 iput(new_dir);
818 return -EPERM;
819 }
820 if (!old_dir->i_op || !old_dir->i_op->rename) {
821 iput(old_dir);
822 iput(new_dir);
823 return -EPERM;
824 }
825 new_dir->i_count++;
826 down(&new_dir->i_sem);
827 error = old_dir->i_op->rename(old_dir, old_base, old_len,
828 new_dir, new_base, new_len);
829 up(&new_dir->i_sem);
830 iput(new_dir);
831 return error;
832 }
833
834 asmlinkage int sys_rename(const char * oldname, const char * newname)
835 {
836 int error;
837 char * from, * to;
838
839 error = getname(oldname,&from);
840 if (!error) {
841 error = getname(newname,&to);
842 if (!error) {
843 error = do_rename(from,to);
844 putname(to);
845 }
846 putname(from);
847 }
848 return error;
849 }