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