1 /* 2 * dblist.c -- directory block list functions 3 * 4 * Copyright 1997 by Theodore Ts'o 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12 #include <stdio.h> 13 #if HAVE_UNISTD_H 14 #include <unistd.h> 15 #endif 16 #include <string.h> 17 #include <time.h> 18 19 #include "ext2_fs.h" 20 #include "ext2fsP.h" 21 22 static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b); 23 24 /* 25 * Returns the number of directories in the filesystem as reported by 26 * the group descriptors. Of course, the group descriptors could be 27 * wrong! 28 */ 29 errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs) 30 { 31 dgrp_t i; 32 ext2_ino_t num_dirs, max_dirs; 33 34 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 35 36 num_dirs = 0; 37 max_dirs = fs->super->s_inodes_per_group; 38 for (i = 0; i < fs->group_desc_count; i++) { 39 if (fs->group_desc[i].bg_used_dirs_count > max_dirs) 40 num_dirs += max_dirs / 8; 41 else 42 num_dirs += fs->group_desc[i].bg_used_dirs_count; 43 } 44 if (num_dirs > fs->super->s_inodes_count) 45 num_dirs = fs->super->s_inodes_count; 46 47 *ret_num_dirs = num_dirs; 48 49 return 0; 50 } 51 52 /* 53 * helper function for making a new directory block list (for 54 * initialize and copy). 55 */ 56 static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count, 57 struct ext2_db_entry *list, 58 ext2_dblist *ret_dblist) 59 { 60 ext2_dblist dblist; 61 errcode_t retval; 62 size_t len; 63 64 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 65 66 if ((ret_dblist == 0) && fs->dblist && 67 (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST)) 68 return 0; 69 70 retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist); 71 if (retval) 72 return retval; 73 memset(dblist, 0, sizeof(struct ext2_struct_dblist)); 74 75 dblist->magic = EXT2_ET_MAGIC_DBLIST; 76 dblist->fs = fs; 77 if (size) 78 dblist->size = size; 79 else { 80 retval = ext2fs_get_num_dirs(fs, &dblist->size); 81 if (retval) 82 goto cleanup; 83 dblist->size = (dblist->size * 2) + 12; 84 } 85 len = (size_t) sizeof(struct ext2_db_entry) * dblist->size; 86 dblist->count = count; 87 retval = ext2fs_get_array(dblist->size, sizeof(struct ext2_db_entry), 88 &dblist->list); 89 if (retval) 90 goto cleanup; 91 92 if (list) 93 memcpy(dblist->list, list, len); 94 else 95 memset(dblist->list, 0, len); 96 if (ret_dblist) 97 *ret_dblist = dblist; 98 else 99 fs->dblist = dblist; 100 return 0; 101 cleanup: 102 if (dblist) 103 ext2fs_free_mem(&dblist); 104 return retval; 105 } 106 107 /* 108 * Initialize a directory block list 109 */ 110 errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist) 111 { 112 ext2_dblist dblist; 113 errcode_t retval; 114 115 retval = make_dblist(fs, 0, 0, 0, &dblist); 116 if (retval) 117 return retval; 118 119 dblist->sorted = 1; 120 if (ret_dblist) 121 *ret_dblist = dblist; 122 else 123 fs->dblist = dblist; 124 125 return 0; 126 } 127 128 /* 129 * Copy a directory block list 130 */ 131 errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest) 132 { 133 ext2_dblist dblist; 134 errcode_t retval; 135 136 retval = make_dblist(src->fs, src->size, src->count, src->list, 137 &dblist); 138 if (retval) 139 return retval; 140 dblist->sorted = src->sorted; 141 *dest = dblist; 142 return 0; 143 } 144 145 /* 146 * Close a directory block list 147 * 148 * (moved to closefs.c) 149 */ 150 151 152 /* 153 * Add a directory block to the directory block list 154 */ 155 errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, 156 int blockcnt) 157 { 158 struct ext2_db_entry *new_entry; 159 errcode_t retval; 160 unsigned long old_size; 161 162 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); 163 164 if (dblist->count >= dblist->size) { 165 old_size = dblist->size * sizeof(struct ext2_db_entry); 166 dblist->size += dblist->size > 200 ? dblist->size / 2 : 100; 167 retval = ext2fs_resize_mem(old_size, (size_t) dblist->size * 168 sizeof(struct ext2_db_entry), 169 &dblist->list); 170 if (retval) { 171 dblist->size -= 100; 172 return retval; 173 } 174 } 175 new_entry = dblist->list + ( (int) dblist->count++); 176 new_entry->blk = blk; 177 new_entry->ino = ino; 178 new_entry->blockcnt = blockcnt; 179 180 dblist->sorted = 0; 181 182 return 0; 183 } 184 185 /* 186 * Change the directory block to the directory block list 187 */ 188 errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk, 189 int blockcnt) 190 { 191 dgrp_t i; 192 193 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); 194 195 for (i=0; i < dblist->count; i++) { 196 if ((dblist->list[i].ino != ino) || 197 (dblist->list[i].blockcnt != blockcnt)) 198 continue; 199 dblist->list[i].blk = blk; 200 dblist->sorted = 0; 201 return 0; 202 } 203 return EXT2_ET_DB_NOT_FOUND; 204 } 205 206 void ext2fs_dblist_sort(ext2_dblist dblist, 207 EXT2_QSORT_TYPE (*sortfunc)(const void *, 208 const void *)) 209 { 210 if (!sortfunc) 211 sortfunc = dir_block_cmp; 212 qsort(dblist->list, (size_t) dblist->count, 213 sizeof(struct ext2_db_entry), sortfunc); 214 dblist->sorted = 1; 215 } 216 217 /* 218 * This function iterates over the directory block list 219 */ 220 errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, 221 int (*func)(ext2_filsys fs, 222 struct ext2_db_entry *db_info, 223 void *priv_data), 224 void *priv_data) 225 { 226 ext2_ino_t i; 227 int ret; 228 229 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); 230 231 if (!dblist->sorted) 232 ext2fs_dblist_sort(dblist, 0); 233 for (i=0; i < dblist->count; i++) { 234 ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data); 235 if (ret & DBLIST_ABORT) 236 return 0; 237 } 238 return 0; 239 } 240 241 static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b) 242 { 243 const struct ext2_db_entry *db_a = 244 (const struct ext2_db_entry *) a; 245 const struct ext2_db_entry *db_b = 246 (const struct ext2_db_entry *) b; 247 248 if (db_a->blk != db_b->blk) 249 return (int) (db_a->blk - db_b->blk); 250 251 if (db_a->ino != db_b->ino) 252 return (int) (db_a->ino - db_b->ino); 253 254 return (int) (db_a->blockcnt - db_b->blockcnt); 255 } 256 257 int ext2fs_dblist_count(ext2_dblist dblist) 258 { 259 return (int) dblist->count; 260 } 261 262 errcode_t ext2fs_dblist_get_last(ext2_dblist dblist, 263 struct ext2_db_entry **entry) 264 { 265 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); 266 267 if (dblist->count == 0) 268 return EXT2_ET_DBLIST_EMPTY; 269 270 if (entry) 271 *entry = dblist->list + ( (int) dblist->count-1); 272 return 0; 273 } 274 275 errcode_t ext2fs_dblist_drop_last(ext2_dblist dblist) 276 { 277 EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); 278 279 if (dblist->count == 0) 280 return EXT2_ET_DBLIST_EMPTY; 281 282 dblist->count--; 283 return 0; 284 } 285