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