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