badblocks.c revision 9f8046fc6dfc13eee2f5c363214e60b533872cac
1/*
2 * badblocks.c --- routines to manipulate the bad block structure
3 *
4 * 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%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#include <fcntl.h>
18#include <time.h>
19#if HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25
26#include "ext2_fs.h"
27#include "ext2fsP.h"
28
29/*
30 * Helper function for making a badblocks list
31 */
32static errcode_t make_badblocks_list(int size, int num, blk_t *list,
33				     ext2_badblocks_list *ret)
34{
35	ext2_badblocks_list	bb;
36	errcode_t		retval;
37
38	retval = ext2fs_get_mem(sizeof(struct ext2_struct_badblocks_list),
39				(void **) &bb);
40	if (retval)
41		return retval;
42	memset(bb, 0, sizeof(struct ext2_struct_badblocks_list));
43	bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
44	bb->size = size ? size : 10;
45	bb->num = num;
46	retval = ext2fs_get_mem(bb->size * sizeof(blk_t), (void **) &bb->list);
47	if (!bb->list) {
48		ext2fs_free_mem((void **) &bb);
49		return retval;
50	}
51	if (list)
52		memcpy(bb->list, list, bb->size * sizeof(blk_t));
53	else
54		memset(bb->list, 0, bb->size * sizeof(blk_t));
55	*ret = bb;
56	return 0;
57}
58
59
60/*
61 * This procedure creates an empty badblocks list.
62 */
63errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
64{
65	return make_badblocks_list(size, 0, 0, ret);
66}
67
68/*
69 * This procedure copies a badblocks list
70 */
71errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
72				ext2_badblocks_list *dest)
73{
74	errcode_t	retval;
75
76	retval = make_badblocks_list(src->size, src->num, src->list,
77				     dest);
78	if (retval)
79		return retval;
80	(*dest)->badblocks_flags = src->badblocks_flags;
81	return 0;
82}
83
84
85/*
86 * This procedure frees a badblocks list.
87 *
88 * (note: moved to closefs.c)
89 */
90
91
92/*
93 * This procedure adds a block to a badblocks list.
94 */
95errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
96{
97	errcode_t	retval;
98	int		i, j;
99	unsigned long	old_size;
100
101	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
102
103	if (bb->num >= bb->size) {
104		old_size = bb->size * sizeof(blk_t);
105		bb->size += 100;
106		retval = ext2fs_resize_mem(old_size, bb->size * sizeof(blk_t),
107					   (void **) &bb->list);
108		if (retval) {
109			bb->size -= 100;
110			return retval;
111		}
112	}
113
114	/*
115	 * Add special case code for appending to the end of the list
116	 */
117	i = bb->num-1;
118	if ((bb->num != 0) && (bb->list[i] == blk))
119		return 0;
120	if ((bb->num == 0) || (bb->list[i] < blk)) {
121		bb->list[bb->num++] = blk;
122		return 0;
123	}
124
125	j = bb->num;
126	for (i=0; i < bb->num; i++) {
127		if (bb->list[i] == blk)
128			return 0;
129		if (bb->list[i] > blk) {
130			j = i;
131			break;
132		}
133	}
134	for (i=bb->num; i > j; i--)
135		bb->list[i] = bb->list[i-1];
136	bb->list[j] = blk;
137	bb->num++;
138	return 0;
139}
140
141/*
142 * This procedure tests to see if a particular block is on a badblocks
143 * list.
144 */
145int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
146{
147	int	low, high, mid;
148
149	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
150		return 0;
151
152	if (bb->num == 0)
153		return 0;
154
155	low = 0;
156	high = bb->num-1;
157	if (blk == bb->list[low])
158		return 1;
159	if (blk == bb->list[high])
160		return 1;
161
162	while (low < high) {
163		mid = (low+high)/2;
164		if (mid == low || mid == high)
165			break;
166		if (blk == bb->list[mid])
167			return 1;
168		if (blk < bb->list[mid])
169			high = mid;
170		else
171			low = mid;
172	}
173	return 0;
174}
175
176errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
177					      ext2_badblocks_iterate *ret)
178{
179	ext2_badblocks_iterate iter;
180	errcode_t		retval;
181
182	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
183
184	retval = ext2fs_get_mem(sizeof(struct ext2_struct_badblocks_iterate),
185			      (void **) &iter);
186	if (retval)
187		return retval;
188
189	iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
190	iter->bb = bb;
191	iter->ptr = 0;
192	*ret = iter;
193	return 0;
194}
195
196int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
197{
198	ext2_badblocks_list	bb;
199
200	if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
201		return 0;
202
203	bb = iter->bb;
204
205	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
206		return 0;
207
208	if (iter->ptr < bb->num) {
209		*blk = bb->list[iter->ptr++];
210		return 1;
211	}
212	*blk = 0;
213	return 0;
214}
215
216void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
217{
218	if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
219		return;
220
221	iter->bb = 0;
222	ext2fs_free_mem((void **) &iter);
223}
224
225int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
226{
227	EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
228	EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
229
230	if (bb1->num != bb2->num)
231		return 0;
232
233	if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
234		return 0;
235	return 1;
236}
237