1e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/*
2e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * blkmap64_ba.c --- Simple bitarray implementation for bitmaps
3e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
4e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Copyright (C) 2008 Theodore Ts'o.
5e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall *
6e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * %Begin-Header%
7e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * This file may be redistributed under the terms of the GNU Public
8e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * License.
9e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * %End-Header%
10e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall */
11e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
12e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <stdio.h>
13e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <string.h>
14e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if HAVE_UNISTD_H
15e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <unistd.h>
16e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
17e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <fcntl.h>
18e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <time.h>
19e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if HAVE_SYS_STAT_H
20e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <sys/stat.h>
21e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
22e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#if HAVE_SYS_TYPES_H
23e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include <sys/types.h>
24e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#endif
25e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
26e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "ext2_fs.h"
27e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "ext2fsP.h"
28e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall#include "bmap64.h"
29e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
30e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/*
31e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Private data for bit array implementation of bitmap ops.
32e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * Currently, this is just a pointer to our big flat hunk of memory,
33e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall * exactly equivalent to the old-skool char * bitmap member.
34e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall */
35e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
36e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstruct ext2fs_ba_private_struct {
37e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	char *bitarray;
38e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall};
39e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
40e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgralltypedef struct ext2fs_ba_private_struct *ext2fs_ba_private;
41e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
42e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t ba_alloc_private_data (ext2fs_generic_bitmap bitmap)
43e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
44e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp;
45e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t	retval;
46e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t		size;
47e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
48e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/*
49e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * Since we only have the one pointer, we could just shove our
50e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * private data in the void *private field itself, but then
51e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * we'd have to do a fair bit of rewriting if we ever added a
52e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * field.  I'm agnostic.
53e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 */
54e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_get_mem(sizeof (ext2fs_ba_private), &bp);
55e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval)
56e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return retval;
57e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
58e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
59e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
60e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ext2fs_get_mem(size, &bp->bitarray);
61e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval) {
62e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem(&bp);
63e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bp = 0;
64e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return retval;
65e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
66e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	bitmap->private = (void *) bp;
67e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
68e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
69e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
70e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),
71e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			     ext2fs_generic_bitmap bitmap)
72e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
73e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp;
74e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t	retval;
75e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t		size;
76e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
77e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ba_alloc_private_data (bitmap);
78e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval)
79e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return retval;
80e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
81e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	bp = (ext2fs_ba_private) bitmap->private;
82e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
83e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	memset(bp->bitarray, 0, size);
84e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
85e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
86e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
87e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
88e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void ba_free_bmap(ext2fs_generic_bitmap bitmap)
89e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
90e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
91e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
92e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!bp)
93e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return;
94e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
95e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (bp->bitarray) {
96e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_free_mem (&bp->bitarray);
97e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bp->bitarray = 0;
98e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
99e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_free_mem (&bp);
100e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	bp = 0;
101e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
102e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
103e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t ba_copy_bmap(ext2fs_generic_bitmap src,
104e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			      ext2fs_generic_bitmap dest)
105e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
106e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private src_bp = (ext2fs_ba_private) src->private;
107e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private dest_bp;
108e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t retval;
109e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t size;
110e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
111e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	retval = ba_alloc_private_data (dest);
112e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (retval)
113e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return retval;
114e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
115e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	dest_bp = (ext2fs_ba_private) dest->private;
116e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
117e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = (size_t) (((src->real_end - src->start) / 8) + 1);
118e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	memcpy (dest_bp->bitarray, src_bp->bitarray, size);
119e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
120e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
121e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
122e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
123e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t ba_resize_bmap(ext2fs_generic_bitmap bmap,
124e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				__u64 new_end, __u64 new_real_end)
125e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
126e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bmap->private;
127e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	errcode_t	retval;
128e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size_t		size, new_size;
129e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	__u64		bitno;
130e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
131e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/*
132e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * If we're expanding the bitmap, make sure all of the new
133e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * parts of the bitmap are zero.
134e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 */
135e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (new_end > bmap->end) {
136e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bitno = bmap->real_end;
137e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (bitno > new_end)
138e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			bitno = new_end;
139e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		for (; bitno > bmap->end; bitno--)
140e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			ext2fs_clear_bit64(bitno - bmap->start, bp->bitarray);
141e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
142e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (new_real_end == bmap->real_end) {
143e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bmap->end = new_end;
144e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return 0;
145e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
146e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
147e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	size = ((bmap->real_end - bmap->start) / 8) + 1;
148e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	new_size = ((new_real_end - bmap->start) / 8) + 1;
149e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
150e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (size != new_size) {
151e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		retval = ext2fs_resize_mem(size, new_size, &bp->bitarray);
152e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (retval)
153e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return retval;
154e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
155e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (new_size > size)
156e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		memset(bp->bitarray + size, 0, new_size - size);
157e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
158e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	bmap->end = new_end;
159e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	bmap->real_end = new_real_end;
160e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
161e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
162e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
163e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
164e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int ba_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
165e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
166e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
167e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t bitno = (blk64_t) arg;
168e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
169e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return ext2fs_set_bit64(bitno - bitmap->start, bp->bitarray);
170e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
171e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
172e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int ba_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
173e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
174e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
175e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t bitno = (blk64_t) arg;
176e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
177e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return ext2fs_clear_bit64(bitno - bitmap->start, bp->bitarray);
178e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
179e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
180e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int ba_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
181e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
182e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
183e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t bitno = (blk64_t) arg;
184e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
185e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return ext2fs_test_bit64(bitno - bitmap->start, bp->bitarray);
186e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
187e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
188e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void ba_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
189e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				unsigned int num)
190e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
191e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
192e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t bitno = (blk64_t) arg;
193e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int i;
194e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
195e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	for (i = 0; i < num; i++)
196e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_fast_set_bit64(bitno + i - bitmap->start, bp->bitarray);
197e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
198e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
199e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void ba_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
200e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				  unsigned int num)
201e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
202e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
203e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	blk64_t bitno = (blk64_t) arg;
204e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int i;
205e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
206e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	for (i = 0; i < num; i++)
207e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		ext2fs_fast_clear_bit64(bitno + i - bitmap->start, bp->bitarray);
208e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
209e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
210e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic int ba_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap,
211e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     __u64 start, unsigned int len)
212e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
213e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
214e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	__u64 start_byte, len_byte = len >> 3;
215e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int start_bit, len_bit = len % 8;
216e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int first_bit = 0;
217e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned int last_bit  = 0;
218e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int mark_count = 0;
219e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int mark_bit = 0;
220e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int i;
221e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	const char *ADDR;
222e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
223e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ADDR = bp->bitarray;
224e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	start -= bitmap->start;
225e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	start_byte = start >> 3;
226e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	start_bit = start % 8;
227e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
228e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (start_bit != 0) {
229e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/*
230e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * The compared start block number or start inode number
231e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * is not the first bit in a byte.
232e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 */
233e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		mark_count = 8 - start_bit;
234e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (len < 8 - start_bit) {
235e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			mark_count = (int)len;
236e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			mark_bit = len + start_bit - 1;
237e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		} else
238e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			mark_bit = 7;
239e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
240e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		for (i = mark_count; i > 0; i--, mark_bit--)
241e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			first_bit |= 1 << mark_bit;
242e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
243e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/*
244e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * Compare blocks or inodes in the first byte.
245e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * If there is any marked bit, this function returns 0.
246e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 */
247e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (first_bit & ADDR[start_byte])
248e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return 0;
249e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		else if (len <= 8 - start_bit)
250e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return 1;
251e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
252e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		start_byte++;
253e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		len_bit = (len - mark_count) % 8;
254e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		len_byte = (len - mark_count) >> 3;
255e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
256e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
257e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/*
258e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * The compared start block number or start inode number is
259e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 * the first bit in a byte.
260e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	 */
261e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (len_bit != 0) {
262e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/*
263e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * The compared end block number or end inode number is
264e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * not the last bit in a byte.
265e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 */
266e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--)
267e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			last_bit |= 1 << mark_bit;
268e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
269e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		/*
270e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * Compare blocks or inodes in the last byte.
271e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 * If there is any marked bit, this function returns 0.
272e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		 */
273e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (last_bit & ADDR[start_byte + len_byte])
274e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return 0;
275e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		else if (len_byte == 0)
276e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return 1;
277e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
278e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
279e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* Check whether all bytes are 0 */
280e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return ext2fs_mem_is_zero(ADDR + start_byte, len_byte);
281e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
282e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
283e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
284e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t ba_set_bmap_range(ext2fs_generic_bitmap bitmap,
285e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     __u64 start, size_t num, void *in)
286e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
287e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
288e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
289e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	memcpy (bp->bitarray + (start >> 3), in, (num + 7) >> 3);
290e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
291e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
292e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
293e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
294e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t ba_get_bmap_range(ext2fs_generic_bitmap bitmap,
295e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				     __u64 start, size_t num, void *out)
296e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
297e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
298e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
299e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	memcpy (out, bp->bitarray + (start >> 3), (num + 7) >> 3);
300e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
301e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return 0;
302e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
303e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
304e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void ba_clear_bmap(ext2fs_generic_bitmap bitmap)
305e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
306e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
307e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
308e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	memset(bp->bitarray, 0,
309e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
310e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
311e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
312e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic void ba_print_stats(ext2fs_generic_bitmap bitmap)
313e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
314e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	fprintf(stderr, "%16llu Bytes used by bitarray\n",
315e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		((bitmap->real_end - bitmap->start) >> 3) + 1 +
316e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		sizeof(struct ext2fs_ba_private_struct));
317e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
318e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
319e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall/* Find the first zero bit between start and end, inclusive. */
320e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstatic errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap,
321e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				    __u64 start, __u64 end, __u64 *out)
322e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall{
323e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
324e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned long bitpos = start - bitmap->start;
325e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned long count = end - start + 1;
326e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	int byte_found = 0; /* whether a != 0xff byte has been found */
327e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	const unsigned char *pos;
328e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	unsigned long max_loop_count, i;
329e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
330e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (start < bitmap->start || end > bitmap->end || start > end)
331e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return EINVAL;
332e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
333e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (bitmap->cluster_bits)
334e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return EINVAL;
335e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
336e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* scan bits until we hit a byte boundary */
337e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	while ((bitpos & 0x7) != 0 && count > 0) {
338e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (!ext2fs_test_bit64(bitpos, bp->bitarray)) {
339e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			*out = bitpos + bitmap->start;
340e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return 0;
341e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
342e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bitpos++;
343e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		count--;
344e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
345e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
346e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!count)
347e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		return ENOENT;
348e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
349e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3);
350e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* scan bytes until 8-byte (64-bit) aligned */
351e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	while (count >= 8 && (((unsigned long)pos) & 0x07)) {
352e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (*pos != 0xff) {
353e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			byte_found = 1;
354e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			break;
355e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
356e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		pos++;
357e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		count -= 8;
358e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bitpos += 8;
359e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
360e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
361e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	if (!byte_found) {
362e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		max_loop_count = count >> 6; /* 8-byte blocks */
363e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		i = max_loop_count;
364e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		while (i) {
365e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (*((const __u64 *)pos) != ((__u64)-1))
366e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				break;
367e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			pos += 8;
368e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			i--;
369e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
370e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		count -= 64 * (max_loop_count - i);
371e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bitpos += 64 * (max_loop_count - i);
372e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
373e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		max_loop_count = count >> 3;
374e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		i = max_loop_count;
375e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		while (i) {
376e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			if (*pos != 0xff) {
377e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				byte_found = 1;
378e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall				break;
379e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			}
380e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			pos++;
381e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			i--;
382e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
383e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		count -= 8 * (max_loop_count - i);
384e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bitpos += 8 * (max_loop_count - i);
385e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
386e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
387e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	/* Here either count < 8 or byte_found == 1. */
388e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	while (count-- > 0) {
389e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		if (!ext2fs_test_bit64(bitpos, bp->bitarray)) {
390e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			*out = bitpos + bitmap->start;
391e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall			return 0;
392e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		}
393e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall		bitpos++;
394e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	}
395e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
396e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	return ENOENT;
397e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall}
398e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall
399e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrallstruct ext2_bitmap_ops ext2fs_blkmap64_bitarray = {
400e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.type = EXT2FS_BMAP64_BITARRAY,
401e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.new_bmap = ba_new_bmap,
402e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.free_bmap = ba_free_bmap,
403e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.copy_bmap = ba_copy_bmap,
404e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.resize_bmap = ba_resize_bmap,
405e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.mark_bmap = ba_mark_bmap,
406e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.unmark_bmap = ba_unmark_bmap,
407e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.test_bmap = ba_test_bmap,
408e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.test_clear_bmap_extent = ba_test_clear_bmap_extent,
409e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.mark_bmap_extent = ba_mark_bmap_extent,
410e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.unmark_bmap_extent = ba_unmark_bmap_extent,
411e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.set_bmap_range = ba_set_bmap_range,
412e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.get_bmap_range = ba_get_bmap_range,
413e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.clear_bmap = ba_clear_bmap,
414e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.print_stats = ba_print_stats,
415e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall	.find_first_zero = ba_find_first_zero
416e0ed7404719a9ddd2ba427a80db5365c8bad18c0JP Abgrall};
417