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

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: 
                     15: #include <string.h>
                     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);
1.1.1.5   root      170:        if (inode) {
                    171:                inode->i_atime=CURRENT_TIME;
                    172:                inode->i_dirt=1;
                    173:        }
1.1.1.4   root      174:        return inode;
                    175: }
                    176: 
1.1.1.5   root      177: struct inode * lnamei(const char * pathname)
1.1.1.4   root      178: {
                    179:        return _namei(pathname, NULL, 0);
                    180: }
                    181: 
                    182: /*
                    183:  *     namei()
                    184:  *
                    185:  * is used by most simple commands to get the inode of a specified name.
                    186:  * Open, link etc use their own routines, but this is enough for things
                    187:  * like 'chmod' etc.
                    188:  */
1.1.1.5   root      189: struct inode * namei(const char * pathname)
1.1.1.4   root      190: {
                    191:        return _namei(pathname,NULL,1);
1.1       root      192: }
                    193: 
                    194: /*
                    195:  *     open_namei()
                    196:  *
                    197:  * namei for open - this is in fact almost the whole open-routine.
                    198:  */
                    199: int open_namei(const char * pathname, int flag, int mode,
1.1.1.5   root      200:        struct inode ** res_inode)
1.1       root      201: {
                    202:        const char * basename;
1.1.1.5   root      203:        int namelen,error;
                    204:        struct inode * dir, *inode;
1.1       root      205: 
                    206:        if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
                    207:                flag |= O_WRONLY;
                    208:        mode &= 0777 & ~current->umask;
                    209:        mode |= I_REGULAR;
1.1.1.4   root      210:        if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
1.1       root      211:                return -ENOENT;
                    212:        if (!namelen) {                 /* special case: '/usr/' etc */
                    213:                if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
                    214:                        *res_inode=dir;
                    215:                        return 0;
                    216:                }
                    217:                iput(dir);
                    218:                return -EISDIR;
                    219:        }
1.1.1.5   root      220:        dir->i_count++;         /* lookup eats the dir */
                    221:        error = lookup(dir,basename,namelen,&inode);
                    222:        if (error) {
1.1       root      223:                if (!(flag & O_CREAT)) {
                    224:                        iput(dir);
1.1.1.5   root      225:                        return error;
1.1       root      226:                }
                    227:                if (!permission(dir,MAY_WRITE)) {
                    228:                        iput(dir);
                    229:                        return -EACCES;
                    230:                }
1.1.1.5   root      231:                if (!dir->i_op || !dir->i_op->create) {
1.1       root      232:                        iput(dir);
1.1.1.5   root      233:                        return -EACCES;
1.1       root      234:                }
1.1.1.5   root      235:                return dir->i_op->create(dir,basename,namelen,mode,res_inode);
1.1       root      236:        }
1.1.1.4   root      237:        if (flag & O_EXCL) {
                    238:                iput(dir);
1.1.1.5   root      239:                iput(inode);
1.1       root      240:                return -EEXIST;
1.1.1.4   root      241:        }
1.1.1.5   root      242:        if (!(inode = follow_link(dir,inode)))
                    243:                return -ELOOP;
1.1       root      244:        if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
1.1.1.2   root      245:            !permission(inode,ACC_MODE(flag))) {
1.1       root      246:                iput(inode);
                    247:                return -EPERM;
                    248:        }
                    249:        inode->i_atime = CURRENT_TIME;
                    250:        if (flag & O_TRUNC)
1.1.1.6 ! root      251:                if (inode->i_op && inode->i_op->truncate)
        !           252:                        inode->i_op->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);
1.1.1.6 ! root      273:                return -EACCES;
1.1.1.2   root      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);
1.1.1.6 ! root      296:                return -EACCES;
1.1       root      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);
1.1.1.6 ! root      319:                return -EACCES;
1.1.1.3   root      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);
1.1.1.6 ! root      338:                return -EPERM;
1.1       root      339:        }
                    340:        if (!permission(dir,MAY_WRITE)) {
                    341:                iput(dir);
1.1.1.6 ! root      342:                return -EACCES;
1.1       root      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)
1.1.1.6 ! root      359:                return -ENOENT;
1.1.1.4   root      360:        if (!namelen) {
                    361:                iput(dir);
1.1.1.6 ! root      362:                return -ENOENT;
1.1.1.4   root      363:        }
                    364:        if (!permission(dir,MAY_WRITE)) {
                    365:                iput(dir);
1.1.1.6 ! root      366:                return -EACCES;
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.