Whamcloud - gitweb
f990c10df46d59c40ea3e0c616c2916c7f02f5e0
[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         }
81         len = sizeof(struct ext2_db_entry) * dblist->size;
82         dblist->count = count;
83         dblist->list = malloc(len);
84         if (dblist->list == NULL) {
85                 retval = ENOMEM;
86                 goto cleanup;
87         }
88         if (list)
89                 memcpy(dblist->list, list, len);
90         else
91                 memset(dblist->list, 0, len);
92         *ret_dblist = dblist;
93         return 0;
94 cleanup:
95         if (dblist)
96                 free(dblist);
97         return retval;
98 }
99
100 /*
101  * Initialize a directory block list
102  */
103 errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
104 {
105         ext2_dblist     dblist;
106         errcode_t       retval;
107
108         retval = make_dblist(fs, 0, 0, 0, &dblist);
109         if (retval)
110                 return retval;
111
112         dblist->sorted = 1;
113         if (ret_dblist)
114                 *ret_dblist = dblist;
115         else
116                 fs->dblist = dblist;
117
118         return 0;
119 }
120
121 /*
122  * Copy a directory block list
123  */
124 errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
125 {
126         ext2_dblist     dblist;
127         errcode_t       retval;
128
129         retval = make_dblist(src->fs, src->size, src->count, src->list,
130                              &dblist);
131         if (retval)
132                 return retval;
133         dblist->sorted = src->sorted;
134         *dest = dblist;
135         return 0;
136 }
137
138 /*
139  * Close a directory block list
140  *
141  * (moved to closefs.c)
142  */
143
144
145 /*
146  * Add a directory block to the directory block list
147  */
148 errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ino_t ino, blk_t blk,
149                                int blockcnt)
150 {
151         struct ext2_db_entry    *nlist, *new;
152         
153         EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
154
155         if (dblist->count >= dblist->size) {
156                 dblist->size += 100;
157                 nlist = realloc(dblist->list,
158                                 dblist->size * sizeof(struct ext2_db_entry));
159                 if (nlist == 0) {
160                         dblist->size -= 100;
161                         return ENOMEM;
162                 }
163                 dblist->list = nlist;
164         }
165         new = dblist->list + dblist->count++;
166         new->blk = blk;
167         new->ino = ino;
168         new->blockcnt = blockcnt;
169
170         dblist->sorted = 0;
171
172         return 0;
173 }
174
175 /*
176  * Change the directory block to the directory block list
177  */
178 errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ino_t ino, blk_t blk,
179                                int blockcnt)
180 {
181         struct ext2_db_entry    *ent;
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