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

1.1.1.2   root        1: /*
                      2:  *  linux/fs/namei.c
                      3:  *
1.1.1.10! root        4:  *  Copyright (C) 1991, 1992  Linus Torvalds
1.1.1.2   root        5:  */
                      6: 
1.1.1.3   root        7: /*
                      8:  * Some corrections by tytso.
                      9:  */
                     10: 
1.1.1.9   root       11: #include <const.h>
                     12: 
1.1       root       13: #include <asm/segment.h>
                     14: 
1.1.1.10! root       15: #include <linux/errno.h>
1.1.1.9   root       16: #include <linux/sched.h>
                     17: #include <linux/kernel.h>
1.1.1.7   root       18: #include <linux/string.h>
1.1.1.9   root       19: #include <linux/fcntl.h>
1.1.1.8   root       20: #include <linux/stat.h>
1.1       root       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);
                    171:        return inode;
                    172: }
                    173: 
1.1.1.5   root      174: struct inode * lnamei(const char * pathname)
1.1.1.4   root      175: {
                    176:        return _namei(pathname, NULL, 0);
                    177: }
                    178: 
                    179: /*
                    180:  *     namei()
                    181:  *
                    182:  * is used by most simple commands to get the inode of a specified name.
                    183:  * Open, link etc use their own routines, but this is enough for things
                    184:  * like 'chmod' etc.
                    185:  */
1.1.1.5   root      186: struct inode * namei(const char * pathname)
1.1.1.4   root      187: {
                    188:        return _namei(pathname,NULL,1);
1.1       root      189: }
                    190: 
                    191: /*
                    192:  *     open_namei()
                    193:  *
                    194:  * namei for open - this is in fact almost the whole open-routine.
                    195:  */
                    196: int open_namei(const char * pathname, int flag, int mode,
1.1.1.5   root      197:        struct inode ** res_inode)
1.1       root      198: {
                    199:        const char * basename;
1.1.1.10! root      200:        int namelen,error,i;
1.1.1.5   root      201:        struct inode * dir, *inode;
1.1.1.10! root      202:        struct task_struct ** p;
1.1       root      203: 
                    204:        if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
                    205:                flag |= O_WRONLY;
1.1.1.8   root      206:        mode &= 07777 & ~current->umask;
1.1       root      207:        mode |= I_REGULAR;
1.1.1.4   root      208:        if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
1.1       root      209:                return -ENOENT;
                    210:        if (!namelen) {                 /* special case: '/usr/' etc */
                    211:                if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
                    212:                        *res_inode=dir;
                    213:                        return 0;
                    214:                }
                    215:                iput(dir);
                    216:                return -EISDIR;
                    217:        }
1.1.1.5   root      218:        dir->i_count++;         /* lookup eats the dir */
                    219:        error = lookup(dir,basename,namelen,&inode);
                    220:        if (error) {
1.1       root      221:                if (!(flag & O_CREAT)) {
                    222:                        iput(dir);
1.1.1.5   root      223:                        return error;
1.1       root      224:                }
                    225:                if (!permission(dir,MAY_WRITE)) {
                    226:                        iput(dir);
                    227:                        return -EACCES;
                    228:                }
1.1.1.5   root      229:                if (!dir->i_op || !dir->i_op->create) {
1.1       root      230:                        iput(dir);
1.1.1.5   root      231:                        return -EACCES;
1.1       root      232:                }
1.1.1.10! root      233:                if (IS_RDONLY(dir)) {
        !           234:                        iput(dir);
        !           235:                        return -EROFS;
        !           236:                }
1.1.1.5   root      237:                return dir->i_op->create(dir,basename,namelen,mode,res_inode);
1.1       root      238:        }
1.1.1.4   root      239:        if (flag & O_EXCL) {
                    240:                iput(dir);
1.1.1.5   root      241:                iput(inode);
1.1       root      242:                return -EEXIST;
1.1.1.4   root      243:        }
1.1.1.5   root      244:        if (!(inode = follow_link(dir,inode)))
                    245:                return -ELOOP;
1.1.1.10! root      246:        if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
        !           247:                if (IS_NODEV(inode)) {
        !           248:                        iput(inode);
        !           249:                        return -EACCES;
        !           250:                }
        !           251:        } else {
        !           252:                if (IS_RDONLY(inode) && (flag & (O_TRUNC | O_ACCMODE))) {
        !           253:                        iput(inode);
        !           254:                        return -EROFS;
        !           255:                }
        !           256:        }
1.1       root      257:        if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
1.1.1.2   root      258:            !permission(inode,ACC_MODE(flag))) {
1.1       root      259:                iput(inode);
                    260:                return -EPERM;
                    261:        }
1.1.1.10! root      262:        if ((inode->i_count > 1) && (flag & O_ACCMODE))
        !           263:                for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
        !           264:                        if (!*p)
        !           265:                                continue;
        !           266:                        if (inode == (*p)->executable) {
        !           267:                                iput(inode);
        !           268:                                return -ETXTBSY;
        !           269:                        }
        !           270:                        for (i=0; i < (*p)->numlibraries; i++)
        !           271:                                if (inode == (*p)->libraries[i].library) {
        !           272:                                        iput(inode);
        !           273:                                        return -ETXTBSY;
        !           274:                                }
        !           275:                }
1.1       root      276:        if (flag & O_TRUNC)
1.1.1.7   root      277:                if (inode->i_op && inode->i_op->truncate) {
                    278:                        inode->i_size = 0;
1.1.1.6   root      279:                        inode->i_op->truncate(inode);
1.1.1.7   root      280:                }
1.1.1.10! root      281:        if (!IS_RDONLY(inode)) {
        !           282:                inode->i_atime = CURRENT_TIME;
        !           283:                inode->i_dirt = 1;
        !           284:        }
1.1       root      285:        *res_inode = inode;
                    286:        return 0;
                    287: }
                    288: 
1.1.1.8   root      289: int do_mknod(const char * filename, int mode, int dev)
1.1.1.2   root      290: {
                    291:        const char * basename;
                    292:        int namelen;
1.1.1.5   root      293:        struct inode * dir;
1.1.1.2   root      294:        
1.1.1.4   root      295:        if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
1.1.1.2   root      296:                return -ENOENT;
                    297:        if (!namelen) {
                    298:                iput(dir);
                    299:                return -ENOENT;
                    300:        }
1.1.1.10! root      301:        if (IS_RDONLY(dir)) {
        !           302:                iput(dir);
        !           303:                return -EROFS;
        !           304:        }
1.1.1.2   root      305:        if (!permission(dir,MAY_WRITE)) {
                    306:                iput(dir);
1.1.1.6   root      307:                return -EACCES;
1.1.1.2   root      308:        }
1.1.1.5   root      309:        if (!dir->i_op || !dir->i_op->mknod) {
1.1.1.2   root      310:                iput(dir);
1.1.1.5   root      311:                return -EPERM;
1.1.1.2   root      312:        }
1.1.1.5   root      313:        return dir->i_op->mknod(dir,basename,namelen,mode,dev);
1.1.1.2   root      314: }
                    315: 
1.1.1.8   root      316: int sys_mknod(const char * filename, int mode, int dev)
                    317: {
1.1.1.9   root      318:        if (S_ISFIFO(mode) || suser())
1.1.1.8   root      319:                return do_mknod(filename,mode,dev);
                    320:        return -EPERM;
                    321: }
                    322: 
1.1       root      323: int sys_mkdir(const char * pathname, int mode)
                    324: {
                    325:        const char * basename;
                    326:        int namelen;
1.1.1.5   root      327:        struct inode * dir;
1.1       root      328: 
1.1.1.4   root      329:        if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
1.1       root      330:                return -ENOENT;
                    331:        if (!namelen) {
                    332:                iput(dir);
                    333:                return -ENOENT;
                    334:        }
1.1.1.10! root      335:        if (IS_RDONLY(dir)) {
        !           336:                iput(dir);
        !           337:                return -EROFS;
        !           338:        }
1.1       root      339:        if (!permission(dir,MAY_WRITE)) {
                    340:                iput(dir);
1.1.1.6   root      341:                return -EACCES;
1.1       root      342:        }
1.1.1.5   root      343:        if (!dir->i_op || !dir->i_op->mkdir) {
1.1       root      344:                iput(dir);
1.1.1.5   root      345:                return -EPERM;
1.1       root      346:        }
1.1.1.5   root      347:        return dir->i_op->mkdir(dir,basename,namelen,mode);
1.1       root      348: }
                    349: 
                    350: int sys_rmdir(const char * name)
                    351: {
                    352:        const char * basename;
                    353:        int namelen;
1.1.1.5   root      354:        struct inode * dir;
1.1       root      355: 
1.1.1.4   root      356:        if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
1.1       root      357:                return -ENOENT;
                    358:        if (!namelen) {
                    359:                iput(dir);
                    360:                return -ENOENT;
                    361:        }
1.1.1.10! root      362:        if (IS_RDONLY(dir)) {
        !           363:                iput(dir);
        !           364:                return -EROFS;
        !           365:        }
1.1.1.3   root      366:        if (!permission(dir,MAY_WRITE)) {
                    367:                iput(dir);
1.1.1.6   root      368:                return -EACCES;
1.1.1.3   root      369:        }
1.1.1.5   root      370:        if (!dir->i_op || !dir->i_op->rmdir) {
1.1       root      371:                iput(dir);
                    372:                return -EPERM;
                    373:        }
1.1.1.5   root      374:        return dir->i_op->rmdir(dir,basename,namelen);
1.1       root      375: }
                    376: 
                    377: int sys_unlink(const char * name)
                    378: {
                    379:        const char * basename;
                    380:        int namelen;
1.1.1.5   root      381:        struct inode * dir;
1.1       root      382: 
1.1.1.4   root      383:        if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
1.1       root      384:                return -ENOENT;
                    385:        if (!namelen) {
                    386:                iput(dir);
1.1.1.6   root      387:                return -EPERM;
1.1       root      388:        }
1.1.1.10! root      389:        if (IS_RDONLY(dir)) {
        !           390:                iput(dir);
        !           391:                return -EROFS;
        !           392:        }
1.1       root      393:        if (!permission(dir,MAY_WRITE)) {
                    394:                iput(dir);
1.1.1.6   root      395:                return -EACCES;
1.1       root      396:        }
1.1.1.5   root      397:        if (!dir->i_op || !dir->i_op->unlink) {
1.1.1.2   root      398:                iput(dir);
                    399:                return -EPERM;
1.1.1.3   root      400:        }
1.1.1.5   root      401:        return dir->i_op->unlink(dir,basename,namelen);
1.1       root      402: }
                    403: 
1.1.1.4   root      404: int sys_symlink(const char * oldname, const char * newname)
                    405: {
1.1.1.5   root      406:        struct inode * dir;
1.1.1.4   root      407:        const char * basename;
1.1.1.5   root      408:        int namelen;
1.1.1.4   root      409: 
                    410:        dir = dir_namei(newname,&namelen,&basename, NULL);
                    411:        if (!dir)
1.1.1.6   root      412:                return -ENOENT;
1.1.1.4   root      413:        if (!namelen) {
                    414:                iput(dir);
1.1.1.6   root      415:                return -ENOENT;
1.1.1.4   root      416:        }
1.1.1.10! root      417:        if (IS_RDONLY(dir)) {
        !           418:                iput(dir);
        !           419:                return -EROFS;
        !           420:        }
1.1.1.4   root      421:        if (!permission(dir,MAY_WRITE)) {
                    422:                iput(dir);
1.1.1.6   root      423:                return -EACCES;
1.1.1.4   root      424:        }
1.1.1.5   root      425:        if (!dir->i_op || !dir->i_op->symlink) {
1.1.1.4   root      426:                iput(dir);
1.1.1.5   root      427:                return -EPERM;
1.1.1.4   root      428:        }
1.1.1.5   root      429:        return dir->i_op->symlink(dir,basename,namelen,oldname);
1.1.1.4   root      430: }
                    431: 
1.1       root      432: int sys_link(const char * oldname, const char * newname)
                    433: {
1.1.1.5   root      434:        struct inode * oldinode, * dir;
1.1       root      435:        const char * basename;
                    436:        int namelen;
                    437: 
1.1.1.5   root      438:        oldinode = namei(oldname);
1.1       root      439:        if (!oldinode)
                    440:                return -ENOENT;
1.1.1.4   root      441:        dir = dir_namei(newname,&namelen,&basename, NULL);
1.1       root      442:        if (!dir) {
                    443:                iput(oldinode);
                    444:                return -EACCES;
                    445:        }
                    446:        if (!namelen) {
                    447:                iput(oldinode);
                    448:                iput(dir);
                    449:                return -EPERM;
                    450:        }
1.1.1.10! root      451:        if (IS_RDONLY(dir)) {
        !           452:                iput(oldinode);
        !           453:                iput(dir);
        !           454:                return -EROFS;
        !           455:        }
1.1       root      456:        if (dir->i_dev != oldinode->i_dev) {
                    457:                iput(dir);
                    458:                iput(oldinode);
                    459:                return -EXDEV;
                    460:        }
                    461:        if (!permission(dir,MAY_WRITE)) {
                    462:                iput(dir);
                    463:                iput(oldinode);
                    464:                return -EACCES;
                    465:        }
1.1.1.5   root      466:        if (!dir->i_op || !dir->i_op->link) {
1.1       root      467:                iput(dir);
                    468:                iput(oldinode);
1.1.1.5   root      469:                return -EPERM;
1.1       root      470:        }
1.1.1.5   root      471:        return dir->i_op->link(oldinode, dir, basename, namelen);
                    472: }
                    473: 
                    474: int sys_rename(const char * oldname, const char * newname)
                    475: {
                    476:        struct inode * old_dir, * new_dir;
                    477:        const char * old_base, * new_base;
                    478:        int old_len, new_len;
                    479: 
                    480:        old_dir = dir_namei(oldname,&old_len,&old_base, NULL);
                    481:        if (!old_dir)
                    482:                return -ENOENT;
                    483:        if (!permission(old_dir,MAY_WRITE)) {
                    484:                iput(old_dir);
                    485:                return -EACCES;
1.1       root      486:        }
1.1.1.5   root      487:        if (!old_len || (get_fs_byte(old_base) == '.' &&
                    488:            (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
                    489:             old_len == 2)))) {
                    490:                iput(old_dir);
                    491:                return -EPERM;
                    492:        }
                    493:        new_dir = dir_namei(newname,&new_len,&new_base, NULL);
                    494:        if (!new_dir) {
                    495:                iput(old_dir);
                    496:                return -ENOENT;
                    497:        }
                    498:        if (!permission(new_dir,MAY_WRITE)) {
                    499:                iput(old_dir);
                    500:                iput(new_dir);
                    501:                return -EACCES;
                    502:        }
                    503:        if (!new_len || (get_fs_byte(new_base) == '.' &&
                    504:            (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
                    505:             new_len == 2)))) {
                    506:                iput(old_dir);
                    507:                iput(new_dir);
                    508:                return -EPERM;
                    509:        }
                    510:        if (new_dir->i_dev != old_dir->i_dev) {
                    511:                iput(old_dir);
                    512:                iput(new_dir);
                    513:                return -EXDEV;
                    514:        }
1.1.1.10! root      515:        if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
        !           516:                iput(old_dir);
        !           517:                iput(new_dir);
        !           518:                return -EROFS;
        !           519:        }
1.1.1.5   root      520:        if (!old_dir->i_op || !old_dir->i_op->rename) {
                    521:                iput(old_dir);
                    522:                iput(new_dir);
                    523:                return -EPERM;
                    524:        }
                    525:        return old_dir->i_op->rename(old_dir, old_base, old_len, 
                    526:                new_dir, new_base, new_len);
1.1       root      527: }

unix.superglobalmegacorp.com

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