2 * inodemap.c --- ext2resizer indoe mapper
4 * Copyright (C) 1997 Theodore Ts'o
11 #include "resize2fs.h"
13 struct inode_map_entry {
17 struct inode_map_struct {
18 struct inode_map_entry *list;
24 typedef struct inode_map_struct *inode_map;
27 * Create inode map table
29 static errcode_t create_inode_map(inode_map *imap, int size)
33 new = malloc(sizeof(struct inode_map_struct));
36 memset(new, 0, sizeof(struct inode_map_struct));
38 new->size = size ? size : 50;
42 new->list = malloc(sizeof(struct inode_map_struct) * new->size);
52 * Add an entry to the inode table map
54 static errcode_t add_inode_map_entry(inode_map imap, ino_t old, ino_t new)
56 struct inode_map_entry *p;
59 if (imap->num >= imap->size) {
60 newsize = imap->size + 100;
61 p = realloc(imap->list,
62 sizeof(struct inode_map_struct) * newsize);
69 if (imap->list[imap->num-1].old > old)
72 imap->list[imap->num].old = old;
73 imap->list[imap->num].new = new;
79 * Helper function for qsort
81 static int inode_map_cmp(const void *a, const void *b)
83 const struct inode_map_entry *db_a =
84 (const struct inode_map_entry *) a;
85 const struct inode_map_entry *db_b =
86 (const struct inode_map_entry *) b;
88 return (db_a->old - db_b->old);
92 * Given an inode map and inode number, look up the old inode number
93 * and return the new inode number
95 static ino_t inode_map_translate(inode_map imap, ino_t old)
98 ino_t lowval, highval;
102 qsort(imap->list, imap->num,
103 sizeof(struct inode_map_entry), inode_map_cmp);
108 while (low <= high) {
115 /* Interpolate for efficiency */
116 lowval = imap->list[low].old;
117 highval = imap->list[high].old;
121 else if (old > highval)
124 range = ((float) (old - lowval)) /
126 mid = low + ((int) (range * (high-low)));
129 if (old == imap->list[mid].old)
130 return imap->list[mid].new;
131 if (old < imap->list[mid].old)
144 int check_and_change_inodes(ino_t dir, int entry,
145 struct ext2_dir_entry *dirent, int offset,
146 int blocksize, char *buf, void *private)
148 struct istruct *is = private;
154 new = inode_map_translate(is->imap, dirent->inode);
158 if (is->flags & RESIZE_DEBUG_INODEMAP)
159 printf("Inode translate (dir=%ld, name=%.*s, %ld->%ld)\n",
160 dir, dirent->name_len, dirent->name,
165 return DIRENT_CHANGED;
168 errcode_t ext2fs_inode_move(ext2_resize_t rfs)
170 ino_t ino, start, end, new;
171 struct ext2_inode inode;
172 ext2_inode_scan scan;
178 if (rfs->old_fs->group_desc_count <=
179 rfs->new_fs->group_desc_count)
182 retval = create_inode_map(&imap, 0);
186 retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
190 retval = ext2fs_inode_scan_goto_blockgroup(scan,
191 rfs->new_fs->group_desc_count);
193 ext2fs_close_inode_scan(scan);
197 new = EXT2_FIRST_INODE(rfs->new_fs->super);
200 * First, copy all of the inodes that need to be moved
201 * elsewhere in the inode table
204 retval = ext2fs_get_next_inode(scan, &ino, &inode);
210 if (!ext2fs_test_inode_bitmap(rfs->old_fs->inode_map, ino))
217 if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map,
221 if (new > rfs->new_fs->super->s_inodes_count)
224 ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new);
225 retval = ext2fs_write_inode(rfs->old_fs, new, &inode);
228 group = (new-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
229 if (LINUX_S_ISDIR(inode.i_mode))
230 rfs->new_fs->group_desc[group].bg_used_dirs_count++;
232 if (rfs->flags & RESIZE_DEBUG_INODEMAP)
233 printf("Inode moved %ld->%ld\n", ino, new);
235 add_inode_map_entry(imap, ino, new);
238 * Now, we iterate over all of the directories to update the
242 is.flags = rfs->flags;
243 retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist, 0, 0,
244 check_and_change_inodes, &is);