Annotation of linux/fs/ext/namei.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  *  linux/fs/ext/namei.c
                      3:  *
1.1.1.2   root        4:  *  Copyright (C) 1992  Remy Card ([email protected])
1.1       root        5:  *
                      6:  *  from
                      7:  *
                      8:  *  linux/fs/minix/namei.c
                      9:  *
1.1.1.2   root       10:  *  Copyright (C) 1991, 1992  Linus Torvalds
1.1       root       11:  */
                     12: 
                     13: #include <linux/sched.h>
                     14: #include <linux/ext_fs.h>
                     15: #include <linux/kernel.h>
                     16: #include <linux/string.h>
                     17: #include <linux/stat.h>
                     18: #include <linux/fcntl.h>
1.1.1.2   root       19: #include <linux/errno.h>
                     20: 
1.1       root       21: #include <asm/segment.h>
                     22: 
                     23: /*
                     24:  * comment out this line if you want names > EXT_NAME_LEN chars to be
                     25:  * truncated. Else they will be disallowed.
                     26:  */
                     27: /* #define NO_TRUNCATE */
                     28: 
                     29: /*
                     30:  * EXT_DIR_PAD defines the directory entries boundaries
                     31:  *
                     32:  * NOTE: It must be a power of 2 and must be greater or equal than 8
                     33:  * because a directory entry needs 8 bytes for its fixed part
                     34:  * (4 bytes for the inode, 2 bytes for the entry length and 2 bytes
                     35:  * for the name length)
                     36:  */
                     37: #define EXT_DIR_PAD 8
                     38: 
                     39: /*
                     40:  *
                     41:  * EXT_DIR_MIN_SIZE is the minimal size of a directory entry
                     42:  *
                     43:  * During allocations, a directory entry is split into 2 ones
                     44:  * *ONLY* if the size of the unused part is greater than or 
                     45:  * equal to EXT_DIR_MIN_SIZE
                     46:  */
                     47: #define EXT_DIR_MIN_SIZE 12
                     48: 
                     49: /*
                     50:  * ok, we cannot use strncmp, as the name is not in our data space.
                     51:  * Thus we'll have to use ext_match. No big problem. Match also makes
                     52:  * some sanity tests.
                     53:  *
                     54:  * NOTE! unlike strncmp, ext_match returns 1 for success, 0 for failure.
                     55:  */
                     56: static int ext_match(int len,const char * name,struct ext_dir_entry * de)
                     57: {
                     58:        register int same __asm__("ax");
                     59: 
                     60:        if (!de || !de->inode || len > EXT_NAME_LEN)
                     61:                return 0;
                     62:        /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
                     63:        if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
                     64:                return 1;
                     65:        if (len < EXT_NAME_LEN && len != de->name_len)
                     66:                return 0;
                     67:        __asm__("cld\n\t"
                     68:                "fs ; repe ; cmpsb\n\t"
                     69:                "setz %%al"
                     70:                :"=a" (same)
                     71:                :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
                     72:                :"cx","di","si");
                     73:        return same;
                     74: }
                     75: 
                     76: /*
                     77:  *     ext_find_entry()
                     78:  *
                     79:  * finds an entry in the specified directory with the wanted name. It
                     80:  * returns the cache buffer in which the entry was found, and the entry
                     81:  * itself (as a parameter - res_dir). It does NOT read the inode of the
                     82:  * entry - you'll have to do that yourself if you want to.
                     83:  *
                     84:  * addition for the ext file system : this function returns the previous
                     85:  * and next directory entries in the parameters prev_dir and next_dir
                     86:  */
                     87: static struct buffer_head * ext_find_entry(struct inode * dir,
                     88:        const char * name, int namelen, struct ext_dir_entry ** res_dir,
                     89:        struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir)
                     90: {
                     91:        long offset;
                     92:        struct buffer_head * bh;
                     93:        struct ext_dir_entry * de;
                     94: 
                     95:        *res_dir = NULL;
                     96:        if (!dir)
                     97:                return NULL;
                     98: #ifdef NO_TRUNCATE
                     99:        if (namelen > EXT_NAME_LEN)
                    100:                return NULL;
                    101: #else
                    102:        if (namelen > EXT_NAME_LEN)
                    103:                namelen = EXT_NAME_LEN;
                    104: #endif
1.1.1.3 ! root      105:        bh = ext_bread(dir,0,0);
        !           106:        if (!bh)
1.1       root      107:                return NULL;
                    108:        if (prev_dir)
                    109:                *prev_dir = NULL;
                    110:        if (next_dir)
                    111:                *next_dir = NULL;
                    112:        offset = 0;
                    113:        de = (struct ext_dir_entry *) bh->b_data;
                    114:        while (offset < dir->i_size) {
                    115:                if ((char *)de >= BLOCK_SIZE+bh->b_data) {
                    116:                        brelse(bh);
                    117:                        bh = NULL;
1.1.1.3 ! root      118:                        bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0);
        !           119:                        if (!bh)
1.1       root      120:                                continue;
                    121:                        de = (struct ext_dir_entry *) bh->b_data;
                    122:                        if (prev_dir)
                    123:                                *prev_dir = NULL;
                    124:                }
1.1.1.3 ! root      125:                if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
        !           126:                    de->rec_len < de->name_len + 8) {
        !           127:                        printk ("ext_find_entry: bad dir entry\n");
        !           128:                        printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
        !           129:                                dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
        !           130:                        brelse (bh);
        !           131:                        return NULL;
        !           132:                }
1.1       root      133:                if (ext_match(namelen,name,de)) {
                    134:                        *res_dir = de;
                    135:                        if (next_dir)
                    136:                                if (offset + de->rec_len < dir->i_size)
                    137:                                        *next_dir = (struct ext_dir_entry *)
                    138:                                                ((char *) de + de->rec_len);
                    139:                                else
                    140:                                        *next_dir = NULL;
                    141:                        return bh;
                    142:                }
                    143:                offset += de->rec_len;
                    144:                if (prev_dir)
                    145:                        *prev_dir = de;
                    146:                de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
                    147:        }
                    148:        brelse(bh);
                    149:        return NULL;
                    150: }
                    151: 
                    152: int ext_lookup(struct inode * dir,const char * name, int len,
                    153:        struct inode ** result)
                    154: {
                    155:        int ino;
                    156:        struct ext_dir_entry * de;
                    157:        struct buffer_head * bh;
                    158: 
                    159:        *result = NULL;
                    160:        if (!dir)
                    161:                return -ENOENT;
                    162:        if (!S_ISDIR(dir->i_mode)) {
                    163:                iput(dir);
                    164:                return -ENOENT;
                    165:        }
                    166:        if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) {
                    167:                iput(dir);
                    168:                return -ENOENT;
                    169:        }
                    170:        ino = de->inode;
                    171:        brelse(bh);
                    172:        if (!(*result = iget(dir->i_dev,ino))) {
                    173:                iput(dir);
                    174:                return -EACCES;
                    175:        }
                    176:        iput(dir);
                    177:        return 0;
                    178: }
                    179: 
                    180: /*
                    181:  *     ext_add_entry()
                    182:  *
                    183:  * adds a file entry to the specified directory, using the same
                    184:  * semantics as ext_find_entry(). It returns NULL if it failed.
                    185:  *
                    186:  * NOTE!! The inode part of 'de' is left at 0 - which means you
                    187:  * may not sleep between calling this and putting something into
                    188:  * the entry, as someone else might have used it while you slept.
                    189:  */
                    190: static struct buffer_head * ext_add_entry(struct inode * dir,
                    191:        const char * name, int namelen, struct ext_dir_entry ** res_dir)
                    192: {
1.1.1.3 ! root      193:        int i;
1.1       root      194:        long offset;
                    195:        unsigned short rec_len;
                    196:        struct buffer_head * bh;
                    197:        struct ext_dir_entry * de, * de1;
                    198: 
                    199:        *res_dir = NULL;
                    200:        if (!dir)
                    201:                return NULL;
                    202: #ifdef NO_TRUNCATE
                    203:        if (namelen > EXT_NAME_LEN)
                    204:                return NULL;
                    205: #else
                    206:        if (namelen > EXT_NAME_LEN)
                    207:                namelen = EXT_NAME_LEN;
                    208: #endif
                    209:        if (!namelen)
                    210:                return NULL;
1.1.1.3 ! root      211:        bh = ext_bread(dir,0,0);
        !           212:        if (!bh)
1.1       root      213:                return NULL;
                    214:        rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD;
                    215:        offset = 0;
                    216:        de = (struct ext_dir_entry *) bh->b_data;
                    217:        while (1) {
                    218:                if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) {
                    219: #ifdef EXTFS_DEBUG
                    220: printk ("ext_add_entry: skipping to next block\n");
                    221: #endif
                    222:                        brelse(bh);
                    223:                        bh = NULL;
1.1.1.3 ! root      224:                        bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1);
        !           225:                        if (!bh)
1.1       root      226:                                return NULL;
                    227:                        de = (struct ext_dir_entry *) bh->b_data;
                    228:                }
                    229:                if (offset >= dir->i_size) {
                    230:                        /* Check that the directory entry fits in the block */
                    231:                        if (offset % BLOCK_SIZE == 0 
                    232:                            || (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) {
                    233:                                if ((offset % BLOCK_SIZE) != 0) {
                    234:                                        /* If the entry does not fit in the
                    235:                                           block, the remainder of the block
                    236:                                           becomes an unused entry */
                    237:                                        de->inode = 0;
                    238:                                        de->rec_len = BLOCK_SIZE
                    239:                                                - (offset & (BLOCK_SIZE - 1));
                    240:                                        de->name_len = 0;
                    241:                                        offset += de->rec_len;
                    242:                                        dir->i_size += de->rec_len;
                    243:                                        dir->i_dirt = 1;
                    244:                                        dir->i_ctime = CURRENT_TIME;
                    245:                                        bh->b_dirt = 1;
                    246:                                }
                    247:                                brelse (bh);
                    248:                                bh = NULL;
                    249: #ifdef EXTFS_DEBUG
                    250: printk ("ext_add_entry : creating next block\n");
                    251: #endif
1.1.1.3 ! root      252:                                bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1);
        !           253:                                if (!bh)
1.1       root      254:                                        return NULL; /* Other thing to do ??? */
                    255:                                de = (struct ext_dir_entry *) bh->b_data;
                    256:                        }
                    257:                        /* Allocate the entry */
                    258:                        de->inode=0;
                    259:                        de->rec_len = rec_len;
                    260:                        dir->i_size += de->rec_len;
                    261:                        dir->i_dirt = 1;
                    262:                        dir->i_ctime = CURRENT_TIME;
                    263:                }
1.1.1.3 ! root      264:                if (de->rec_len < 8 || de->rec_len % 4 != 0 ||
        !           265:                    de->rec_len < de->name_len + 8) {
        !           266:                        printk ("ext_addr_entry: bad dir entry\n");
        !           267:                        printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
        !           268:                                dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len);
        !           269:                        brelse (bh);
        !           270:                        return NULL;
        !           271:                }
1.1       root      272:                if (!de->inode && de->rec_len >= rec_len) {
                    273:                        if (de->rec_len > rec_len
                    274:                            && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) {
                    275:                                /* The found entry is too big : it is split
                    276:                                   into 2 ones :
                    277:                                   - the 1st one will be used to hold the name,
                    278:                                   - the 2nd one is unused */
                    279:                                de1 = (struct ext_dir_entry *) ((char *) de + rec_len);
                    280:                                de1->inode = 0;
                    281:                                de1->rec_len = de->rec_len - rec_len;
                    282:                                de1->name_len = 0;
                    283:                                de->rec_len = rec_len;
                    284:                        }
                    285:                        dir->i_mtime = CURRENT_TIME;
                    286:                        de->name_len = namelen;
                    287:                        for (i=0; i < namelen ; i++)
1.1.1.3 ! root      288:                                de->name[i]=get_fs_byte(name+i);
1.1       root      289:                        bh->b_dirt = 1;
                    290:                        *res_dir = de;
                    291:                        return bh;
                    292:                }
                    293:                offset += de->rec_len;
                    294:                de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
                    295:        }
                    296:        brelse(bh);
                    297:        return NULL;
                    298: }
                    299: 
                    300: int ext_create(struct inode * dir,const char * name, int len, int mode,
                    301:        struct inode ** result)
                    302: {
                    303:        struct inode * inode;
                    304:        struct buffer_head * bh;
                    305:        struct ext_dir_entry * de;
                    306: 
                    307:        *result = NULL;
                    308:        if (!dir)
                    309:                return -ENOENT;
                    310:        inode = ext_new_inode(dir->i_dev);
                    311:        if (!inode) {
                    312:                iput(dir);
                    313:                return -ENOSPC;
                    314:        }
                    315:        inode->i_op = &ext_file_inode_operations;
                    316:        inode->i_mode = mode;
                    317:        inode->i_dirt = 1;
                    318:        bh = ext_add_entry(dir,name,len,&de);
                    319:        if (!bh) {
                    320:                inode->i_nlink--;
                    321:                inode->i_dirt = 1;
                    322:                iput(inode);
                    323:                iput(dir);
                    324:                return -ENOSPC;
                    325:        }
                    326:        de->inode = inode->i_ino;
                    327:        bh->b_dirt = 1;
                    328:        brelse(bh);
                    329:        iput(dir);
                    330:        *result = inode;
                    331:        return 0;
                    332: }
                    333: 
                    334: int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
                    335: {
                    336:        struct inode * inode;
                    337:        struct buffer_head * bh;
                    338:        struct ext_dir_entry * de;
                    339: 
                    340:        if (!dir)
                    341:                return -ENOENT;
                    342:        bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
                    343:        if (bh) {
                    344:                brelse(bh);
                    345:                iput(dir);
                    346:                return -EEXIST;
                    347:        }
                    348:        inode = ext_new_inode(dir->i_dev);
                    349:        if (!inode) {
                    350:                iput(dir);
                    351:                return -ENOSPC;
                    352:        }
                    353:        inode->i_uid = current->euid;
                    354:        inode->i_mode = mode;
                    355:        inode->i_op = NULL;
                    356:        if (S_ISREG(inode->i_mode))
                    357:                inode->i_op = &ext_file_inode_operations;
                    358:        else if (S_ISDIR(inode->i_mode))
                    359:                inode->i_op = &ext_dir_inode_operations;
                    360:        else if (S_ISLNK(inode->i_mode))
                    361:                inode->i_op = &ext_symlink_inode_operations;
                    362:        else if (S_ISCHR(inode->i_mode))
                    363:                inode->i_op = &ext_chrdev_inode_operations;
                    364:        else if (S_ISBLK(inode->i_mode))
                    365:                inode->i_op = &ext_blkdev_inode_operations;
                    366:        else if (S_ISFIFO(inode->i_mode)) {
                    367:                inode->i_op = &ext_fifo_inode_operations;
                    368:                inode->i_pipe = 1;
1.1.1.3 ! root      369:                PIPE_BASE(*inode) = NULL;
1.1       root      370:                PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
1.1.1.3 ! root      371:                PIPE_READ_WAIT(*inode) = PIPE_WRITE_WAIT(*inode) = NULL;
1.1       root      372:                PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0;
                    373:        }
                    374:        if (S_ISBLK(mode) || S_ISCHR(mode))
                    375:                inode->i_rdev = rdev;
                    376:        inode->i_mtime = inode->i_atime = CURRENT_TIME;
                    377:        inode->i_dirt = 1;
                    378:        bh = ext_add_entry(dir,name,len,&de);
                    379:        if (!bh) {
                    380:                inode->i_nlink--;
                    381:                inode->i_dirt = 1;
                    382:                iput(inode);
                    383:                iput(dir);
                    384:                return -ENOSPC;
                    385:        }
                    386:        de->inode = inode->i_ino;
                    387:        bh->b_dirt = 1;
                    388:        brelse(bh);
                    389:        iput(dir);
                    390:        iput(inode);
                    391:        return 0;
                    392: }
                    393: 
                    394: int ext_mkdir(struct inode * dir, const char * name, int len, int mode)
                    395: {
                    396:        struct inode * inode;
                    397:        struct buffer_head * bh, *dir_block;
                    398:        struct ext_dir_entry * de;
                    399:        
                    400:        bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
                    401:        if (bh) {
                    402:                brelse(bh);
                    403:                iput(dir);
                    404:                return -EEXIST;
                    405:        }
                    406:        inode = ext_new_inode(dir->i_dev);
                    407:        if (!inode) {
                    408:                iput(dir);
                    409:                return -ENOSPC;
                    410:        }
                    411:        inode->i_op = &ext_dir_inode_operations;
                    412:        inode->i_size = 2 * 16; /* Each entry is coded on 16 bytes for "." and ".."
                    413:                                        - 4 bytes for the inode number,
                    414:                                        - 2 bytes for the record length
                    415:                                        - 2 bytes for the name length
                    416:                                        - 8 bytes for the name */
                    417:        inode->i_mtime = inode->i_atime = CURRENT_TIME;
1.1.1.3 ! root      418:        dir_block = ext_bread(inode,0,1);
        !           419:        if (!dir_block) {
1.1       root      420:                iput(dir);
                    421:                inode->i_nlink--;
                    422:                inode->i_dirt = 1;
                    423:                iput(inode);
                    424:                return -ENOSPC;
                    425:        }
                    426:        de = (struct ext_dir_entry *) dir_block->b_data;
                    427:        de->inode=inode->i_ino;
                    428:        de->rec_len=16;
                    429:        de->name_len=1;
                    430:        strcpy(de->name,".");
                    431:        de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
                    432:        de->inode = dir->i_ino;
                    433:        de->rec_len=16;
                    434:        de->name_len=2;
                    435:        strcpy(de->name,"..");
                    436:        inode->i_nlink = 2;
                    437:        dir_block->b_dirt = 1;
                    438:        brelse(dir_block);
1.1.1.3 ! root      439:        inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask);
1.1       root      440:        inode->i_dirt = 1;
                    441:        bh = ext_add_entry(dir,name,len,&de);
                    442:        if (!bh) {
                    443:                iput(dir);
                    444:                inode->i_nlink=0;
                    445:                iput(inode);
                    446:                return -ENOSPC;
                    447:        }
                    448:        de->inode = inode->i_ino;
                    449:        bh->b_dirt = 1;
                    450:        dir->i_nlink++;
                    451:        dir->i_dirt = 1;
                    452:        iput(dir);
                    453:        iput(inode);
                    454:        brelse(bh);
                    455:        return 0;
                    456: }
                    457: 
                    458: /*
                    459:  * routine to check that the specified directory is empty (for rmdir)
                    460:  */
                    461: static int empty_dir(struct inode * inode)
                    462: {
                    463:        unsigned long offset;
                    464:        struct buffer_head * bh;
                    465:        struct ext_dir_entry * de, * de1;
                    466: 
1.1.1.3 ! root      467:        if (inode->i_size < 2 * 12 || !(bh = ext_bread(inode,0,0))) {
1.1       root      468:                printk("warning - bad directory on dev %04x\n",inode->i_dev);
1.1.1.3 ! root      469:                return 1;
1.1       root      470:        }
                    471:        de = (struct ext_dir_entry *) bh->b_data;
                    472:        de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len);
                    473:        if (de->inode != inode->i_ino || !de1->inode || 
                    474:            strcmp(".",de->name) || strcmp("..",de1->name)) {
                    475:                printk("warning - bad directory on dev %04x\n",inode->i_dev);
1.1.1.3 ! root      476:                return 1;
1.1       root      477:        }
                    478:        offset = de->rec_len + de1->rec_len;
                    479:        de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len);
                    480:        while (offset < inode->i_size ) {
                    481:                if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) {
                    482:                        brelse(bh);
1.1.1.3 ! root      483:                        bh = ext_bread(inode, offset >> BLOCK_SIZE_BITS,1);
        !           484:                        if (!bh) {
1.1       root      485:                                offset += BLOCK_SIZE;
                    486:                                continue;
                    487:                        }
                    488:                        de = (struct ext_dir_entry *) bh->b_data;
                    489:                }
1.1.1.3 ! root      490:                if (de->rec_len < 8 || de->rec_len %4 != 0 ||
        !           491:                    de->rec_len < de->name_len + 8) {
        !           492:                        printk ("empty_dir: bad dir entry\n");
        !           493:                        printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n",
        !           494:                                inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len);
        !           495:                        brelse (bh);
        !           496:                        return 1;
        !           497:                }
1.1       root      498:                if (de->inode) {
                    499:                        brelse(bh);
                    500:                        return 0;
                    501:                }
                    502:                offset += de->rec_len;
                    503:                de = (struct ext_dir_entry *) ((char *) de + de->rec_len);
                    504:        }
                    505:        brelse(bh);
                    506:        return 1;
                    507: }
                    508: 
                    509: static inline void ext_merge_entries (struct ext_dir_entry * de,
                    510:        struct ext_dir_entry * pde, struct ext_dir_entry * nde)
                    511: {
                    512:        if (! nde->inode)
                    513:                de->rec_len += nde->rec_len;
                    514:        if (! pde->inode)
                    515:                pde->rec_len += de->rec_len;
                    516: }
                    517: 
                    518: int ext_rmdir(struct inode * dir, const char * name, int len)
                    519: {
                    520:        int retval;
                    521:        struct inode * inode;
                    522:        struct buffer_head * bh;
                    523:        struct ext_dir_entry * de, * pde, * nde;
                    524: 
                    525:        inode = NULL;
                    526:        bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
                    527:        retval = -ENOENT;
                    528:        if (!bh)
                    529:                goto end_rmdir;
                    530:        retval = -EPERM;
                    531:        if (!(inode = iget(dir->i_dev, de->inode)))
                    532:                goto end_rmdir;
                    533:        if ((dir->i_mode & S_ISVTX) && current->euid &&
                    534:           inode->i_uid != current->euid)
                    535:                goto end_rmdir;
                    536:        if (inode->i_dev != dir->i_dev)
                    537:                goto end_rmdir;
                    538:        if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
                    539:                goto end_rmdir;
                    540:        if (!S_ISDIR(inode->i_mode)) {
                    541:                retval = -ENOTDIR;
                    542:                goto end_rmdir;
                    543:        }
                    544:        if (!empty_dir(inode)) {
                    545:                retval = -ENOTEMPTY;
                    546:                goto end_rmdir;
                    547:        }
                    548:        if (inode->i_count > 1) {
                    549:                retval = -EBUSY;
                    550:                goto end_rmdir;
                    551:        }
                    552:        if (inode->i_nlink != 2)
                    553:                printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
                    554:        de->inode = 0;
                    555:        de->name_len = 0;
                    556:        ext_merge_entries (de, pde, nde);
                    557:        bh->b_dirt = 1;
                    558:        inode->i_nlink=0;
                    559:        inode->i_dirt=1;
                    560:        dir->i_nlink--;
                    561:        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
                    562:        dir->i_dirt=1;
                    563:        retval = 0;
                    564: end_rmdir:
                    565:        iput(dir);
                    566:        iput(inode);
                    567:        brelse(bh);
                    568:        return retval;
                    569: }
                    570: 
                    571: int ext_unlink(struct inode * dir, const char * name, int len)
                    572: {
                    573:        int retval;
                    574:        struct inode * inode;
                    575:        struct buffer_head * bh;
                    576:        struct ext_dir_entry * de, * pde, * nde;
                    577: 
                    578:        retval = -ENOENT;
                    579:        inode = NULL;
                    580:        bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
                    581:        if (!bh)
                    582:                goto end_unlink;
                    583:        if (!(inode = iget(dir->i_dev, de->inode)))
                    584:                goto end_unlink;
                    585:        retval = -EPERM;
                    586:        if ((dir->i_mode & S_ISVTX) && !suser() &&
                    587:            current->euid != inode->i_uid &&
                    588:            current->euid != dir->i_uid)
                    589:                goto end_unlink;
                    590:        if (S_ISDIR(inode->i_mode))
                    591:                goto end_unlink;
                    592:        if (!inode->i_nlink) {
                    593:                printk("Deleting nonexistent file (%04x:%d), %d\n",
                    594:                        inode->i_dev,inode->i_ino,inode->i_nlink);
                    595:                inode->i_nlink=1;
                    596:        }
                    597:        de->inode = 0;
                    598:        de->name_len = 0;
                    599:        ext_merge_entries (de, pde, nde);
                    600:        bh->b_dirt = 1;
                    601:        inode->i_nlink--;
                    602:        inode->i_dirt = 1;
                    603:        inode->i_ctime = CURRENT_TIME;
                    604:        retval = 0;
                    605: end_unlink:
                    606:        brelse(bh);
                    607:        iput(inode);
                    608:        iput(dir);
                    609:        return retval;
                    610: }
                    611: 
                    612: int ext_symlink(struct inode * dir, const char * name, int len, const char * symname)
                    613: {
                    614:        struct ext_dir_entry * de;
                    615:        struct inode * inode = NULL;
                    616:        struct buffer_head * bh = NULL, * name_block = NULL;
                    617:        int i;
                    618:        char c;
                    619: 
                    620:        if (!(inode = ext_new_inode(dir->i_dev))) {
                    621:                iput(dir);
                    622:                return -ENOSPC;
                    623:        }
                    624:        inode->i_mode = S_IFLNK | 0777;
                    625:        inode->i_op = &ext_symlink_inode_operations;
1.1.1.3 ! root      626:        name_block = ext_bread(inode,0,1);
        !           627:        if (!name_block) {
1.1       root      628:                iput(dir);
                    629:                inode->i_nlink--;
                    630:                inode->i_dirt = 1;
                    631:                iput(inode);
                    632:                return -ENOSPC;
                    633:        }
                    634:        i = 0;
                    635:        while (i < 1023 && (c=get_fs_byte(symname++)))
                    636:                name_block->b_data[i++] = c;
                    637:        name_block->b_data[i] = 0;
                    638:        name_block->b_dirt = 1;
                    639:        brelse(name_block);
                    640:        inode->i_size = i;
                    641:        inode->i_dirt = 1;
                    642:        bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
                    643:        if (bh) {
                    644:                inode->i_nlink--;
                    645:                inode->i_dirt = 1;
                    646:                iput(inode);
                    647:                brelse(bh);
                    648:                iput(dir);
                    649:                return -EEXIST;
                    650:        }
                    651:        bh = ext_add_entry(dir,name,len,&de);
                    652:        if (!bh) {
                    653:                inode->i_nlink--;
                    654:                inode->i_dirt = 1;
                    655:                iput(inode);
                    656:                iput(dir);
                    657:                return -ENOSPC;
                    658:        }
                    659:        de->inode = inode->i_ino;
                    660:        bh->b_dirt = 1;
                    661:        brelse(bh);
                    662:        iput(dir);
                    663:        iput(inode);
                    664:        return 0;
                    665: }
                    666: 
                    667: int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
                    668: {
                    669:        struct ext_dir_entry * de;
                    670:        struct buffer_head * bh;
                    671: 
                    672:        if (S_ISDIR(oldinode->i_mode)) {
                    673:                iput(oldinode);
                    674:                iput(dir);
                    675:                return -EPERM;
                    676:        }
                    677:        bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
                    678:        if (bh) {
                    679:                brelse(bh);
                    680:                iput(dir);
                    681:                iput(oldinode);
                    682:                return -EEXIST;
                    683:        }
                    684:        bh = ext_add_entry(dir,name,len,&de);
                    685:        if (!bh) {
                    686:                iput(dir);
                    687:                iput(oldinode);
                    688:                return -ENOSPC;
                    689:        }
                    690:        de->inode = oldinode->i_ino;
                    691:        bh->b_dirt = 1;
                    692:        brelse(bh);
                    693:        iput(dir);
                    694:        oldinode->i_nlink++;
                    695:        oldinode->i_ctime = CURRENT_TIME;
                    696:        oldinode->i_dirt = 1;
                    697:        iput(oldinode);
                    698:        return 0;
                    699: }
                    700: 
                    701: static int subdir(struct inode * new, struct inode * old)
                    702: {
                    703:        unsigned short fs;
                    704:        int ino;
                    705:        int result;
                    706: 
                    707:        __asm__("mov %%fs,%0":"=r" (fs));
                    708:        __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10));
                    709:        new->i_count++;
                    710:        result = 0;
                    711:        for (;;) {
                    712:                if (new == old) {
                    713:                        result = 1;
                    714:                        break;
                    715:                }
                    716:                if (new->i_dev != old->i_dev)
                    717:                        break;
                    718:                ino = new->i_ino;
                    719:                if (ext_lookup(new,"..",2,&new))
                    720:                        break;
                    721:                if (new->i_ino == ino)
                    722:                        break;
                    723:        }
                    724:        iput(new);
                    725:        __asm__("mov %0,%%fs"::"r" (fs));
                    726:        return result;
                    727: }
                    728: 
                    729: #define PARENT_INO(buffer) \
                    730: ((struct ext_dir_entry *) ((char *) buffer + \
                    731: ((struct ext_dir_entry *) buffer)->rec_len))->inode
                    732: 
                    733: #define PARENT_NAME(buffer) \
                    734: ((struct ext_dir_entry *) ((char *) buffer + \
                    735: ((struct ext_dir_entry *) buffer)->rec_len))->name
                    736: 
                    737: /*
                    738:  * rename uses retrying to avoid race-conditions: at least they should be minimal.
                    739:  * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
                    740:  * checks fail, it tries to restart itself again. Very practical - no changes
                    741:  * are done until we know everything works ok.. and then all the changes can be
                    742:  * done in one fell swoop when we have claimed all the buffers needed.
                    743:  *
                    744:  * Anybody can rename anything with this: the permission checks are left to the
                    745:  * higher-level routines.
                    746:  */
                    747: static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len,
                    748:        struct inode * new_dir, const char * new_name, int new_len)
                    749: {
                    750:        struct inode * old_inode, * new_inode;
                    751:        struct buffer_head * old_bh, * new_bh, * dir_bh;
                    752:        struct ext_dir_entry * old_de, * new_de, * pde, * nde;
                    753:        int retval;
                    754: 
                    755:        goto start_up;
                    756: try_again:
                    757:        brelse(old_bh);
                    758:        brelse(new_bh);
                    759:        brelse(dir_bh);
                    760:        iput(old_inode);
                    761:        iput(new_inode);
                    762:        current->counter = 0;
                    763:        schedule();
                    764: start_up:
                    765:        old_inode = new_inode = NULL;
                    766:        old_bh = new_bh = dir_bh = NULL;
                    767:        old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde);
                    768:        retval = -ENOENT;
                    769:        if (!old_bh)
                    770:                goto end_rename;
                    771:        old_inode = iget(old_dir->i_dev, old_de->inode);
                    772:        if (!old_inode)
                    773:                goto end_rename;
                    774:        if ((old_dir->i_mode & S_ISVTX) && 
                    775:            current->euid != old_inode->i_uid &&
                    776:            current->euid != old_dir->i_uid && !suser())
                    777:                goto end_rename;
                    778:        new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
                    779:        if (new_bh) {
                    780:                new_inode = iget(new_dir->i_dev, new_de->inode);
                    781:                if (!new_inode) {
                    782:                        brelse(new_bh);
                    783:                        new_bh = NULL;
                    784:                }
                    785:        }
                    786:        if (new_inode == old_inode) {
                    787:                retval = 0;
                    788:                goto end_rename;
                    789:        }
1.1.1.2   root      790:        if (S_ISDIR(new_inode->i_mode)) {
                    791:                retval = -EEXIST;
                    792:                goto end_rename;
                    793:        }
1.1       root      794:        if (S_ISDIR(old_inode->i_mode)) {
                    795:                retval = -EEXIST;
                    796:                if (new_bh)
                    797:                        goto end_rename;
                    798:                retval = -EACCES;
                    799:                if (!permission(old_inode, MAY_WRITE))
                    800:                        goto end_rename;
                    801:                retval = -EINVAL;
                    802:                if (subdir(new_dir, old_inode))
                    803:                        goto end_rename;
                    804:                retval = -EIO;
1.1.1.3 ! root      805:                dir_bh = ext_bread(old_inode,0,0);
        !           806:                if (!dir_bh)
1.1       root      807:                        goto end_rename;
                    808:                if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
                    809:                        goto end_rename;
                    810:        }
                    811:        if (!new_bh)
                    812:                new_bh = ext_add_entry(new_dir,new_name,new_len,&new_de);
                    813:        retval = -ENOSPC;
                    814:        if (!new_bh)
                    815:                goto end_rename;
                    816: /* sanity checking before doing the rename - avoid races */
                    817:        if (new_inode && (new_de->inode != new_inode->i_ino))
                    818:                goto try_again;
                    819:        if (new_de->inode && !new_inode)
                    820:                goto try_again;
                    821:        if (old_de->inode != old_inode->i_ino)
                    822:                goto try_again;
                    823: /* ok, that's it */
                    824:        old_de->inode = 0;
                    825:        old_de->name_len = 0;
                    826:        new_de->inode = old_inode->i_ino;
1.1.1.2   root      827:        ext_merge_entries (old_de, pde, nde);
1.1       root      828:        if (new_inode) {
                    829:                new_inode->i_nlink--;
                    830:                new_inode->i_dirt = 1;
                    831:        }
                    832:        old_bh->b_dirt = 1;
                    833:        new_bh->b_dirt = 1;
                    834:        if (dir_bh) {
                    835:                PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
                    836:                dir_bh->b_dirt = 1;
                    837:                old_dir->i_nlink--;
                    838:                new_dir->i_nlink++;
                    839:                old_dir->i_dirt = 1;
                    840:                new_dir->i_dirt = 1;
                    841:        }
                    842:        retval = 0;
                    843: end_rename:
                    844:        brelse(dir_bh);
                    845:        brelse(old_bh);
                    846:        brelse(new_bh);
                    847:        iput(old_inode);
                    848:        iput(new_inode);
                    849:        iput(old_dir);
                    850:        iput(new_dir);
                    851:        return retval;
                    852: }
                    853: 
                    854: /*
                    855:  * Ok, rename also locks out other renames, as they can change the parent of
                    856:  * a directory, and we don't want any races. Other races are checked for by
                    857:  * "do_rename()", which restarts if there are inconsistencies.
                    858:  *
                    859:  * Note that there is no race between different filesystems: it's only within
                    860:  * the same device that races occur: many renames can happen at once, as long
                    861:  * as they are on different partitions.
                    862:  */
                    863: int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
                    864:        struct inode * new_dir, const char * new_name, int new_len)
                    865: {
1.1.1.2   root      866:        static struct wait_queue * wait = NULL;
1.1       root      867:        static int lock = 0;
                    868:        int result;
                    869: 
                    870:        while (lock)
                    871:                sleep_on(&wait);
                    872:        lock = 1;
                    873:        result = do_ext_rename(old_dir, old_name, old_len,
                    874:                new_dir, new_name, new_len);
                    875:        lock = 0;
                    876:        wake_up(&wait);
                    877:        return result;
                    878: }

unix.superglobalmegacorp.com

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