imager.c revision fff45483ede7fe38a31b3364a9c07e2418776dee
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			return EXT2_ET_MISSING_INODE_TABLE;
77		left = fs->inode_blocks_per_group;
78		while (left) {
79			c = BUF_BLOCKS;
80			if (c > left)
81				c = left;
82			retval = io_channel_read_blk(fs->io, blk, c, buf);
83			if (retval)
84				goto errout;
85			cp = buf;
86			while (c) {
87				if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
88					d = c;
89					goto skip_sparse;
90				}
91				/* Skip zero blocks */
92				if (check_zero_block(cp, fs->blocksize)) {
93					c--;
94					blk++;
95					left--;
96					cp += fs->blocksize;
97					lseek(fd, fs->blocksize, SEEK_CUR);
98					continue;
99				}
100				/* Find non-zero blocks */
101				for (d=1; d < c; d++) {
102					if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
103						break;
104				}
105			skip_sparse:
106				actual = write(fd, cp, fs->blocksize * d);
107				if (actual == -1) {
108					retval = errno;
109					goto errout;
110				}
111				if (actual != fs->blocksize * d) {
112					retval = EXT2_ET_SHORT_WRITE;
113					goto errout;
114				}
115				blk += d;
116				left -= d;
117				cp += fs->blocksize * d;
118				c -= d;
119			}
120		}
121	}
122	retval = 0;
123
124errout:
125	free(buf);
126	return retval;
127}
128
129/*
130 * Read in the inode table and stuff it into place
131 */
132errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags)
133{
134	unsigned int	group, c, left;
135	char		*buf;
136	blk_t		blk;
137	ssize_t		actual;
138	errcode_t	retval;
139
140	buf = malloc(fs->blocksize * BUF_BLOCKS);
141	if (!buf)
142		return ENOMEM;
143
144	for (group = 0; group < fs->group_desc_count; group++) {
145		blk = fs->group_desc[(unsigned)group].bg_inode_table;
146		if (!blk) {
147			retval = EXT2_ET_MISSING_INODE_TABLE;
148			goto errout;
149		}
150		left = fs->inode_blocks_per_group;
151		while (left) {
152			c = BUF_BLOCKS;
153			if (c > left)
154				c = left;
155			actual = read(fd, buf, fs->blocksize * c);
156			if (actual == -1) {
157				retval = errno;
158				goto errout;
159			}
160			if (actual != fs->blocksize * c) {
161				retval = EXT2_ET_SHORT_READ;
162				goto errout;
163			}
164			retval = io_channel_write_blk(fs->io, blk, c, buf);
165			if (retval)
166				goto errout;
167
168			blk += c;
169			left -= c;
170		}
171	}
172	retval = ext2fs_flush_icache(fs);
173
174errout:
175	free(buf);
176	return retval;
177}
178
179/*
180 * Write out superblock and group descriptors
181 */
182errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags)
183{
184	char		*buf, *cp;
185	ssize_t		actual;
186	errcode_t	retval;
187
188	buf = malloc(fs->blocksize);
189	if (!buf)
190		return ENOMEM;
191
192	/*
193	 * Write out the superblock
194	 */
195	memset(buf, 0, fs->blocksize);
196	memcpy(buf, fs->super, SUPERBLOCK_SIZE);
197	actual = write(fd, buf, fs->blocksize);
198	if (actual == -1) {
199		retval = errno;
200		goto errout;
201	}
202	if (actual != fs->blocksize) {
203		retval = EXT2_ET_SHORT_WRITE;
204		goto errout;
205	}
206
207	/*
208	 * Now write out the block group descriptors
209	 */
210	cp = (char *) fs->group_desc;
211	actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
212	if (actual == -1) {
213		retval = errno;
214		goto errout;
215	}
216	if (actual != fs->blocksize * fs->desc_blocks) {
217		retval = EXT2_ET_SHORT_WRITE;
218		goto errout;
219	}
220
221	retval = 0;
222
223errout:
224	free(buf);
225	return retval;
226}
227
228/*
229 * Read the superblock and group descriptors and overwrite them.
230 */
231errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags)
232{
233	char		*buf;
234	ssize_t		actual, size;
235	errcode_t	retval;
236
237	size = fs->blocksize * (fs->group_desc_count + 1);
238	buf = malloc(size);
239	if (!buf)
240		return ENOMEM;
241
242	/*
243	 * Read it all in.
244	 */
245	actual = read(fd, buf, size);
246	if (actual == -1) {
247		retval = errno;
248		goto errout;
249	}
250	if (actual != size) {
251		retval = EXT2_ET_SHORT_READ;
252		goto errout;
253	}
254
255	/*
256	 * Now copy in the superblock and group descriptors
257	 */
258	memcpy(fs->super, buf, SUPERBLOCK_SIZE);
259
260	memcpy(fs->group_desc, buf + fs->blocksize,
261	       fs->blocksize * fs->group_desc_count);
262
263	retval = 0;
264
265errout:
266	free(buf);
267	return retval;
268}
269
270/*
271 * Write the block/inode bitmaps.
272 */
273errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
274{
275	char		*ptr;
276	int		c, size;
277	char		zero_buf[1024];
278	ssize_t		actual;
279	errcode_t	retval;
280
281	if (flags & IMAGER_FLAG_INODEMAP) {
282		if (!fs->inode_map) {
283			retval = ext2fs_read_inode_bitmap(fs);
284			if (retval)
285				return retval;
286		}
287		ptr = fs->inode_map->bitmap;
288		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
289	} else {
290		if (!fs->block_map) {
291			retval = ext2fs_read_block_bitmap(fs);
292			if (retval)
293				return retval;
294		}
295		ptr = fs->block_map->bitmap;
296		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
297	}
298	size = size * fs->group_desc_count;
299
300	actual = write(fd, ptr, size);
301	if (actual == -1) {
302		retval = errno;
303		goto errout;
304	}
305	if (actual != size) {
306		retval = EXT2_ET_SHORT_WRITE;
307		goto errout;
308	}
309	size = size % fs->blocksize;
310	memset(zero_buf, 0, sizeof(zero_buf));
311	if (size) {
312		size = fs->blocksize - size;
313		while (size) {
314			c = size;
315			if (c > sizeof(zero_buf))
316				c = sizeof(zero_buf);
317			actual = write(fd, zero_buf, c);
318			if (actual == -1) {
319				retval = errno;
320				goto errout;
321			}
322			if (actual != c) {
323				retval = EXT2_ET_SHORT_WRITE;
324				goto errout;
325			}
326			size -= c;
327		}
328	}
329	retval = 0;
330errout:
331	return (retval);
332}
333
334
335/*
336 * Read the block/inode bitmaps.
337 */
338errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
339{
340	char		*ptr, *buf = 0;
341	int		size;
342	ssize_t		actual;
343	errcode_t	retval;
344
345	if (flags & IMAGER_FLAG_INODEMAP) {
346		if (!fs->inode_map) {
347			retval = ext2fs_read_inode_bitmap(fs);
348			if (retval)
349				return retval;
350		}
351		ptr = fs->inode_map->bitmap;
352		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
353	} else {
354		if (!fs->block_map) {
355			retval = ext2fs_read_block_bitmap(fs);
356			if (retval)
357				return retval;
358		}
359		ptr = fs->block_map->bitmap;
360		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
361	}
362	size = size * fs->group_desc_count;
363
364	buf = malloc(size);
365	if (!buf)
366		return ENOMEM;
367
368	actual = read(fd, buf, size);
369	if (actual == -1) {
370		retval = errno;
371		goto errout;
372	}
373	if (actual != size) {
374		retval = EXT2_ET_SHORT_WRITE;
375		goto errout;
376	}
377	memcpy(ptr, buf, size);
378
379	retval = 0;
380errout:
381	if (buf)
382		free(buf);
383	return (retval);
384}
385