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