libext2fs: 32-bit bitmap refactorization, part 3

Create new functions ext2fs_{set,get}_{inode,block}_bitmap_range()
which allow programs like e2fsck, dumpe2fs, etc. to get and set chunks
of the bitmap at a time.

Move the representation details of the 32-bit old-style bitmaps into
gen_bitmap.c.

Change calls in dumpe2fs, mke2s, et. al to use the new abstractions.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
index 7d14cff..b033fa3 100644
--- a/lib/ext2fs/bitmaps.c
+++ b/lib/ext2fs/bitmaps.c
@@ -52,7 +52,6 @@
 				       const char *descr,
 				       ext2fs_inode_bitmap *ret)
 {
-	errcode_t	retval;
 	__u32		start, end, real_end;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -72,7 +71,6 @@
 				       const char *descr,
 				       ext2fs_block_bitmap *ret)
 {
-	errcode_t	retval;
 	__u32		start, end, real_end;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -148,3 +146,38 @@
 					      bm1, bm2));
 }
 
+errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *in)
+{
+	return (ext2fs_set_generic_bitmap_range(bmap,
+						EXT2_ET_MAGIC_INODE_BITMAP,
+						start, num, in));
+}
+
+errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *out)
+{
+	return (ext2fs_get_generic_bitmap_range(bmap,
+						EXT2_ET_MAGIC_INODE_BITMAP,
+						start, num, out));
+}
+
+errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *in)
+{
+	return (ext2fs_set_generic_bitmap_range(bmap, 
+						EXT2_ET_MAGIC_BLOCK_BITMAP,
+						start, num, in));
+}
+
+errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *out)
+{
+	return (ext2fs_get_generic_bitmap_range(bmap,
+						EXT2_ET_MAGIC_BLOCK_BITMAP,
+						start, num, out));
+}
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 5ce018d..20c63c0 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -100,17 +100,6 @@
 
 typedef struct struct_ext2_filsys *ext2_filsys;
 
-struct ext2fs_struct_generic_bitmap {
-	errcode_t	magic;
-	ext2_filsys 	fs;
-	__u32		start, end;
-	__u32		real_end;
-	char	*	description;
-	char	*	bitmap;
-	errcode_t	base_error_code;
-	__u32		reserved[7];
-};
-
 #define EXT2FS_MARK_ERROR 	0
 #define EXT2FS_UNMARK_ERROR 	1
 #define EXT2FS_TEST_ERROR	2
@@ -553,6 +542,8 @@
 /* bitmaps.c */
 extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
 extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
+extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
+				    ext2fs_generic_bitmap *dest);
 extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
 extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
 extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
@@ -579,6 +570,18 @@
 					     ext2fs_block_bitmap bm2);
 extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
 					     ext2fs_inode_bitmap bm2);
+extern errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *in);
+extern errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
+					ext2_ino_t start, unsigned int num,
+					void *out);
+extern errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *in);
+extern errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
+					blk_t start, unsigned int num,
+					void *out);
 
 
 /* block.c */
@@ -782,6 +785,14 @@
 extern errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
 					       ext2fs_generic_bitmap bm1,
 					       ext2fs_generic_bitmap bm2);
+extern errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+						 errcode_t magic,
+						 __u32 start, __u32 num,
+						 void *out);
+extern errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+						 errcode_t magic,
+						 __u32 start, __u32 num,
+						 void *in);
 
 /* getsize.c */
 extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
diff --git a/lib/ext2fs/gen_bitmap.c b/lib/ext2fs/gen_bitmap.c
index 5de8198..66172e5 100644
--- a/lib/ext2fs/gen_bitmap.c
+++ b/lib/ext2fs/gen_bitmap.c
@@ -27,6 +27,17 @@
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
+struct ext2fs_struct_generic_bitmap {
+	errcode_t	magic;
+	ext2_filsys 	fs;
+	__u32		start, end;
+	__u32		real_end;
+	char	*	description;
+	char	*	bitmap;
+	errcode_t	base_error_code;
+	__u32		reserved[7];
+};
+
 /* 
  * Used by previously inlined function, so we have to export this and
  * not change the function signature
@@ -284,14 +295,44 @@
 	     i <= map->real_end && i > map->end; 
 	     i++, j++)
 		ext2fs_set_bit(j, map->bitmap);
-}	
+}
+
+errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+					  errcode_t magic,
+					  __u32 start, __u32 num,
+					  void *out)
+{
+	if (!bmap || (bmap->magic != magic))
+		return magic;
+
+	if ((start < bmap->start) || (start+num-1 > bmap->real_end))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	memcpy(out, bmap->bitmap + (start >> 3), (num+7) >> 3);
+	return 0;
+}
+
+errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
+					  errcode_t magic,
+					  __u32 start, __u32 num,
+					  void *in)
+{
+	if (!bmap || (bmap->magic != magic))
+		return magic;
+
+	if ((start < bmap->start) || (start+num-1 > bmap->real_end))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	memcpy(bmap->bitmap + (start >> 3), in, (num+7) >> 3);
+	return 0;
+}
 
 int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
 				   blk_t block, int num)
 {
 	int	i;
 
-	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+	if ((block < bitmap->start) || (block+num-1 > bitmap->real_end)) {
 		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
 				   block, bitmap->description);
 		return 0;
diff --git a/lib/ext2fs/imager.c b/lib/ext2fs/imager.c
index ac8309c..9f7534a 100644
--- a/lib/ext2fs/imager.c
+++ b/lib/ext2fs/imager.c
@@ -277,11 +277,12 @@
  */
 errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
 {
-	char		*ptr;
-	int		c, size;
-	char		zero_buf[1024];
-	ssize_t		actual;
-	errcode_t	retval;
+	ext2fs_generic_bitmap	bmap;
+	errcode_t		err, retval;
+	ssize_t			actual;
+	__u32			itr, cnt, size;
+	int			c, total_size;
+	char			buf[1024];
 
 	if (flags & IMAGER_FLAG_INODEMAP) {
 		if (!fs->inode_map) {
@@ -289,7 +290,10 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->inode_map->bitmap;
+		bmap = fs->inode_map;
+		err = EXT2_ET_MAGIC_INODE_BITMAP;
+		itr = 1;
+		cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
 	} else {
 		if (!fs->block_map) {
@@ -297,43 +301,51 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->block_map->bitmap;
+		bmap = fs->block_map;
+		err = EXT2_ET_MAGIC_BLOCK_BITMAP;
+		itr = fs->super->s_first_data_block;
+		cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
 	}
-	size = size * fs->group_desc_count;
+	total_size = size * fs->group_desc_count;
 
-	actual = write(fd, ptr, size);
-	if (actual == -1) {
-		retval = errno;
-		goto errout;
+	while (cnt > 0) {
+		size = sizeof(buf);
+		if (size > (cnt >> 3))
+			size = (cnt >> 3);
+
+		retval = ext2fs_get_generic_bitmap_range(bmap, 
+				 err, itr, size << 3, buf);
+		if (retval)
+			return retval;
+
+		actual = write(fd, buf, size);
+		if (actual == -1)
+			return errno;
+		if (actual != (int) size)
+			return EXT2_ET_SHORT_READ;
+		
+		itr += size << 3;
+		cnt -= size << 3;
 	}
-	if (actual != size) {
-		retval = EXT2_ET_SHORT_WRITE;
-		goto errout;
-	}
-	size = size % fs->blocksize;
-	memset(zero_buf, 0, sizeof(zero_buf));
+
+	size = total_size % fs->blocksize;
+	memset(buf, 0, sizeof(buf));
 	if (size) {
 		size = fs->blocksize - size;
 		while (size) {
 			c = size;
-			if (c > (int) sizeof(zero_buf))
-				c = sizeof(zero_buf);
-			actual = write(fd, zero_buf, c);
-			if (actual == -1) {
-				retval = errno;
-				goto errout;
-			}
-			if (actual != c) {
-				retval = EXT2_ET_SHORT_WRITE;
-				goto errout;
-			}
+			if (c > (int) sizeof(buf))
+				c = sizeof(buf);
+			actual = write(fd, buf, c);
+			if (actual == -1)
+				return errno;
+			if (actual != c)
+				return EXT2_ET_SHORT_WRITE;
 			size -= c;
 		}
 	}
-	retval = 0;
-errout:
-	return (retval);
+	return 0;
 }
 
 
@@ -342,10 +354,12 @@
  */
 errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
 {
-	char		*ptr, *buf = 0;
-	int		size;
-	ssize_t		actual;
-	errcode_t	retval;
+	ext2fs_generic_bitmap	bmap;
+	errcode_t		err, retval;
+	__u32			itr, cnt;
+	char			buf[1024];
+	unsigned int		size;
+	ssize_t			actual;
 
 	if (flags & IMAGER_FLAG_INODEMAP) {
 		if (!fs->inode_map) {
@@ -353,7 +367,10 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->inode_map->bitmap;
+		bmap = fs->inode_map;
+		err = EXT2_ET_MAGIC_INODE_BITMAP;
+		itr = 1;
+		cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
 	} else {
 		if (!fs->block_map) {
@@ -361,29 +378,31 @@
 			if (retval)
 				return retval;
 		}
-		ptr = fs->block_map->bitmap;
+		bmap = fs->block_map;
+		err = EXT2_ET_MAGIC_BLOCK_BITMAP;
+		itr = fs->super->s_first_data_block;
+		cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
 		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
 	}
-	size = size * fs->group_desc_count;
 
-	buf = malloc(size);
-	if (!buf)
-		return ENOMEM;
+	while (cnt > 0) {
+		size = sizeof(buf);
+		if (size > (cnt >> 3))
+			size = (cnt >> 3);
 
-	actual = read(fd, buf, size);
-	if (actual == -1) {
-		retval = errno;
-		goto errout;
+		actual = read(fd, buf, size);
+		if (actual == -1)
+			return errno;
+		if (actual != (int) size)
+			return EXT2_ET_SHORT_READ;
+
+		retval = ext2fs_set_generic_bitmap_range(bmap, 
+				 err, itr, size << 3, buf);
+		if (retval)
+			return retval;
+
+		itr += size << 3;
+		cnt -= size << 3;
 	}
-	if (actual != size) {
-		retval = EXT2_ET_SHORT_WRITE;
-		goto errout;
-	}
-	memcpy(ptr, buf, size);
-	
-	retval = 0;
-errout:
-	if (buf)
-		free(buf);
-	return (retval);
+	return 0;
 }
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index cb470b8..603b590 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -58,10 +58,11 @@
 	int		block_nbytes, inode_nbytes;
 	unsigned int	nbits;
 	errcode_t	retval;
-	char 		*block_bitmap, *inode_bitmap;
 	char 		*block_buf, *inode_buf;
 	int		lazy_flag = 0;
 	blk_t		blk;
+	blk_t		blk_itr = fs->super->s_first_data_block;
+	ext2_ino_t	ino_itr = 1;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -71,9 +72,7 @@
 				    EXT2_FEATURE_COMPAT_LAZY_BG))
 		lazy_flag = 1;
 	inode_nbytes = block_nbytes = 0;
-	block_bitmap = inode_bitmap = 0;
 	if (do_block) {
-		block_bitmap = fs->block_map->bitmap;
 		block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
 		retval = ext2fs_get_mem(fs->blocksize, &block_buf);
 		if (retval)
@@ -81,7 +80,6 @@
 		memset(block_buf, 0xff, fs->blocksize);
 	}
 	if (do_inode) {
-		inode_bitmap = fs->inode_map->bitmap;
 		inode_nbytes = (size_t) 
 			((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
 		retval = ext2fs_get_mem(fs->blocksize, &inode_buf);
@@ -91,14 +89,18 @@
 	}
 
 	for (i = 0; i < fs->group_desc_count; i++) {
-		if (!block_bitmap || !do_block)
+		if (!do_block)
 			goto skip_block_bitmap;
 
 		if (lazy_flag && fs->group_desc[i].bg_flags &
 		    EXT2_BG_BLOCK_UNINIT) 
 			goto skip_this_block_bitmap;
  
-		memcpy(block_buf, block_bitmap, block_nbytes);
+		retval = ext2fs_get_block_bitmap_range(fs->block_map, 
+				blk_itr, block_nbytes << 3, block_buf);
+		if (retval)
+			return retval;
+
 		if (i == fs->group_desc_count - 1) {
 			/* Force bitmap padding for the last group */
 			nbits = ((fs->super->s_blocks_count
@@ -122,17 +124,21 @@
 				return EXT2_ET_BLOCK_BITMAP_WRITE;
 		}
 	skip_this_block_bitmap:
-		block_bitmap += block_nbytes;
+		blk_itr += block_nbytes << 3;
 	skip_block_bitmap:
 
-		if (!inode_bitmap || !do_inode)
+		if (!do_inode)
 			continue;
 
 		if (lazy_flag && fs->group_desc[i].bg_flags &
 		    EXT2_BG_INODE_UNINIT) 
 			goto skip_this_inode_bitmap;
  
-		memcpy(inode_buf, inode_bitmap, inode_nbytes);
+		retval = ext2fs_get_inode_bitmap_range(fs->inode_map, 
+				ino_itr, inode_nbytes << 3, inode_buf);
+		if (retval)
+			return retval;
+
 		blk = fs->group_desc[i].bg_inode_bitmap;
 		if (blk) {
 #ifdef EXT2_BIG_ENDIAN_BITMAPS
@@ -147,7 +153,7 @@
 				return EXT2_ET_INODE_BITMAP_WRITE;
 		}
 	skip_this_inode_bitmap:
-		inode_bitmap += inode_nbytes;
+		ino_itr += inode_nbytes << 3;
 
 	}
 	if (do_block) {
@@ -167,10 +173,16 @@
 	char *block_bitmap = 0, *inode_bitmap = 0;
 	char *buf;
 	errcode_t retval;
-	int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
-	int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
+	unsigned int block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	unsigned inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
 	int lazy_flag = 0;
+	int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE;
+	unsigned int	cnt;
 	blk_t	blk;
+	blk_t	blk_itr = fs->super->s_first_data_block;
+	blk_t   blk_cnt;
+	ext2_ino_t ino_itr = 1;
+	ext2_ino_t ino_cnt;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -190,8 +202,12 @@
 		retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
 		if (retval)
 			goto cleanup;
-		block_bitmap = fs->block_map->bitmap;
-	}
+		retval = ext2fs_get_mem(do_image ? fs->blocksize : 
+					block_nbytes, &block_bitmap);
+		if (retval)
+			goto cleanup;
+	} else
+		block_nbytes = 0;
 	if (do_inode) {
 		if (fs->inode_map)
 			ext2fs_free_inode_bitmap(fs->inode_map);
@@ -199,30 +215,54 @@
 		retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
 		if (retval)
 			goto cleanup;
-		inode_bitmap = fs->inode_map->bitmap;
-	}
+		retval = ext2fs_get_mem(do_image ? fs->blocksize : 
+					inode_nbytes, &inode_bitmap);
+		if (retval)
+			goto cleanup;
+	} else
+		inode_nbytes = 0;
 	ext2fs_free_mem(&buf);
 
 	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
-		if (inode_bitmap) {
-			blk = (fs->image_header->offset_inodemap /
-			       fs->blocksize);
-			retval = io_channel_read_blk(fs->image_io, blk,
-			     -(inode_nbytes * fs->group_desc_count),
-			     inode_bitmap);
+		blk = (fs->image_header->offset_inodemap / fs->blocksize);
+		ino_cnt = fs->super->s_inodes_count;
+		while (inode_nbytes > 0) {
+			retval = io_channel_read_blk(fs->image_io, blk++,
+						     1, inode_bitmap);
 			if (retval)
 				goto cleanup;
-		}
-		if (block_bitmap) {
-			blk = (fs->image_header->offset_blockmap /
-			       fs->blocksize);
-			retval = io_channel_read_blk(fs->image_io, blk, 
-			     -(block_nbytes * fs->group_desc_count),
-			     block_bitmap);
+			cnt = fs->blocksize << 3;
+			if (cnt > ino_cnt)
+				cnt = ino_cnt;
+			retval = ext2fs_set_inode_bitmap_range(fs->inode_map, 
+					       ino_itr, cnt, inode_bitmap);
 			if (retval)
 				goto cleanup;
+			ino_itr += fs->blocksize << 3;
+			ino_cnt -= fs->blocksize << 3;
+			inode_nbytes -= fs->blocksize;
 		}
-		return 0;
+		blk = (fs->image_header->offset_blockmap /
+		       fs->blocksize);
+		blk_cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * 
+			fs->group_desc_count;
+		while (block_nbytes > 0) {
+			retval = io_channel_read_blk(fs->image_io, blk++,
+						     1, block_bitmap);
+			if (retval)
+				goto cleanup;
+			cnt = fs->blocksize << 3;
+			if (cnt > blk_cnt)
+				cnt = blk_cnt;
+			retval = ext2fs_set_block_bitmap_range(fs->block_map, 
+				       blk_itr, cnt, block_bitmap);
+			if (retval)
+				goto cleanup;
+			blk_itr += fs->blocksize << 3;
+			blk_cnt -= fs->blocksize << 3;
+			block_nbytes -= fs->blocksize;
+		}
+		goto success_cleanup;
 	}
 
 	for (i = 0; i < fs->group_desc_count; i++) {
@@ -245,7 +285,12 @@
 #endif
 			} else
 				memset(block_bitmap, 0xff, block_nbytes);
-			block_bitmap += block_nbytes;
+			cnt = block_nbytes << 3;
+			retval = ext2fs_set_block_bitmap_range(fs->block_map, 
+					       blk_itr, cnt, block_bitmap);
+			if (retval)
+				goto cleanup;
+			blk_itr += block_nbytes << 3;
 		}
 		if (inode_bitmap) {
 			blk = fs->group_desc[i].bg_inode_bitmap;
@@ -266,9 +311,19 @@
 #endif
 			} else
 				memset(inode_bitmap, 0xff, inode_nbytes);
-			inode_bitmap += inode_nbytes;
+			cnt = inode_nbytes << 3;
+			retval = ext2fs_set_inode_bitmap_range(fs->inode_map, 
+					       ino_itr, cnt, inode_bitmap);
+			if (retval)
+				goto cleanup;
+			ino_itr += inode_nbytes << 3;
 		}
 	}
+success_cleanup:
+	if (inode_bitmap)
+		ext2fs_free_mem(&inode_bitmap);
+	if (block_bitmap)
+		ext2fs_free_mem(&block_bitmap);
 	return 0;
 	
 cleanup:
@@ -280,6 +335,10 @@
 		ext2fs_free_mem(&fs->inode_map);
 		fs->inode_map = 0;
 	}
+	if (inode_bitmap)
+		ext2fs_free_mem(&inode_bitmap);
+	if (block_bitmap)
+		ext2fs_free_mem(&block_bitmap);
 	if (buf)
 		ext2fs_free_mem(&buf);
 	return retval;