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