This source file includes following definitions.
- permission
- lookup
- follow_link
- dir_namei
- _namei
- lnamei
- namei
- open_namei
- do_mknod
- sys_mknod
- sys_mkdir
- sys_rmdir
- sys_unlink
- sys_symlink
- sys_link
- 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 permission(struct inode * inode,int mask)
36 {
37 int mode = inode->i_mode;
38
39
40 if (inode->i_dev && !inode->i_nlink)
41 return 0;
42 else if (current->euid == inode->i_uid)
43 mode >>= 6;
44 else if (in_group_p(inode->i_gid))
45 mode >>= 3;
46 if (((mode & mask & 0007) == mask) || suser())
47 return 1;
48 return 0;
49 }
50
51
52
53
54
55
56 int lookup(struct inode * dir,const char * name, int len,
57 struct inode ** result)
58 {
59 struct super_block * sb;
60
61 *result = NULL;
62 if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
63 if (dir == current->root)
64 len = 1;
65 else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
66 sb = dir->i_sb;
67 iput(dir);
68 if (dir = sb->s_covered)
69 dir->i_count++;
70 }
71 }
72 if (!dir)
73 return -ENOENT;
74 if (!dir->i_op || !dir->i_op->lookup) {
75 iput(dir);
76 return -ENOTDIR;
77 }
78 if (!permission(dir,MAY_EXEC)) {
79 iput(dir);
80 return -EACCES;
81 }
82 if (!len) {
83 *result = dir;
84 return 0;
85 }
86 return dir->i_op->lookup(dir,name,len,result);
87 }
88
89 int follow_link(struct inode * dir, struct inode * inode,
90 int flag, int mode, struct inode ** res_inode)
91 {
92 if (!dir || !inode) {
93 iput(dir);
94 iput(inode);
95 *res_inode = NULL;
96 return -ENOENT;
97 }
98 if (!inode->i_op || !inode->i_op->follow_link) {
99 iput(dir);
100 *res_inode = inode;
101 return 0;
102 }
103 return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
104 }
105
106
107
108
109
110
111
112 static int dir_namei(const char * pathname, int * namelen, const char ** name,
113 struct inode * base, struct inode ** res_inode)
114 {
115 char c;
116 const char * thisname;
117 int len,error;
118 struct inode * inode;
119
120 *res_inode = NULL;
121 if (!base) {
122 base = current->pwd;
123 base->i_count++;
124 }
125 if ((c=get_fs_byte(pathname))=='/') {
126 iput(base);
127 base = current->root;
128 pathname++;
129 base->i_count++;
130 }
131 while (1) {
132 thisname = pathname;
133 for(len=0;(c=get_fs_byte(pathname++))&&(c!='/');len++)
134 ;
135 if (!c)
136 break;
137 base->i_count++;
138 error = lookup(base,thisname,len,&inode);
139 if (error) {
140 iput(base);
141 return error;
142 }
143 error = follow_link(base,inode,0,0,&base);
144 if (error)
145 return error;
146 }
147 if (!base->i_op || !base->i_op->lookup) {
148 iput(base);
149 return -ENOTDIR;
150 }
151 *name = thisname;
152 *namelen = len;
153 *res_inode = base;
154 return 0;
155 }
156
157 static int _namei(const char * pathname, struct inode * base,
158 int follow_links, struct inode ** res_inode)
159 {
160 const char * basename;
161 int namelen,error;
162 struct inode * inode;
163
164 *res_inode = NULL;
165 error = dir_namei(pathname,&namelen,&basename,base,&base);
166 if (error)
167 return error;
168 base->i_count++;
169 error = lookup(base,basename,namelen,&inode);
170 if (error) {
171 iput(base);
172 return error;
173 }
174 if (follow_links) {
175 error = follow_link(base,inode,0,0,&inode);
176 if (error)
177 return error;
178 } else
179 iput(base);
180 *res_inode = inode;
181 return 0;
182 }
183
184 int lnamei(const char * pathname, struct inode ** res_inode)
185 {
186 return _namei(pathname,NULL,0,res_inode);
187 }
188
189
190
191
192
193
194
195
196 int namei(const char * pathname, struct inode ** res_inode)
197 {
198 return _namei(pathname,NULL,1,res_inode);
199 }
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 int open_namei(const char * pathname, int flag, int mode,
215 struct inode ** res_inode, struct inode * base)
216 {
217 const char * basename;
218 int namelen,error,i;
219 struct inode * dir, *inode;
220 struct task_struct ** p;
221
222 mode &= 07777 & ~current->umask;
223 mode |= S_IFREG;
224 error = dir_namei(pathname,&namelen,&basename,base,&dir);
225 if (error)
226 return error;
227 if (!namelen) {
228 if (!(flag & 2)) {
229 *res_inode=dir;
230 return 0;
231 }
232 iput(dir);
233 return -EISDIR;
234 }
235 dir->i_count++;
236 error = lookup(dir,basename,namelen,&inode);
237 if (error) {
238 if (!(flag & O_CREAT)) {
239 iput(dir);
240 return error;
241 }
242 if (!permission(dir,MAY_WRITE)) {
243 iput(dir);
244 return -EACCES;
245 }
246 if (!dir->i_op || !dir->i_op->create) {
247 iput(dir);
248 return -EACCES;
249 }
250 if (IS_RDONLY(dir)) {
251 iput(dir);
252 return -EROFS;
253 }
254 return dir->i_op->create(dir,basename,namelen,mode,res_inode);
255 }
256 if (flag & O_EXCL) {
257 iput(dir);
258 iput(inode);
259 return -EEXIST;
260 }
261 if (error = follow_link(dir,inode,flag,mode,&inode))
262 return error;
263 if (S_ISDIR(inode->i_mode) && (flag & 2)) {
264 iput(inode);
265 return -EPERM;
266 }
267 if (!permission(inode,ACC_MODE(flag))) {
268 iput(inode);
269 return -EACCES;
270 }
271 if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
272 if (IS_NODEV(inode)) {
273 iput(inode);
274 return -EACCES;
275 }
276 } else {
277 if (IS_RDONLY(inode) && (flag & 2)) {
278 iput(inode);
279 return -EROFS;
280 }
281 }
282 if ((inode->i_count > 1) && (flag & 2))
283 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
284 if (!*p)
285 continue;
286 if (inode == (*p)->executable) {
287 iput(inode);
288 return -ETXTBSY;
289 }
290 for (i=0; i < (*p)->numlibraries; i++)
291 if (inode == (*p)->libraries[i].library) {
292 iput(inode);
293 return -ETXTBSY;
294 }
295 }
296 *res_inode = inode;
297 return 0;
298 }
299
300 int do_mknod(const char * filename, int mode, dev_t dev)
301 {
302 const char * basename;
303 int namelen, error;
304 struct inode * dir;
305
306 error = dir_namei(filename,&namelen,&basename, NULL, &dir);
307 if (error)
308 return error;
309 if (!namelen) {
310 iput(dir);
311 return -ENOENT;
312 }
313 if (IS_RDONLY(dir)) {
314 iput(dir);
315 return -EROFS;
316 }
317 if (!permission(dir,MAY_WRITE)) {
318 iput(dir);
319 return -EACCES;
320 }
321 if (!dir->i_op || !dir->i_op->mknod) {
322 iput(dir);
323 return -EPERM;
324 }
325 return dir->i_op->mknod(dir,basename,namelen,mode,dev);
326 }
327
328 int sys_mknod(const char * filename, int mode, dev_t dev)
329 {
330 if (S_ISFIFO(mode) || suser())
331 return do_mknod(filename,mode,dev);
332 return -EPERM;
333 }
334
335 int sys_mkdir(const char * pathname, int mode)
336 {
337 const char * basename;
338 int namelen, error;
339 struct inode * dir;
340
341 error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
342 if (error)
343 return error;
344 if (!namelen) {
345 iput(dir);
346 return -ENOENT;
347 }
348 if (IS_RDONLY(dir)) {
349 iput(dir);
350 return -EROFS;
351 }
352 if (!permission(dir,MAY_WRITE)) {
353 iput(dir);
354 return -EACCES;
355 }
356 if (!dir->i_op || !dir->i_op->mkdir) {
357 iput(dir);
358 return -EPERM;
359 }
360 return dir->i_op->mkdir(dir,basename,namelen,mode);
361 }
362
363 int sys_rmdir(const char * name)
364 {
365 const char * basename;
366 int namelen, error;
367 struct inode * dir;
368
369 error = dir_namei(name,&namelen,&basename,NULL,&dir);
370 if (error)
371 return error;
372 if (!namelen) {
373 iput(dir);
374 return -ENOENT;
375 }
376 if (IS_RDONLY(dir)) {
377 iput(dir);
378 return -EROFS;
379 }
380 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
381 iput(dir);
382 return -EACCES;
383 }
384 if (!dir->i_op || !dir->i_op->rmdir) {
385 iput(dir);
386 return -EPERM;
387 }
388 return dir->i_op->rmdir(dir,basename,namelen);
389 }
390
391 int sys_unlink(const char * name)
392 {
393 const char * basename;
394 int namelen, error;
395 struct inode * dir;
396
397 error = dir_namei(name,&namelen,&basename,NULL,&dir);
398 if (error)
399 return error;
400 if (!namelen) {
401 iput(dir);
402 return -EPERM;
403 }
404 if (IS_RDONLY(dir)) {
405 iput(dir);
406 return -EROFS;
407 }
408 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
409 iput(dir);
410 return -EACCES;
411 }
412 if (!dir->i_op || !dir->i_op->unlink) {
413 iput(dir);
414 return -EPERM;
415 }
416 return dir->i_op->unlink(dir,basename,namelen);
417 }
418
419 int sys_symlink(const char * oldname, const char * newname)
420 {
421 struct inode * dir;
422 const char * basename;
423 int namelen, error;
424
425 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
426 if (error)
427 return error;
428 if (!namelen) {
429 iput(dir);
430 return -ENOENT;
431 }
432 if (IS_RDONLY(dir)) {
433 iput(dir);
434 return -EROFS;
435 }
436 if (!permission(dir,MAY_WRITE)) {
437 iput(dir);
438 return -EACCES;
439 }
440 if (!dir->i_op || !dir->i_op->symlink) {
441 iput(dir);
442 return -EPERM;
443 }
444 return dir->i_op->symlink(dir,basename,namelen,oldname);
445 }
446
447 int sys_link(const char * oldname, const char * newname)
448 {
449 struct inode * oldinode, * dir;
450 const char * basename;
451 int namelen, error;
452
453 error = namei(oldname, &oldinode);
454 if (error)
455 return error;
456 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
457 if (error) {
458 iput(oldinode);
459 return error;
460 }
461 if (!namelen) {
462 iput(oldinode);
463 iput(dir);
464 return -EPERM;
465 }
466 if (IS_RDONLY(dir)) {
467 iput(oldinode);
468 iput(dir);
469 return -EROFS;
470 }
471 if (dir->i_dev != oldinode->i_dev) {
472 iput(dir);
473 iput(oldinode);
474 return -EXDEV;
475 }
476 if (!permission(dir,MAY_WRITE)) {
477 iput(dir);
478 iput(oldinode);
479 return -EACCES;
480 }
481 if (!dir->i_op || !dir->i_op->link) {
482 iput(dir);
483 iput(oldinode);
484 return -EPERM;
485 }
486 return dir->i_op->link(oldinode, dir, basename, namelen);
487 }
488
489 int sys_rename(const char * oldname, const char * newname)
490 {
491 struct inode * old_dir, * new_dir;
492 const char * old_base, * new_base;
493 int old_len, new_len, error;
494
495 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
496 if (error)
497 return error;
498 if (!permission(old_dir,MAY_WRITE)) {
499 iput(old_dir);
500 return -EACCES;
501 }
502 if (!old_len || (get_fs_byte(old_base) == '.' &&
503 (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
504 old_len == 2)))) {
505 iput(old_dir);
506 return -EPERM;
507 }
508 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
509 if (error) {
510 iput(old_dir);
511 return error;
512 }
513 if (!permission(new_dir,MAY_WRITE)) {
514 iput(old_dir);
515 iput(new_dir);
516 return -EACCES;
517 }
518 if (!new_len || (get_fs_byte(new_base) == '.' &&
519 (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
520 new_len == 2)))) {
521 iput(old_dir);
522 iput(new_dir);
523 return -EPERM;
524 }
525 if (new_dir->i_dev != old_dir->i_dev) {
526 iput(old_dir);
527 iput(new_dir);
528 return -EXDEV;
529 }
530 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
531 iput(old_dir);
532 iput(new_dir);
533 return -EROFS;
534 }
535 if (!old_dir->i_op || !old_dir->i_op->rename) {
536 iput(old_dir);
537 iput(new_dir);
538 return -EPERM;
539 }
540 return old_dir->i_op->rename(old_dir, old_base, old_len,
541 new_dir, new_base, new_len);
542 }