blob: 00eb7172300c52dcc1eda7c5bada92626d999353 [file] [log] [blame]
Mike Frysinger1fd98e02005-05-09 22:10:42 +00001/*
2 * image.c --- writes out the critical parts of the filesystem as a
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00003 * flat file.
Mike Frysinger1fd98e02005-05-09 22:10:42 +00004 *
5 * Copyright (C) 2000 Theodore Ts'o.
6 *
7 * Note: this uses the POSIX IO interfaces, unlike most of the other
Tim Rikerc1ef7bd2006-01-25 00:08:53 +00008 * functions in this library. So sue me.
Mike Frysinger1fd98e02005-05-09 22:10:42 +00009 *
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
Mike Frysingerd5826902005-06-12 00:45:09 +000069 buf = xmalloc(fs->blocksize * BUF_BLOCKS);
Tim Rikerc1ef7bd2006-01-25 00:08:53 +000070
Mike Frysinger1fd98e02005-05-09 22:10:42 +000071 for (group = 0; group < fs->group_desc_count; group++) {
72 blk = fs->group_desc[(unsigned)group].bg_inode_table;
73 if (!blk)
74 return EXT2_ET_MISSING_INODE_TABLE;
75 left = fs->inode_blocks_per_group;
76 while (left) {
77 c = BUF_BLOCKS;
78 if (c > left)
79 c = left;
80 retval = io_channel_read_blk(fs->io, blk, c, buf);
81 if (retval)
82 goto errout;
83 cp = buf;
84 while (c) {
85 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
86 d = c;
87 goto skip_sparse;
88 }
89 /* Skip zero blocks */
90 if (check_zero_block(cp, fs->blocksize)) {
91 c--;
92 blk++;
93 left--;
94 cp += fs->blocksize;
95 lseek(fd, fs->blocksize, SEEK_CUR);
96 continue;
97 }
98 /* Find non-zero blocks */
99 for (d=1; d < c; d++) {
100 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
101 break;
102 }
103 skip_sparse:
104 actual = write(fd, cp, fs->blocksize * d);
105 if (actual == -1) {
106 retval = errno;
107 goto errout;
108 }
109 if (actual != (ssize_t) (fs->blocksize * d)) {
110 retval = EXT2_ET_SHORT_WRITE;
111 goto errout;
112 }
113 blk += d;
114 left -= d;
115 cp += fs->blocksize * d;
116 c -= d;
117 }
118 }
119 }
120 retval = 0;
121
122errout:
123 free(buf);
124 return retval;
125}
126
127/*
128 * Read in the inode table and stuff it into place
129 */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000130errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000131 int flags EXT2FS_ATTR((unused)))
132{
133 unsigned int group, c, left;
134 char *buf;
135 blk_t blk;
136 ssize_t actual;
137 errcode_t retval;
138
Mike Frysingerd5826902005-06-12 00:45:09 +0000139 buf = xmalloc(fs->blocksize * BUF_BLOCKS);
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000140
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000141 for (group = 0; group < fs->group_desc_count; group++) {
142 blk = fs->group_desc[(unsigned)group].bg_inode_table;
143 if (!blk) {
144 retval = EXT2_ET_MISSING_INODE_TABLE;
145 goto errout;
146 }
147 left = fs->inode_blocks_per_group;
148 while (left) {
149 c = BUF_BLOCKS;
150 if (c > left)
151 c = left;
152 actual = read(fd, buf, fs->blocksize * c);
153 if (actual == -1) {
154 retval = errno;
155 goto errout;
156 }
157 if (actual != (ssize_t) (fs->blocksize * c)) {
158 retval = EXT2_ET_SHORT_READ;
159 goto errout;
160 }
161 retval = io_channel_write_blk(fs->io, blk, c, buf);
162 if (retval)
163 goto errout;
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000164
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000165 blk += c;
166 left -= c;
167 }
168 }
169 retval = ext2fs_flush_icache(fs);
170
171errout:
172 free(buf);
173 return retval;
174}
175
176/*
177 * Write out superblock and group descriptors
178 */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000179errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000180 int flags EXT2FS_ATTR((unused)))
181{
182 char *buf, *cp;
183 ssize_t actual;
184 errcode_t retval;
185
Mike Frysingerd5826902005-06-12 00:45:09 +0000186 buf = xmalloc(fs->blocksize);
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000187
188 /*
189 * Write out the superblock
190 */
191 memset(buf, 0, fs->blocksize);
192 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
193 actual = write(fd, buf, fs->blocksize);
194 if (actual == -1) {
195 retval = errno;
196 goto errout;
197 }
198 if (actual != (ssize_t) fs->blocksize) {
199 retval = EXT2_ET_SHORT_WRITE;
200 goto errout;
201 }
202
203 /*
204 * Now write out the block group descriptors
205 */
206 cp = (char *) fs->group_desc;
207 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
208 if (actual == -1) {
209 retval = errno;
210 goto errout;
211 }
212 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
213 retval = EXT2_ET_SHORT_WRITE;
214 goto errout;
215 }
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000216
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000217 retval = 0;
218
219errout:
220 free(buf);
221 return retval;
222}
223
224/*
225 * Read the superblock and group descriptors and overwrite them.
226 */
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000227errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000228 int flags EXT2FS_ATTR((unused)))
229{
230 char *buf;
231 ssize_t actual, size;
232 errcode_t retval;
233
234 size = fs->blocksize * (fs->group_desc_count + 1);
Mike Frysingerd5826902005-06-12 00:45:09 +0000235 buf = xmalloc(size);
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000236
237 /*
238 * Read it all in.
239 */
240 actual = read(fd, buf, size);
241 if (actual == -1) {
242 retval = errno;
243 goto errout;
244 }
245 if (actual != size) {
246 retval = EXT2_ET_SHORT_READ;
247 goto errout;
248 }
249
250 /*
251 * Now copy in the superblock and group descriptors
252 */
253 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
254
255 memcpy(fs->group_desc, buf + fs->blocksize,
256 fs->blocksize * fs->group_desc_count);
257
258 retval = 0;
259
260errout:
261 free(buf);
262 return retval;
263}
264
265/*
266 * Write the block/inode bitmaps.
267 */
268errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
269{
270 char *ptr;
271 int c, size;
272 char zero_buf[1024];
273 ssize_t actual;
274 errcode_t retval;
275
276 if (flags & IMAGER_FLAG_INODEMAP) {
277 if (!fs->inode_map) {
278 retval = ext2fs_read_inode_bitmap(fs);
279 if (retval)
280 return retval;
281 }
282 ptr = fs->inode_map->bitmap;
283 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
284 } else {
285 if (!fs->block_map) {
286 retval = ext2fs_read_block_bitmap(fs);
287 if (retval)
288 return retval;
289 }
290 ptr = fs->block_map->bitmap;
291 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
292 }
293 size = size * fs->group_desc_count;
294
295 actual = write(fd, ptr, size);
296 if (actual == -1) {
297 retval = errno;
298 goto errout;
299 }
300 if (actual != size) {
301 retval = EXT2_ET_SHORT_WRITE;
302 goto errout;
303 }
304 size = size % fs->blocksize;
305 memset(zero_buf, 0, sizeof(zero_buf));
306 if (size) {
307 size = fs->blocksize - size;
308 while (size) {
309 c = size;
310 if (c > (int) sizeof(zero_buf))
311 c = sizeof(zero_buf);
312 actual = write(fd, zero_buf, c);
313 if (actual == -1) {
314 retval = errno;
315 goto errout;
316 }
317 if (actual != c) {
318 retval = EXT2_ET_SHORT_WRITE;
319 goto errout;
320 }
321 size -= c;
322 }
323 }
324 retval = 0;
325errout:
326 return (retval);
327}
328
329
330/*
331 * Read the block/inode bitmaps.
332 */
333errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
334{
335 char *ptr, *buf = 0;
336 int size;
337 ssize_t actual;
338 errcode_t retval;
339
340 if (flags & IMAGER_FLAG_INODEMAP) {
341 if (!fs->inode_map) {
342 retval = ext2fs_read_inode_bitmap(fs);
343 if (retval)
344 return retval;
345 }
346 ptr = fs->inode_map->bitmap;
347 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
348 } else {
349 if (!fs->block_map) {
350 retval = ext2fs_read_block_bitmap(fs);
351 if (retval)
352 return retval;
353 }
354 ptr = fs->block_map->bitmap;
355 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
356 }
357 size = size * fs->group_desc_count;
358
Mike Frysingerd5826902005-06-12 00:45:09 +0000359 buf = xmalloc(size);
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000360
361 actual = read(fd, buf, size);
362 if (actual == -1) {
363 retval = errno;
364 goto errout;
365 }
366 if (actual != size) {
367 retval = EXT2_ET_SHORT_WRITE;
368 goto errout;
369 }
370 memcpy(ptr, buf, size);
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000371
Mike Frysinger1fd98e02005-05-09 22:10:42 +0000372 retval = 0;
373errout:
374 if (buf)
375 free(buf);
376 return (retval);
377}