blob: 596fbbebe002f4d1ee3206d27c722bde8aa77105 [file] [log] [blame]
Mike Frysinger1fd98e02005-05-09 22:10:42 +00001/*
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 != (ssize_t) (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,
133 int flags EXT2FS_ATTR((unused)))
134{
135 unsigned int group, c, left;
136 char *buf;
137 blk_t blk;
138 ssize_t actual;
139 errcode_t retval;
140
141 buf = malloc(fs->blocksize * BUF_BLOCKS);
142 if (!buf)
143 return ENOMEM;
144
145 for (group = 0; group < fs->group_desc_count; group++) {
146 blk = fs->group_desc[(unsigned)group].bg_inode_table;
147 if (!blk) {
148 retval = EXT2_ET_MISSING_INODE_TABLE;
149 goto errout;
150 }
151 left = fs->inode_blocks_per_group;
152 while (left) {
153 c = BUF_BLOCKS;
154 if (c > left)
155 c = left;
156 actual = read(fd, buf, fs->blocksize * c);
157 if (actual == -1) {
158 retval = errno;
159 goto errout;
160 }
161 if (actual != (ssize_t) (fs->blocksize * c)) {
162 retval = EXT2_ET_SHORT_READ;
163 goto errout;
164 }
165 retval = io_channel_write_blk(fs->io, blk, c, buf);
166 if (retval)
167 goto errout;
168
169 blk += c;
170 left -= c;
171 }
172 }
173 retval = ext2fs_flush_icache(fs);
174
175errout:
176 free(buf);
177 return retval;
178}
179
180/*
181 * Write out superblock and group descriptors
182 */
183errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
184 int flags EXT2FS_ATTR((unused)))
185{
186 char *buf, *cp;
187 ssize_t actual;
188 errcode_t retval;
189
190 buf = malloc(fs->blocksize);
191 if (!buf)
192 return ENOMEM;
193
194 /*
195 * Write out the superblock
196 */
197 memset(buf, 0, fs->blocksize);
198 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
199 actual = write(fd, buf, fs->blocksize);
200 if (actual == -1) {
201 retval = errno;
202 goto errout;
203 }
204 if (actual != (ssize_t) fs->blocksize) {
205 retval = EXT2_ET_SHORT_WRITE;
206 goto errout;
207 }
208
209 /*
210 * Now write out the block group descriptors
211 */
212 cp = (char *) fs->group_desc;
213 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
214 if (actual == -1) {
215 retval = errno;
216 goto errout;
217 }
218 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
219 retval = EXT2_ET_SHORT_WRITE;
220 goto errout;
221 }
222
223 retval = 0;
224
225errout:
226 free(buf);
227 return retval;
228}
229
230/*
231 * Read the superblock and group descriptors and overwrite them.
232 */
233errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
234 int flags EXT2FS_ATTR((unused)))
235{
236 char *buf;
237 ssize_t actual, size;
238 errcode_t retval;
239
240 size = fs->blocksize * (fs->group_desc_count + 1);
241 buf = malloc(size);
242 if (!buf)
243 return ENOMEM;
244
245 /*
246 * Read it all in.
247 */
248 actual = read(fd, buf, size);
249 if (actual == -1) {
250 retval = errno;
251 goto errout;
252 }
253 if (actual != size) {
254 retval = EXT2_ET_SHORT_READ;
255 goto errout;
256 }
257
258 /*
259 * Now copy in the superblock and group descriptors
260 */
261 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
262
263 memcpy(fs->group_desc, buf + fs->blocksize,
264 fs->blocksize * fs->group_desc_count);
265
266 retval = 0;
267
268errout:
269 free(buf);
270 return retval;
271}
272
273/*
274 * Write the block/inode bitmaps.
275 */
276errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
277{
278 char *ptr;
279 int c, size;
280 char zero_buf[1024];
281 ssize_t actual;
282 errcode_t retval;
283
284 if (flags & IMAGER_FLAG_INODEMAP) {
285 if (!fs->inode_map) {
286 retval = ext2fs_read_inode_bitmap(fs);
287 if (retval)
288 return retval;
289 }
290 ptr = fs->inode_map->bitmap;
291 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
292 } else {
293 if (!fs->block_map) {
294 retval = ext2fs_read_block_bitmap(fs);
295 if (retval)
296 return retval;
297 }
298 ptr = fs->block_map->bitmap;
299 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
300 }
301 size = size * fs->group_desc_count;
302
303 actual = write(fd, ptr, size);
304 if (actual == -1) {
305 retval = errno;
306 goto errout;
307 }
308 if (actual != size) {
309 retval = EXT2_ET_SHORT_WRITE;
310 goto errout;
311 }
312 size = size % fs->blocksize;
313 memset(zero_buf, 0, sizeof(zero_buf));
314 if (size) {
315 size = fs->blocksize - size;
316 while (size) {
317 c = size;
318 if (c > (int) sizeof(zero_buf))
319 c = sizeof(zero_buf);
320 actual = write(fd, zero_buf, c);
321 if (actual == -1) {
322 retval = errno;
323 goto errout;
324 }
325 if (actual != c) {
326 retval = EXT2_ET_SHORT_WRITE;
327 goto errout;
328 }
329 size -= c;
330 }
331 }
332 retval = 0;
333errout:
334 return (retval);
335}
336
337
338/*
339 * Read the block/inode bitmaps.
340 */
341errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
342{
343 char *ptr, *buf = 0;
344 int size;
345 ssize_t actual;
346 errcode_t retval;
347
348 if (flags & IMAGER_FLAG_INODEMAP) {
349 if (!fs->inode_map) {
350 retval = ext2fs_read_inode_bitmap(fs);
351 if (retval)
352 return retval;
353 }
354 ptr = fs->inode_map->bitmap;
355 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
356 } else {
357 if (!fs->block_map) {
358 retval = ext2fs_read_block_bitmap(fs);
359 if (retval)
360 return retval;
361 }
362 ptr = fs->block_map->bitmap;
363 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
364 }
365 size = size * fs->group_desc_count;
366
367 buf = malloc(size);
368 if (!buf)
369 return ENOMEM;
370
371 actual = read(fd, buf, size);
372 if (actual == -1) {
373 retval = errno;
374 goto errout;
375 }
376 if (actual != size) {
377 retval = EXT2_ET_SHORT_WRITE;
378 goto errout;
379 }
380 memcpy(ptr, buf, size);
381
382 retval = 0;
383errout:
384 if (buf)
385 free(buf);
386 return (retval);
387}