This source file includes following definitions.
- permission
- lookup
- follow_link
- dir_namei
- _namei
- lnamei
- namei
- open_namei
- 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 <linux/sched.h>
12 #include <linux/kernel.h>
13 #include <asm/segment.h>
14
15 #include <string.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <const.h>
19 #include <sys/stat.h>
20
21 struct inode * _namei(const char * filename, struct inode * base,
22 int follow_links);
23
24 #define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 int permission(struct inode * inode,int mask)
40 {
41 int mode = inode->i_mode;
42
43
44 if (inode->i_dev && !inode->i_nlink)
45 return 0;
46 else if (current->euid == inode->i_uid)
47 mode >>= 6;
48 else if (in_group_p(inode->i_gid))
49 mode >>= 3;
50 if (((mode & mask & 0007) == mask) || suser())
51 return 1;
52 return 0;
53 }
54
55
56
57
58
59
60 int lookup(struct inode * dir,const char * name, int len,
61 struct inode ** result)
62 {
63 struct super_block * sb;
64
65 *result = NULL;
66 if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
67 if (dir == current->root)
68 len = 1;
69 else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
70 sb = dir->i_sb;
71 iput(dir);
72 if (dir = sb->s_covered)
73 dir->i_count++;
74 }
75 }
76 if (!dir)
77 return -ENOENT;
78 if (!permission(dir,MAY_EXEC)) {
79 iput(dir);
80 return -EACCES;
81 }
82 if (!len) {
83 *result = dir;
84 return 0;
85 }
86 if (!dir->i_op || !dir->i_op->lookup) {
87 iput(dir);
88 return -ENOENT;
89 }
90 return dir->i_op->lookup(dir,name,len,result);
91 }
92
93 struct inode * follow_link(struct inode * dir, struct inode * inode)
94 {
95 if (!dir || !inode) {
96 iput(dir);
97 iput(inode);
98 return NULL;
99 }
100 if (!inode->i_op || !inode->i_op->follow_link) {
101 iput(dir);
102 return inode;
103 }
104 return inode->i_op->follow_link(dir,inode);
105 }
106
107
108
109
110
111
112
113 static struct inode * dir_namei(const char * pathname,
114 int * namelen, const char ** name, struct inode * base)
115 {
116 char c;
117 const char * thisname;
118 int len,error;
119 struct inode * inode;
120
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 NULL;
142 }
143 if (!(base = follow_link(base,inode)))
144 return NULL;
145 }
146 *name = thisname;
147 *namelen = len;
148 return base;
149 }
150
151 struct inode * _namei(const char * pathname, struct inode * base,
152 int follow_links)
153 {
154 const char * basename;
155 int namelen,error;
156 struct inode * inode;
157
158 if (!(base = dir_namei(pathname,&namelen,&basename,base)))
159 return NULL;
160 base->i_count++;
161 error = lookup(base,basename,namelen,&inode);
162 if (error) {
163 iput(base);
164 return NULL;
165 }
166 if (follow_links)
167 inode = follow_link(base,inode);
168 else
169 iput(base);
170 if (inode) {
171 inode->i_atime=CURRENT_TIME;
172 inode->i_dirt=1;
173 }
174 return inode;
175 }
176
177 struct inode * lnamei(const char * pathname)
178 {
179 return _namei(pathname, NULL, 0);
180 }
181
182
183
184
185
186
187
188
189 struct inode * namei(const char * pathname)
190 {
191 return _namei(pathname,NULL,1);
192 }
193
194
195
196
197
198
199 int open_namei(const char * pathname, int flag, int mode,
200 struct inode ** res_inode)
201 {
202 const char * basename;
203 int namelen,error;
204 struct inode * dir, *inode;
205
206 if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
207 flag |= O_WRONLY;
208 mode &= 0777 & ~current->umask;
209 mode |= I_REGULAR;
210 if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
211 return -ENOENT;
212 if (!namelen) {
213 if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
214 *res_inode=dir;
215 return 0;
216 }
217 iput(dir);
218 return -EISDIR;
219 }
220 dir->i_count++;
221 error = lookup(dir,basename,namelen,&inode);
222 if (error) {
223 if (!(flag & O_CREAT)) {
224 iput(dir);
225 return error;
226 }
227 if (!permission(dir,MAY_WRITE)) {
228 iput(dir);
229 return -EACCES;
230 }
231 if (!dir->i_op || !dir->i_op->create) {
232 iput(dir);
233 return -EACCES;
234 }
235 return dir->i_op->create(dir,basename,namelen,mode,res_inode);
236 }
237 if (flag & O_EXCL) {
238 iput(dir);
239 iput(inode);
240 return -EEXIST;
241 }
242 if (!(inode = follow_link(dir,inode)))
243 return -ELOOP;
244 if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
245 !permission(inode,ACC_MODE(flag))) {
246 iput(inode);
247 return -EPERM;
248 }
249 inode->i_atime = CURRENT_TIME;
250 if (flag & O_TRUNC)
251 if (inode->i_op && inode->i_op->truncate)
252 inode->i_op->truncate(inode);
253 *res_inode = inode;
254 return 0;
255 }
256
257 int sys_mknod(const char * filename, int mode, int dev)
258 {
259 const char * basename;
260 int namelen;
261 struct inode * dir;
262
263 if (!suser())
264 return -EPERM;
265 if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
266 return -ENOENT;
267 if (!namelen) {
268 iput(dir);
269 return -ENOENT;
270 }
271 if (!permission(dir,MAY_WRITE)) {
272 iput(dir);
273 return -EACCES;
274 }
275 if (!dir->i_op || !dir->i_op->mknod) {
276 iput(dir);
277 return -EPERM;
278 }
279 return dir->i_op->mknod(dir,basename,namelen,mode,dev);
280 }
281
282 int sys_mkdir(const char * pathname, int mode)
283 {
284 const char * basename;
285 int namelen;
286 struct inode * dir;
287
288 if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
289 return -ENOENT;
290 if (!namelen) {
291 iput(dir);
292 return -ENOENT;
293 }
294 if (!permission(dir,MAY_WRITE)) {
295 iput(dir);
296 return -EACCES;
297 }
298 if (!dir->i_op || !dir->i_op->mkdir) {
299 iput(dir);
300 return -EPERM;
301 }
302 return dir->i_op->mkdir(dir,basename,namelen,mode);
303 }
304
305 int sys_rmdir(const char * name)
306 {
307 const char * basename;
308 int namelen;
309 struct inode * dir;
310
311 if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
312 return -ENOENT;
313 if (!namelen) {
314 iput(dir);
315 return -ENOENT;
316 }
317 if (!permission(dir,MAY_WRITE)) {
318 iput(dir);
319 return -EACCES;
320 }
321 if (!dir->i_op || !dir->i_op->rmdir) {
322 iput(dir);
323 return -EPERM;
324 }
325 return dir->i_op->rmdir(dir,basename,namelen);
326 }
327
328 int sys_unlink(const char * name)
329 {
330 const char * basename;
331 int namelen;
332 struct inode * dir;
333
334 if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
335 return -ENOENT;
336 if (!namelen) {
337 iput(dir);
338 return -EPERM;
339 }
340 if (!permission(dir,MAY_WRITE)) {
341 iput(dir);
342 return -EACCES;
343 }
344 if (!dir->i_op || !dir->i_op->unlink) {
345 iput(dir);
346 return -EPERM;
347 }
348 return dir->i_op->unlink(dir,basename,namelen);
349 }
350
351 int sys_symlink(const char * oldname, const char * newname)
352 {
353 struct inode * dir;
354 const char * basename;
355 int namelen;
356
357 dir = dir_namei(newname,&namelen,&basename, NULL);
358 if (!dir)
359 return -ENOENT;
360 if (!namelen) {
361 iput(dir);
362 return -ENOENT;
363 }
364 if (!permission(dir,MAY_WRITE)) {
365 iput(dir);
366 return -EACCES;
367 }
368 if (!dir->i_op || !dir->i_op->symlink) {
369 iput(dir);
370 return -EPERM;
371 }
372 return dir->i_op->symlink(dir,basename,namelen,oldname);
373 }
374
375 int sys_link(const char * oldname, const char * newname)
376 {
377 struct inode * oldinode, * dir;
378 const char * basename;
379 int namelen;
380
381 oldinode = namei(oldname);
382 if (!oldinode)
383 return -ENOENT;
384 dir = dir_namei(newname,&namelen,&basename, NULL);
385 if (!dir) {
386 iput(oldinode);
387 return -EACCES;
388 }
389 if (!namelen) {
390 iput(oldinode);
391 iput(dir);
392 return -EPERM;
393 }
394 if (dir->i_dev != oldinode->i_dev) {
395 iput(dir);
396 iput(oldinode);
397 return -EXDEV;
398 }
399 if (!permission(dir,MAY_WRITE)) {
400 iput(dir);
401 iput(oldinode);
402 return -EACCES;
403 }
404 if (!dir->i_op || !dir->i_op->link) {
405 iput(dir);
406 iput(oldinode);
407 return -EPERM;
408 }
409 return dir->i_op->link(oldinode, dir, basename, namelen);
410 }
411
412 int sys_rename(const char * oldname, const char * newname)
413 {
414 struct inode * old_dir, * new_dir;
415 const char * old_base, * new_base;
416 int old_len, new_len;
417
418 old_dir = dir_namei(oldname,&old_len,&old_base, NULL);
419 if (!old_dir)
420 return -ENOENT;
421 if (!permission(old_dir,MAY_WRITE)) {
422 iput(old_dir);
423 return -EACCES;
424 }
425 if (!old_len || (get_fs_byte(old_base) == '.' &&
426 (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
427 old_len == 2)))) {
428 iput(old_dir);
429 return -EPERM;
430 }
431 new_dir = dir_namei(newname,&new_len,&new_base, NULL);
432 if (!new_dir) {
433 iput(old_dir);
434 return -ENOENT;
435 }
436 if (!permission(new_dir,MAY_WRITE)) {
437 iput(old_dir);
438 iput(new_dir);
439 return -EACCES;
440 }
441 if (!new_len || (get_fs_byte(new_base) == '.' &&
442 (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
443 new_len == 2)))) {
444 iput(old_dir);
445 iput(new_dir);
446 return -EPERM;
447 }
448 if (new_dir->i_dev != old_dir->i_dev) {
449 iput(old_dir);
450 iput(new_dir);
451 return -EXDEV;
452 }
453 if (!old_dir->i_op || !old_dir->i_op->rename) {
454 iput(old_dir);
455 iput(new_dir);
456 return -EPERM;
457 }
458 return old_dir->i_op->rename(old_dir, old_base, old_len,
459 new_dir, new_base, new_len);
460 }