Annotation of linux/fs/msdos/namei.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *  linux/fs/msdos/namei.c
                      3:  *
                      4:  *  Written 1992 by Werner Almesberger
                      5:  */
                      6: 
                      7: #include <asm/segment.h>
                      8: 
                      9: #include <linux/sched.h>
                     10: #include <linux/msdos_fs.h>
                     11: #include <linux/kernel.h>
                     12: #include <linux/errno.h>
                     13: #include <linux/string.h>
                     14: #include <linux/stat.h>
                     15: 
                     16: /* MS-DOS "device special files" */
                     17: 
                     18: static char *reserved_names[] = {
                     19:     "CON     ","PRN     ","NUL     ","AUX     ",
                     20:     "LPT1    ","LPT2    ","LPT3    ","LPT4    ",
                     21:     "COM1    ","COM2    ","COM3    ","COM4    ",
                     22:     NULL };
                     23: 
                     24: 
                     25: /* Formats an MS-DOS file name. Rejects invalid names. */
                     26: 
                     27: static int msdos_format_name(char conv,const char *name,int len,char *res)
                     28: {
                     29:        char *walk,**reserved;
                     30:        char c;
                     31:        int space;
                     32: 
                     33:        if (get_fs_byte(name) == DELETED_FLAG) return -EINVAL;
                     34:        if (get_fs_byte(name) == '.' && (len == 1 || (len == 2 &&
                     35:            get_fs_byte(name+1) == '.'))) {
                     36:                memset(res+1,' ',10);
                     37:                while (len--) *res++ = '.';
                     38:                return 0;
                     39:        }
                     40:        space = 0; /* to make GCC happy */
                     41:        c = 0;
                     42:        for (walk = res; len && walk-res < 8; walk++) {
                     43:                c = get_fs_byte(name++);
                     44:                len--;
                     45:                if (c == ' ' && conv != 'r') return -EINVAL;
                     46:                if (c >= 'A' && c <= 'Z') {
                     47:                        if (conv != 'r') return -EINVAL;
                     48:                        c += 32;
                     49:                }
                     50:                if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
                     51:                if (c == '.') break;
                     52:                space = c == ' ';
                     53:                *walk = c >= 'a' && c <= 'z' ? c-32 : c;
                     54:        }
                     55:        if (space) return -EINVAL;
                     56:        if (conv == 's' && len && c != '.') {
                     57:                c = get_fs_byte(name++);
                     58:                len--;
                     59:                if (c != '.') return -EINVAL;
                     60:        }
                     61:        while (c != '.' && len--) c = get_fs_byte(name++);
                     62:        if (walk == res) return -EINVAL;
                     63:        if (c == '.') {
                     64:                while (walk-res < 8) *walk++ = ' ';
                     65:                while (len > 0 && walk-res < MSDOS_NAME) {
                     66:                        c = get_fs_byte(name++);
                     67:                        len--;
                     68:                        if (c == ' ' && conv != 'r') return -EINVAL;
                     69:                        if (c < ' ' || c == ':' || c == '\\' || c == '.')
                     70:                                return -EINVAL;
                     71:                        if (c >= 'A' && c <= 'Z') {
                     72:                                if (conv != 'r') return -EINVAL;
                     73:                                c += 32;
                     74:                        }
                     75:                        space = c == ' ';
                     76:                        *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
                     77:                }
                     78:                if (space) return -EINVAL;
                     79:                if (conv == 's' && len) return -EINVAL;
                     80:        }
                     81:        while (walk-res < MSDOS_NAME) *walk++ = ' ';
                     82:        for (reserved = reserved_names; *reserved; reserved++)
                     83:                if (!strncmp(res,*reserved,8)) return -EINVAL;
                     84:        return 0;
                     85: }
                     86: 
                     87: 
                     88: /* Locates a directory entry. */
                     89: 
                     90: static int msdos_find(struct inode *dir,const char *name,int len,
                     91:     struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
                     92: {
                     93:        char msdos_name[MSDOS_NAME];
                     94:        int res;
                     95: 
                     96:        if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
                     97:            msdos_name)) < 0) return res;
                     98:        return msdos_scan(dir,msdos_name,bh,de,ino);
                     99: }
                    100: 
                    101: 
                    102: int msdos_lookup(struct inode *dir,const char *name,int len,
                    103:     struct inode **result)
                    104: {
                    105:        int ino,res;
                    106:        struct msdos_dir_entry *de;
                    107:        struct buffer_head *bh;
                    108:        struct inode *next;
                    109: 
                    110:        *result = NULL;
                    111:        if (!dir) return -ENOENT;
                    112:        if (!S_ISDIR(dir->i_mode)) {
                    113:                iput(dir);
                    114:                return -ENOENT;
                    115:        }
                    116:        if (len == 1 && get_fs_byte(name) == '.') {
                    117:                *result = dir;
                    118:                return 0;
                    119:        }
                    120:        if (len == 2 && get_fs_byte(name) == '.' && get_fs_byte(name+1) == '.')
                    121:            {
                    122:                ino = msdos_parent_ino(dir,0);
                    123:                iput(dir);
                    124:                if (ino < 0) return ino;
                    125:                if (!(*result = iget(dir->i_dev,ino))) return -EACCES;
                    126:                return 0;
                    127:        }
                    128:        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
                    129:                iput(dir);
                    130:                return res;
                    131:        }
                    132:        if (bh) brelse(bh);
                    133: /* printk("lookup: ino=%d\r\n",ino); */
                    134:        if (!(*result = iget(dir->i_dev,ino))) {
                    135:                iput(dir);
                    136:                return -EACCES;
                    137:        }
                    138:        if ((*result)->i_data[D_BUSY]) { /* mkdir in progress */
                    139:                iput(*result);
                    140:                iput(dir);
                    141:                return -ENOENT;
                    142:        }
                    143:        while ((*result)->i_data[D_OLD]) {
                    144:                next = (struct inode *) ((*result)->i_data[D_OLD]);
                    145:                iput(*result);
                    146:                if (!(*result = iget(next->i_dev,next->i_ino)))
                    147:                        panic("msdos_lookup: Can't happen");
                    148:        }
                    149:        iput(dir);
                    150:        return 0;
                    151: }
                    152: 
                    153: 
                    154: /* Creates a directory entry (name is already formatted). */
                    155: 
                    156: static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
                    157:     struct inode **result)
                    158: {
                    159:        struct buffer_head *bh;
                    160:        struct msdos_dir_entry *de;
                    161:        int res,ino;
                    162: 
                    163:        if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
                    164:                if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
                    165:                if ((res = msdos_add_cluster(dir)) < 0) return res;
                    166:                if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
                    167:        }
                    168:        memcpy(de->name,name,MSDOS_NAME);
                    169:        de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
                    170:        de->start = 0;
                    171:        date_unix2dos(CURRENT_TIME,&de->time,&de->date);
                    172:        de->size = 0;
                    173:        bh->b_dirt = 1;
                    174:        if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result);
                    175:        brelse(bh);
                    176:        if (!*result) return -EIO;
                    177:        (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
                    178:            CURRENT_TIME;
                    179:        (*result)->i_dirt = 1;
                    180:        return 0;
                    181: }
                    182: 
                    183: 
                    184: int msdos_create(struct inode *dir,const char *name,int len,int mode,
                    185:        struct inode **result)
                    186: {
                    187:        struct buffer_head *bh;
                    188:        struct msdos_dir_entry *de;
                    189:        char msdos_name[MSDOS_NAME];
                    190:        int ino,res;
                    191: 
                    192:        if (!dir) return -ENOENT;
                    193:        if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
                    194:            msdos_name)) < 0) {
                    195:                iput(dir);
                    196:                return res;
                    197:        }
                    198:        lock_creation();
                    199:        if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
                    200:                unlock_creation();
                    201:                brelse(bh);
                    202:                iput(dir);
                    203:                return -EEXIST;
                    204:        }
                    205:        res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result);
                    206:        unlock_creation();
                    207:        iput(dir);
                    208:        return res;
                    209: }
                    210: 
                    211: 
                    212: int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
                    213: {
                    214:        struct buffer_head *bh;
                    215:        struct msdos_dir_entry *de;
                    216:        struct inode *inode,*dot;
                    217:        char msdos_name[MSDOS_NAME];
                    218:        int ino,res;
                    219: 
                    220:        if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
                    221:            msdos_name)) < 0) {
                    222:                iput(dir);
                    223:                return res;
                    224:        }
                    225:        lock_creation();
                    226:        if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) {
                    227:                unlock_creation();
                    228:                brelse(bh);
                    229:                iput(dir);
                    230:                return -EEXIST;
                    231:        }
                    232:        if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) {
                    233:                unlock_creation();
                    234:                iput(dir);
                    235:                return res;
                    236:        }
                    237:        inode->i_data[D_BUSY] = 1; /* prevent lookups */
                    238:        if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error;
                    239:        if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0)
                    240:                goto mkdir_error;
                    241:        dot->i_size = inode->i_size;
                    242:        dot->i_data[D_START] = inode->i_data[D_START];
                    243:        dot->i_dirt = 1;
                    244:        iput(dot);
                    245:        if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0)
                    246:                goto mkdir_error;
                    247:        unlock_creation();
                    248:        dot->i_size = dir->i_size;
                    249:        dot->i_data[D_START] = dir->i_data[D_START];
                    250:        dot->i_dirt = 1;
                    251:        inode->i_data[D_BUSY] = 0;
                    252:        iput(dot);
                    253:        iput(inode);
                    254:        iput(dir);
                    255:        return 0;
                    256: mkdir_error:
                    257:        iput(inode);
                    258:        if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
                    259:        unlock_creation();
                    260:        return res;
                    261: }
                    262: 
                    263: 
                    264: int msdos_rmdir(struct inode *dir,const char *name,int len)
                    265: {
                    266:        int res,ino,pos;
                    267:        struct buffer_head *bh,*dbh;
                    268:        struct msdos_dir_entry *de,*dde;
                    269:        struct inode *inode;
                    270: 
                    271:        bh = NULL;
                    272:        inode = NULL;
                    273:        res = -EINVAL;
                    274:        if (len == 1 && get_fs_byte(name) == '.') goto rmdir_done;
                    275:        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
                    276:        res = -ENOENT;
                    277:        if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
                    278:        res = -ENOTDIR;
                    279:        if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
                    280:        res = -EBUSY;
                    281:        if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done;
                    282:        if (inode->i_count > 1) goto rmdir_done;
                    283:        if (inode->i_data[D_START]) { /* may be zero in mkdir */
                    284:                res = -ENOTEMPTY;
                    285:                pos = 0;
                    286:                dbh = NULL;
                    287:                while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
                    288:                        if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
                    289:                            DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
                    290:                            MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
                    291:                            MSDOS_NAME)) goto rmdir_done;
                    292:                if (dbh) brelse(dbh);
                    293:        }
                    294:        inode->i_nlink = 0;
                    295:        dir->i_mtime = CURRENT_TIME;
                    296:        inode->i_dirt = dir->i_dirt = 1;
                    297:        de->name[0] = DELETED_FLAG;
                    298:        bh->b_dirt = 1;
                    299:        res = 0;
                    300: rmdir_done:
                    301:        brelse(bh);
                    302:        iput(dir);
                    303:        iput(inode);
                    304:        return res;
                    305: }
                    306: 
                    307: 
                    308: int msdos_unlink(struct inode *dir,const char *name,int len)
                    309: {
                    310:        int res,ino;
                    311:        struct buffer_head *bh;
                    312:        struct msdos_dir_entry *de;
                    313:        struct inode *inode;
                    314: 
                    315:        bh = NULL;
                    316:        inode = NULL;
                    317:        if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
                    318:                goto unlink_done;
                    319:        if (!(inode = iget(dir->i_dev,ino))) {
                    320:                res = -ENOENT;
                    321:                goto unlink_done;
                    322:        }
                    323:        if (!S_ISREG(inode->i_mode)) {
                    324:                res = -EPERM;
                    325:                goto unlink_done;
                    326:        }
                    327:        inode->i_nlink = 0;
                    328:        inode->i_data[D_BUSY] = 1;
                    329:        inode->i_dirt = 1;
                    330:        de->name[0] = DELETED_FLAG;
                    331:        bh->b_dirt = 1;
                    332: unlink_done:
                    333:        brelse(bh);
                    334:        iput(inode);
                    335:        iput(dir);
                    336:        return res;
                    337: }
                    338: 
                    339: 
                    340: static int rename_same_dir(struct inode *old_dir,char *old_name,
                    341:     struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
                    342:     struct msdos_dir_entry *old_de,int old_ino)
                    343: {
                    344:        struct buffer_head *new_bh;
                    345:        struct msdos_dir_entry *new_de;
                    346:        struct inode *new_inode,*old_inode;
                    347:        int new_ino;
                    348:        int exists;
                    349: 
                    350:        if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0;
                    351:        exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
                    352:        if (*(unsigned char *) old_de->name == DELETED_FLAG) {
                    353:                if (exists) brelse(new_bh);
                    354:                return -ENOENT;
                    355:        }
                    356:        if (exists) {
                    357:                if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
                    358:                        brelse(new_bh);
                    359:                        return -EIO;
                    360:                }
                    361:                if (S_ISDIR(new_inode->i_mode)) {
                    362:                        iput(new_inode);
                    363:                        brelse(new_bh);
                    364:                        return -EPERM;
                    365:                }
                    366:                new_inode->i_nlink = 0;
                    367:                new_inode->i_data[D_BUSY] = 1;
                    368:                new_inode->i_dirt = 1;
                    369:                new_de->name[0] = DELETED_FLAG;
                    370:                new_bh->b_dirt = 1;
                    371:                iput(new_inode);
                    372:                brelse(new_bh);
                    373:        }
                    374:        memcpy(old_de->name,new_name,MSDOS_NAME);
                    375:        old_bh->b_dirt = 1;
                    376:        if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
                    377:                if (old_inode = iget(old_dir->i_dev,old_ino)) {
                    378:                        msdos_read_inode(old_inode);
                    379:                        iput(old_inode);
                    380:                }
                    381:        return 0;
                    382: }
                    383: 
                    384: 
                    385: static int rename_diff_dir(struct inode *old_dir,char *old_name,
                    386:     struct inode *new_dir,char *new_name,struct buffer_head *old_bh,
                    387:     struct msdos_dir_entry *old_de,int old_ino)
                    388: {
                    389:        struct buffer_head *new_bh,*free_bh,*dotdot_bh;
                    390:        struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
                    391:        struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk;
                    392:        int new_ino,free_ino,dotdot_ino;
                    393:        int error,exists,ino;
                    394: 
                    395:        if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
                    396:        if (old_ino == new_dir->i_ino) return -EINVAL;
                    397:        if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
                    398:        while (walk->i_ino != MSDOS_ROOT_INO) {
                    399:                ino = msdos_parent_ino(walk,1);
                    400:                iput(walk);
                    401:                if (ino < 0) return ino;
                    402:                if (ino == old_ino) return -EINVAL;
                    403:                if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
                    404:        }
                    405:        iput(walk);
                    406:        if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
                    407:            return error;
                    408:        exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
                    409:            >= 0;
                    410:        if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
                    411:                brelse(free_bh);
                    412:                if (exists) brelse(new_bh);
                    413:                return -EIO;
                    414:        }
                    415:        if (*(unsigned char *) old_de->name == DELETED_FLAG) {
                    416:                iput(old_inode);
                    417:                brelse(free_bh);
                    418:                if (exists) brelse(new_bh);
                    419:                return -ENOENT;
                    420:        }
                    421:        new_inode = NULL; /* to make GCC happy */
                    422:        if (exists) {
                    423:                if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
                    424:                        iput(old_inode);
                    425:                        brelse(new_bh);
                    426:                        return -EIO;
                    427:                }
                    428:                if (S_ISDIR(new_inode->i_mode)) {
                    429:                        iput(new_inode);
                    430:                        iput(old_inode);
                    431:                        brelse(new_bh);
                    432:                        return -EPERM;
                    433:                }
                    434:                new_inode->i_nlink = 0;
                    435:                new_inode->i_data[D_BUSY] = 1;
                    436:                new_inode->i_dirt = 1;
                    437:                new_de->name[0] = DELETED_FLAG;
                    438:                new_bh->b_dirt = 1;
                    439:        }
                    440:        memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
                    441:        memcpy(free_de->name,new_name,MSDOS_NAME);
                    442:        if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
                    443:                free_de->name[0] = DELETED_FLAG;
                    444: /*  Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
                    445:                brelse(free_bh);
                    446:                if (exists) {
                    447:                        iput(new_inode);
                    448:                        brelse(new_bh);
                    449:                }
                    450:                return -EIO;
                    451:        }
                    452:        msdos_read_inode(free_inode);
                    453:        old_inode->i_data[D_BUSY] = 1;
                    454:        old_inode->i_dirt = 1;
                    455:        old_de->name[0] = DELETED_FLAG;
                    456:        old_bh->b_dirt = 1;
                    457:        free_bh->b_dirt = 1;
                    458:        if (!exists) iput(free_inode);
                    459:        else {
                    460:                new_inode->i_data[D_DEPEND] = (int) free_inode;
                    461:                free_inode->i_data[D_OLD] = (int) new_inode;
                    462:                /* free_inode is put when putting new_inode */
                    463:                iput(new_inode);
                    464:                brelse(new_bh);
                    465:        }
                    466:        if (S_ISDIR(old_inode->i_mode)) {
                    467:                if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
                    468:                    &dotdot_de,&dotdot_ino)) < 0) goto rename_done;
                    469:                if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
                    470:                        brelse(dotdot_bh);
                    471:                        error = -EIO;
                    472:                        goto rename_done;
                    473:                }
                    474:                dotdot_de->start = dotdot_inode->i_data[D_START] =
                    475:                    new_dir->i_data[D_START];
                    476:                dotdot_inode->i_dirt = 1;
                    477:                dotdot_bh->b_dirt = 1;
                    478:                iput(dotdot_inode);
                    479:                brelse(dotdot_bh);
                    480:        }
                    481:        error = 0;
                    482: rename_done:
                    483:        brelse(free_bh);
                    484:        iput(old_inode);
                    485:        return error;
                    486: }
                    487: 
                    488: 
                    489: int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
                    490:        struct inode *new_dir,const char *new_name,int new_len)
                    491: {
                    492:        char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
                    493:        struct buffer_head *old_bh;
                    494:        struct msdos_dir_entry *old_de;
                    495:        int old_ino,error;
                    496: 
                    497:        if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
                    498:            old_name,old_len,old_msdos_name)) < 0) goto rename_done;
                    499:        if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
                    500:            new_name,new_len,new_msdos_name)) < 0) goto rename_done;
                    501:        if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
                    502:            &old_ino)) < 0) goto rename_done;
                    503:        lock_creation();
                    504:        if (old_dir == new_dir)
                    505:                error = rename_same_dir(old_dir,old_msdos_name,new_dir,
                    506:                    new_msdos_name,old_bh,old_de,old_ino);
                    507:        else error = rename_diff_dir(old_dir,old_msdos_name,new_dir,
                    508:                    new_msdos_name,old_bh,old_de,old_ino);
                    509:        unlock_creation();
                    510:        brelse(old_bh);
                    511: rename_done:
                    512:        iput(old_dir);
                    513:        iput(new_dir);
                    514:        return error;
                    515: }

unix.superglobalmegacorp.com

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