blob: 9fda70cca70cc53d5c52c695420256389d15e9ed [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * badblocks.c --- routines to manipulate the bad block structure
3 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * Copyright (C) 1994, 1995, 1996 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%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 */
11
12#include <stdio.h>
13#include <string.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000014#if HAVE_UNISTD_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000015#include <unistd.h>
Theodore Ts'o4cbe8af1997-08-10 23:07:40 +000016#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000017#include <fcntl.h>
18#include <time.h>
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000019#if HAVE_SYS_STAT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000020#include <sys/stat.h>
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000021#endif
22#if HAVE_SYS_TYPES_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000023#include <sys/types.h>
Theodore Ts'o1d2ff461997-10-19 23:00:21 +000024#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000025
Theodore Ts'ob5abe6f1998-01-19 14:47:53 +000026#include "ext2_fs.h"
Theodore Ts'o21c84b71997-04-29 16:15:03 +000027#include "ext2fsP.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000028
29/*
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000030 * Helper function for making a badblocks list
Theodore Ts'o3839e651997-04-26 13:21:57 +000031 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -040032static errcode_t make_u32_list(int size, int num, __u32 *list,
33 ext2_u32_list *ret)
Theodore Ts'o3839e651997-04-26 13:21:57 +000034{
Theodore Ts'ob7a00562002-07-20 00:28:07 -040035 ext2_u32_list bb;
36 errcode_t retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000037
Theodore Ts'ob7a00562002-07-20 00:28:07 -040038 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list),
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000039 (void **) &bb);
40 if (retval)
41 return retval;
Theodore Ts'ob7a00562002-07-20 00:28:07 -040042 memset(bb, 0, sizeof(struct ext2_struct_u32_list));
Theodore Ts'of3db3561997-04-26 13:34:30 +000043 bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
Theodore Ts'o3839e651997-04-26 13:21:57 +000044 bb->size = size ? size : 10;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000045 bb->num = num;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000046 retval = ext2fs_get_mem(bb->size * sizeof(blk_t), (void **) &bb->list);
Theodore Ts'o3839e651997-04-26 13:21:57 +000047 if (!bb->list) {
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000048 ext2fs_free_mem((void **) &bb);
49 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +000050 }
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000051 if (list)
52 memcpy(bb->list, list, bb->size * sizeof(blk_t));
53 else
54 memset(bb->list, 0, bb->size * sizeof(blk_t));
Theodore Ts'o3839e651997-04-26 13:21:57 +000055 *ret = bb;
56 return 0;
57}
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000058
59
60/*
Theodore Ts'ob7a00562002-07-20 00:28:07 -040061 * This procedure creates an empty u32 list.
62 */
63errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
64{
65 return make_u32_list(size, 0, 0, ret);
66}
67
68/*
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000069 * This procedure creates an empty badblocks list.
70 */
71errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
72{
Theodore Ts'ob7a00562002-07-20 00:28:07 -040073 return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000074}
75
Theodore Ts'ob7a00562002-07-20 00:28:07 -040076
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000077/*
78 * This procedure copies a badblocks list
79 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -040080errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000081{
82 errcode_t retval;
83
Theodore Ts'ob7a00562002-07-20 00:28:07 -040084 retval = make_u32_list(src->size, src->num, src->list, dest);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000085 if (retval)
86 return retval;
87 (*dest)->badblocks_flags = src->badblocks_flags;
88 return 0;
89}
90
Theodore Ts'ob7a00562002-07-20 00:28:07 -040091errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
92 ext2_badblocks_list *dest)
93{
94 return ext2fs_u32_copy((ext2_u32_list) src,
95 (ext2_u32_list *) dest);
96}
Theodore Ts'o3839e651997-04-26 13:21:57 +000097
98/*
99 * This procedure frees a badblocks list.
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000100 *
101 * (note: moved to closefs.c)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000102 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000103
Theodore Ts'o3839e651997-04-26 13:21:57 +0000104
105/*
106 * This procedure adds a block to a badblocks list.
107 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400108errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000109{
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000110 errcode_t retval;
111 int i, j;
Theodore Ts'o76f875d1998-04-27 01:41:13 +0000112 unsigned long old_size;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000113
Theodore Ts'of3db3561997-04-26 13:34:30 +0000114 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
115
Theodore Ts'o3839e651997-04-26 13:21:57 +0000116 if (bb->num >= bb->size) {
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400117 old_size = bb->size * sizeof(__u32);
Theodore Ts'of75c28d1998-08-01 04:18:06 +0000118 bb->size += 100;
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400119 retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000120 (void **) &bb->list);
Theodore Ts'o76f875d1998-04-27 01:41:13 +0000121 if (retval) {
Theodore Ts'of75c28d1998-08-01 04:18:06 +0000122 bb->size -= 100;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000123 return retval;
Theodore Ts'o76f875d1998-04-27 01:41:13 +0000124 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000125 }
126
Theodore Ts'o9b9fe8a1999-11-08 22:05:04 +0000127 /*
128 * Add special case code for appending to the end of the list
129 */
130 i = bb->num-1;
131 if ((bb->num != 0) && (bb->list[i] == blk))
132 return 0;
133 if ((bb->num == 0) || (bb->list[i] < blk)) {
134 bb->list[bb->num++] = blk;
135 return 0;
136 }
137
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000138 j = bb->num;
139 for (i=0; i < bb->num; i++) {
140 if (bb->list[i] == blk)
141 return 0;
142 if (bb->list[i] > blk) {
143 j = i;
144 break;
145 }
146 }
147 for (i=bb->num; i > j; i--)
148 bb->list[i] = bb->list[i-1];
149 bb->list[j] = blk;
150 bb->num++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000151 return 0;
152}
153
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400154errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
155{
156 return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
157}
158
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400159/*
160 * This procedure finds a particular block is on a badblocks
161 * list.
162 */
163int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
164{
165 int low, high, mid;
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400166
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400167 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
168 return -1;
169
170 if (bb->num == 0)
171 return -1;
172
173 low = 0;
174 high = bb->num-1;
175 if (blk == bb->list[low])
176 return low;
177 if (blk == bb->list[high])
178 return high;
179
180 while (low < high) {
181 mid = (low+high)/2;
182 if (mid == low || mid == high)
183 break;
184 if (blk == bb->list[mid])
185 return mid;
186 if (blk < bb->list[mid])
187 high = mid;
188 else
189 low = mid;
190 }
191 return -1;
192}
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400193
Theodore Ts'o3839e651997-04-26 13:21:57 +0000194/*
195 * This procedure tests to see if a particular block is on a badblocks
196 * list.
197 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400198int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000199{
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400200 if (ext2fs_u32_list_find(bb, blk) < 0)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000201 return 0;
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400202 else
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000203 return 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000204}
205
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400206int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000207{
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400208 return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
209}
210
211
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400212/*
213 * Remove a block from the badblock list
214 */
215int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
216{
217 int remloc, i;
218
219 if (bb->num == 0)
220 return -1;
221
222 remloc = ext2fs_u32_list_find(bb, blk);
223 if (remloc < 0)
224 return -1;
225
226 for (i = remloc ; i < bb->num-1; i++)
227 bb->list[i] = bb->list[i+1];
228 bb->num--;
229 return 0;
230}
231
232void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
233{
234 ext2fs_u32_list_del(bb, blk);
235}
236
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400237errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
238 ext2_u32_iterate *ret)
239{
240 ext2_u32_iterate iter;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000241 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000242
Theodore Ts'of3db3561997-04-26 13:34:30 +0000243 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
244
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400245 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate),
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000246 (void **) &iter);
247 if (retval)
248 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000249
Theodore Ts'of3db3561997-04-26 13:34:30 +0000250 iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000251 iter->bb = bb;
252 iter->ptr = 0;
253 *ret = iter;
254 return 0;
255}
256
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400257errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
258 ext2_badblocks_iterate *ret)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000259{
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400260 return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
261 (ext2_u32_iterate *) ret);
262}
263
264
265int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
266{
267 ext2_u32_list bb;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000268
269 if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
270 return 0;
271
272 bb = iter->bb;
273
274 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
275 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000276
277 if (iter->ptr < bb->num) {
278 *blk = bb->list[iter->ptr++];
279 return 1;
280 }
281 *blk = 0;
282 return 0;
283}
284
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400285int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
286{
287 return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
288 (__u32 *) blk);
289}
290
291
292void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000293{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000294 if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
295 return;
296
Theodore Ts'o3839e651997-04-26 13:21:57 +0000297 iter->bb = 0;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000298 ext2fs_free_mem((void **) &iter);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000299}
Theodore Ts'o57dca852000-07-04 19:20:25 +0000300
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400301void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
302{
303 ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
304}
305
306
307int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
Theodore Ts'o57dca852000-07-04 19:20:25 +0000308{
309 EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
310 EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
311
312 if (bb1->num != bb2->num)
313 return 0;
314
315 if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
316 return 0;
317 return 1;
318}
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400319
320int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
321{
322 return ext2fs_u32_list_equal((ext2_u32_list) bb1,
323 (ext2_u32_list) bb2);
324}
Theodore Ts'o220c0042003-03-14 00:59:42 -0500325
326int ext2fs_u32_list_count(ext2_u32_list bb)
327{
328 return bb->num;
329}