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 *res_inode=dir;
231 return 0;
232 }
233 iput(dir);
234 return -EISDIR;
235 }
236 dir->i_count++;
237 error = lookup(dir,basename,namelen,&inode);
238 if (error) {
239 if (!(flag & O_CREAT)) {
240 iput(dir);
241 return error;
242 }
243 if (!permission(dir,MAY_WRITE)) {
244 iput(dir);
245 return -EACCES;
246 }
247 if (!dir->i_op || !dir->i_op->create) {
248 iput(dir);
249 return -EACCES;
250 }
251 if (IS_RDONLY(dir)) {
252 iput(dir);
253 return -EROFS;
254 }
255 return dir->i_op->create(dir,basename,namelen,mode,res_inode);
256 }
257 if (flag & O_EXCL) {
258 iput(dir);
259 iput(inode);
260 return -EEXIST;
261 }
262 error = follow_link(dir,inode,flag,mode,&inode);
263 if (error)
264 return error;
265 if (S_ISDIR(inode->i_mode) && (flag & 2)) {
266 iput(inode);
267 return -EPERM;
268 }
269 if (!permission(inode,ACC_MODE(flag))) {
270 iput(inode);
271 return -EACCES;
272 }
273 if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
274 if (IS_NODEV(inode)) {
275 iput(inode);
276 return -EACCES;
277 }
278 } else {
279 if (IS_RDONLY(inode) && (flag & 2)) {
280 iput(inode);
281 return -EROFS;
282 }
283 }
284 if ((inode->i_count > 1) && (flag & 2))
285 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
286 if (!*p)
287 continue;
288 if (inode == (*p)->executable) {
289 iput(inode);
290 return -ETXTBSY;
291 }
292 for (i=0; i < (*p)->numlibraries; i++)
293 if (inode == (*p)->libraries[i].library) {
294 iput(inode);
295 return -ETXTBSY;
296 }
297 }
298 *res_inode = inode;
299 return 0;
300 }
301
302 int do_mknod(const char * filename, int mode, dev_t dev)
303 {
304 const char * basename;
305 int namelen, error;
306 struct inode * dir;
307
308 error = dir_namei(filename,&namelen,&basename, NULL, &dir);
309 if (error)
310 return error;
311 if (!namelen) {
312 iput(dir);
313 return -ENOENT;
314 }
315 if (IS_RDONLY(dir)) {
316 iput(dir);
317 return -EROFS;
318 }
319 if (!permission(dir,MAY_WRITE)) {
320 iput(dir);
321 return -EACCES;
322 }
323 if (!dir->i_op || !dir->i_op->mknod) {
324 iput(dir);
325 return -EPERM;
326 }
327 return dir->i_op->mknod(dir,basename,namelen,mode,dev);
328 }
329
330 int sys_mknod(const char * filename, int mode, dev_t dev)
331 {
332 if (S_ISFIFO(mode) || suser())
333 return do_mknod(filename,mode,dev);
334 return -EPERM;
335 }
336
337 int sys_mkdir(const char * pathname, int mode)
338 {
339 const char * basename;
340 int namelen, error;
341 struct inode * dir;
342
343 error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
344 if (error)
345 return error;
346 if (!namelen) {
347 iput(dir);
348 return -ENOENT;
349 }
350 if (IS_RDONLY(dir)) {
351 iput(dir);
352 return -EROFS;
353 }
354 if (!permission(dir,MAY_WRITE)) {
355 iput(dir);
356 return -EACCES;
357 }
358 if (!dir->i_op || !dir->i_op->mkdir) {
359 iput(dir);
360 return -EPERM;
361 }
362 return dir->i_op->mkdir(dir,basename,namelen,mode);
363 }
364
365 int sys_rmdir(const char * name)
366 {
367 const char * basename;
368 int namelen, error;
369 struct inode * dir;
370
371 error = dir_namei(name,&namelen,&basename,NULL,&dir);
372 if (error)
373 return error;
374 if (!namelen) {
375 iput(dir);
376 return -ENOENT;
377 }
378 if (IS_RDONLY(dir)) {
379 iput(dir);
380 return -EROFS;
381 }
382 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
383 iput(dir);
384 return -EACCES;
385 }
386 if (!dir->i_op || !dir->i_op->rmdir) {
387 iput(dir);
388 return -EPERM;
389 }
390 return dir->i_op->rmdir(dir,basename,namelen);
391 }
392
393 int sys_unlink(const char * name)
394 {
395 const char * basename;
396 int namelen, error;
397 struct inode * dir;
398
399 error = dir_namei(name,&namelen,&basename,NULL,&dir);
400 if (error)
401 return error;
402 if (!namelen) {
403 iput(dir);
404 return -EPERM;
405 }
406 if (IS_RDONLY(dir)) {
407 iput(dir);
408 return -EROFS;
409 }
410 if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
411 iput(dir);
412 return -EACCES;
413 }
414 if (!dir->i_op || !dir->i_op->unlink) {
415 iput(dir);
416 return -EPERM;
417 }
418 return dir->i_op->unlink(dir,basename,namelen);
419 }
420
421 int sys_symlink(const char * oldname, const char * newname)
422 {
423 struct inode * dir;
424 const char * basename;
425 int namelen, error;
426
427 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
428 if (error)
429 return error;
430 if (!namelen) {
431 iput(dir);
432 return -ENOENT;
433 }
434 if (IS_RDONLY(dir)) {
435 iput(dir);
436 return -EROFS;
437 }
438 if (!permission(dir,MAY_WRITE)) {
439 iput(dir);
440 return -EACCES;
441 }
442 if (!dir->i_op || !dir->i_op->symlink) {
443 iput(dir);
444 return -EPERM;
445 }
446 return dir->i_op->symlink(dir,basename,namelen,oldname);
447 }
448
449 int sys_link(const char * oldname, const char * newname)
450 {
451 struct inode * oldinode, * dir;
452 const char * basename;
453 int namelen, error;
454
455 error = namei(oldname, &oldinode);
456 if (error)
457 return error;
458 error = dir_namei(newname,&namelen,&basename,NULL,&dir);
459 if (error) {
460 iput(oldinode);
461 return error;
462 }
463 if (!namelen) {
464 iput(oldinode);
465 iput(dir);
466 return -EPERM;
467 }
468 if (IS_RDONLY(dir)) {
469 iput(oldinode);
470 iput(dir);
471 return -EROFS;
472 }
473 if (dir->i_dev != oldinode->i_dev) {
474 iput(dir);
475 iput(oldinode);
476 return -EXDEV;
477 }
478 if (!permission(dir,MAY_WRITE)) {
479 iput(dir);
480 iput(oldinode);
481 return -EACCES;
482 }
483 if (!dir->i_op || !dir->i_op->link) {
484 iput(dir);
485 iput(oldinode);
486 return -EPERM;
487 }
488 return dir->i_op->link(oldinode, dir, basename, namelen);
489 }
490
491 int sys_rename(const char * oldname, const char * newname)
492 {
493 struct inode * old_dir, * new_dir;
494 const char * old_base, * new_base;
495 int old_len, new_len, error;
496
497 error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
498 if (error)
499 return error;
500 if (!permission(old_dir,MAY_WRITE)) {
501 iput(old_dir);
502 return -EACCES;
503 }
504 if (!old_len || (get_fs_byte(old_base) == '.' &&
505 (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
506 old_len == 2)))) {
507 iput(old_dir);
508 return -EPERM;
509 }
510 error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
511 if (error) {
512 iput(old_dir);
513 return error;
514 }
515 if (!permission(new_dir,MAY_WRITE)) {
516 iput(old_dir);
517 iput(new_dir);
518 return -EACCES;
519 }
520 if (!new_len || (get_fs_byte(new_base) == '.' &&
521 (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
522 new_len == 2)))) {
523 iput(old_dir);
524 iput(new_dir);
525 return -EPERM;
526 }
527 if (new_dir->i_dev != old_dir->i_dev) {
528 iput(old_dir);
529 iput(new_dir);
530 return -EXDEV;
531 }
532 if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
533 iput(old_dir);
534 iput(new_dir);
535 return -EROFS;
536 }
537 if (!old_dir->i_op || !old_dir->i_op->rename) {
538 iput(old_dir);
539 iput(new_dir);
540 return -EPERM;
541 }
542 return old_dir->i_op->rename(old_dir, old_base, old_len,
543 new_dir, new_base, new_len);
544 }