badblocks.c revision f75c28de4731c2cd09f6ca1a23e25c968a1edc2f
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * badblocks.c --- routines to manipulate the bad block structure
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *
621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %Begin-Header%
721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * License.
921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * %End-Header%
103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
144cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
164cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
191d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
211d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
221d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
241d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
26b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#if EXT2_FLAT_INCLUDES
27b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
28b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#else
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <linux/ext2_fs.h>
30b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#endif
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o#include "ext2fsP.h"
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
35a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * Helper function for making a badblocks list
363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
37a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'ostatic errcode_t make_badblocks_list(int size, int num, blk_t *list,
38a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o				     ext2_badblocks_list *ret)
393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2_badblocks_list	bb;
417b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
42a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
437b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct ext2_struct_badblocks_list),
447b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &bb);
457b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
467b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
4721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	memset(bb, 0, sizeof(struct ext2_struct_badblocks_list));
48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	bb->size = size ? size : 10;
50a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	bb->num = num;
517b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(bb->size * sizeof(blk_t), (void **) &bb->list);
523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (!bb->list) {
537b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &bb);
547b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
56a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (list)
57a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		memcpy(bb->list, list, bb->size * sizeof(blk_t));
58a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	else
59a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		memset(bb->list, 0, bb->size * sizeof(blk_t));
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*ret = bb;
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
63a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
64a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
65a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o/*
66a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * This procedure creates an empty badblocks list.
67a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o */
68a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oerrcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
69a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o{
70a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	return make_badblocks_list(size, 0, 0, ret);
71a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o}
72a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
73a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o/*
74a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o * This procedure copies a badblocks list
75a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o */
76a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'oerrcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
77a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o				ext2_badblocks_list *dest)
78a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o{
79a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	errcode_t	retval;
80a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
81a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	retval = make_badblocks_list(src->size, src->num, src->list,
82a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o				     dest);
83a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (retval)
84a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return retval;
85a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	(*dest)->badblocks_flags = src->badblocks_flags;
86a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	return 0;
87a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o}
88a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This procedure frees a badblocks list.
9221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *
9321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o * (note: moved to closefs.c)
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
95f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This procedure adds a block to a badblocks list.
993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
10021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'oerrcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
1013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
1027b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t	retval;
1037b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	int		i, j;
10476f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o	unsigned long	old_size;
1053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
106f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
107f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
1083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (bb->num >= bb->size) {
10976f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o		old_size = bb->size * sizeof(blk_t);
110f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o		bb->size += 100;
11176f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o		retval = ext2fs_resize_mem(old_size, bb->size * sizeof(blk_t),
1127b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o					   (void **) &bb->list);
11376f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o		if (retval) {
114f75c28de4731c2cd09f6ca1a23e25c968a1edc2fTheodore Ts'o			bb->size -= 100;
1157b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
11676f875daa1c9c2cdc72f0c6f0f7be4bbc7f0fc07Theodore Ts'o		}
1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
11921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	j = bb->num;
12021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	for (i=0; i < bb->num; i++) {
12121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (bb->list[i] == blk)
12221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			return 0;
12321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (bb->list[i] > blk) {
12421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			j = i;
12521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			break;
12621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		}
12721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
12821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	for (i=bb->num; i > j; i--)
12921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		bb->list[i] = bb->list[i-1];
13021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	bb->list[j] = blk;
13121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	bb->num++;
1323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * This procedure tests to see if a particular block is on a badblocks
1373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * list.
1383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
13921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'oint ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
1403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
14121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	int	low, high, mid;
1423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
14321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
14421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return 0;
145f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
146f635d7f65bd002984ce9a202d491d4f187b996b2Theodore Ts'o	if (bb->num == 0)
147f635d7f65bd002984ce9a202d491d4f187b996b2Theodore Ts'o		return 0;
148f635d7f65bd002984ce9a202d491d4f187b996b2Theodore Ts'o
14921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	low = 0;
15021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	high = bb->num-1;
15121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (blk == bb->list[low])
15221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return 1;
15321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	if (blk == bb->list[high])
15421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		return 1;
1553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
15621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	while (low < high) {
15721c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		mid = (low+high)/2;
15821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (mid == low || mid == high)
15921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			break;
16021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (blk == bb->list[mid])
16121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			return 1;
16221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		if (blk < bb->list[mid])
16321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			high = mid;
16421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o		else
16521c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o			low = mid;
16621c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	}
1673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
17021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'oerrcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
17121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o					      ext2_badblocks_iterate *ret)
1723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
17321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2_badblocks_iterate iter;
1747b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
1753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
176f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
177f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
1787b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct ext2_struct_badblocks_iterate),
1797b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			      (void **) &iter);
1807b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
1817b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
1823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
183f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
1843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	iter->bb = bb;
1853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	iter->ptr = 0;
1863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*ret = iter;
1873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
1883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
1893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
19021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'oint ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
1913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
19221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o	ext2_badblocks_list	bb;
193f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
194f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
195f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		return 0;
196f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
197f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	bb = iter->bb;
198f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
199f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
200f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		return 0;
2013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
2023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (iter->ptr < bb->num) {
2033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		*blk = bb->list[iter->ptr++];
2043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		return 1;
2053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
2063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*blk = 0;
2073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
2083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
2093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
21021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'ovoid ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
2113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
212f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
213f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o		return;
214f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
2153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	iter->bb = 0;
2167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	ext2fs_free_mem((void **) &iter);
2173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
218