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,i;
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 for (i = 0; i < 5; i++) {
301 dir->i_count++;
302 error = lookup(dir,basename,namelen,&inode);
303 if (!error)
304 break;
305 if (!(flag & O_CREAT)) {
306 iput(dir);
307 return error;
308 }
309 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
310 iput(dir);
311 return -EACCES;
312 }
313 if (!dir->i_op || !dir->i_op->create) {
314 iput(dir);
315 return -EACCES;
316 }
317 if (IS_RDONLY(dir)) {
318 iput(dir);
319 return -EROFS;
320 }
321 dir->i_count++;
322 error = dir->i_op->create(dir,basename,namelen,mode,res_inode);
323 if (error != -EEXIST) {
324 iput(dir);
325 return error;
326 }
327 }
328 if (error) {
329 iput(dir);
330 return error;
331 }
332 if ((flag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
333 iput(dir);
334 iput(inode);
335 return -EEXIST;
336 }
337 error = follow_link(dir,inode,flag,mode,&inode);
338 if (error)
339 return error;
340 if (S_ISDIR(inode->i_mode) && (flag & 2)) {
341 iput(inode);
342 return -EISDIR;
343 }
344 if (!permission(inode,ACC_MODE(flag))) {
345 iput(inode);
346 return -EACCES;
347 }
348 if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
349 if (IS_NODEV(inode)) {
350 iput(inode);
351 return -EACCES;
352 }
353 } else {
354 if (IS_RDONLY(inode) && (flag & 2)) {
355 iput(inode);
356 return -EROFS;
357 }
358 }
359 if ((inode->i_count > 1) && (flag & 2)) {
360 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
361 struct vm_area_struct * mpnt;
362 if (!*p)
363 continue;
364 if (inode == (*p)->executable) {
365 iput(inode);
366 return -ETXTBSY;
367 }
368 for(mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next) {
369 if (mpnt->vm_page_prot & PAGE_RW)
370 continue;
371 if (inode == mpnt->vm_inode) {
372 iput(inode);
373 return -ETXTBSY;
374 }
375 }
376 }
377 }
378 if (flag & O_TRUNC) {
379 inode->i_size = 0;
380 if (inode->i_op && inode->i_op->truncate)
381 inode->i_op->truncate(inode);
382 if ((error = notify_change(NOTIFY_SIZE, inode))) {
383 iput(inode);
384 return error;
385 }
386 inode->i_dirt = 1;
387 }
388 *res_inode = inode;
389 return 0;
390 }
391
392 int do_mknod(const char * filename, int mode, dev_t dev)
393 {
394 const char * basename;
395 int namelen, error;
396 struct inode * dir;
397
398 mode &= ~current->umask;
399 error = dir_namei(filename,&namelen,&basename, NULL, &dir);
400 if (error)
401 return error;
402 if (!namelen) {
403 iput(dir);
404 return -ENOENT;
405 }
406 if (IS_RDONLY(dir)) {
407 iput(dir);
408 return -EROFS;
409 }
410 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
411 iput(dir);
412 return -EACCES;
413 }
414 if (!dir->i_op || !dir->i_op->mknod) {
415 iput(dir);
416 return -EPERM;
417 }
418 return dir->i_op->mknod(dir,basename,namelen,mode,dev);
419 }
420
421 asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
422 {
423 int error;
424 char * tmp;
425
426 if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !suser()))
427 return -EPERM;
428 switch (mode & S_IFMT) {
429 case 0:
430 mode |= S_IFREG;
431 break;
432 case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO:
433 break;
434 default:
435 return -EINVAL;
436 }
437 error = getname(filename,&tmp);
438 if (!error) {
439 error = do_mknod(tmp,mode,dev);
440 putname(tmp);
441 }
442 return error;
443 }
444
445 static int do_mkdir(const char * pathname, int mode)
446 {
447 const char * basename;
448 int namelen, error;
449 struct inode * dir;
450
451 error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
452 if (error)
453 return error;
454 if (!namelen) {
455 iput(dir);
456 return -ENOENT;
457 }
458 if (IS_RDONLY(dir)) {
459 iput(dir);
460 return -EROFS;
461 }
462 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
463 iput(dir);
464 return -EACCES;
465 }
466 if (!dir->i_op || !dir->i_op->mkdir) {
467 iput(dir);
468 return -EPERM;
469 }
470 return dir->i_op->mkdir(dir,basename,namelen,mode);
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 return dir->i_op->symlink(dir,basename,namelen,oldname);
594 }
595
596 asmlinkage int sys_symlink(const char * oldname, const char * newname)
597 {
598 int error;
599 char * from, * to;
600
601 error = getname(oldname,&from);
602 if (!error) {
603 error = getname(newname,&to);
604 if (!error) {
605 error = do_symlink(from,to);
606 putname(to);
607 }
608 putname(from);
609 }
610 return error;
611 }
612
613 static int do_link(struct inode * oldinode, const char * newname)
614 {
615 struct inode * dir;
616 const char * basename;
617 int namelen, error;
618
619 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
620 if (error) {
621 iput(oldinode);
622 return error;
623 }
624 if (!namelen) {
625 iput(oldinode);
626 iput(dir);
627 return -EPERM;
628 }
629 if (IS_RDONLY(dir)) {
630 iput(oldinode);
631 iput(dir);
632 return -EROFS;
633 }
634 if (dir->i_dev != oldinode->i_dev) {
635 iput(dir);
636 iput(oldinode);
637 return -EXDEV;
638 }
639 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
640 iput(dir);
641 iput(oldinode);
642 return -EACCES;
643 }
644 if (!dir->i_op || !dir->i_op->link) {
645 iput(dir);
646 iput(oldinode);
647 return -EPERM;
648 }
649 return dir->i_op->link(oldinode, dir, basename, namelen);
650 }
651
652 asmlinkage int sys_link(const char * oldname, const char * newname)
653 {
654 int error;
655 char * to;
656 struct inode * oldinode;
657
658 error = namei(oldname, &oldinode);
659 if (error)
660 return error;
661 error = getname(newname,&to);
662 if (error) {
663 iput(oldinode);
664 return error;
665 }
666 error = do_link(oldinode,to);
667 putname(to);
668 return error;
669 }
670
671 static int do_rename(const char * oldname, const char * newname)
672 {
673 struct inode * old_dir, * new_dir;
674 const char * old_base, * new_base;
675 int old_len, new_len, error;
676
677 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
678 if (error)
679 return error;
680 if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) {
681 iput(old_dir);
682 return -EACCES;
683 }
684 if (!old_len || (old_base[0] == '.' &&
685 (old_len == 1 || (old_base[1] == '.' &&
686 old_len == 2)))) {
687 iput(old_dir);
688 return -EPERM;
689 }
690 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
691 if (error) {
692 iput(old_dir);
693 return error;
694 }
695 if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) {
696 iput(old_dir);
697 iput(new_dir);
698 return -EACCES;
699 }
700 if (!new_len || (new_base[0] == '.' &&
701 (new_len == 1 || (new_base[1] == '.' &&
702 new_len == 2)))) {
703 iput(old_dir);
704 iput(new_dir);
705 return -EPERM;
706 }
707 if (new_dir->i_dev != old_dir->i_dev) {
708 iput(old_dir);
709 iput(new_dir);
710 return -EXDEV;
711 }
712 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
713 iput(old_dir);
714 iput(new_dir);
715 return -EROFS;
716 }
717 if (!old_dir->i_op || !old_dir->i_op->rename) {
718 iput(old_dir);
719 iput(new_dir);
720 return -EPERM;
721 }
722 return old_dir->i_op->rename(old_dir, old_base, old_len,
723 new_dir, new_base, new_len);
724 }
725
726 asmlinkage int sys_rename(const char * oldname, const char * newname)
727 {
728 int error;
729 char * from, * to;
730
731 error = getname(oldname,&from);
732 if (!error) {
733 error = getname(newname,&to);
734 if (!error) {
735 error = do_rename(from,to);
736 putname(to);
737 }
738 putname(from);
739 }
740 return error;
741 }