Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * rw_bitmaps.c --- routines to read and write the  inode and block bitmaps.
      3  *
      4  * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
      5  *
      6  * %Begin-Header%
      7  * This file may be redistributed under the terms of the GNU Library
      8  * General Public License, version 2.
      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 #ifdef HAVE_SYS_STAT_H
     20 #include <sys/stat.h>
     21 #endif
     22 #ifdef HAVE_SYS_TYPES_H
     23 #include <sys/types.h>
     24 #endif
     25 
     26 #include "ext2_fs.h"
     27 #include "ext2fs.h"
     28 #include "e2image.h"
     29 
     30 static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
     31 {
     32 	dgrp_t 		i;
     33 	unsigned int	j;
     34 	int		block_nbytes, inode_nbytes;
     35 	unsigned int	nbits;
     36 	errcode_t	retval;
     37 	char 		*block_buf, *inode_buf;
     38 	int		csum_flag = 0;
     39 	blk_t		blk;
     40 	blk_t		blk_itr = fs->super->s_first_data_block;
     41 	ext2_ino_t	ino_itr = 1;
     42 
     43 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
     44 
     45 	if (!(fs->flags & EXT2_FLAG_RW))
     46 		return EXT2_ET_RO_FILSYS;
     47 
     48 	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
     49 				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
     50 		csum_flag = 1;
     51 
     52 	inode_nbytes = block_nbytes = 0;
     53 	if (do_block) {
     54 		block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
     55 		retval = ext2fs_get_memalign(fs->blocksize, fs->blocksize,
     56 					     &block_buf);
     57 		if (retval)
     58 			return retval;
     59 		memset(block_buf, 0xff, fs->blocksize);
     60 	}
     61 	if (do_inode) {
     62 		inode_nbytes = (size_t)
     63 			((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
     64 		retval = ext2fs_get_memalign(fs->blocksize, fs->blocksize,
     65 					     &inode_buf);
     66 		if (retval)
     67 			return retval;
     68 		memset(inode_buf, 0xff, fs->blocksize);
     69 	}
     70 
     71 	for (i = 0; i < fs->group_desc_count; i++) {
     72 		if (!do_block)
     73 			goto skip_block_bitmap;
     74 
     75 		if (csum_flag && fs->group_desc[i].bg_flags &
     76 		    EXT2_BG_BLOCK_UNINIT)
     77 			goto skip_this_block_bitmap;
     78 
     79 		retval = ext2fs_get_block_bitmap_range(fs->block_map,
     80 				blk_itr, block_nbytes << 3, block_buf);
     81 		if (retval)
     82 			return retval;
     83 
     84 		if (i == fs->group_desc_count - 1) {
     85 			/* Force bitmap padding for the last group */
     86 			nbits = ((fs->super->s_blocks_count
     87 				  - fs->super->s_first_data_block)
     88 				 % EXT2_BLOCKS_PER_GROUP(fs->super));
     89 			if (nbits)
     90 				for (j = nbits; j < fs->blocksize * 8; j++)
     91 					ext2fs_set_bit(j, block_buf);
     92 		}
     93 		blk = fs->group_desc[i].bg_block_bitmap;
     94 		if (blk) {
     95 			retval = io_channel_write_blk(fs->io, blk, 1,
     96 						      block_buf);
     97 			if (retval)
     98 				return EXT2_ET_BLOCK_BITMAP_WRITE;
     99 		}
    100 	skip_this_block_bitmap:
    101 		blk_itr += block_nbytes << 3;
    102 	skip_block_bitmap:
    103 
    104 		if (!do_inode)
    105 			continue;
    106 
    107 		if (csum_flag && fs->group_desc[i].bg_flags &
    108 		    EXT2_BG_INODE_UNINIT)
    109 			goto skip_this_inode_bitmap;
    110 
    111 		retval = ext2fs_get_inode_bitmap_range(fs->inode_map,
    112 				ino_itr, inode_nbytes << 3, inode_buf);
    113 		if (retval)
    114 			return retval;
    115 
    116 		blk = fs->group_desc[i].bg_inode_bitmap;
    117 		if (blk) {
    118 			retval = io_channel_write_blk(fs->io, blk, 1,
    119 						      inode_buf);
    120 			if (retval)
    121 				return EXT2_ET_INODE_BITMAP_WRITE;
    122 		}
    123 	skip_this_inode_bitmap:
    124 		ino_itr += inode_nbytes << 3;
    125 
    126 	}
    127 	if (do_block) {
    128 		fs->flags &= ~EXT2_FLAG_BB_DIRTY;
    129 		ext2fs_free_mem(&block_buf);
    130 	}
    131 	if (do_inode) {
    132 		fs->flags &= ~EXT2_FLAG_IB_DIRTY;
    133 		ext2fs_free_mem(&inode_buf);
    134 	}
    135 	return 0;
    136 }
    137 
    138 static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
    139 {
    140 	dgrp_t i;
    141 	char *block_bitmap = 0, *inode_bitmap = 0;
    142 	char *buf;
    143 	errcode_t retval;
    144 	int block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
    145 	int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
    146 	int csum_flag = 0;
    147 	int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE;
    148 	unsigned int	cnt;
    149 	blk_t	blk;
    150 	blk_t	blk_itr = fs->super->s_first_data_block;
    151 	blk_t   blk_cnt;
    152 	ext2_ino_t ino_itr = 1;
    153 	ext2_ino_t ino_cnt;
    154 
    155 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
    156 
    157 	fs->write_bitmaps = ext2fs_write_bitmaps;
    158 
    159 	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
    160 				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
    161 		csum_flag = 1;
    162 
    163 	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
    164 	if (retval)
    165 		return retval;
    166 	if (do_block) {
    167 		if (fs->block_map)
    168 			ext2fs_free_block_bitmap(fs->block_map);
    169 		strcpy(buf, "block bitmap for ");
    170 		strcat(buf, fs->device_name);
    171 		retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
    172 		if (retval)
    173 			goto cleanup;
    174 		if (do_image)
    175 			retval = ext2fs_get_mem(fs->blocksize, &block_bitmap);
    176 		else
    177 			retval = ext2fs_get_memalign((unsigned) block_nbytes,
    178 						     fs->blocksize,
    179 						     &block_bitmap);
    180 
    181 		if (retval)
    182 			goto cleanup;
    183 	} else
    184 		block_nbytes = 0;
    185 	if (do_inode) {
    186 		if (fs->inode_map)
    187 			ext2fs_free_inode_bitmap(fs->inode_map);
    188 		strcpy(buf, "inode bitmap for ");
    189 		strcat(buf, fs->device_name);
    190 		retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
    191 		if (retval)
    192 			goto cleanup;
    193 		retval = ext2fs_get_mem(do_image ? fs->blocksize :
    194 					(unsigned) inode_nbytes, &inode_bitmap);
    195 		if (retval)
    196 			goto cleanup;
    197 	} else
    198 		inode_nbytes = 0;
    199 	ext2fs_free_mem(&buf);
    200 
    201 	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
    202 		blk = (fs->image_header->offset_inodemap / fs->blocksize);
    203 		ino_cnt = fs->super->s_inodes_count;
    204 		while (inode_nbytes > 0) {
    205 			retval = io_channel_read_blk(fs->image_io, blk++,
    206 						     1, inode_bitmap);
    207 			if (retval)
    208 				goto cleanup;
    209 			cnt = fs->blocksize << 3;
    210 			if (cnt > ino_cnt)
    211 				cnt = ino_cnt;
    212 			retval = ext2fs_set_inode_bitmap_range(fs->inode_map,
    213 					       ino_itr, cnt, inode_bitmap);
    214 			if (retval)
    215 				goto cleanup;
    216 			ino_itr += fs->blocksize << 3;
    217 			ino_cnt -= fs->blocksize << 3;
    218 			inode_nbytes -= fs->blocksize;
    219 		}
    220 		blk = (fs->image_header->offset_blockmap /
    221 		       fs->blocksize);
    222 		blk_cnt = EXT2_BLOCKS_PER_GROUP(fs->super) *
    223 			fs->group_desc_count;
    224 		while (block_nbytes > 0) {
    225 			retval = io_channel_read_blk(fs->image_io, blk++,
    226 						     1, block_bitmap);
    227 			if (retval)
    228 				goto cleanup;
    229 			cnt = fs->blocksize << 3;
    230 			if (cnt > blk_cnt)
    231 				cnt = blk_cnt;
    232 			retval = ext2fs_set_block_bitmap_range(fs->block_map,
    233 				       blk_itr, cnt, block_bitmap);
    234 			if (retval)
    235 				goto cleanup;
    236 			blk_itr += fs->blocksize << 3;
    237 			blk_cnt -= fs->blocksize << 3;
    238 			block_nbytes -= fs->blocksize;
    239 		}
    240 		goto success_cleanup;
    241 	}
    242 
    243 	for (i = 0; i < fs->group_desc_count; i++) {
    244 		if (block_bitmap) {
    245 			blk = fs->group_desc[i].bg_block_bitmap;
    246 			if (csum_flag && fs->group_desc[i].bg_flags &
    247 			    EXT2_BG_BLOCK_UNINIT &&
    248 			    ext2fs_group_desc_csum_verify(fs, i))
    249 				blk = 0;
    250 			if (blk) {
    251 				retval = io_channel_read_blk(fs->io, blk,
    252 					     -block_nbytes, block_bitmap);
    253 				if (retval) {
    254 					retval = EXT2_ET_BLOCK_BITMAP_READ;
    255 					goto cleanup;
    256 				}
    257 			} else
    258 				memset(block_bitmap, 0, block_nbytes);
    259 			cnt = block_nbytes << 3;
    260 			retval = ext2fs_set_block_bitmap_range(fs->block_map,
    261 					       blk_itr, cnt, block_bitmap);
    262 			if (retval)
    263 				goto cleanup;
    264 			blk_itr += block_nbytes << 3;
    265 		}
    266 		if (inode_bitmap) {
    267 			blk = fs->group_desc[i].bg_inode_bitmap;
    268 			if (csum_flag && fs->group_desc[i].bg_flags &
    269 			    EXT2_BG_INODE_UNINIT &&
    270 			    ext2fs_group_desc_csum_verify(fs, i))
    271 				blk = 0;
    272 			if (blk) {
    273 				retval = io_channel_read_blk(fs->io, blk,
    274 					     -inode_nbytes, inode_bitmap);
    275 				if (retval) {
    276 					retval = EXT2_ET_INODE_BITMAP_READ;
    277 					goto cleanup;
    278 				}
    279 			} else
    280 				memset(inode_bitmap, 0, inode_nbytes);
    281 			cnt = inode_nbytes << 3;
    282 			retval = ext2fs_set_inode_bitmap_range(fs->inode_map,
    283 					       ino_itr, cnt, inode_bitmap);
    284 			if (retval)
    285 				goto cleanup;
    286 			ino_itr += inode_nbytes << 3;
    287 		}
    288 	}
    289 success_cleanup:
    290 	if (inode_bitmap)
    291 		ext2fs_free_mem(&inode_bitmap);
    292 	if (block_bitmap)
    293 		ext2fs_free_mem(&block_bitmap);
    294 	return 0;
    295 
    296 cleanup:
    297 	if (do_block) {
    298 		ext2fs_free_mem(&fs->block_map);
    299 		fs->block_map = 0;
    300 	}
    301 	if (do_inode) {
    302 		ext2fs_free_mem(&fs->inode_map);
    303 		fs->inode_map = 0;
    304 	}
    305 	if (inode_bitmap)
    306 		ext2fs_free_mem(&inode_bitmap);
    307 	if (block_bitmap)
    308 		ext2fs_free_mem(&block_bitmap);
    309 	if (buf)
    310 		ext2fs_free_mem(&buf);
    311 	return retval;
    312 }
    313 
    314 errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs)
    315 {
    316 	return read_bitmaps(fs, 1, 0);
    317 }
    318 
    319 errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
    320 {
    321 	return read_bitmaps(fs, 0, 1);
    322 }
    323 
    324 errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
    325 {
    326 	return write_bitmaps(fs, 1, 0);
    327 }
    328 
    329 errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
    330 {
    331 	return write_bitmaps(fs, 0, 1);
    332 }
    333 
    334 errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
    335 {
    336 	if (fs->inode_map && fs->block_map)
    337 		return 0;
    338 
    339 	return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
    340 }
    341 
    342 errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
    343 {
    344 	int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs);
    345 	int do_block = fs->block_map && ext2fs_test_bb_dirty(fs);
    346 
    347 	if (!do_inode && !do_block)
    348 		return 0;
    349 
    350 	return write_bitmaps(fs, do_inode, do_block);
    351 }
    352