Whamcloud - gitweb
ChangeLog, dblist.c, ext2fs.h, jump.funcs:
[tools/e2fsprogs.git] / lib / ext2fs / dblist.c
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 Public
8  * License.
9  * %End-Header%
10  * 
11  */
12
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <time.h>
18 #ifdef HAVE_ERRNO_H
19 #include <errno.h>
20 #endif
21
22 #include <linux/ext2_fs.h>
23
24 #include "ext2fsP.h"
25
26 static int dir_block_cmp(const void *a, const void *b);
27
28 /*
29  * Returns the number of directories in the filesystem as reported by
30  * the group descriptors.  Of course, the group descriptors could be
31  * wrong!
32  */
33 errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ino_t *ret_num_dirs)
34 {
35         int     i;
36         ino_t   num_dirs;
37
38         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
39         
40         num_dirs = 0;
41         for (i = 0; i < fs->group_desc_count; i++)
42                 num_dirs += fs->group_desc[i].bg_used_dirs_count;
43
44         *ret_num_dirs = num_dirs;
45
46         return 0;
47 }
48
49 /*
50  * helper function for making a new directory block list (for
51  * initialize and copy).
52  */
53 static errcode_t make_dblist(ext2_filsys fs, ino_t size, ino_t count,
54                              struct ext2_db_entry *list,
55                              ext2_dblist *ret_dblist)
56 {
57         ext2_dblist     dblist;
58         errcode_t       retval;
59         size_t          len;
60
61         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
62
63         if ((ret_dblist == 0) && fs->dblist &&
64             (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
65                 return 0;
66
67         dblist = malloc(sizeof(struct ext2_struct_dblist));
68         if (!dblist)
69                 return ENOMEM;
70         memset(dblist, 0, sizeof(struct ext2_struct_dblist));
71
72         dblist->magic = EXT2_ET_MAGIC_DBLIST;
73         dblist->fs = fs;
74         if (size)
75                 dblist->size = size;
76         else {
77                 retval = ext2fs_get_num_dirs(fs, &dblist->size);
78                 if (retval)
79                         goto cleanup;
80                 dblist->size = (dblist->size * 2) + 12;
81         }
82         len = sizeof(struct ext2_db_entry) * dblist->size;
83         dblist->count = count;
84         dblist->list = malloc(len);
85         if (dblist->list == NULL) {
86                 retval = ENOMEM;
87                 goto cleanup;
88         }
89         if (list)
90                 memcpy(dblist->list, list, len);
91         else
92                 memset(dblist->list, 0, len);
93         *ret_dblist = dblist;
94         return 0;
95 cleanup:
96         if (dblist)
97                 free(dblist);
98         return retval;
99 }
100
101 /*
102  * Initialize a directory block list
103  */
104 errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
105 {
106         ext2_dblist     dblist;
107         errcode_t       retval;
108
109         retval = make_dblist(fs, 0, 0, 0, &dblist);
110         if (retval)
111                 return retval;
112
113         dblist->sorted = 1;
114         if (ret_dblist)
115                 *ret_dblist = dblist;
116         else
117                 fs->dblist = dblist;
118
119         return 0;
120 }
121
122 /*
123  * Copy a directory block list
124  */
125 errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
126 {
127         ext2_dblist     dblist;
128         errcode_t       retval;
129
130         retval = make_dblist(src->fs, src->size, src->count, src->list,
131                              &dblist);
132         if (retval)
133                 return retval;
134         dblist->sorted = src->sorted;
135         *dest = dblist;
136         return 0;
137 }
138
139 /*
140  * Close a directory block list
141  *
142  * (moved to closefs.c)
143  */
144
145
146 /*
147  * Add a directory block to the directory block list
148  */
149 errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ino_t ino, blk_t blk,
150                                int blockcnt)
151 {
152         struct ext2_db_entry    *nlist, *new;
153         
154         EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
155
156         if (dblist->count >= dblist->size) {
157                 dblist->size += 100;
158                 nlist = realloc(dblist->list,
159                                 dblist->size * sizeof(struct ext2_db_entry));
160                 if (nlist == 0) {
161                         dblist->size -= 100;
162                         return ENOMEM;
163                 }
164                 dblist->list = nlist;
165         }
166         new = dblist->list + dblist->count++;
167         new->blk = blk;
168         new->ino = ino;
169         new->blockcnt = blockcnt;
170
171         dblist->sorted = 0;
172
173         return 0;
174 }
175
176 /*
177  * Change the directory block to the directory block list
178  */
179 errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ino_t ino, blk_t blk,
180                                int blockcnt)
181 {
182         int                     i;
183         
184         EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
185
186         for (i=0; i < dblist->count; i++) {
187                 if ((dblist->list[i].ino != ino) ||
188                     (dblist->list[i].blockcnt != blockcnt))
189                         continue;
190                 dblist->list[i].blk = blk;
191                 dblist->sorted = 0;
192                 return 0;
193         }
194         return ENOENT;
195 }
196
197 /*
198  * This function iterates over the directory block list
199  */
200 errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
201                                 int (*func)(ext2_filsys fs,
202                                             struct ext2_db_entry *db_info,
203                                             void        *private),
204                                 void *private)
205 {
206         ino_t   i;
207         int     ret;
208         
209         EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
210
211         if (!dblist->sorted) {
212                 qsort(dblist->list, dblist->count,
213                       sizeof(struct ext2_db_entry), dir_block_cmp);
214                 dblist->sorted = 1;
215         }
216         for (i=0; i < dblist->count; i++) {
217                 ret = (*func)(dblist->fs, &dblist->list[i], private);
218                 if (ret & DBLIST_ABORT)
219                         return 0;
220         }
221         return 0;
222 }
223
224
225 static int dir_block_cmp(const void *a, const void *b)
226 {
227         const struct ext2_db_entry *db_a =
228                 (const struct ext2_db_entry *) a;
229         const struct ext2_db_entry *db_b =
230                 (const struct ext2_db_entry *) b;
231
232         if (db_a->blk != db_b->blk)
233                 return (db_a->blk - db_b->blk);
234         
235         if (db_a->ino != db_b->ino)
236                 return (db_a->ino - db_b->ino);
237
238         return (db_a->blockcnt - db_b->blockcnt);
239 }
240
241 int ext2fs_dblist_count(ext2_dblist dblist)
242 {
243         return (int) dblist->count;
244 }