Annotation of linux/fs/namei.c, revision 1.1.1.7

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.