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