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 for(mpnt = (*p)->mm->mmap; mpnt; mpnt = mpnt->vm_next) {
357 if (inode != mpnt->vm_inode)
358 continue;
359 if (mpnt->vm_page_prot & PAGE_RW)
360 continue;
361 if (mpnt->vm_flags & VM_DENYWRITE) {
362 iput(inode);
363 return -ETXTBSY;
364 }
365 }
366 }
367 }
368 if (flag & O_TRUNC) {
369 inode->i_size = 0;
370 if (inode->i_op && inode->i_op->truncate)
371 inode->i_op->truncate(inode);
372 if ((error = notify_change(NOTIFY_SIZE, inode))) {
373 iput(inode);
374 return error;
375 }
376 inode->i_dirt = 1;
377 }
378 *res_inode = inode;
379 return 0;
380 }
381
382 int do_mknod(const char * filename, int mode, dev_t dev)
383 {
384 const char * basename;
385 int namelen, error;
386 struct inode * dir;
387
388 mode &= ~current->fs->umask;
389 error = dir_namei(filename,&namelen,&basename, NULL, &dir);
390 if (error)
391 return error;
392 if (!namelen) {
393 iput(dir);
394 return -ENOENT;
395 }
396 if (IS_RDONLY(dir)) {
397 iput(dir);
398 return -EROFS;
399 }
400 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
401 iput(dir);
402 return -EACCES;
403 }
404 if (!dir->i_op || !dir->i_op->mknod) {
405 iput(dir);
406 return -EPERM;
407 }
408 dir->i_count++;
409 down(&dir->i_sem);
410 error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
411 up(&dir->i_sem);
412 iput(dir);
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 dir->i_count++;
466 down(&dir->i_sem);
467 error = dir->i_op->mkdir(dir,basename,namelen,mode);
468 up(&dir->i_sem);
469 iput(dir);
470 return error;
471 }
472
473 asmlinkage int sys_mkdir(const char * pathname, int mode)
474 {
475 int error;
476 char * tmp;
477
478 error = getname(pathname,&tmp);
479 if (!error) {
480 error = do_mkdir(tmp,mode);
481 putname(tmp);
482 }
483 return error;
484 }
485
486 static int do_rmdir(const char * name)
487 {
488 const char * basename;
489 int namelen, error;
490 struct inode * dir;
491
492 error = dir_namei(name,&namelen,&basename,NULL,&dir);
493 if (error)
494 return error;
495 if (!namelen) {
496 iput(dir);
497 return -ENOENT;
498 }
499 if (IS_RDONLY(dir)) {
500 iput(dir);
501 return -EROFS;
502 }
503 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
504 iput(dir);
505 return -EACCES;
506 }
507 if (!dir->i_op || !dir->i_op->rmdir) {
508 iput(dir);
509 return -EPERM;
510 }
511 return dir->i_op->rmdir(dir,basename,namelen);
512 }
513
514 asmlinkage int sys_rmdir(const char * pathname)
515 {
516 int error;
517 char * tmp;
518
519 error = getname(pathname,&tmp);
520 if (!error) {
521 error = do_rmdir(tmp);
522 putname(tmp);
523 }
524 return error;
525 }
526
527 static int do_unlink(const char * name)
528 {
529 const char * basename;
530 int namelen, error;
531 struct inode * dir;
532
533 error = dir_namei(name,&namelen,&basename,NULL,&dir);
534 if (error)
535 return error;
536 if (!namelen) {
537 iput(dir);
538 return -EPERM;
539 }
540 if (IS_RDONLY(dir)) {
541 iput(dir);
542 return -EROFS;
543 }
544 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
545 iput(dir);
546 return -EACCES;
547 }
548 if (!dir->i_op || !dir->i_op->unlink) {
549 iput(dir);
550 return -EPERM;
551 }
552 return dir->i_op->unlink(dir,basename,namelen);
553 }
554
555 asmlinkage int sys_unlink(const char * pathname)
556 {
557 int error;
558 char * tmp;
559
560 error = getname(pathname,&tmp);
561 if (!error) {
562 error = do_unlink(tmp);
563 putname(tmp);
564 }
565 return error;
566 }
567
568 static int do_symlink(const char * oldname, const char * newname)
569 {
570 struct inode * dir;
571 const char * basename;
572 int namelen, error;
573
574 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
575 if (error)
576 return error;
577 if (!namelen) {
578 iput(dir);
579 return -ENOENT;
580 }
581 if (IS_RDONLY(dir)) {
582 iput(dir);
583 return -EROFS;
584 }
585 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
586 iput(dir);
587 return -EACCES;
588 }
589 if (!dir->i_op || !dir->i_op->symlink) {
590 iput(dir);
591 return -EPERM;
592 }
593 dir->i_count++;
594 down(&dir->i_sem);
595 error = dir->i_op->symlink(dir,basename,namelen,oldname);
596 up(&dir->i_sem);
597 iput(dir);
598 return error;
599 }
600
601 asmlinkage int sys_symlink(const char * oldname, const char * newname)
602 {
603 int error;
604 char * from, * to;
605
606 error = getname(oldname,&from);
607 if (!error) {
608 error = getname(newname,&to);
609 if (!error) {
610 error = do_symlink(from,to);
611 putname(to);
612 }
613 putname(from);
614 }
615 return error;
616 }
617
618 static int do_link(struct inode * oldinode, const char * newname)
619 {
620 struct inode * dir;
621 const char * basename;
622 int namelen, error;
623
624 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
625 if (error) {
626 iput(oldinode);
627 return error;
628 }
629 if (!namelen) {
630 iput(oldinode);
631 iput(dir);
632 return -EPERM;
633 }
634 if (IS_RDONLY(dir)) {
635 iput(oldinode);
636 iput(dir);
637 return -EROFS;
638 }
639 if (dir->i_dev != oldinode->i_dev) {
640 iput(dir);
641 iput(oldinode);
642 return -EXDEV;
643 }
644 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
645 iput(dir);
646 iput(oldinode);
647 return -EACCES;
648 }
649 if (!dir->i_op || !dir->i_op->link) {
650 iput(dir);
651 iput(oldinode);
652 return -EPERM;
653 }
654 dir->i_count++;
655 down(&dir->i_sem);
656 error = dir->i_op->link(oldinode, dir, basename, namelen);
657 up(&dir->i_sem);
658 iput(dir);
659 return error;
660 }
661
662 asmlinkage int sys_link(const char * oldname, const char * newname)
663 {
664 int error;
665 char * to;
666 struct inode * oldinode;
667
668 error = namei(oldname, &oldinode);
669 if (error)
670 return error;
671 error = getname(newname,&to);
672 if (error) {
673 iput(oldinode);
674 return error;
675 }
676 error = do_link(oldinode,to);
677 putname(to);
678 return error;
679 }
680
681 static int do_rename(const char * oldname, const char * newname)
682 {
683 struct inode * old_dir, * new_dir;
684 const char * old_base, * new_base;
685 int old_len, new_len, error;
686
687 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
688 if (error)
689 return error;
690 if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
691 iput(old_dir);
692 return -EACCES;
693 }
694 if (!old_len || (old_base[0] == '.' &&
695 (old_len == 1 || (old_base[1] == '.' &&
696 old_len == 2)))) {
697 iput(old_dir);
698 return -EPERM;
699 }
700 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
701 if (error) {
702 iput(old_dir);
703 return error;
704 }
705 if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
706 iput(old_dir);
707 iput(new_dir);
708 return -EACCES;
709 }
710 if (!new_len || (new_base[0] == '.' &&
711 (new_len == 1 || (new_base[1] == '.' &&
712 new_len == 2)))) {
713 iput(old_dir);
714 iput(new_dir);
715 return -EPERM;
716 }
717 if (new_dir->i_dev != old_dir->i_dev) {
718 iput(old_dir);
719 iput(new_dir);
720 return -EXDEV;
721 }
722 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
723 iput(old_dir);
724 iput(new_dir);
725 return -EROFS;
726 }
727 if (!old_dir->i_op || !old_dir->i_op->rename) {
728 iput(old_dir);
729 iput(new_dir);
730 return -EPERM;
731 }
732 new_dir->i_count++;
733 down(&new_dir->i_sem);
734 error = old_dir->i_op->rename(old_dir, old_base, old_len,
735 new_dir, new_base, new_len);
736 up(&new_dir->i_sem);
737 iput(new_dir);
738 return error;
739 }
740
741 asmlinkage int sys_rename(const char * oldname, const char * newname)
742 {
743 int error;
744 char * from, * to;
745
746 error = getname(oldname,&from);
747 if (!error) {
748 error = getname(newname,&to);
749 if (!error) {
750 error = do_rename(from,to);
751 putname(to);
752 }
753 putname(from);
754 }
755 return error;
756 }