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

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: }

unix.superglobalmegacorp.com

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