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->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->pwd;
167 base->i_count++;
168 }
169 if ((c = *pathname) == '/') {
170 iput(base);
171 base = current->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->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)->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->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 down(&dir->i_sem);
411 error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
412 up(&dir->i_sem);
413 return error;
414 }
415
416 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
417 {
418 int error;
419 char * tmp;
420
421 if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !suser()))
422 return -EPERM;
423 switch (mode & S_IFMT) {
424 case 0:
425 mode |= S_IFREG;
426 break;
427 case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO:
428 break;
429 default:
430 return -EINVAL;
431 }
432 error = getname(filename,&tmp);
433 if (!error) {
434 error = do_mknod(tmp,mode,dev);
435 putname(tmp);
436 }
437 return error;
438 }
439
440 static int do_mkdir(const char * pathname, int mode)
441 {
442 const char * basename;
443 int namelen, error;
444 struct inode * dir;
445
446 error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
447 if (error)
448 return error;
449 if (!namelen) {
450 iput(dir);
451 return -ENOENT;
452 }
453 if (IS_RDONLY(dir)) {
454 iput(dir);
455 return -EROFS;
456 }
457 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
458 iput(dir);
459 return -EACCES;
460 }
461 if (!dir->i_op || !dir->i_op->mkdir) {
462 iput(dir);
463 return -EPERM;
464 }
465 down(&dir->i_sem);
466 error = dir->i_op->mkdir(dir,basename,namelen,mode);
467 up(&dir->i_sem);
468 return error;
469 }
470
471 asmlinkage int sys_mkdir(const char * pathname, int mode)
472 {
473 int error;
474 char * tmp;
475
476 error = getname(pathname,&tmp);
477 if (!error) {
478 error = do_mkdir(tmp,mode);
479 putname(tmp);
480 }
481 return error;
482 }
483
484 static int do_rmdir(const char * name)
485 {
486 const char * basename;
487 int namelen, error;
488 struct inode * dir;
489
490 error = dir_namei(name,&namelen,&basename,NULL,&dir);
491 if (error)
492 return error;
493 if (!namelen) {
494 iput(dir);
495 return -ENOENT;
496 }
497 if (IS_RDONLY(dir)) {
498 iput(dir);
499 return -EROFS;
500 }
501 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
502 iput(dir);
503 return -EACCES;
504 }
505 if (!dir->i_op || !dir->i_op->rmdir) {
506 iput(dir);
507 return -EPERM;
508 }
509 return dir->i_op->rmdir(dir,basename,namelen);
510 }
511
512 asmlinkage int sys_rmdir(const char * pathname)
513 {
514 int error;
515 char * tmp;
516
517 error = getname(pathname,&tmp);
518 if (!error) {
519 error = do_rmdir(tmp);
520 putname(tmp);
521 }
522 return error;
523 }
524
525 static int do_unlink(const char * name)
526 {
527 const char * basename;
528 int namelen, error;
529 struct inode * dir;
530
531 error = dir_namei(name,&namelen,&basename,NULL,&dir);
532 if (error)
533 return error;
534 if (!namelen) {
535 iput(dir);
536 return -EPERM;
537 }
538 if (IS_RDONLY(dir)) {
539 iput(dir);
540 return -EROFS;
541 }
542 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
543 iput(dir);
544 return -EACCES;
545 }
546 if (!dir->i_op || !dir->i_op->unlink) {
547 iput(dir);
548 return -EPERM;
549 }
550 return dir->i_op->unlink(dir,basename,namelen);
551 }
552
553 asmlinkage int sys_unlink(const char * pathname)
554 {
555 int error;
556 char * tmp;
557
558 error = getname(pathname,&tmp);
559 if (!error) {
560 error = do_unlink(tmp);
561 putname(tmp);
562 }
563 return error;
564 }
565
566 static int do_symlink(const char * oldname, const char * newname)
567 {
568 struct inode * dir;
569 const char * basename;
570 int namelen, error;
571
572 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
573 if (error)
574 return error;
575 if (!namelen) {
576 iput(dir);
577 return -ENOENT;
578 }
579 if (IS_RDONLY(dir)) {
580 iput(dir);
581 return -EROFS;
582 }
583 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
584 iput(dir);
585 return -EACCES;
586 }
587 if (!dir->i_op || !dir->i_op->symlink) {
588 iput(dir);
589 return -EPERM;
590 }
591 down(&dir->i_sem);
592 error = dir->i_op->symlink(dir,basename,namelen,oldname);
593 up(&dir->i_sem);
594 return error;
595 }
596
597 asmlinkage int sys_symlink(const char * oldname, const char * newname)
598 {
599 int error;
600 char * from, * to;
601
602 error = getname(oldname,&from);
603 if (!error) {
604 error = getname(newname,&to);
605 if (!error) {
606 error = do_symlink(from,to);
607 putname(to);
608 }
609 putname(from);
610 }
611 return error;
612 }
613
614 static int do_link(struct inode * oldinode, const char * newname)
615 {
616 struct inode * dir;
617 const char * basename;
618 int namelen, error;
619
620 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
621 if (error) {
622 iput(oldinode);
623 return error;
624 }
625 if (!namelen) {
626 iput(oldinode);
627 iput(dir);
628 return -EPERM;
629 }
630 if (IS_RDONLY(dir)) {
631 iput(oldinode);
632 iput(dir);
633 return -EROFS;
634 }
635 if (dir->i_dev != oldinode->i_dev) {
636 iput(dir);
637 iput(oldinode);
638 return -EXDEV;
639 }
640 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
641 iput(dir);
642 iput(oldinode);
643 return -EACCES;
644 }
645 if (!dir->i_op || !dir->i_op->link) {
646 iput(dir);
647 iput(oldinode);
648 return -EPERM;
649 }
650 down(&dir->i_sem);
651 error = dir->i_op->link(oldinode, dir, basename, namelen);
652 up(&dir->i_sem);
653 return error;
654 }
655
656 asmlinkage int sys_link(const char * oldname, const char * newname)
657 {
658 int error;
659 char * to;
660 struct inode * oldinode;
661
662 error = namei(oldname, &oldinode);
663 if (error)
664 return error;
665 error = getname(newname,&to);
666 if (error) {
667 iput(oldinode);
668 return error;
669 }
670 error = do_link(oldinode,to);
671 putname(to);
672 return error;
673 }
674
675 static int do_rename(const char * oldname, const char * newname)
676 {
677 struct inode * old_dir, * new_dir;
678 const char * old_base, * new_base;
679 int old_len, new_len, error;
680
681 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
682 if (error)
683 return error;
684 if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
685 iput(old_dir);
686 return -EACCES;
687 }
688 if (!old_len || (old_base[0] == '.' &&
689 (old_len == 1 || (old_base[1] == '.' &&
690 old_len == 2)))) {
691 iput(old_dir);
692 return -EPERM;
693 }
694 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
695 if (error) {
696 iput(old_dir);
697 return error;
698 }
699 if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
700 iput(old_dir);
701 iput(new_dir);
702 return -EACCES;
703 }
704 if (!new_len || (new_base[0] == '.' &&
705 (new_len == 1 || (new_base[1] == '.' &&
706 new_len == 2)))) {
707 iput(old_dir);
708 iput(new_dir);
709 return -EPERM;
710 }
711 if (new_dir->i_dev != old_dir->i_dev) {
712 iput(old_dir);
713 iput(new_dir);
714 return -EXDEV;
715 }
716 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
717 iput(old_dir);
718 iput(new_dir);
719 return -EROFS;
720 }
721 if (!old_dir->i_op || !old_dir->i_op->rename) {
722 iput(old_dir);
723 iput(new_dir);
724 return -EPERM;
725 }
726 down(&new_dir->i_sem);
727 error = old_dir->i_op->rename(old_dir, old_base, old_len,
728 new_dir, new_base, new_len);
729 up(&new_dir->i_sem);
730 return error;
731 }
732
733 asmlinkage int sys_rename(const char * oldname, const char * newname)
734 {
735 int error;
736 char * from, * to;
737
738 error = getname(oldname,&from);
739 if (!error) {
740 error = getname(newname,&to);
741 if (!error) {
742 error = do_rename(from,to);
743 putname(to);
744 }
745 putname(from);
746 }
747 return error;
748 }