/* * Add a directory block to the directory block list */ errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, int blockcnt) { struct ext2_db_entry *new_entry; errcode_t retval; unsigned long old_size; EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); if (dblist->count >= dblist->size) { old_size = dblist->size * sizeof(struct ext2_db_entry); dblist->size += 100; retval = ext2fs_resize_mem(old_size, (size_t) dblist->size * sizeof(struct ext2_db_entry), &dblist->list); if (retval) { dblist->size -= 100; return retval; } } new_entry = dblist->list + ( (int) dblist->count++); new_entry->blk = blk; new_entry->ino = ino; new_entry->blockcnt = blockcnt; dblist->sorted = 0; return 0; }
/* * This subroutine is called during pass1 to create a directory info * entry. During pass1, the passed-in parent is 0; it will get filled * in during pass2. */ void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks) { struct dx_dir_info *dir; int i, j; errcode_t retval; unsigned long old_size; #if 0 printf("add_dx_dir_info for inode %lu...\n", ino); #endif if (!ctx->dx_dir_info) { ctx->dx_dir_info_count = 0; ctx->dx_dir_info_size = 100; /* Guess */ ctx->dx_dir_info = (struct dx_dir_info *) e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size * sizeof (struct dx_dir_info), "directory map"); } if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) { old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info); ctx->dx_dir_info_size += 10; retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size * sizeof(struct dx_dir_info), (void **) &ctx->dx_dir_info); if (retval) { ctx->dx_dir_info_size -= 10; return; } } /* * Normally, add_dx_dir_info is called with each inode in * sequential order; but once in a while (like when pass 3 * needs to recreate the root directory or lost+found * directory) it is called out of order. In those cases, we * need to move the dx_dir_info entries down to make room, since * the dx_dir_info array needs to be sorted by inode number for * get_dx_dir_info()'s sake. */ if (ctx->dx_dir_info_count && ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) { for (i = ctx->dx_dir_info_count-1; i > 0; i--) if (ctx->dx_dir_info[i-1].ino < ino) break; dir = &ctx->dx_dir_info[i]; if (dir->ino != ino) for (j = ctx->dx_dir_info_count++; j > i; j--) ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1]; } else dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++]; dir->ino = ino; dir->numblocks = num_blocks; dir->hashversion = 0; dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks * sizeof (struct dx_dirblock_info), "dx_block info array"); }
/* * insert_refcount_el() --- Insert a new entry into the sorted list at a * specified position. */ static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount, ea_key_t ea_key, int pos) { struct ea_refcount_el *el; errcode_t retval; size_t new_size = 0; int num; if (refcount->count >= refcount->size) { new_size = refcount->size + 100; #ifdef DEBUG printf("Reallocating refcount %d entries...\n", new_size); #endif retval = ext2fs_resize_mem((size_t) refcount->size * sizeof(struct ea_refcount_el), (size_t) new_size * sizeof(struct ea_refcount_el), &refcount->list); if (retval) return 0; refcount->size = new_size; } num = (int) refcount->count - pos; if (num < 0) return 0; /* should never happen */ if (num) { memmove(&refcount->list[pos+1], &refcount->list[pos], sizeof(struct ea_refcount_el) * num); } refcount->count++; el = &refcount->list[pos]; el->ea_key = ea_key; el->ea_value = 0; return el; }
void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks) { struct dx_dir_info *dir; int i, j; errcode_t retval; unsigned long old_size; #if 0 printf("add_dx_dir_info for inode %lu...\n", ino); #endif if (!ctx->dx_dir_info) { ctx->dx_dir_info_count = 0; ctx->dx_dir_info_size = 100; ctx->dx_dir_info = (struct dx_dir_info *) e2fsck_allocate_memory(ctx, ctx->dx_dir_info_size * sizeof (struct dx_dir_info), "directory map"); } if (ctx->dx_dir_info_count >= ctx->dx_dir_info_size) { old_size = ctx->dx_dir_info_size * sizeof(struct dx_dir_info); ctx->dx_dir_info_size += 10; retval = ext2fs_resize_mem(old_size, ctx->dx_dir_info_size * sizeof(struct dx_dir_info), &ctx->dx_dir_info); if (retval) { ctx->dx_dir_info_size -= 10; return; } } if (ctx->dx_dir_info_count && ctx->dx_dir_info[ctx->dx_dir_info_count-1].ino >= ino) { for (i = ctx->dx_dir_info_count-1; i > 0; i--) if (ctx->dx_dir_info[i-1].ino < ino) break; dir = &ctx->dx_dir_info[i]; if (dir->ino != ino) for (j = ctx->dx_dir_info_count++; j > i; j--) ctx->dx_dir_info[j] = ctx->dx_dir_info[j-1]; } else dir = &ctx->dx_dir_info[ctx->dx_dir_info_count++]; dir->ino = ino; dir->numblocks = num_blocks; dir->hashversion = 0; dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks * sizeof (struct dx_dirblock_info), "dx_block info array"); }
static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct set_badblock_record *rec = (struct set_badblock_record *) priv_data; errcode_t retval; unsigned long old_size; if (!*block_nr) return 0; /* * If the block number is outrageous, clear it and ignore it. */ if (*block_nr >= fs->super->s_blocks_count || *block_nr < fs->super->s_first_data_block) { *block_nr = 0; return BLOCK_CHANGED; } if (blockcnt < 0) { if (rec->ind_blocks_size >= rec->max_ind_blocks) { old_size = rec->max_ind_blocks * sizeof(blk_t); rec->max_ind_blocks += 10; retval = ext2fs_resize_mem(old_size, rec->max_ind_blocks * sizeof(blk_t), &rec->ind_blocks); if (retval) { rec->max_ind_blocks -= 10; rec->err = retval; return BLOCK_ABORT; } } rec->ind_blocks[rec->ind_blocks_size++] = *block_nr; } /* * Mark the block as unused, and update accounting information */ ext2fs_block_alloc_stats(fs, *block_nr, -1); *block_nr = 0; return BLOCK_CHANGED; }
/* * insert_icount_el() --- Insert a new entry into the sorted list at a * specified position. */ static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount, ext2_ino_t ino, int pos) { struct ext2_icount_el *el; errcode_t retval; ext2_ino_t new_size = 0; int num; if (icount->last_lookup && icount->last_lookup->ino == ino) return icount->last_lookup; if (icount->count >= icount->size) { if (icount->count) { new_size = icount->list[(unsigned)icount->count-1].ino; new_size = (ext2_ino_t) (icount->count * ((float) icount->num_inodes / new_size)); } if (new_size < (icount->size + 100)) new_size = icount->size + 100; #if 0 printf("Reallocating icount %u entries...\n", new_size); #endif retval = ext2fs_resize_mem((size_t) icount->size * sizeof(struct ext2_icount_el), (size_t) new_size * sizeof(struct ext2_icount_el), &icount->list); if (retval) return 0; icount->size = new_size; } num = (int) icount->count - pos; if (num < 0) return 0; /* should never happen */ if (num) { memmove(&icount->list[pos+1], &icount->list[pos], sizeof(struct ext2_icount_el) * num); } icount->count++; el = &icount->list[pos]; el->count = 0; el->ino = ino; icount->last_lookup = el; return el; }
/* * This procedure adds a block to a badblocks list. */ errcode_t ext2fs_u32_list_add(ext2_u32_list bb, u32 blk) { errcode_t retval; int i, j; unsigned long old_size; EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST); if (bb->num >= bb->size) { old_size = bb->size * sizeof(u32); bb->size += 100; retval = ext2fs_resize_mem(old_size, bb->size * sizeof(u32), &bb->list); if (retval) { bb->size -= 100; return retval; } } /* * Add special case code for appending to the end of the list */ i = bb->num-1; if ((bb->num != 0) && (bb->list[i] == blk)) return 0; if ((bb->num == 0) || (bb->list[i] < blk)) { bb->list[bb->num++] = blk; return 0; } j = bb->num; for (i=0; i < bb->num; i++) { if (bb->list[i] == blk) return 0; if (bb->list[i] > blk) { j = i; break; } } for (i=bb->num; i > j; i--) bb->list[i] = bb->list[i-1]; bb->list[j] = blk; bb->num++; return 0; }
errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end, ext2fs_generic_bitmap bmap) { errcode_t retval; size_t size, new_size; __u32 bitno; if (!bmap) return EXT2_ET_INVALID_ARGUMENT; EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP); /* * If we're expanding the bitmap, make sure all of the new * parts of the bitmap are zero. */ if (new_end > bmap->end) { bitno = bmap->real_end; if (bitno > new_end) bitno = new_end; for (; bitno > bmap->end; bitno--) ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap); } if (new_real_end == bmap->real_end) { bmap->end = new_end; return 0; } size = ((bmap->real_end - bmap->start) / 8) + 1; new_size = ((new_real_end - bmap->start) / 8) + 1; if (size != new_size) { retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap); if (retval) return retval; } if (new_size > size) memset(bmap->bitmap + size, 0, new_size - size); bmap->end = new_end; bmap->real_end = new_real_end; return 0; }
/* * Add an entry to the extent table */ errcode_t ext2fs_add_extent_entry(ext2_extent extent, __u64 old_loc, __u64 new_loc) { struct ext2_extent_entry *ent; errcode_t retval; __u64 newsize; __u64 curr; if (extent->num >= extent->size) { newsize = extent->size + 100; retval = ext2fs_resize_mem(sizeof(struct ext2_extent_entry) * extent->size, sizeof(struct ext2_extent_entry) * newsize, &extent->list); if (retval) return retval; extent->size = newsize; } curr = extent->num; ent = extent->list + curr; if (curr) { /* * Check to see if this can be coalesced with the last * extent */ ent--; if ((ent->old_loc + ent->size == old_loc) && (ent->new_loc + ent->size == new_loc)) { ent->size++; return 0; } /* * Now see if we're going to ruin the sorting */ if (ent->old_loc + ent->size > old_loc) extent->sorted = 0; ent++; } ent->old_loc = old_loc; ent->new_loc = new_loc; ent->size = 1; extent->num++; return 0; }
errcode_t ext2fs_resize_generic_bitmap(errcode_t magic, __u32 new_end, __u32 new_real_end, ext2fs_generic_bitmap bmap) { errcode_t retval; size_t size, new_size; __u32 bitno; if (!bmap || (bmap->magic != magic)) return magic; /* * If we're expanding the bitmap, make sure all of the new * parts of the bitmap are zero. */ if (new_end > bmap->end) { bitno = bmap->real_end; if (bitno > new_end) bitno = new_end; for (; bitno > bmap->end; bitno--) ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap); } if (new_real_end == bmap->real_end) { bmap->end = new_end; return 0; } size = ((bmap->real_end - bmap->start) / 8) + 1; new_size = ((new_real_end - bmap->start) / 8) + 1; if (size != new_size) { retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap); if (retval) return retval; } if (new_size > size) memset(bmap->bitmap + size, 0, new_size - size); bmap->end = new_end; bmap->real_end = new_real_end; return 0; }
/* * Schedule a function to be called at (normal) program termination. * If you want this to be called during a signal exit, you must capture * the signal and call exit() yourself! */ errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data) { struct exit_data *ed, *free_ed = NULL; size_t x; errcode_t ret; if (func == NULL) return EXT2_ET_INVALID_ARGUMENT; for (x = 0, ed = items; x < nr_items; x++, ed++) { if (ed->func == func && ed->data == data) return EXT2_ET_FILE_EXISTS; if (ed->func == NULL) free_ed = ed; } if (free_ed) { free_ed->func = func; free_ed->data = data; return 0; } if (nr_items == 0) { ret = atexit(handle_exit); if (ret) return ret; } ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data), &items); if (ret) return ret; items[nr_items].func = func; items[nr_items].data = data; nr_items++; return 0; }
/* * This subroutine is called during pass1 to create a directory info * entry. During pass1, the passed-in parent is 0; it will get filled * in during pass2. */ void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent) { struct dir_info_db *db; struct dir_info *dir, ent, *old_array; int i, j; errcode_t retval; unsigned long old_size; #ifdef DIRINFO_DEBUG printf("add_dir_info for inode (%lu, %lu)...\n", ino, parent); #endif if (!ctx->dir_info) setup_db(ctx); db = ctx->dir_info; if (ctx->dir_info->count >= ctx->dir_info->size) { old_size = ctx->dir_info->size * sizeof(struct dir_info); ctx->dir_info->size += 10; old_array = ctx->dir_info->array; retval = ext2fs_resize_mem(old_size, ctx->dir_info->size * sizeof(struct dir_info), &ctx->dir_info->array); if (retval) { fprintf(stderr, "Couldn't reallocate dir_info " "structure to %d entries\n", ctx->dir_info->size); fatal_error(ctx, 0); ctx->dir_info->size -= 10; return; } if (old_array != ctx->dir_info->array) ctx->dir_info->last_lookup = NULL; } ent.ino = ino; ent.parent = parent; ent.dotdot = parent; if (db->tdb) { e2fsck_put_dir_info(ctx, &ent); return; } /* * Normally, add_dir_info is called with each inode in * sequential order; but once in a while (like when pass 3 * needs to recreate the root directory or lost+found * directory) it is called out of order. In those cases, we * need to move the dir_info entries down to make room, since * the dir_info array needs to be sorted by inode number for * get_dir_info()'s sake. */ if (ctx->dir_info->count && ctx->dir_info->array[ctx->dir_info->count-1].ino >= ino) { for (i = ctx->dir_info->count-1; i > 0; i--) if (ctx->dir_info->array[i-1].ino < ino) break; dir = &ctx->dir_info->array[i]; if (dir->ino != ino) for (j = ctx->dir_info->count++; j > i; j--) ctx->dir_info->array[j] = ctx->dir_info->array[j-1]; } else dir = &ctx->dir_info->array[ctx->dir_info->count++]; dir->ino = ino; dir->dotdot = parent; dir->parent = parent; }