Upstream-Status: inappropriate From 3d47e37e21f6a2ced489d49e8bf5a5c24bb9baaf Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sun, 5 Jun 2011 09:36:11 -0500 Subject: [PATCH 04/19] Add a dirwalker for walking through directory entries The code to walk directory items was messy, to say the least. Write a clean structure to do this. Also, remove d_name[0]. This is bad style, and newer compilers will think it is really a zero-length array and will abort if trying to write any data to it, since the compiler thinks it has no contents. --- genext2fs.c | 210 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 154 insertions(+), 56 deletions(-) diff --git a/genext2fs.c b/genext2fs.c index 0b5ba6f..03d1b27 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -533,7 +533,6 @@ typedef struct typedef struct { directory_decl - char d_name[0]; } directory; typedef uint8 block[BLOCKSIZE]; @@ -795,6 +794,8 @@ static inline uint8 * get_workblk(void) { unsigned char* b=calloc(1,BLOCKSIZE); + if (!b) + error_msg_and_die("get_workblk() failed, out of memory"); return b; } static inline void @@ -902,6 +903,126 @@ put_nod(nod_info *ni) free(ni); } +// Used to hold state information while walking a directory inode. +typedef struct +{ + directory d; + filesystem *fs; + uint32 nod; + directory *last_d; + uint8 *b; + blk_info *bi; +} dirwalker; + +// Start a directory walk on the given inode. You must pass in a +// dirwalker structure, then use that dirwalker for future operations. +// Call put_dir when you are done walking the directory. +static inline directory * +get_dir(filesystem *fs, uint32 nod, dirwalker *dw) +{ + dw->fs = fs; + dw->b = get_blk(fs, nod, &dw->bi); + dw->nod = nod; + dw->last_d = (directory *) dw->b; + + memcpy(&dw->d, dw->last_d, sizeof(directory)); + return &dw->d; +} + +// Move to the next directory. +static inline directory * +next_dir(dirwalker *dw) +{ + directory *next_d = (directory *)((int8*)dw->last_d + dw->d.d_rec_len); + + memcpy(dw->last_d, &dw->d, sizeof(directory)); + + if (((int8 *) next_d) >= ((int8 *) dw->b + BLOCKSIZE)) + return NULL; + + dw->last_d = next_d; + memcpy(&dw->d, next_d, sizeof(directory)); + return &dw->d; +} + +// Call then when you are done with the directory walk. +static inline void +put_dir(dirwalker *dw) +{ + memcpy(dw->last_d, &dw->d, sizeof(directory)); + + if (dw->nod == 0) + free_workblk(dw->b); + else + put_blk(dw->bi); +} + +// Create a new directory block with the given inode as it's destination +// and append it to the current dirwalker. +static directory * +new_dir(filesystem *fs, uint32 dnod, const char *name, int nlen, dirwalker *dw) +{ + directory *d; + + dw->fs = fs; + dw->b = get_workblk(); + dw->nod = 0; + dw->last_d = (directory *) dw->b; + d = &dw->d; + d->d_inode = dnod; + d->d_rec_len = BLOCKSIZE; + d->d_name_len = nlen; + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen); + return d; +} + +// Shrink the current directory entry, make a new one with the free +// space, and return the new directory entry (making it current). +static inline directory * +shrink_dir(dirwalker *dw, uint32 nod, const char *name, int nlen) +{ + int reclen, preclen; + directory *d = &dw->d; + + reclen = d->d_rec_len; + d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4); + preclen = d->d_rec_len; + reclen -= preclen; + memcpy(dw->last_d, &dw->d, sizeof(directory)); + + dw->last_d = (directory *) (((int8 *) dw->last_d) + preclen); + d->d_rec_len = reclen; + d->d_inode = nod; + d->d_name_len = nlen; + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen); + + return d; +} + +// Return the current block the directory is walking +static inline uint8 * +dir_data(dirwalker *dw) +{ + return dw->b; +} + +// Return the pointer to the name for the current directory +static inline char * +dir_name(dirwalker *dw) +{ + return ((char *) dw->last_d) + sizeof(directory); +} + +// Set the name for the current directory. Note that this doesn't +// verify that there is space for the directory name, you must do +// that yourself. +static void +dir_set_name(dirwalker *dw, const char *name, int nlen) +{ + dw->d.d_name_len = nlen; + strncpy(((char *) dw->last_d) + sizeof(directory), name, nlen); +} + // allocate a given block/inode in the bitmap // allocate first free if item == 0 static uint32 @@ -1354,11 +1475,10 @@ extend_blk(filesystem *fs, uint32 nod, block b, int amount) static void add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name) { - blockwalker bw; + blockwalker bw, lbw; uint32 bk; - uint8 *b; - blk_info *bi; directory *d; + dirwalker dw; int reclen, nlen; inode *node; inode *pnode; @@ -1376,55 +1496,46 @@ add2dir(filesystem *fs, uint32 dnod, uint32 nod, const char* name) if(reclen > BLOCKSIZE) error_msg_and_die("bad name '%s' (too long)", name); init_bw(&bw); + lbw = bw; while((bk = walk_bw(fs, dnod, &bw, 0, 0)) != WALK_END) // for all blocks in dir { - b = get_blk(fs, bk, &bi); // for all dir entries in block - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) + for(d = get_dir(fs, bk, &dw); d; d = next_dir(&dw)) { // if empty dir entry, large enough, use it if((!d->d_inode) && (d->d_rec_len >= reclen)) { d->d_inode = nod; node = get_nod(fs, nod, &ni); + dir_set_name(&dw, name, nlen); + put_dir(&dw); node->i_links_count++; - d->d_name_len = nlen; - strncpy(d->d_name, name, nlen); put_nod(ni); goto out; } // if entry with enough room (last one?), shrink it & use it if(d->d_rec_len >= (sizeof(directory) + rndup(d->d_name_len, 4) + reclen)) { - reclen = d->d_rec_len; - d->d_rec_len = sizeof(directory) + rndup(d->d_name_len, 4); - reclen -= d->d_rec_len; - d = (directory*) (((int8*)d) + d->d_rec_len); - d->d_rec_len = reclen; - d->d_inode = nod; node = get_nod(fs, nod, &ni); + d = shrink_dir(&dw, nod, name, nlen); + put_dir(&dw); node->i_links_count++; - d->d_name_len = nlen; - strncpy(d->d_name, name, nlen); put_nod(ni); goto out; } } + put_dir(&dw); + lbw = bw; } // we found no free entry in the directory, so we add a block - if(!(b = get_workblk())) - error_msg_and_die("get_workblk() failed."); - d = (directory*)b; - d->d_inode = nod; node = get_nod(fs, nod, &ni); + d = new_dir(fs, nod, name, nlen, &dw); node->i_links_count++; put_nod(ni); - d->d_rec_len = BLOCKSIZE; - d->d_name_len = nlen; - strncpy(d->d_name, name, nlen); - extend_blk(fs, dnod, b, 1); + next_dir(&dw); // Force the data into the buffer + extend_blk(fs, dnod, dir_data(&dw), 1); + put_dir(&dw); pnode->i_size += BLOCKSIZE; - free_workblk(b); out: put_nod(dni); } @@ -1435,20 +1546,18 @@ find_dir(filesystem *fs, uint32 nod, const char * name) { blockwalker bw; uint32 bk; - blk_info *bi; int nlen = strlen(name); init_bw(&bw); while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) { directory *d; - uint8 *b; - b = get_blk(fs, bk, &bi); - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) - if(d->d_inode && (nlen == d->d_name_len) && !strncmp(d->d_name, name, nlen)) { - put_blk(bi); + dirwalker dw; + for (d = get_dir(fs, bk, &dw); d; d=next_dir(&dw)) + if(d->d_inode && (nlen == d->d_name_len) && !strncmp(dir_name(&dw), name, nlen)) { + put_dir(&dw); return d->d_inode; } - put_blk(bi); + put_dir(&dw); } return 0; } @@ -2090,8 +2199,7 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp { uint32 i; filesystem *fs; - directory *d; - uint8 * b; + dirwalker dw; uint32 nod, first_block; uint32 nbgroups,nbinodes_per_group,overhead_per_group,free_blocks, free_blocks_per_group,nbblocks_per_group,min_nbgroups; @@ -2217,26 +2325,20 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp itab0->i_links_count = 2; put_nod(ni); - if(!(b = get_workblk())) - error_msg_and_die("get_workblk() failed."); - d = (directory*)b; - d->d_inode = EXT2_ROOT_INO; - d->d_rec_len = sizeof(directory)+4; - d->d_name_len = 1; - strcpy(d->d_name, "."); - d = (directory*)(b + d->d_rec_len); - d->d_inode = EXT2_ROOT_INO; - d->d_rec_len = BLOCKSIZE - (sizeof(directory)+4); - d->d_name_len = 2; - strcpy(d->d_name, ".."); - extend_blk(fs, EXT2_ROOT_INO, b, 1); + new_dir(fs, EXT2_ROOT_INO, ".", 1, &dw); + shrink_dir(&dw, EXT2_ROOT_INO, "..", 2); + next_dir(&dw); // Force the data into the buffer + extend_blk(fs, EXT2_ROOT_INO, dir_data(&dw), 1); + put_dir(&dw); // make lost+found directory and reserve blocks if(fs->sb.s_r_blocks_count) { inode *node; + uint8 *b; nod = mkdir_fs(fs, EXT2_ROOT_INO, "lost+found", FM_IRWXU, 0, 0, fs_timestamp, fs_timestamp); + b = get_workblk(); memset(b, 0, BLOCKSIZE); ((directory*)b)->d_rec_len = BLOCKSIZE; /* We run into problems with e2fsck if directory lost+found grows @@ -2246,11 +2348,11 @@ init_fs(int nbblocks, int nbinodes, int nbresrvd, int holes, uint32 fs_timestamp fs->sb.s_r_blocks_count = fs->sb.s_blocks_count * MAX_RESERVED_BLOCKS; for(i = 1; i < fs->sb.s_r_blocks_count; i++) extend_blk(fs, nod, b, 1); + free_workblk(b); node = get_nod(fs, nod, &ni); node->i_size = fs->sb.s_r_blocks_count * BLOCKSIZE; put_nod(ni); } - free_workblk(b); // administrative info fs->sb.s_state = 1; @@ -2368,19 +2470,15 @@ print_dir(filesystem *fs, uint32 nod) while((bk = walk_bw(fs, nod, &bw, 0, 0)) != WALK_END) { directory *d; - uint8 *b; - blk_info *bi; - b = get_blk(fs, bk, &bi); - for(d = (directory*)b; (int8*)d + sizeof(*d) < (int8*)b + BLOCKSIZE; d = (directory*)((int8*)d + d->d_rec_len)) + dirwalker dw; + for (d = get_dir(fs, bk, &dw); d; d = next_dir(&dw)) if(d->d_inode) { - int i; printf("entry '"); - for(i = 0; i < d->d_name_len; i++) - putchar(d->d_name[i]); + fwrite(dir_name(&dw), 1, d->d_name_len, stdout); printf("' (inode %d): rec_len: %d (name_len: %d)\n", d->d_inode, d->d_rec_len, d->d_name_len); } - put_blk(bi); + put_dir(&dw); } } -- 1.7.4.1