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
30static 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
138static 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	}
289success_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
296cleanup:
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
314errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs)
315{
316	return read_bitmaps(fs, 1, 0);
317}
318
319errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
320{
321	return read_bitmaps(fs, 0, 1);
322}
323
324errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
325{
326	return write_bitmaps(fs, 1, 0);
327}
328
329errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
330{
331	return write_bitmaps(fs, 0, 1);
332}
333
334errcode_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
342errcode_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