imager.c revision f93625b292e69e03755fd63cf3fa6f2cce14a344
1/*
2 * image.c --- writes out the critical parts of the filesystem as a
3 * 	flat file.
4 *
5 * Copyright (C) 2000 Theodore Ts'o.
6 *
7 * Note: this uses the POSIX IO interfaces, unlike most of the other
8 * functions in this library.  So sue me.
9 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Public
12 * License.
13 * %End-Header%
14 */
15
16#include <stdio.h>
17#include <string.h>
18#if HAVE_UNISTD_H
19#include <unistd.h>
20#endif
21#if HAVE_ERRNO_H
22#include <errno.h>
23#endif
24#include <fcntl.h>
25#include <time.h>
26#if HAVE_SYS_STAT_H
27#include <sys/stat.h>
28#endif
29#if HAVE_SYS_TYPES_H
30#include <sys/types.h>
31#endif
32
33#include "ext2_fs.h"
34#include "ext2fs.h"
35
36#ifndef HAVE_TYPE_SSIZE_T
37typedef int ssize_t;
38#endif
39
40/*
41 * This function returns 1 if the specified block is all zeros
42 */
43static int check_zero_block(char *buf, int blocksize)
44{
45	char	*cp = buf;
46	int	left = blocksize;
47
48	while (left > 0) {
49		if (*cp++)
50			return 0;
51		left--;
52	}
53	return 1;
54}
55
56/*
57 * Write the inode table out as a single block.
58 */
59#define BUF_BLOCKS	32
60
61errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
62{
63	unsigned int	group, left, c, d;
64	char		*buf, *cp;
65	blk_t		blk;
66	ssize_t		actual;
67	errcode_t	retval;
68
69	buf = malloc(fs->blocksize * BUF_BLOCKS);
70	if (!buf)
71		return ENOMEM;
72
73	for (group = 0; group < fs->group_desc_count; group++) {
74		blk = fs->group_desc[(unsigned)group].bg_inode_table;
75		if (!blk) {
76			retval = EXT2_ET_MISSING_INODE_TABLE;
77			goto errout;
78		}
79		left = fs->inode_blocks_per_group;
80		while (left) {
81			c = BUF_BLOCKS;
82			if (c > left)
83				c = left;
84			retval = io_channel_read_blk(fs->io, blk, c, buf);
85			if (retval)
86				goto errout;
87			cp = buf;
88			while (c) {
89				if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
90					d = c;
91					goto skip_sparse;
92				}
93				/* Skip zero blocks */
94				if (check_zero_block(cp, fs->blocksize)) {
95					c--;
96					blk++;
97					left--;
98					cp += fs->blocksize;
99					lseek(fd, fs->blocksize, SEEK_CUR);
100					continue;
101				}
102				/* Find non-zero blocks */
103				for (d=1; d < c; d++) {
104					if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
105						break;
106				}
107			skip_sparse:
108				actual = write(fd, cp, fs->blocksize * d);
109				if (actual == -1) {
110					retval = errno;
111					goto errout;
112				}
113				if (actual != (ssize_t) (fs->blocksize * d)) {
114					retval = EXT2_ET_SHORT_WRITE;
115					goto errout;
116				}
117				blk += d;
118				left -= d;
119				cp += fs->blocksize * d;
120				c -= d;
121			}
122		}
123	}
124	retval = 0;
125
126errout:
127	free(buf);
128	return retval;
129}
130
131/*
132 * Read in the inode table and stuff it into place
133 */
134errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
135				  int flags EXT2FS_ATTR((unused)))
136{
137	unsigned int	group, c, left;
138	char		*buf;
139	blk_t		blk;
140	ssize_t		actual;
141	errcode_t	retval;
142
143	buf = malloc(fs->blocksize * BUF_BLOCKS);
144	if (!buf)
145		return ENOMEM;
146
147	for (group = 0; group < fs->group_desc_count; group++) {
148		blk = fs->group_desc[(unsigned)group].bg_inode_table;
149		if (!blk) {
150			retval = EXT2_ET_MISSING_INODE_TABLE;
151			goto errout;
152		}
153		left = fs->inode_blocks_per_group;
154		while (left) {
155			c = BUF_BLOCKS;
156			if (c > left)
157				c = left;
158			actual = read(fd, buf, fs->blocksize * c);
159			if (actual == -1) {
160				retval = errno;
161				goto errout;
162			}
163			if (actual != (ssize_t) (fs->blocksize * c)) {
164				retval = EXT2_ET_SHORT_READ;
165				goto errout;
166			}
167			retval = io_channel_write_blk(fs->io, blk, c, buf);
168			if (retval)
169				goto errout;
170
171			blk += c;
172			left -= c;
173		}
174	}
175	retval = ext2fs_flush_icache(fs);
176
177errout:
178	free(buf);
179	return retval;
180}
181
182/*
183 * Write out superblock and group descriptors
184 */
185errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
186				   int flags EXT2FS_ATTR((unused)))
187{
188	char		*buf, *cp;
189	ssize_t		actual;
190	errcode_t	retval;
191
192	buf = malloc(fs->blocksize);
193	if (!buf)
194		return ENOMEM;
195
196	/*
197	 * Write out the superblock
198	 */
199	memset(buf, 0, fs->blocksize);
200	memcpy(buf, fs->super, SUPERBLOCK_SIZE);
201	actual = write(fd, buf, fs->blocksize);
202	if (actual == -1) {
203		retval = errno;
204		goto errout;
205	}
206	if (actual != (ssize_t) fs->blocksize) {
207		retval = EXT2_ET_SHORT_WRITE;
208		goto errout;
209	}
210
211	/*
212	 * Now write out the block group descriptors
213	 */
214	cp = (char *) fs->group_desc;
215	actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
216	if (actual == -1) {
217		retval = errno;
218		goto errout;
219	}
220	if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
221		retval = EXT2_ET_SHORT_WRITE;
222		goto errout;
223	}
224
225	retval = 0;
226
227errout:
228	free(buf);
229	return retval;
230}
231
232/*
233 * Read the superblock and group descriptors and overwrite them.
234 */
235errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
236				  int flags EXT2FS_ATTR((unused)))
237{
238	char		*buf;
239	ssize_t		actual, size;
240	errcode_t	retval;
241
242	size = fs->blocksize * (fs->group_desc_count + 1);
243	buf = malloc(size);
244	if (!buf)
245		return ENOMEM;
246
247	/*
248	 * Read it all in.
249	 */
250	actual = read(fd, buf, size);
251	if (actual == -1) {
252		retval = errno;
253		goto errout;
254	}
255	if (actual != size) {
256		retval = EXT2_ET_SHORT_READ;
257		goto errout;
258	}
259
260	/*
261	 * Now copy in the superblock and group descriptors
262	 */
263	memcpy(fs->super, buf, SUPERBLOCK_SIZE);
264
265	memcpy(fs->group_desc, buf + fs->blocksize,
266	       fs->blocksize * fs->group_desc_count);
267
268	retval = 0;
269
270errout:
271	free(buf);
272	return retval;
273}
274
275/*
276 * Write the block/inode bitmaps.
277 */
278errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
279{
280	char		*ptr;
281	int		c, size;
282	char		zero_buf[1024];
283	ssize_t		actual;
284	errcode_t	retval;
285
286	if (flags & IMAGER_FLAG_INODEMAP) {
287		if (!fs->inode_map) {
288			retval = ext2fs_read_inode_bitmap(fs);
289			if (retval)
290				return retval;
291		}
292		ptr = fs->inode_map->bitmap;
293		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
294	} else {
295		if (!fs->block_map) {
296			retval = ext2fs_read_block_bitmap(fs);
297			if (retval)
298				return retval;
299		}
300		ptr = fs->block_map->bitmap;
301		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
302	}
303	size = size * fs->group_desc_count;
304
305	actual = write(fd, ptr, size);
306	if (actual == -1) {
307		retval = errno;
308		goto errout;
309	}
310	if (actual != size) {
311		retval = EXT2_ET_SHORT_WRITE;
312		goto errout;
313	}
314	size = size % fs->blocksize;
315	memset(zero_buf, 0, sizeof(zero_buf));
316	if (size) {
317		size = fs->blocksize - size;
318		while (size) {
319			c = size;
320			if (c > (int) sizeof(zero_buf))
321				c = sizeof(zero_buf);
322			actual = write(fd, zero_buf, c);
323			if (actual == -1) {
324				retval = errno;
325				goto errout;
326			}
327			if (actual != c) {
328				retval = EXT2_ET_SHORT_WRITE;
329				goto errout;
330			}
331			size -= c;
332		}
333	}
334	retval = 0;
335errout:
336	return (retval);
337}
338
339
340/*
341 * Read the block/inode bitmaps.
342 */
343errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
344{
345	char		*ptr, *buf = 0;
346	int		size;
347	ssize_t		actual;
348	errcode_t	retval;
349
350	if (flags & IMAGER_FLAG_INODEMAP) {
351		if (!fs->inode_map) {
352			retval = ext2fs_read_inode_bitmap(fs);
353			if (retval)
354				return retval;
355		}
356		ptr = fs->inode_map->bitmap;
357		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
358	} else {
359		if (!fs->block_map) {
360			retval = ext2fs_read_block_bitmap(fs);
361			if (retval)
362				return retval;
363		}
364		ptr = fs->block_map->bitmap;
365		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
366	}
367	size = size * fs->group_desc_count;
368
369	buf = malloc(size);
370	if (!buf)
371		return ENOMEM;
372
373	actual = read(fd, buf, size);
374	if (actual == -1) {
375		retval = errno;
376		goto errout;
377	}
378	if (actual != size) {
379		retval = EXT2_ET_SHORT_WRITE;
380		goto errout;
381	}
382	memcpy(ptr, buf, size);
383
384	retval = 0;
385errout:
386	if (buf)
387		free(buf);
388	return (retval);
389}
390