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