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