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

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       root       11: #include <asm/segment.h>
                     12: 
1.1.1.10  root       13: #include <linux/errno.h>
1.1.1.9   root       14: #include <linux/sched.h>
                     15: #include <linux/kernel.h>
1.1.1.7   root       16: #include <linux/string.h>
1.1.1.9   root       17: #include <linux/fcntl.h>
1.1.1.8   root       18: #include <linux/stat.h>
1.1       root       19: 
1.1.1.11! root       20: #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
1.1       root       21: 
                     22: /*
1.1.1.5   root       23:  * comment out this line if you want names > MINIX_NAME_LEN chars to be
1.1       root       24:  * truncated. Else they will be disallowed.
                     25:  */
                     26: /* #define NO_TRUNCATE */
                     27: 
                     28: /*
                     29:  *     permission()
                     30:  *
                     31:  * is used to check for read/write/execute permissions on a file.
                     32:  * I don't know if we should look at just the euid or both euid and
                     33:  * uid, but that should be easily changed.
                     34:  */
1.1.1.5   root       35: int permission(struct inode * inode,int mask)
1.1       root       36: {
                     37:        int mode = inode->i_mode;
                     38: 
                     39: /* special case: not even root can read/write a deleted file */
1.1.1.5   root       40:        if (inode->i_dev && !inode->i_nlink)
1.1       root       41:                return 0;
1.1.1.5   root       42:        else if (current->euid == inode->i_uid)
1.1       root       43:                mode >>= 6;
1.1.1.4   root       44:        else if (in_group_p(inode->i_gid))
1.1       root       45:                mode >>= 3;
1.1.1.2   root       46:        if (((mode & mask & 0007) == mask) || suser())
                     47:                return 1;
                     48:        return 0;
1.1       root       49: }
                     50: 
                     51: /*
1.1.1.5   root       52:  * lookup() looks up one part of a pathname, using the fs-dependent
                     53:  * routines (currently minix_lookup) for it. It also checks for
                     54:  * fathers (pseudo-roots, mount-points)
1.1       root       55:  */
1.1.1.5   root       56: int lookup(struct inode * dir,const char * name, int len,
                     57:        struct inode ** result)
1.1       root       58: {
1.1.1.2   root       59:        struct super_block * sb;
1.1       root       60: 
1.1.1.5   root       61:        *result = NULL;
                     62:        if (len==2 && get_fs_byte(name)=='.' && get_fs_byte(name+1)=='.') {
                     63:                if (dir == current->root)
                     64:                        len = 1;
                     65:                else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
                     66:                        sb = dir->i_sb;
                     67:                        iput(dir);
                     68:                        if (dir = sb->s_covered)
                     69:                                dir->i_count++;
1.1.1.2   root       70:                }
                     71:        }
1.1.1.5   root       72:        if (!dir)
                     73:                return -ENOENT;
                     74:        if (!permission(dir,MAY_EXEC)) {
                     75:                iput(dir);
                     76:                return -EACCES;
1.1       root       77:        }
1.1.1.5   root       78:        if (!len) {
                     79:                *result = dir;
                     80:                return 0;
                     81:        }
                     82:        if (!dir->i_op || !dir->i_op->lookup) {
                     83:                iput(dir);
                     84:                return -ENOENT;
1.1       root       85:        }
1.1.1.5   root       86:        return dir->i_op->lookup(dir,name,len,result);
1.1       root       87: }
                     88: 
1.1.1.11! root       89: int follow_link(struct inode * dir, struct inode * inode,
        !            90:        int flag, int mode, struct inode ** res_inode)
1.1.1.4   root       91: {
1.1.1.5   root       92:        if (!dir || !inode) {
1.1.1.4   root       93:                iput(dir);
1.1.1.5   root       94:                iput(inode);
1.1.1.11! root       95:                *res_inode = NULL;
        !            96:                return -ENOENT;
1.1.1.4   root       97:        }
1.1.1.5   root       98:        if (!inode->i_op || !inode->i_op->follow_link) {
1.1.1.4   root       99:                iput(dir);
1.1.1.11! root      100:                *res_inode = inode;
        !           101:                return 0;
1.1.1.4   root      102:        }
1.1.1.11! root      103:        return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
1.1.1.4   root      104: }
                    105: 
1.1       root      106: /*
1.1.1.5   root      107:  *     dir_namei()
1.1       root      108:  *
1.1.1.5   root      109:  * dir_namei() returns the inode of the directory of the
                    110:  * specified name, and the name within that directory.
1.1       root      111:  */
1.1.1.11! root      112: static int dir_namei(const char * pathname, int * namelen, const char ** name,
        !           113:        struct inode * base, struct inode ** res_inode)
1.1       root      114: {
                    115:        char c;
                    116:        const char * thisname;
1.1.1.5   root      117:        int len,error;
                    118:        struct inode * inode;
                    119: 
1.1.1.11! root      120:        *res_inode = NULL;
1.1.1.5   root      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.11! root      141:                        return error;
1.1.1.4   root      142:                }
1.1.1.11! root      143:                error = follow_link(base,inode,0,0,&base);
        !           144:                if (error)
        !           145:                        return error;
1.1       root      146:        }
1.1.1.5   root      147:        *name = thisname;
                    148:        *namelen = len;
1.1.1.11! root      149:        *res_inode = base;
        !           150:        return 0;
1.1       root      151: }
                    152: 
1.1.1.11! root      153: static int _namei(const char * pathname, struct inode * base,
        !           154:        int follow_links, struct inode ** res_inode)
1.1       root      155: {
                    156:        const char * basename;
1.1.1.5   root      157:        int namelen,error;
                    158:        struct inode * inode;
1.1       root      159: 
1.1.1.11! root      160:        *res_inode = NULL;
        !           161:        error = dir_namei(pathname,&namelen,&basename,base,&base);
        !           162:        if (error)
        !           163:                return error;
1.1.1.5   root      164:        base->i_count++;        /* lookup uses up base */
                    165:        error = lookup(base,basename,namelen,&inode);
                    166:        if (error) {
1.1.1.4   root      167:                iput(base);
1.1.1.11! root      168:                return error;
1.1       root      169:        }
1.1.1.11! root      170:        if (follow_links) {
        !           171:                error = follow_link(base,inode,0,0,&inode);
        !           172:                if (error)
        !           173:                        return error;
        !           174:        } else
1.1.1.4   root      175:                iput(base);
1.1.1.11! root      176:        *res_inode = inode;
        !           177:        return 0;
1.1.1.4   root      178: }
                    179: 
1.1.1.11! root      180: int lnamei(const char * pathname, struct inode ** res_inode)
1.1.1.4   root      181: {
1.1.1.11! root      182:        return _namei(pathname,NULL,0,res_inode);
1.1.1.4   root      183: }
                    184: 
                    185: /*
                    186:  *     namei()
                    187:  *
                    188:  * is used by most simple commands to get the inode of a specified name.
                    189:  * Open, link etc use their own routines, but this is enough for things
                    190:  * like 'chmod' etc.
                    191:  */
1.1.1.11! root      192: int namei(const char * pathname, struct inode ** res_inode)
1.1.1.4   root      193: {
1.1.1.11! root      194:        return _namei(pathname,NULL,1,res_inode);
1.1       root      195: }
                    196: 
                    197: /*
                    198:  *     open_namei()
                    199:  *
                    200:  * namei for open - this is in fact almost the whole open-routine.
1.1.1.11! root      201:  *
        !           202:  * Note that the low bits of "flag" aren't the same asin the open
        !           203:  * system call - they are 00 - no permissions needed
        !           204:  *                       01 - read permission needed
        !           205:  *                       10 - write permission needed
        !           206:  *                       11 - read/write permissions needed
        !           207:  * which is a lot more logical, and also allows the "no perm" needed
        !           208:  * for symlinks (where the permissions are checked later).
1.1       root      209:  */
                    210: int open_namei(const char * pathname, int flag, int mode,
1.1.1.11! root      211:        struct inode ** res_inode, struct inode * base)
1.1       root      212: {
                    213:        const char * basename;
1.1.1.10  root      214:        int namelen,error,i;
1.1.1.5   root      215:        struct inode * dir, *inode;
1.1.1.10  root      216:        struct task_struct ** p;
1.1       root      217: 
1.1.1.8   root      218:        mode &= 07777 & ~current->umask;
1.1.1.11! root      219:        mode |= S_IFREG;
        !           220:        error = dir_namei(pathname,&namelen,&basename,base,&dir);
        !           221:        if (error)
        !           222:                return error;
1.1       root      223:        if (!namelen) {                 /* special case: '/usr/' etc */
1.1.1.11! root      224:                if (!(flag & 2)) {
1.1       root      225:                        *res_inode=dir;
                    226:                        return 0;
                    227:                }
                    228:                iput(dir);
                    229:                return -EISDIR;
                    230:        }
1.1.1.5   root      231:        dir->i_count++;         /* lookup eats the dir */
                    232:        error = lookup(dir,basename,namelen,&inode);
                    233:        if (error) {
1.1       root      234:                if (!(flag & O_CREAT)) {
                    235:                        iput(dir);
1.1.1.5   root      236:                        return error;
1.1       root      237:                }
                    238:                if (!permission(dir,MAY_WRITE)) {
                    239:                        iput(dir);
                    240:                        return -EACCES;
                    241:                }
1.1.1.5   root      242:                if (!dir->i_op || !dir->i_op->create) {
1.1       root      243:                        iput(dir);
1.1.1.5   root      244:                        return -EACCES;
1.1       root      245:                }
1.1.1.10  root      246:                if (IS_RDONLY(dir)) {
                    247:                        iput(dir);
                    248:                        return -EROFS;
                    249:                }
1.1.1.5   root      250:                return dir->i_op->create(dir,basename,namelen,mode,res_inode);
1.1       root      251:        }
1.1.1.4   root      252:        if (flag & O_EXCL) {
                    253:                iput(dir);
1.1.1.5   root      254:                iput(inode);
1.1       root      255:                return -EEXIST;
1.1.1.4   root      256:        }
1.1.1.11! root      257:        if (error = follow_link(dir,inode,flag,mode,&inode))
        !           258:                return error;
        !           259:        if (S_ISDIR(inode->i_mode) && (flag & 2)) {
        !           260:                iput(inode);
        !           261:                return -EPERM;
        !           262:        }
        !           263:        if (!permission(inode,ACC_MODE(flag))) {
        !           264:                iput(inode);
        !           265:                return -EACCES;
        !           266:        }
1.1.1.10  root      267:        if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
                    268:                if (IS_NODEV(inode)) {
                    269:                        iput(inode);
                    270:                        return -EACCES;
                    271:                }
                    272:        } else {
1.1.1.11! root      273:                if (IS_RDONLY(inode) && (flag & 2)) {
1.1.1.10  root      274:                        iput(inode);
                    275:                        return -EROFS;
                    276:                }
                    277:        }
1.1.1.11! root      278:        if ((inode->i_count > 1) && (flag & 2))
1.1.1.10  root      279:                for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
                    280:                        if (!*p)
                    281:                                continue;
                    282:                        if (inode == (*p)->executable) {
                    283:                                iput(inode);
                    284:                                return -ETXTBSY;
                    285:                        }
                    286:                        for (i=0; i < (*p)->numlibraries; i++)
                    287:                                if (inode == (*p)->libraries[i].library) {
                    288:                                        iput(inode);
                    289:                                        return -ETXTBSY;
                    290:                                }
                    291:                }
1.1       root      292:        *res_inode = inode;
                    293:        return 0;
                    294: }
                    295: 
1.1.1.8   root      296: int do_mknod(const char * filename, int mode, int dev)
1.1.1.2   root      297: {
                    298:        const char * basename;
1.1.1.11! root      299:        int namelen, error;
1.1.1.5   root      300:        struct inode * dir;
1.1.1.11! root      301: 
        !           302:        error = dir_namei(filename,&namelen,&basename, NULL, &dir);
        !           303:        if (error)
        !           304:                return error;
1.1.1.2   root      305:        if (!namelen) {
                    306:                iput(dir);
                    307:                return -ENOENT;
                    308:        }
1.1.1.10  root      309:        if (IS_RDONLY(dir)) {
                    310:                iput(dir);
                    311:                return -EROFS;
                    312:        }
1.1.1.2   root      313:        if (!permission(dir,MAY_WRITE)) {
                    314:                iput(dir);
1.1.1.6   root      315:                return -EACCES;
1.1.1.2   root      316:        }
1.1.1.5   root      317:        if (!dir->i_op || !dir->i_op->mknod) {
1.1.1.2   root      318:                iput(dir);
1.1.1.5   root      319:                return -EPERM;
1.1.1.2   root      320:        }
1.1.1.5   root      321:        return dir->i_op->mknod(dir,basename,namelen,mode,dev);
1.1.1.2   root      322: }
                    323: 
1.1.1.8   root      324: int sys_mknod(const char * filename, int mode, int dev)
                    325: {
1.1.1.9   root      326:        if (S_ISFIFO(mode) || suser())
1.1.1.8   root      327:                return do_mknod(filename,mode,dev);
                    328:        return -EPERM;
                    329: }
                    330: 
1.1       root      331: int sys_mkdir(const char * pathname, int mode)
                    332: {
                    333:        const char * basename;
1.1.1.11! root      334:        int namelen, error;
1.1.1.5   root      335:        struct inode * dir;
1.1       root      336: 
1.1.1.11! root      337:        error = dir_namei(pathname,&namelen,&basename,NULL,&dir);
        !           338:        if (error)
        !           339:                return error;
1.1       root      340:        if (!namelen) {
                    341:                iput(dir);
                    342:                return -ENOENT;
                    343:        }
1.1.1.10  root      344:        if (IS_RDONLY(dir)) {
                    345:                iput(dir);
                    346:                return -EROFS;
                    347:        }
1.1       root      348:        if (!permission(dir,MAY_WRITE)) {
                    349:                iput(dir);
1.1.1.6   root      350:                return -EACCES;
1.1       root      351:        }
1.1.1.5   root      352:        if (!dir->i_op || !dir->i_op->mkdir) {
1.1       root      353:                iput(dir);
1.1.1.5   root      354:                return -EPERM;
1.1       root      355:        }
1.1.1.5   root      356:        return dir->i_op->mkdir(dir,basename,namelen,mode);
1.1       root      357: }
                    358: 
                    359: int sys_rmdir(const char * name)
                    360: {
                    361:        const char * basename;
1.1.1.11! root      362:        int namelen, error;
1.1.1.5   root      363:        struct inode * dir;
1.1       root      364: 
1.1.1.11! root      365:        error = dir_namei(name,&namelen,&basename,NULL,&dir);
        !           366:        if (error)
        !           367:                return error;
1.1       root      368:        if (!namelen) {
                    369:                iput(dir);
                    370:                return -ENOENT;
                    371:        }
1.1.1.10  root      372:        if (IS_RDONLY(dir)) {
                    373:                iput(dir);
                    374:                return -EROFS;
                    375:        }
1.1.1.3   root      376:        if (!permission(dir,MAY_WRITE)) {
                    377:                iput(dir);
1.1.1.6   root      378:                return -EACCES;
1.1.1.3   root      379:        }
1.1.1.5   root      380:        if (!dir->i_op || !dir->i_op->rmdir) {
1.1       root      381:                iput(dir);
                    382:                return -EPERM;
                    383:        }
1.1.1.5   root      384:        return dir->i_op->rmdir(dir,basename,namelen);
1.1       root      385: }
                    386: 
                    387: int sys_unlink(const char * name)
                    388: {
                    389:        const char * basename;
1.1.1.11! root      390:        int namelen, error;
1.1.1.5   root      391:        struct inode * dir;
1.1       root      392: 
1.1.1.11! root      393:        error = dir_namei(name,&namelen,&basename,NULL,&dir);
        !           394:        if (error)
        !           395:                return error;
1.1       root      396:        if (!namelen) {
                    397:                iput(dir);
1.1.1.6   root      398:                return -EPERM;
1.1       root      399:        }
1.1.1.10  root      400:        if (IS_RDONLY(dir)) {
                    401:                iput(dir);
                    402:                return -EROFS;
                    403:        }
1.1       root      404:        if (!permission(dir,MAY_WRITE)) {
                    405:                iput(dir);
1.1.1.6   root      406:                return -EACCES;
1.1       root      407:        }
1.1.1.5   root      408:        if (!dir->i_op || !dir->i_op->unlink) {
1.1.1.2   root      409:                iput(dir);
                    410:                return -EPERM;
1.1.1.3   root      411:        }
1.1.1.5   root      412:        return dir->i_op->unlink(dir,basename,namelen);
1.1       root      413: }
                    414: 
1.1.1.4   root      415: int sys_symlink(const char * oldname, const char * newname)
                    416: {
1.1.1.5   root      417:        struct inode * dir;
1.1.1.4   root      418:        const char * basename;
1.1.1.11! root      419:        int namelen, error;
1.1.1.4   root      420: 
1.1.1.11! root      421:        error = dir_namei(newname,&namelen,&basename,NULL,&dir);
        !           422:        if (error)
        !           423:                return error;
1.1.1.4   root      424:        if (!namelen) {
                    425:                iput(dir);
1.1.1.6   root      426:                return -ENOENT;
1.1.1.4   root      427:        }
1.1.1.10  root      428:        if (IS_RDONLY(dir)) {
                    429:                iput(dir);
                    430:                return -EROFS;
                    431:        }
1.1.1.4   root      432:        if (!permission(dir,MAY_WRITE)) {
                    433:                iput(dir);
1.1.1.6   root      434:                return -EACCES;
1.1.1.4   root      435:        }
1.1.1.5   root      436:        if (!dir->i_op || !dir->i_op->symlink) {
1.1.1.4   root      437:                iput(dir);
1.1.1.5   root      438:                return -EPERM;
1.1.1.4   root      439:        }
1.1.1.5   root      440:        return dir->i_op->symlink(dir,basename,namelen,oldname);
1.1.1.4   root      441: }
                    442: 
1.1       root      443: int sys_link(const char * oldname, const char * newname)
                    444: {
1.1.1.5   root      445:        struct inode * oldinode, * dir;
1.1       root      446:        const char * basename;
1.1.1.11! root      447:        int namelen, error;
1.1       root      448: 
1.1.1.11! root      449:        error = namei(oldname, &oldinode);
        !           450:        if (error)
        !           451:                return error;
        !           452:        error = dir_namei(newname,&namelen,&basename,NULL,&dir);
        !           453:        if (error) {
1.1       root      454:                iput(oldinode);
1.1.1.11! root      455:                return error;
1.1       root      456:        }
                    457:        if (!namelen) {
                    458:                iput(oldinode);
                    459:                iput(dir);
                    460:                return -EPERM;
                    461:        }
1.1.1.10  root      462:        if (IS_RDONLY(dir)) {
                    463:                iput(oldinode);
                    464:                iput(dir);
                    465:                return -EROFS;
                    466:        }
1.1       root      467:        if (dir->i_dev != oldinode->i_dev) {
                    468:                iput(dir);
                    469:                iput(oldinode);
                    470:                return -EXDEV;
                    471:        }
                    472:        if (!permission(dir,MAY_WRITE)) {
                    473:                iput(dir);
                    474:                iput(oldinode);
                    475:                return -EACCES;
                    476:        }
1.1.1.5   root      477:        if (!dir->i_op || !dir->i_op->link) {
1.1       root      478:                iput(dir);
                    479:                iput(oldinode);
1.1.1.5   root      480:                return -EPERM;
1.1       root      481:        }
1.1.1.5   root      482:        return dir->i_op->link(oldinode, dir, basename, namelen);
                    483: }
                    484: 
                    485: int sys_rename(const char * oldname, const char * newname)
                    486: {
                    487:        struct inode * old_dir, * new_dir;
                    488:        const char * old_base, * new_base;
1.1.1.11! root      489:        int old_len, new_len, error;
1.1.1.5   root      490: 
1.1.1.11! root      491:        error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir);
        !           492:        if (error)
        !           493:                return error;
1.1.1.5   root      494:        if (!permission(old_dir,MAY_WRITE)) {
                    495:                iput(old_dir);
                    496:                return -EACCES;
1.1       root      497:        }
1.1.1.5   root      498:        if (!old_len || (get_fs_byte(old_base) == '.' &&
                    499:            (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
                    500:             old_len == 2)))) {
                    501:                iput(old_dir);
                    502:                return -EPERM;
                    503:        }
1.1.1.11! root      504:        error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir);
        !           505:        if (error) {
1.1.1.5   root      506:                iput(old_dir);
1.1.1.11! root      507:                return error;
1.1.1.5   root      508:        }
                    509:        if (!permission(new_dir,MAY_WRITE)) {
                    510:                iput(old_dir);
                    511:                iput(new_dir);
                    512:                return -EACCES;
                    513:        }
                    514:        if (!new_len || (get_fs_byte(new_base) == '.' &&
                    515:            (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
                    516:             new_len == 2)))) {
                    517:                iput(old_dir);
                    518:                iput(new_dir);
                    519:                return -EPERM;
                    520:        }
                    521:        if (new_dir->i_dev != old_dir->i_dev) {
                    522:                iput(old_dir);
                    523:                iput(new_dir);
                    524:                return -EXDEV;
                    525:        }
1.1.1.10  root      526:        if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
                    527:                iput(old_dir);
                    528:                iput(new_dir);
                    529:                return -EROFS;
                    530:        }
1.1.1.5   root      531:        if (!old_dir->i_op || !old_dir->i_op->rename) {
                    532:                iput(old_dir);
                    533:                iput(new_dir);
                    534:                return -EPERM;
                    535:        }
                    536:        return old_dir->i_op->rename(old_dir, old_base, old_len, 
                    537:                new_dir, new_base, new_len);
1.1       root      538: }

unix.superglobalmegacorp.com

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