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