1/* vi: set sw=4 ts=4: */ 2/* 3 * irel_ma.c 4 * 5 * Copyright (C) 1996, 1997 Theodore Ts'o. 6 * 7 * %Begin-Header% 8 * This file may be redistributed under the terms of the GNU Public 9 * License. 10 * %End-Header% 11 */ 12 13#include <fcntl.h> 14#include <stdio.h> 15#include <string.h> 16#if HAVE_UNISTD_H 17#include <unistd.h> 18#endif 19#if HAVE_ERRNO_H 20#include <errno.h> 21#endif 22 23#include "ext2_fs.h" 24#include "ext2fs.h" 25#include "irel.h" 26 27static errcode_t ima_put(ext2_irel irel, ext2_ino_t old, 28 struct ext2_inode_relocate_entry *ent); 29static errcode_t ima_get(ext2_irel irel, ext2_ino_t old, 30 struct ext2_inode_relocate_entry *ent); 31static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old, 32 struct ext2_inode_relocate_entry *ent); 33static errcode_t ima_start_iter(ext2_irel irel); 34static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old, 35 struct ext2_inode_relocate_entry *ent); 36static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino, 37 struct ext2_inode_reference *ref); 38static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino); 39static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref); 40static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new); 41static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old); 42static errcode_t ima_free(ext2_irel irel); 43 44/* 45 * This data structure stores the array of inode references; there is 46 * a structure for each inode. 47 */ 48struct inode_reference_entry { 49 __u16 num; 50 struct ext2_inode_reference *refs; 51}; 52 53struct irel_ma { 54 __u32 magic; 55 ext2_ino_t max_inode; 56 ext2_ino_t ref_current; 57 int ref_iter; 58 ext2_ino_t *orig_map; 59 struct ext2_inode_relocate_entry *entries; 60 struct inode_reference_entry *ref_entries; 61}; 62 63errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode, 64 ext2_irel *new_irel) 65{ 66 ext2_irel irel = 0; 67 errcode_t retval; 68 struct irel_ma *ma = 0; 69 size_t size; 70 71 *new_irel = 0; 72 73 /* 74 * Allocate memory structures 75 */ 76 retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table), 77 &irel); 78 if (retval) 79 goto errout; 80 memset(irel, 0, sizeof(struct ext2_inode_relocation_table)); 81 82 retval = ext2fs_get_mem(strlen(name)+1, &irel->name); 83 if (retval) 84 goto errout; 85 strcpy(irel->name, name); 86 87 retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma); 88 if (retval) 89 goto errout; 90 memset(ma, 0, sizeof(struct irel_ma)); 91 irel->priv_data = ma; 92 93 size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1)); 94 retval = ext2fs_get_mem(size, &ma->orig_map); 95 if (retval) 96 goto errout; 97 memset(ma->orig_map, 0, size); 98 99 size = (size_t) (sizeof(struct ext2_inode_relocate_entry) * 100 (max_inode+1)); 101 retval = ext2fs_get_mem(size, &ma->entries); 102 if (retval) 103 goto errout; 104 memset(ma->entries, 0, size); 105 106 size = (size_t) (sizeof(struct inode_reference_entry) * 107 (max_inode+1)); 108 retval = ext2fs_get_mem(size, &ma->ref_entries); 109 if (retval) 110 goto errout; 111 memset(ma->ref_entries, 0, size); 112 ma->max_inode = max_inode; 113 114 /* 115 * Fill in the irel data structure 116 */ 117 irel->put = ima_put; 118 irel->get = ima_get; 119 irel->get_by_orig = ima_get_by_orig; 120 irel->start_iter = ima_start_iter; 121 irel->next = ima_next; 122 irel->add_ref = ima_add_ref; 123 irel->start_iter_ref = ima_start_iter_ref; 124 irel->next_ref = ima_next_ref; 125 irel->move = ima_move; 126 irel->delete = ima_delete; 127 irel->free = ima_free; 128 129 *new_irel = irel; 130 return 0; 131 132errout: 133 ima_free(irel); 134 return retval; 135} 136 137static errcode_t ima_put(ext2_irel irel, ext2_ino_t old, 138 struct ext2_inode_relocate_entry *ent) 139{ 140 struct inode_reference_entry *ref_ent; 141 struct irel_ma *ma; 142 errcode_t retval; 143 size_t size, old_size; 144 145 ma = irel->priv_data; 146 if (old > ma->max_inode) 147 return EXT2_ET_INVALID_ARGUMENT; 148 149 /* 150 * Force the orig field to the correct value; the application 151 * program shouldn't be messing with this field. 152 */ 153 if (ma->entries[(unsigned) old].new == 0) 154 ent->orig = old; 155 else 156 ent->orig = ma->entries[(unsigned) old].orig; 157 158 /* 159 * If max_refs has changed, reallocate the refs array 160 */ 161 ref_ent = ma->ref_entries + (unsigned) old; 162 if (ref_ent->refs && ent->max_refs != 163 ma->entries[(unsigned) old].max_refs) { 164 size = (sizeof(struct ext2_inode_reference) * ent->max_refs); 165 old_size = (sizeof(struct ext2_inode_reference) * 166 ma->entries[(unsigned) old].max_refs); 167 retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs); 168 if (retval) 169 return retval; 170 } 171 172 ma->entries[(unsigned) old] = *ent; 173 ma->orig_map[(unsigned) ent->orig] = old; 174 return 0; 175} 176 177static errcode_t ima_get(ext2_irel irel, ext2_ino_t old, 178 struct ext2_inode_relocate_entry *ent) 179{ 180 struct irel_ma *ma; 181 182 ma = irel->priv_data; 183 if (old > ma->max_inode) 184 return EXT2_ET_INVALID_ARGUMENT; 185 if (ma->entries[(unsigned) old].new == 0) 186 return ENOENT; 187 *ent = ma->entries[(unsigned) old]; 188 return 0; 189} 190 191static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old, 192 struct ext2_inode_relocate_entry *ent) 193{ 194 struct irel_ma *ma; 195 ext2_ino_t ino; 196 197 ma = irel->priv_data; 198 if (orig > ma->max_inode) 199 return EXT2_ET_INVALID_ARGUMENT; 200 ino = ma->orig_map[(unsigned) orig]; 201 if (ino == 0) 202 return ENOENT; 203 *old = ino; 204 *ent = ma->entries[(unsigned) ino]; 205 return 0; 206} 207 208static errcode_t ima_start_iter(ext2_irel irel) 209{ 210 irel->current = 0; 211 return 0; 212} 213 214static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old, 215 struct ext2_inode_relocate_entry *ent) 216{ 217 struct irel_ma *ma; 218 219 ma = irel->priv_data; 220 while (++irel->current < ma->max_inode) { 221 if (ma->entries[(unsigned) irel->current].new == 0) 222 continue; 223 *old = irel->current; 224 *ent = ma->entries[(unsigned) irel->current]; 225 return 0; 226 } 227 *old = 0; 228 return 0; 229} 230 231static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino, 232 struct ext2_inode_reference *ref) 233{ 234 struct irel_ma *ma; 235 size_t size; 236 struct inode_reference_entry *ref_ent; 237 struct ext2_inode_relocate_entry *ent; 238 errcode_t retval; 239 240 ma = irel->priv_data; 241 if (ino > ma->max_inode) 242 return EXT2_ET_INVALID_ARGUMENT; 243 244 ref_ent = ma->ref_entries + (unsigned) ino; 245 ent = ma->entries + (unsigned) ino; 246 247 /* 248 * If the inode reference array doesn't exist, create it. 249 */ 250 if (ref_ent->refs == 0) { 251 size = (size_t) ((sizeof(struct ext2_inode_reference) * 252 ent->max_refs)); 253 retval = ext2fs_get_mem(size, &ref_ent->refs); 254 if (retval) 255 return retval; 256 memset(ref_ent->refs, 0, size); 257 ref_ent->num = 0; 258 } 259 260 if (ref_ent->num >= ent->max_refs) 261 return EXT2_ET_TOO_MANY_REFS; 262 263 ref_ent->refs[(unsigned) ref_ent->num++] = *ref; 264 return 0; 265} 266 267static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino) 268{ 269 struct irel_ma *ma; 270 271 ma = irel->priv_data; 272 if (ino > ma->max_inode) 273 return EXT2_ET_INVALID_ARGUMENT; 274 if (ma->entries[(unsigned) ino].new == 0) 275 return ENOENT; 276 ma->ref_current = ino; 277 ma->ref_iter = 0; 278 return 0; 279} 280 281static errcode_t ima_next_ref(ext2_irel irel, 282 struct ext2_inode_reference *ref) 283{ 284 struct irel_ma *ma; 285 struct inode_reference_entry *ref_ent; 286 287 ma = irel->priv_data; 288 289 ref_ent = ma->ref_entries + ma->ref_current; 290 291 if ((ref_ent->refs == NULL) || 292 (ma->ref_iter >= ref_ent->num)) { 293 ref->block = 0; 294 ref->offset = 0; 295 return 0; 296 } 297 *ref = ref_ent->refs[ma->ref_iter++]; 298 return 0; 299} 300 301 302static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new) 303{ 304 struct irel_ma *ma; 305 306 ma = irel->priv_data; 307 if ((old > ma->max_inode) || (new > ma->max_inode)) 308 return EXT2_ET_INVALID_ARGUMENT; 309 if (ma->entries[(unsigned) old].new == 0) 310 return ENOENT; 311 312 ma->entries[(unsigned) new] = ma->entries[(unsigned) old]; 313 ext2fs_free_mem(&ma->ref_entries[(unsigned) new].refs); 314 ma->ref_entries[(unsigned) new] = ma->ref_entries[(unsigned) old]; 315 316 ma->entries[(unsigned) old].new = 0; 317 ma->ref_entries[(unsigned) old].num = 0; 318 ma->ref_entries[(unsigned) old].refs = 0; 319 320 ma->orig_map[ma->entries[new].orig] = new; 321 return 0; 322} 323 324static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old) 325{ 326 struct irel_ma *ma; 327 328 ma = irel->priv_data; 329 if (old > ma->max_inode) 330 return EXT2_ET_INVALID_ARGUMENT; 331 if (ma->entries[(unsigned) old].new == 0) 332 return ENOENT; 333 334 ma->entries[old].new = 0; 335 ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs); 336 ma->orig_map[ma->entries[(unsigned) old].orig] = 0; 337 338 ma->ref_entries[(unsigned) old].num = 0; 339 ma->ref_entries[(unsigned) old].refs = 0; 340 return 0; 341} 342 343static errcode_t ima_free(ext2_irel irel) 344{ 345 struct irel_ma *ma; 346 ext2_ino_t ino; 347 348 if (!irel) 349 return 0; 350 351 ma = irel->priv_data; 352 353 if (ma) { 354 ext2fs_free_mem(&ma->orig_map); 355 ext2fs_free_mem(&ma->entries); 356 if (ma->ref_entries) { 357 for (ino = 0; ino <= ma->max_inode; ino++) { 358 ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs); 359 } 360 ext2fs_free_mem(&ma->ref_entries); 361 } 362 ext2fs_free_mem(&ma); 363 } 364 ext2fs_free_mem(&irel->name); 365 ext2fs_free_mem(&irel); 366 return 0; 367} 368