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 <linux/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_size = 0;
253 inode->i_op->truncate(inode);
254 }
255 *res_inode = inode;
256 return 0;
257 }
258
259 int sys_mknod(const char * filename, int mode, int dev)
260 {
261 const char * basename;
262 int namelen;
263 struct inode * dir;
264
265 if (!suser())
266 return -EPERM;
267 if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
268 return -ENOENT;
269 if (!namelen) {
270 iput(dir);
271 return -ENOENT;
272 }
273 if (!permission(dir,MAY_WRITE)) {
274 iput(dir);
275 return -EACCES;
276 }
277 if (!dir->i_op || !dir->i_op->mknod) {
278 iput(dir);
279 return -EPERM;
280 }
281 return dir->i_op->mknod(dir,basename,namelen,mode,dev);
282 }
283
284 int sys_mkdir(const char * pathname, int mode)
285 {
286 const char * basename;
287 int namelen;
288 struct inode * dir;
289
290 if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
291 return -ENOENT;
292 if (!namelen) {
293 iput(dir);
294 return -ENOENT;
295 }
296 if (!permission(dir,MAY_WRITE)) {
297 iput(dir);
298 return -EACCES;
299 }
300 if (!dir->i_op || !dir->i_op->mkdir) {
301 iput(dir);
302 return -EPERM;
303 }
304 return dir->i_op->mkdir(dir,basename,namelen,mode);
305 }
306
307 int sys_rmdir(const char * name)
308 {
309 const char * basename;
310 int namelen;
311 struct inode * dir;
312
313 if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
314 return -ENOENT;
315 if (!namelen) {
316 iput(dir);
317 return -ENOENT;
318 }
319 if (!permission(dir,MAY_WRITE)) {
320 iput(dir);
321 return -EACCES;
322 }
323 if (!dir->i_op || !dir->i_op->rmdir) {
324 iput(dir);
325 return -EPERM;
326 }
327 return dir->i_op->rmdir(dir,basename,namelen);
328 }
329
330 int sys_unlink(const char * name)
331 {
332 const char * basename;
333 int namelen;
334 struct inode * dir;
335
336 if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
337 return -ENOENT;
338 if (!namelen) {
339 iput(dir);
340 return -EPERM;
341 }
342 if (!permission(dir,MAY_WRITE)) {
343 iput(dir);
344 return -EACCES;
345 }
346 if (!dir->i_op || !dir->i_op->unlink) {
347 iput(dir);
348 return -EPERM;
349 }
350 return dir->i_op->unlink(dir,basename,namelen);
351 }
352
353 int sys_symlink(const char * oldname, const char * newname)
354 {
355 struct inode * dir;
356 const char * basename;
357 int namelen;
358
359 dir = dir_namei(newname,&namelen,&basename, NULL);
360 if (!dir)
361 return -ENOENT;
362 if (!namelen) {
363 iput(dir);
364 return -ENOENT;
365 }
366 if (!permission(dir,MAY_WRITE)) {
367 iput(dir);
368 return -EACCES;
369 }
370 if (!dir->i_op || !dir->i_op->symlink) {
371 iput(dir);
372 return -EPERM;
373 }
374 return dir->i_op->symlink(dir,basename,namelen,oldname);
375 }
376
377 int sys_link(const char * oldname, const char * newname)
378 {
379 struct inode * oldinode, * dir;
380 const char * basename;
381 int namelen;
382
383 oldinode = namei(oldname);
384 if (!oldinode)
385 return -ENOENT;
386 dir = dir_namei(newname,&namelen,&basename, NULL);
387 if (!dir) {
388 iput(oldinode);
389 return -EACCES;
390 }
391 if (!namelen) {
392 iput(oldinode);
393 iput(dir);
394 return -EPERM;
395 }
396 if (dir->i_dev != oldinode->i_dev) {
397 iput(dir);
398 iput(oldinode);
399 return -EXDEV;
400 }
401 if (!permission(dir,MAY_WRITE)) {
402 iput(dir);
403 iput(oldinode);
404 return -EACCES;
405 }
406 if (!dir->i_op || !dir->i_op->link) {
407 iput(dir);
408 iput(oldinode);
409 return -EPERM;
410 }
411 return dir->i_op->link(oldinode, dir, basename, namelen);
412 }
413
414 int sys_rename(const char * oldname, const char * newname)
415 {
416 struct inode * old_dir, * new_dir;
417 const char * old_base, * new_base;
418 int old_len, new_len;
419
420 old_dir = dir_namei(oldname,&old_len,&old_base, NULL);
421 if (!old_dir)
422 return -ENOENT;
423 if (!permission(old_dir,MAY_WRITE)) {
424 iput(old_dir);
425 return -EACCES;
426 }
427 if (!old_len || (get_fs_byte(old_base) == '.' &&
428 (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
429 old_len == 2)))) {
430 iput(old_dir);
431 return -EPERM;
432 }
433 new_dir = dir_namei(newname,&new_len,&new_base, NULL);
434 if (!new_dir) {
435 iput(old_dir);
436 return -ENOENT;
437 }
438 if (!permission(new_dir,MAY_WRITE)) {
439 iput(old_dir);
440 iput(new_dir);
441 return -EACCES;
442 }
443 if (!new_len || (get_fs_byte(new_base) == '.' &&
444 (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
445 new_len == 2)))) {
446 iput(old_dir);
447 iput(new_dir);
448 return -EPERM;
449 }
450 if (new_dir->i_dev != old_dir->i_dev) {
451 iput(old_dir);
452 iput(new_dir);
453 return -EXDEV;
454 }
455 if (!old_dir->i_op || !old_dir->i_op->rename) {
456 iput(old_dir);
457 iput(new_dir);
458 return -EPERM;
459 }
460 return old_dir->i_op->rename(old_dir, old_base, old_len,
461 new_dir, new_base, new_len);
462 }