blob: 7e1d24f35cc2eb5e5ab39a53af9c9645defd5c7e [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
159
160
Theodore Ts'o3839e651997-04-26 13:21:57 +0000161/*
162 * This procedure tests to see if a particular block is on a badblocks
163 * list.
164 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400165int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000166{
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000167 int low, high, mid;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000168
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000169 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
170 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000171
Theodore Ts'of635d7f1997-05-09 02:50:16 +0000172 if (bb->num == 0)
173 return 0;
174
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000175 low = 0;
176 high = bb->num-1;
177 if (blk == bb->list[low])
178 return 1;
179 if (blk == bb->list[high])
180 return 1;
181
182 while (low < high) {
183 mid = (low+high)/2;
184 if (mid == low || mid == high)
185 break;
186 if (blk == bb->list[mid])
Theodore Ts'o3839e651997-04-26 13:21:57 +0000187 return 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000188 if (blk < bb->list[mid])
189 high = mid;
190 else
191 low = mid;
192 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000193 return 0;
194}
195
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400196int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000197{
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400198 return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
199}
200
201
202errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
203 ext2_u32_iterate *ret)
204{
205 ext2_u32_iterate iter;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000206 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000207
Theodore Ts'of3db3561997-04-26 13:34:30 +0000208 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
209
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400210 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate),
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000211 (void **) &iter);
212 if (retval)
213 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000214
Theodore Ts'of3db3561997-04-26 13:34:30 +0000215 iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000216 iter->bb = bb;
217 iter->ptr = 0;
218 *ret = iter;
219 return 0;
220}
221
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400222errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
223 ext2_badblocks_iterate *ret)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000224{
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400225 return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
226 (ext2_u32_iterate *) ret);
227}
228
229
230int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
231{
232 ext2_u32_list bb;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000233
234 if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
235 return 0;
236
237 bb = iter->bb;
238
239 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
240 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000241
242 if (iter->ptr < bb->num) {
243 *blk = bb->list[iter->ptr++];
244 return 1;
245 }
246 *blk = 0;
247 return 0;
248}
249
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400250int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
251{
252 return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
253 (__u32 *) blk);
254}
255
256
257void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000258{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000259 if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
260 return;
261
Theodore Ts'o3839e651997-04-26 13:21:57 +0000262 iter->bb = 0;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000263 ext2fs_free_mem((void **) &iter);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000264}
Theodore Ts'o57dca852000-07-04 19:20:25 +0000265
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400266void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
267{
268 ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
269}
270
271
272int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
Theodore Ts'o57dca852000-07-04 19:20:25 +0000273{
274 EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
275 EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
276
277 if (bb1->num != bb2->num)
278 return 0;
279
280 if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
281 return 0;
282 return 1;
283}
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400284
285int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
286{
287 return ext2fs_u32_list_equal((ext2_u32_list) bb1,
288 (ext2_u32_list) bb2);
289}
Theodore Ts'o220c0042003-03-14 00:59:42 -0500290
291int ext2fs_u32_list_count(ext2_u32_list bb)
292{
293 return bb->num;
294}