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