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

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.1.9 ! root       11: #include <errno.h>
        !            12: #include <const.h>
        !            13: 
1.1       root       14: #include <asm/segment.h>
                     15: 
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.5   root      200:        int namelen,error;
                    201:        struct inode * dir, *inode;
1.1       root      202: 
                    203:        if ((flag & O_TRUNC) && !(flag & O_ACCMODE))
                    204:                flag |= O_WRONLY;
1.1.1.8   root      205:        mode &= 07777 & ~current->umask;
1.1       root      206:        mode |= I_REGULAR;
1.1.1.4   root      207:        if (!(dir = dir_namei(pathname,&namelen,&basename,NULL)))
1.1       root      208:                return -ENOENT;
                    209:        if (!namelen) {                 /* special case: '/usr/' etc */
                    210:                if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) {
                    211:                        *res_inode=dir;
                    212:                        return 0;
                    213:                }
                    214:                iput(dir);
                    215:                return -EISDIR;
                    216:        }
1.1.1.5   root      217:        dir->i_count++;         /* lookup eats the dir */
                    218:        error = lookup(dir,basename,namelen,&inode);
                    219:        if (error) {
1.1       root      220:                if (!(flag & O_CREAT)) {
                    221:                        iput(dir);
1.1.1.5   root      222:                        return error;
1.1       root      223:                }
                    224:                if (!permission(dir,MAY_WRITE)) {
                    225:                        iput(dir);
                    226:                        return -EACCES;
                    227:                }
1.1.1.5   root      228:                if (!dir->i_op || !dir->i_op->create) {
1.1       root      229:                        iput(dir);
1.1.1.5   root      230:                        return -EACCES;
1.1       root      231:                }
1.1.1.5   root      232:                return dir->i_op->create(dir,basename,namelen,mode,res_inode);
1.1       root      233:        }
1.1.1.4   root      234:        if (flag & O_EXCL) {
                    235:                iput(dir);
1.1.1.5   root      236:                iput(inode);
1.1       root      237:                return -EEXIST;
1.1.1.4   root      238:        }
1.1.1.5   root      239:        if (!(inode = follow_link(dir,inode)))
                    240:                return -ELOOP;
1.1       root      241:        if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) ||
1.1.1.2   root      242:            !permission(inode,ACC_MODE(flag))) {
1.1       root      243:                iput(inode);
                    244:                return -EPERM;
                    245:        }
                    246:        inode->i_atime = CURRENT_TIME;
                    247:        if (flag & O_TRUNC)
1.1.1.7   root      248:                if (inode->i_op && inode->i_op->truncate) {
                    249:                        inode->i_size = 0;
1.1.1.6   root      250:                        inode->i_op->truncate(inode);
1.1.1.7   root      251:                }
1.1       root      252:        *res_inode = inode;
                    253:        return 0;
                    254: }
                    255: 
1.1.1.8   root      256: int do_mknod(const char * filename, int mode, int dev)
1.1.1.2   root      257: {
                    258:        const char * basename;
                    259:        int namelen;
1.1.1.5   root      260:        struct inode * dir;
1.1.1.2   root      261:        
1.1.1.4   root      262:        if (!(dir = dir_namei(filename,&namelen,&basename, NULL)))
1.1.1.2   root      263:                return -ENOENT;
                    264:        if (!namelen) {
                    265:                iput(dir);
                    266:                return -ENOENT;
                    267:        }
                    268:        if (!permission(dir,MAY_WRITE)) {
                    269:                iput(dir);
1.1.1.6   root      270:                return -EACCES;
1.1.1.2   root      271:        }
1.1.1.5   root      272:        if (!dir->i_op || !dir->i_op->mknod) {
1.1.1.2   root      273:                iput(dir);
1.1.1.5   root      274:                return -EPERM;
1.1.1.2   root      275:        }
1.1.1.5   root      276:        return dir->i_op->mknod(dir,basename,namelen,mode,dev);
1.1.1.2   root      277: }
                    278: 
1.1.1.8   root      279: int sys_mknod(const char * filename, int mode, int dev)
                    280: {
1.1.1.9 ! root      281:        if (S_ISFIFO(mode) || suser())
1.1.1.8   root      282:                return do_mknod(filename,mode,dev);
                    283:        return -EPERM;
                    284: }
                    285: 
1.1       root      286: int sys_mkdir(const char * pathname, int mode)
                    287: {
                    288:        const char * basename;
                    289:        int namelen;
1.1.1.5   root      290:        struct inode * dir;
1.1       root      291: 
1.1.1.4   root      292:        if (!(dir = dir_namei(pathname,&namelen,&basename, NULL)))
1.1       root      293:                return -ENOENT;
                    294:        if (!namelen) {
                    295:                iput(dir);
                    296:                return -ENOENT;
                    297:        }
                    298:        if (!permission(dir,MAY_WRITE)) {
                    299:                iput(dir);
1.1.1.6   root      300:                return -EACCES;
1.1       root      301:        }
1.1.1.5   root      302:        if (!dir->i_op || !dir->i_op->mkdir) {
1.1       root      303:                iput(dir);
1.1.1.5   root      304:                return -EPERM;
1.1       root      305:        }
1.1.1.5   root      306:        return dir->i_op->mkdir(dir,basename,namelen,mode);
1.1       root      307: }
                    308: 
                    309: int sys_rmdir(const char * name)
                    310: {
                    311:        const char * basename;
                    312:        int namelen;
1.1.1.5   root      313:        struct inode * dir;
1.1       root      314: 
1.1.1.4   root      315:        if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
1.1       root      316:                return -ENOENT;
                    317:        if (!namelen) {
                    318:                iput(dir);
                    319:                return -ENOENT;
                    320:        }
1.1.1.3   root      321:        if (!permission(dir,MAY_WRITE)) {
                    322:                iput(dir);
1.1.1.6   root      323:                return -EACCES;
1.1.1.3   root      324:        }
1.1.1.5   root      325:        if (!dir->i_op || !dir->i_op->rmdir) {
1.1       root      326:                iput(dir);
                    327:                return -EPERM;
                    328:        }
1.1.1.5   root      329:        return dir->i_op->rmdir(dir,basename,namelen);
1.1       root      330: }
                    331: 
                    332: int sys_unlink(const char * name)
                    333: {
                    334:        const char * basename;
                    335:        int namelen;
1.1.1.5   root      336:        struct inode * dir;
1.1       root      337: 
1.1.1.4   root      338:        if (!(dir = dir_namei(name,&namelen,&basename, NULL)))
1.1       root      339:                return -ENOENT;
                    340:        if (!namelen) {
                    341:                iput(dir);
1.1.1.6   root      342:                return -EPERM;
1.1       root      343:        }
                    344:        if (!permission(dir,MAY_WRITE)) {
                    345:                iput(dir);
1.1.1.6   root      346:                return -EACCES;
1.1       root      347:        }
1.1.1.5   root      348:        if (!dir->i_op || !dir->i_op->unlink) {
1.1.1.2   root      349:                iput(dir);
                    350:                return -EPERM;
1.1.1.3   root      351:        }
1.1.1.5   root      352:        return dir->i_op->unlink(dir,basename,namelen);
1.1       root      353: }
                    354: 
1.1.1.4   root      355: int sys_symlink(const char * oldname, const char * newname)
                    356: {
1.1.1.5   root      357:        struct inode * dir;
1.1.1.4   root      358:        const char * basename;
1.1.1.5   root      359:        int namelen;
1.1.1.4   root      360: 
                    361:        dir = dir_namei(newname,&namelen,&basename, NULL);
                    362:        if (!dir)
1.1.1.6   root      363:                return -ENOENT;
1.1.1.4   root      364:        if (!namelen) {
                    365:                iput(dir);
1.1.1.6   root      366:                return -ENOENT;
1.1.1.4   root      367:        }
                    368:        if (!permission(dir,MAY_WRITE)) {
                    369:                iput(dir);
1.1.1.6   root      370:                return -EACCES;
1.1.1.4   root      371:        }
1.1.1.5   root      372:        if (!dir->i_op || !dir->i_op->symlink) {
1.1.1.4   root      373:                iput(dir);
1.1.1.5   root      374:                return -EPERM;
1.1.1.4   root      375:        }
1.1.1.5   root      376:        return dir->i_op->symlink(dir,basename,namelen,oldname);
1.1.1.4   root      377: }
                    378: 
1.1       root      379: int sys_link(const char * oldname, const char * newname)
                    380: {
1.1.1.5   root      381:        struct inode * oldinode, * dir;
1.1       root      382:        const char * basename;
                    383:        int namelen;
                    384: 
1.1.1.5   root      385:        oldinode = namei(oldname);
1.1       root      386:        if (!oldinode)
                    387:                return -ENOENT;
1.1.1.4   root      388:        dir = dir_namei(newname,&namelen,&basename, NULL);
1.1       root      389:        if (!dir) {
                    390:                iput(oldinode);
                    391:                return -EACCES;
                    392:        }
                    393:        if (!namelen) {
                    394:                iput(oldinode);
                    395:                iput(dir);
                    396:                return -EPERM;
                    397:        }
                    398:        if (dir->i_dev != oldinode->i_dev) {
                    399:                iput(dir);
                    400:                iput(oldinode);
                    401:                return -EXDEV;
                    402:        }
                    403:        if (!permission(dir,MAY_WRITE)) {
                    404:                iput(dir);
                    405:                iput(oldinode);
                    406:                return -EACCES;
                    407:        }
1.1.1.5   root      408:        if (!dir->i_op || !dir->i_op->link) {
1.1       root      409:                iput(dir);
                    410:                iput(oldinode);
1.1.1.5   root      411:                return -EPERM;
1.1       root      412:        }
1.1.1.5   root      413:        return dir->i_op->link(oldinode, dir, basename, namelen);
                    414: }
                    415: 
                    416: int sys_rename(const char * oldname, const char * newname)
                    417: {
                    418:        struct inode * old_dir, * new_dir;
                    419:        const char * old_base, * new_base;
                    420:        int old_len, new_len;
                    421: 
                    422:        old_dir = dir_namei(oldname,&old_len,&old_base, NULL);
                    423:        if (!old_dir)
                    424:                return -ENOENT;
                    425:        if (!permission(old_dir,MAY_WRITE)) {
                    426:                iput(old_dir);
                    427:                return -EACCES;
1.1       root      428:        }
1.1.1.5   root      429:        if (!old_len || (get_fs_byte(old_base) == '.' &&
                    430:            (old_len == 1 || (get_fs_byte(old_base+1) == '.' &&
                    431:             old_len == 2)))) {
                    432:                iput(old_dir);
                    433:                return -EPERM;
                    434:        }
                    435:        new_dir = dir_namei(newname,&new_len,&new_base, NULL);
                    436:        if (!new_dir) {
                    437:                iput(old_dir);
                    438:                return -ENOENT;
                    439:        }
                    440:        if (!permission(new_dir,MAY_WRITE)) {
                    441:                iput(old_dir);
                    442:                iput(new_dir);
                    443:                return -EACCES;
                    444:        }
                    445:        if (!new_len || (get_fs_byte(new_base) == '.' &&
                    446:            (new_len == 1 || (get_fs_byte(new_base+1) == '.' &&
                    447:             new_len == 2)))) {
                    448:                iput(old_dir);
                    449:                iput(new_dir);
                    450:                return -EPERM;
                    451:        }
                    452:        if (new_dir->i_dev != old_dir->i_dev) {
                    453:                iput(old_dir);
                    454:                iput(new_dir);
                    455:                return -EXDEV;
                    456:        }
                    457:        if (!old_dir->i_op || !old_dir->i_op->rename) {
                    458:                iput(old_dir);
                    459:                iput(new_dir);
                    460:                return -EPERM;
                    461:        }
                    462:        return old_dir->i_op->rename(old_dir, old_base, old_len, 
                    463:                new_dir, new_base, new_len);
1.1       root      464: }

unix.superglobalmegacorp.com

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