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 (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
129 struct vm_area_struct * mpnt;
130 if (!*p)
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_wcount++;
140 return 0;
141 }
142
143 void put_write_access(struct inode * inode)
144 {
145 inode->i_wcount--;
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 error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
375 up(&dir->i_sem);
376 iput(dir);
377 return error;
378 }
379 up(&dir->i_sem);
380 } else
381 error = lookup(dir,basename,namelen,&inode);
382 if (error) {
383 iput(dir);
384 return error;
385 }
386 error = follow_link(dir,inode,flag,mode,&inode);
387 if (error)
388 return error;
389 if (S_ISDIR(inode->i_mode) && (flag & 2)) {
390 iput(inode);
391 return -EISDIR;
392 }
393 if ((error = permission(inode,ACC_MODE(flag))) != 0) {
394 iput(inode);
395 return error;
396 }
397 if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
398 if (IS_NODEV(inode)) {
399 iput(inode);
400 return -EACCES;
401 }
402 flag &= ~O_TRUNC;
403 } else {
404 if (IS_RDONLY(inode) && (flag & 2)) {
405 iput(inode);
406 return -EROFS;
407 }
408 }
409
410
411
412 if (IS_APPEND(inode) && ((flag & 2) && !(flag & O_APPEND))) {
413 iput(inode);
414 return -EPERM;
415 }
416 if (flag & O_TRUNC) {
417 struct iattr newattrs;
418
419 if ((error = get_write_access(inode))) {
420 iput(inode);
421 return error;
422 }
423 newattrs.ia_size = 0;
424 newattrs.ia_valid = ATTR_SIZE;
425 if ((error = notify_change(inode, &newattrs))) {
426 put_write_access(inode);
427 iput(inode);
428 return error;
429 }
430 inode->i_size = 0;
431 if (inode->i_op && inode->i_op->truncate)
432 inode->i_op->truncate(inode);
433 inode->i_dirt = 1;
434 put_write_access(inode);
435 }
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 down(&dir->i_sem);
468 error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
469 up(&dir->i_sem);
470 iput(dir);
471 return error;
472 }
473
474 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
475 {
476 int error;
477 char * tmp;
478
479 if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser()))
480 return -EPERM;
481 switch (mode & S_IFMT) {
482 case 0:
483 mode |= S_IFREG;
484 break;
485 case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
486 break;
487 default:
488 return -EINVAL;
489 }
490 error = getname(filename,&tmp);
491 if (!error) {
492 error = do_mknod(tmp,mode,dev);
493 putname(tmp);
494 }
495 return error;
496 }
497
498 static int do_mkdir(const char * pathname, int mode)
499 {
500 const char * basename;
501 int namelen, error;
502 struct inode * dir;
503
504 error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
505 if (error)
506 return error;
507 if (!namelen) {
508 iput(dir);
509 return -ENOENT;
510 }
511 if (IS_RDONLY(dir)) {
512 iput(dir);
513 return -EROFS;
514 }
515 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
516 iput(dir);
517 return error;
518 }
519 if (!dir->i_op || !dir->i_op->mkdir) {
520 iput(dir);
521 return -EPERM;
522 }
523 dir->i_count++;
524 down(&dir->i_sem);
525 error = dir->i_op->mkdir(dir, basename, namelen, mode & 0777 & ~current->fs->umask);
526 up(&dir->i_sem);
527 iput(dir);
528 return error;
529 }
530
531 asmlinkage int sys_mkdir(const char * pathname, int mode)
532 {
533 int error;
534 char * tmp;
535
536 error = getname(pathname,&tmp);
537 if (!error) {
538 error = do_mkdir(tmp,mode);
539 putname(tmp);
540 }
541 return error;
542 }
543
544 static int do_rmdir(const char * name)
545 {
546 const char * basename;
547 int namelen, error;
548 struct inode * dir;
549
550 error = dir_namei(name,&namelen,&basename,NULL,&dir);
551 if (error)
552 return error;
553 if (!namelen) {
554 iput(dir);
555 return -ENOENT;
556 }
557 if (IS_RDONLY(dir)) {
558 iput(dir);
559 return -EROFS;
560 }
561 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
562 iput(dir);
563 return error;
564 }
565
566
567
568 if (IS_APPEND(dir)) {
569 iput(dir);
570 return -EPERM;
571 }
572 if (!dir->i_op || !dir->i_op->rmdir) {
573 iput(dir);
574 return -EPERM;
575 }
576 return dir->i_op->rmdir(dir,basename,namelen);
577 }
578
579 asmlinkage int sys_rmdir(const char * pathname)
580 {
581 int error;
582 char * tmp;
583
584 error = getname(pathname,&tmp);
585 if (!error) {
586 error = do_rmdir(tmp);
587 putname(tmp);
588 }
589 return error;
590 }
591
592 static int do_unlink(const char * name)
593 {
594 const char * basename;
595 int namelen, error;
596 struct inode * dir;
597
598 error = dir_namei(name,&namelen,&basename,NULL,&dir);
599 if (error)
600 return error;
601 if (!namelen) {
602 iput(dir);
603 return -EPERM;
604 }
605 if (IS_RDONLY(dir)) {
606 iput(dir);
607 return -EROFS;
608 }
609 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
610 iput(dir);
611 return error;
612 }
613
614
615
616 if (IS_APPEND(dir)) {
617 iput(dir);
618 return -EPERM;
619 }
620 if (!dir->i_op || !dir->i_op->unlink) {
621 iput(dir);
622 return -EPERM;
623 }
624 return dir->i_op->unlink(dir,basename,namelen);
625 }
626
627 asmlinkage int sys_unlink(const char * pathname)
628 {
629 int error;
630 char * tmp;
631
632 error = getname(pathname,&tmp);
633 if (!error) {
634 error = do_unlink(tmp);
635 putname(tmp);
636 }
637 return error;
638 }
639
640 static int do_symlink(const char * oldname, const char * newname)
641 {
642 struct inode * dir;
643 const char * basename;
644 int namelen, error;
645
646 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
647 if (error)
648 return error;
649 if (!namelen) {
650 iput(dir);
651 return -ENOENT;
652 }
653 if (IS_RDONLY(dir)) {
654 iput(dir);
655 return -EROFS;
656 }
657 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
658 iput(dir);
659 return error;
660 }
661 if (!dir->i_op || !dir->i_op->symlink) {
662 iput(dir);
663 return -EPERM;
664 }
665 dir->i_count++;
666 down(&dir->i_sem);
667 error = dir->i_op->symlink(dir,basename,namelen,oldname);
668 up(&dir->i_sem);
669 iput(dir);
670 return error;
671 }
672
673 asmlinkage int sys_symlink(const char * oldname, const char * newname)
674 {
675 int error;
676 char * from, * to;
677
678 error = getname(oldname,&from);
679 if (!error) {
680 error = getname(newname,&to);
681 if (!error) {
682 error = do_symlink(from,to);
683 putname(to);
684 }
685 putname(from);
686 }
687 return error;
688 }
689
690 static int do_link(struct inode * oldinode, const char * newname)
691 {
692 struct inode * dir;
693 const char * basename;
694 int namelen, error;
695
696 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
697 if (error) {
698 iput(oldinode);
699 return error;
700 }
701 if (!namelen) {
702 iput(oldinode);
703 iput(dir);
704 return -EPERM;
705 }
706 if (IS_RDONLY(dir)) {
707 iput(oldinode);
708 iput(dir);
709 return -EROFS;
710 }
711 if (dir->i_dev != oldinode->i_dev) {
712 iput(dir);
713 iput(oldinode);
714 return -EXDEV;
715 }
716 if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
717 iput(dir);
718 iput(oldinode);
719 return error;
720 }
721
722
723
724 if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
725 iput(dir);
726 iput(oldinode);
727 return -EPERM;
728 }
729 if (!dir->i_op || !dir->i_op->link) {
730 iput(dir);
731 iput(oldinode);
732 return -EPERM;
733 }
734 dir->i_count++;
735 down(&dir->i_sem);
736 error = dir->i_op->link(oldinode, dir, basename, namelen);
737 up(&dir->i_sem);
738 iput(dir);
739 return error;
740 }
741
742 asmlinkage int sys_link(const char * oldname, const char * newname)
743 {
744 int error;
745 char * to;
746 struct inode * oldinode;
747
748 error = namei(oldname, &oldinode);
749 if (error)
750 return error;
751 error = getname(newname,&to);
752 if (error) {
753 iput(oldinode);
754 return error;
755 }
756 error = do_link(oldinode,to);
757 putname(to);
758 return error;
759 }
760
761 static int do_rename(const char * oldname, const char * newname)
762 {
763 struct inode * old_dir, * new_dir;
764 const char * old_base, * new_base;
765 int old_len, new_len, error;
766
767 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
768 if (error)
769 return error;
770 if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) {
771 iput(old_dir);
772 return error;
773 }
774 if (!old_len || (old_base[0] == '.' &&
775 (old_len == 1 || (old_base[1] == '.' &&
776 old_len == 2)))) {
777 iput(old_dir);
778 return -EPERM;
779 }
780 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
781 if (error) {
782 iput(old_dir);
783 return error;
784 }
785 if ((error = permission(new_dir,MAY_WRITE | MAY_EXEC)) != 0){
786 iput(old_dir);
787 iput(new_dir);
788 return error;
789 }
790 if (!new_len || (new_base[0] == '.' &&
791 (new_len == 1 || (new_base[1] == '.' &&
792 new_len == 2)))) {
793 iput(old_dir);
794 iput(new_dir);
795 return -EPERM;
796 }
797 if (new_dir->i_dev != old_dir->i_dev) {
798 iput(old_dir);
799 iput(new_dir);
800 return -EXDEV;
801 }
802 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
803 iput(old_dir);
804 iput(new_dir);
805 return -EROFS;
806 }
807
808
809
810 if (IS_APPEND(old_dir)) {
811 iput(old_dir);
812 iput(new_dir);
813 return -EPERM;
814 }
815 if (!old_dir->i_op || !old_dir->i_op->rename) {
816 iput(old_dir);
817 iput(new_dir);
818 return -EPERM;
819 }
820 new_dir->i_count++;
821 down(&new_dir->i_sem);
822 error = old_dir->i_op->rename(old_dir, old_base, old_len,
823 new_dir, new_base, new_len);
824 up(&new_dir->i_sem);
825 iput(new_dir);
826 return error;
827 }
828
829 asmlinkage int sys_rename(const char * oldname, const char * newname)
830 {
831 int error;
832 char * from, * to;
833
834 error = getname(oldname,&from);
835 if (!error) {
836 error = getname(newname,&to);
837 if (!error) {
838 error = do_rename(from,to);
839 putname(to);
840 }
841 putname(from);
842 }
843 return error;
844 }