blob: 42e33bf2380c46ffa5aadeac3e238bce6e8e0153 [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
Theodore Ts'o413a78f2006-11-12 22:22:00 -050029#ifdef __arm__
30#define BUGGY_ARM_GCC
31#endif
32
Theodore Ts'o3839e651997-04-26 13:21:57 +000033/*
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000034 * Helper function for making a badblocks list
Theodore Ts'o3839e651997-04-26 13:21:57 +000035 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -040036static errcode_t make_u32_list(int size, int num, __u32 *list,
37 ext2_u32_list *ret)
Theodore Ts'o3839e651997-04-26 13:21:57 +000038{
Theodore Ts'ob7a00562002-07-20 00:28:07 -040039 ext2_u32_list bb;
40 errcode_t retval;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000041
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040042 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000043 if (retval)
44 return retval;
Theodore Ts'ob7a00562002-07-20 00:28:07 -040045 memset(bb, 0, sizeof(struct ext2_struct_u32_list));
Theodore Ts'of3db3561997-04-26 13:34:30 +000046 bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
Theodore Ts'o3839e651997-04-26 13:21:57 +000047 bb->size = size ? size : 10;
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000048 bb->num = num;
Theodore Ts'o413a78f2006-11-12 22:22:00 -050049#ifdef BUGGY_ARM_GCC
50 bb->list = malloc(bb->size * sizeof(blk_t));
51 if (!bb->list) {
52 free(bb);
53 return EXT2_ET_NO_MEMORY;
54 }
55#else
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040056 retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list);
Theodore Ts'o3839e651997-04-26 13:21:57 +000057 if (!bb->list) {
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -040058 ext2fs_free_mem(&bb);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +000059 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +000060 }
Theodore Ts'o413a78f2006-11-12 22:22:00 -050061#endif
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000062 if (list)
63 memcpy(bb->list, list, bb->size * sizeof(blk_t));
64 else
65 memset(bb->list, 0, bb->size * sizeof(blk_t));
Theodore Ts'o3839e651997-04-26 13:21:57 +000066 *ret = bb;
67 return 0;
68}
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000069
70
71/*
Theodore Ts'ob7a00562002-07-20 00:28:07 -040072 * This procedure creates an empty u32 list.
73 */
74errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
75{
76 return make_u32_list(size, 0, 0, ret);
77}
78
79/*
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000080 * This procedure creates an empty badblocks list.
81 */
82errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
83{
Theodore Ts'ob7a00562002-07-20 00:28:07 -040084 return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000085}
86
Theodore Ts'ob7a00562002-07-20 00:28:07 -040087
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000088/*
89 * This procedure copies a badblocks list
90 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -040091errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000092{
93 errcode_t retval;
94
Theodore Ts'ob7a00562002-07-20 00:28:07 -040095 retval = make_u32_list(src->size, src->num, src->list, dest);
Theodore Ts'oa29f4d31997-04-29 21:26:48 +000096 if (retval)
97 return retval;
98 (*dest)->badblocks_flags = src->badblocks_flags;
99 return 0;
100}
101
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400102errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
103 ext2_badblocks_list *dest)
104{
105 return ext2fs_u32_copy((ext2_u32_list) src,
106 (ext2_u32_list *) dest);
107}
Theodore Ts'o3839e651997-04-26 13:21:57 +0000108
109/*
110 * This procedure frees a badblocks list.
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000111 *
112 * (note: moved to closefs.c)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000113 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000114
Theodore Ts'o3839e651997-04-26 13:21:57 +0000115
116/*
117 * This procedure adds a block to a badblocks list.
118 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400119errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000120{
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000121 errcode_t retval;
122 int i, j;
Theodore Ts'o76f875d1998-04-27 01:41:13 +0000123 unsigned long old_size;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000124
Theodore Ts'of3db3561997-04-26 13:34:30 +0000125 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
126
Theodore Ts'o3839e651997-04-26 13:21:57 +0000127 if (bb->num >= bb->size) {
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400128 old_size = bb->size * sizeof(__u32);
Theodore Ts'of75c28d1998-08-01 04:18:06 +0000129 bb->size += 100;
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400130 retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400131 &bb->list);
Theodore Ts'o76f875d1998-04-27 01:41:13 +0000132 if (retval) {
Theodore Ts'of75c28d1998-08-01 04:18:06 +0000133 bb->size -= 100;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000134 return retval;
Theodore Ts'o76f875d1998-04-27 01:41:13 +0000135 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000136 }
137
Theodore Ts'o9b9fe8a1999-11-08 22:05:04 +0000138 /*
139 * Add special case code for appending to the end of the list
140 */
141 i = bb->num-1;
142 if ((bb->num != 0) && (bb->list[i] == blk))
143 return 0;
144 if ((bb->num == 0) || (bb->list[i] < blk)) {
145 bb->list[bb->num++] = blk;
146 return 0;
147 }
148
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000149 j = bb->num;
150 for (i=0; i < bb->num; i++) {
151 if (bb->list[i] == blk)
152 return 0;
153 if (bb->list[i] > blk) {
154 j = i;
155 break;
156 }
157 }
158 for (i=bb->num; i > j; i--)
159 bb->list[i] = bb->list[i-1];
160 bb->list[j] = blk;
161 bb->num++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000162 return 0;
163}
164
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400165errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
166{
167 return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
168}
169
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400170/*
171 * This procedure finds a particular block is on a badblocks
172 * list.
173 */
174int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
175{
176 int low, high, mid;
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400177
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400178 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
179 return -1;
180
181 if (bb->num == 0)
182 return -1;
183
184 low = 0;
185 high = bb->num-1;
186 if (blk == bb->list[low])
187 return low;
188 if (blk == bb->list[high])
189 return high;
190
191 while (low < high) {
192 mid = (low+high)/2;
193 if (mid == low || mid == high)
194 break;
195 if (blk == bb->list[mid])
196 return mid;
197 if (blk < bb->list[mid])
198 high = mid;
199 else
200 low = mid;
201 }
202 return -1;
203}
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400204
Theodore Ts'o3839e651997-04-26 13:21:57 +0000205/*
206 * This procedure tests to see if a particular block is on a badblocks
207 * list.
208 */
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400209int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000210{
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400211 if (ext2fs_u32_list_find(bb, blk) < 0)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000212 return 0;
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400213 else
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000214 return 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000215}
216
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400217int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000218{
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400219 return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
220}
221
222
Theodore Ts'o7d7bdd52003-06-24 17:34:02 -0400223/*
224 * Remove a block from the badblock list
225 */
226int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
227{
228 int remloc, i;
229
230 if (bb->num == 0)
231 return -1;
232
233 remloc = ext2fs_u32_list_find(bb, blk);
234 if (remloc < 0)
235 return -1;
236
237 for (i = remloc ; i < bb->num-1; i++)
238 bb->list[i] = bb->list[i+1];
239 bb->num--;
240 return 0;
241}
242
243void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
244{
245 ext2fs_u32_list_del(bb, blk);
246}
247
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400248errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
249 ext2_u32_iterate *ret)
250{
251 ext2_u32_iterate iter;
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000252 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000253
Theodore Ts'of3db3561997-04-26 13:34:30 +0000254 EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
255
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400256 retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
Theodore Ts'o7b4e4531997-10-26 03:41:24 +0000257 if (retval)
258 return retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000259
Theodore Ts'of3db3561997-04-26 13:34:30 +0000260 iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000261 iter->bb = bb;
262 iter->ptr = 0;
263 *ret = iter;
264 return 0;
265}
266
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400267errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
268 ext2_badblocks_iterate *ret)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000269{
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400270 return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
271 (ext2_u32_iterate *) ret);
272}
273
274
275int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
276{
277 ext2_u32_list bb;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000278
279 if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
280 return 0;
281
282 bb = iter->bb;
283
284 if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
285 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000286
287 if (iter->ptr < bb->num) {
288 *blk = bb->list[iter->ptr++];
289 return 1;
290 }
291 *blk = 0;
292 return 0;
293}
294
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400295int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
296{
297 return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
298 (__u32 *) blk);
299}
300
301
302void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000303{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000304 if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
305 return;
306
Theodore Ts'o3839e651997-04-26 13:21:57 +0000307 iter->bb = 0;
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400308 ext2fs_free_mem(&iter);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000309}
Theodore Ts'o57dca852000-07-04 19:20:25 +0000310
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400311void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
312{
313 ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
314}
315
316
317int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
Theodore Ts'o57dca852000-07-04 19:20:25 +0000318{
319 EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
320 EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
321
322 if (bb1->num != bb2->num)
323 return 0;
324
325 if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
326 return 0;
327 return 1;
328}
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400329
330int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
331{
332 return ext2fs_u32_list_equal((ext2_u32_list) bb1,
333 (ext2_u32_list) bb2);
334}
Theodore Ts'o220c0042003-03-14 00:59:42 -0500335
336int ext2fs_u32_list_count(ext2_u32_list bb)
337{
338 return bb->num;
339}