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