|
|
1.1.1.2 root 1: /*
2: * linux/fs/namei.c
3: *
4: * (C) 1991 Linus Torvalds
5: */
6:
1.1.1.3 root 7: /*
8: * Some corrections by tytso.
9: */
10:
1.1 root 11: #include <linux/sched.h>
1.1.1.5 ! root 12: #include <linux/minix_fs.h>
1.1 root 13: #include <linux/kernel.h>
14: #include <asm/segment.h>
15:
16: #include <string.h>
17: #include <fcntl.h>
18: #include <errno.h>
19: #include <const.h>
20: #include <sys/stat.h>
21:
1.1.1.5 ! root 22: struct inode * _namei(const char * filename, struct inode * base,
1.1.1.4 root 23: int follow_links);
24:
1.1 root 25: #define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE])
26:
27: /*
1.1.1.5 ! root 28: * comment out this line if you want names > MINIX_NAME_LEN chars to be
1.1 root 29: * truncated. Else they will be disallowed.
30: */
31: /* #define NO_TRUNCATE */
32:
33: /*
34: * permission()
35: *
36: * is used to check for read/write/execute permissions on a file.
37: * I don't know if we should look at just the euid or both euid and
38: * uid, but that should be easily changed.
39: */
1.1.1.5 ! root 40: int permission(struct inode * inode,int mask)
1.1 root 41: {
42: int mode = inode->i_mode;
43:
44: /* special case: not even root can read/write a deleted file */
1.1.1.5 ! root 45: if (inode->i_dev && !inode->i_nlink)
1.1 root 46: return 0;
1.1.1.5 ! root 47: else if (current->euid == inode->i_uid)
1.1 root 48: mode >>= 6;
1.1.1.4 root 49: else if (in_group_p(inode->i_gid))
1.1 root 50: mode >>= 3;
1.1.1.2 root 51: if (((mode & mask & 0007) == mask) || suser())
52: return 1;
53: return 0;
1.1 root 54: }
55:
56: /*
1.1.1.5 ! root 57: * lookup() looks up one part of a pathname, using the fs-dependent
! 58: * routines (currently minix_lookup) for it. It also checks for
! 59: * fathers (pseudo-roots, mount-points)
1.1 root 60: */
1.1.1.5 ! root 61: int lookup(struct inode * dir,const char * name, int len,
! 62: struct inode ** result)
1.1 root 63: {
1.1.1.2 root 64: struct super_block * sb;
1.1 root 65:
1.1.1.5 ! root 66: *result = NULL;
! 67: if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
! 68: if (dir == current->root)
! 69: len = 1;
! 70: else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
! 71: sb = dir->i_sb;
! 72: iput(dir);
! 73: if (dir = sb->s_covered)
! 74: dir->i_count++;
1.1.1.2 root 75: }
76: }
1.1.1.5 ! root 77: if (!dir)
! 78: return -ENOENT;
! 79: if (!permission(dir,MAY_EXEC)) {
! 80: iput(dir);
! 81: return -EACCES;
1.1 root 82: }
1.1.1.5 ! root 83: if (!len) {
! 84: *result = dir;
! 85: return 0;
! 86: }
! 87: if (!dir->i_op || !dir->i_op->lookup) {
! 88: iput(dir);
! 89: return -ENOENT;
1.1 root 90: }
1.1.1.5 ! root 91: return dir->i_op->lookup(dir,name,len,result);
1.1 root 92: }
93:
1.1.1.5 ! root 94: struct inode * follow_link(struct inode * dir, struct inode * inode)
1.1.1.4 root 95: {
1.1.1.5 ! root 96: if (!dir || !inode) {
1.1.1.4 root 97: iput(dir);
1.1.1.5 ! root 98: iput(inode);
1.1.1.4 root 99: return NULL;
100: }
1.1.1.5 ! root 101: if (!inode->i_op || !inode->i_op->follow_link) {
1.1.1.4 root 102: iput(dir);
103: return inode;
104: }
1.1.1.5 ! root 105: return inode->i_op->follow_link(dir,inode);
1.1.1.4 root 106: }
107:
1.1 root 108: /*
1.1.1.5 ! root 109: * dir_namei()
1.1 root 110: *
1.1.1.5 ! root 111: * dir_namei() returns the inode of the directory of the
! 112: * specified name, and the name within that directory.
1.1 root 113: */
1.1.1.5 ! root 114: static struct inode * dir_namei(const char * pathname,
! 115: int * namelen, const char ** name, struct inode * base)
1.1 root 116: {
117: char c;
118: const char * thisname;
1.1.1.5 ! root 119: int len,error;
! 120: struct inode * inode;
! 121:
! 122: if (!base) {
! 123: base = current->pwd;
! 124: base->i_count++;
1.1.1.4 root 125: }
1.1 root 126: if ((c=get_fs_byte(pathname))=='/') {
1.1.1.5 ! root 127: iput(base);
! 128: base = current->root;
1.1 root 129: pathname++;
1.1.1.5 ! root 130: base->i_count++;
1.1.1.4 root 131: }
1.1 root 132: while (1) {
133: thisname = pathname;
1.1.1.5 ! root 134: for(len=0;(c=get_fs_byte(pathname++))&&(c!='/');len++)
1.1 root 135: /* nothing */ ;
136: if (!c)
1.1.1.5 ! root 137: break;
! 138: base->i_count++;
! 139: error = lookup(base,thisname,len,&inode);
! 140: if (error) {
! 141: iput(base);
1.1.1.4 root 142: return NULL;
143: }
1.1.1.5 ! root 144: if (!(base = follow_link(base,inode)))
1.1 root 145: return NULL;
146: }
1.1.1.5 ! root 147: *name = thisname;
! 148: *namelen = len;
! 149: return base;
1.1 root 150: }
151:
1.1.1.5 ! root 152: struct inode * _namei(const char * pathname, struct inode * base,
1.1.1.4 root 153: int follow_links)
1.1 root 154: {
155: const char * basename;
1.1.1.5 ! root 156: int namelen,error;
! 157: struct inode * inode;
1.1 root 158:
1.1.1.4 root 159: if (!(base = dir_namei(pathname,&namelen,&basename,base)))
1.1 root 160: return NULL;
1.1.1.5 ! root 161: base->i_count++; /* lookup uses up base */
! 162: error = lookup(base,basename,namelen,&inode);
! 163: if (error) {
1.1.1.4 root 164: iput(base);
165: return NULL;
1.1 root 166: }
1.1.1.4 root 167: if (follow_links)
168: inode = follow_link(base,inode);
169: else
170: iput(base);
1.1.1.5 ! root 171: if (inode) {
! 172: inode->i_atime=CURRENT_TIME;
! 173: inode->i_dirt=1;
! 174: }
1.1.1.4 root 175: return inode;
176: }
177:
1.1.1.5 ! root 178: struct inode * lnamei(const char * pathname)
1.1.1.4 root 179: {
180: return _namei(pathname, NULL, 0);
181: }
182:
183: /*
184: * namei()
185: *
186: * is used by most simple commands to get the inode of a specified name.
187: * Open, link etc use their own routines, but this is enough for things
188: * like 'chmod' etc.
189: */
1.1.1.5 ! root 190: struct inode * namei(const char * pathname)
1.1.1.4 root 191: {
192: return _namei(pathname,NULL,1);
1.1 root 193: }
194:
195: /*
196: * open_namei()
197: *
198: * namei for open - this is in fact almost the whole open-routine.
199: */
200: int open_namei(const char * pathname, int flag, int mode,
1.1.1.5 ! root 201: struct inode ** res_inode)
1.1 root 202: {
203: const char * basename;
1.1.1.5 ! root 204: int namelen,error;
! 205: struct inode * dir, *inode;
1.1 root 206:
207: if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
208: flag |= O_WRONLY;
209: mode &= 0777 & ~current->umask;
210: mode |= I_REGULAR;
1.1.1.4 root 211: if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
1.1 root 212: return -ENOENT;
213: if (!namelen) { /* special case: '/usr/' etc */
214: if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
215: *res_inode=dir;
216: return 0;
217: }
218: iput(dir);
219: return -EISDIR;
220: }
1.1.1.5 ! root 221: dir->i_count++; /* lookup eats the dir */
! 222: error = lookup(dir,basename,namelen,&inode);
! 223: if (error) {
1.1 root 224: if (!(flag & O_CREAT)) {
225: iput(dir);
1.1.1.5 ! root 226: return error;
1.1 root 227: }
228: if (!permission(dir,MAY_WRITE)) {
229: iput(dir);
230: return -EACCES;
231: }
1.1.1.5 ! root 232: if (!dir->i_op || !dir->i_op->create) {
1.1 root 233: iput(dir);
1.1.1.5 ! root 234: return -EACCES;
1.1 root 235: }
1.1.1.5 ! root 236: return dir->i_op->create(dir,basename,namelen,mode,res_inode);
1.1 root 237: }
1.1.1.4 root 238: if (flag & O_EXCL) {
239: iput(dir);
1.1.1.5 ! root 240: iput(inode);
1.1 root 241: return -EEXIST;
1.1.1.4 root 242: }
1.1.1.5 ! root 243: if (!(inode = follow_link(dir,inode)))
! 244: return -ELOOP;
1.1 root 245: if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
1.1.1.2 root 246: !permission(inode,ACC_MODE(flag))) {
1.1 root 247: iput(inode);
248: return -EPERM;
249: }
250: inode->i_atime = CURRENT_TIME;
251: if (flag & O_TRUNC)
1.1.1.5 ! root 252: minix_truncate(inode);
1.1 root 253: *res_inode = inode;
254: return 0;
255: }
256:
1.1.1.2 root 257: int sys_mknod(const char * filename, int mode, int dev)
258: {
259: const char * basename;
260: int namelen;
1.1.1.5 ! root 261: struct inode * dir;
1.1.1.2 root 262:
263: if (!suser())
264: return -EPERM;
1.1.1.4 root 265: if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
1.1.1.2 root 266: return -ENOENT;
267: if (!namelen) {
268: iput(dir);
269: return -ENOENT;
270: }
271: if (!permission(dir,MAY_WRITE)) {
272: iput(dir);
273: return -EPERM;
274: }
1.1.1.5 ! root 275: if (!dir->i_op || !dir->i_op->mknod) {
1.1.1.2 root 276: iput(dir);
1.1.1.5 ! root 277: return -EPERM;
1.1.1.2 root 278: }
1.1.1.5 ! root 279: return dir->i_op->mknod(dir,basename,namelen,mode,dev);
1.1.1.2 root 280: }
281:
1.1 root 282: int sys_mkdir(const char * pathname, int mode)
283: {
284: const char * basename;
285: int namelen;
1.1.1.5 ! root 286: struct inode * dir;
1.1 root 287:
1.1.1.4 root 288: if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
1.1 root 289: return -ENOENT;
290: if (!namelen) {
291: iput(dir);
292: return -ENOENT;
293: }
294: if (!permission(dir,MAY_WRITE)) {
295: iput(dir);
296: return -EPERM;
297: }
1.1.1.5 ! root 298: if (!dir->i_op || !dir->i_op->mkdir) {
1.1 root 299: iput(dir);
1.1.1.5 ! root 300: return -EPERM;
1.1 root 301: }
1.1.1.5 ! root 302: return dir->i_op->mkdir(dir,basename,namelen,mode);
1.1 root 303: }
304:
305: int sys_rmdir(const char * name)
306: {
307: const char * basename;
308: int namelen;
1.1.1.5 ! root 309: struct inode * dir;
1.1 root 310:
1.1.1.4 root 311: if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
1.1 root 312: return -ENOENT;
313: if (!namelen) {
314: iput(dir);
315: return -ENOENT;
316: }
1.1.1.3 root 317: if (!permission(dir,MAY_WRITE)) {
318: iput(dir);
319: return -EPERM;
320: }
1.1.1.5 ! root 321: if (!dir->i_op || !dir->i_op->rmdir) {
1.1 root 322: iput(dir);
323: return -EPERM;
324: }
1.1.1.5 ! root 325: return dir->i_op->rmdir(dir,basename,namelen);
1.1 root 326: }
327:
328: int sys_unlink(const char * name)
329: {
330: const char * basename;
331: int namelen;
1.1.1.5 ! root 332: struct inode * dir;
1.1 root 333:
1.1.1.4 root 334: if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
1.1 root 335: return -ENOENT;
336: if (!namelen) {
337: iput(dir);
338: return -ENOENT;
339: }
340: if (!permission(dir,MAY_WRITE)) {
341: iput(dir);
342: return -EPERM;
343: }
1.1.1.5 ! root 344: if (!dir->i_op || !dir->i_op->unlink) {
1.1.1.2 root 345: iput(dir);
346: return -EPERM;
1.1.1.3 root 347: }
1.1.1.5 ! root 348: return dir->i_op->unlink(dir,basename,namelen);
1.1 root 349: }
350:
1.1.1.4 root 351: int sys_symlink(const char * oldname, const char * newname)
352: {
1.1.1.5 ! root 353: struct inode * dir;
1.1.1.4 root 354: const char * basename;
1.1.1.5 ! root 355: int namelen;
1.1.1.4 root 356:
357: dir = dir_namei(newname,&namelen,&basename, NULL);
358: if (!dir)
359: return -EACCES;
360: if (!namelen) {
361: iput(dir);
362: return -EPERM;
363: }
364: if (!permission(dir,MAY_WRITE)) {
365: iput(dir);
1.1.1.5 ! root 366: return -EPERM;
1.1.1.4 root 367: }
1.1.1.5 ! root 368: if (!dir->i_op || !dir->i_op->symlink) {
1.1.1.4 root 369: iput(dir);
1.1.1.5 ! root 370: return -EPERM;
1.1.1.4 root 371: }
1.1.1.5 ! root 372: return dir->i_op->symlink(dir,basename,namelen,oldname);
1.1.1.4 root 373: }
374:
1.1 root 375: int sys_link(const char * oldname, const char * newname)
376: {
1.1.1.5 ! root 377: struct inode * oldinode, * dir;
1.1 root 378: const char * basename;
379: int namelen;
380:
1.1.1.5 ! root 381: oldinode = namei(oldname);
1.1 root 382: if (!oldinode)
383: return -ENOENT;
1.1.1.4 root 384: dir = dir_namei(newname,&namelen,&basename, NULL);
1.1 root 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: }
1.1.1.5 ! root 404: if (!dir->i_op || !dir->i_op->link) {
1.1 root 405: iput(dir);
406: iput(oldinode);
1.1.1.5 ! root 407: return -EPERM;
1.1 root 408: }
1.1.1.5 ! root 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;
1.1 root 424: }
1.1.1.5 ! root 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);
1.1 root 460: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.