blob: 79b88ee6b7c8151a9a71c3fb44315f5016e7ca3b [file] [log] [blame]
Theodore Ts'o72ed1262000-11-12 19:32:20 +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#if EXT2_FLAT_INCLUDES
34#include "ext2_fs.h"
35#else
36#include <linux/ext2_fs.h>
37#endif
38
39#include "ext2fs.h"
40
41/*
42 * This function returns 1 if the specified block is all zeros
43 */
44static int check_zero_block(char *buf, int blocksize)
45{
46 char *cp = buf;
47 int left = blocksize;
48
49 while (left > 0) {
50 if (*cp++)
51 return 0;
52 left--;
53 }
54 return 1;
55}
56
57/*
58 * Write the inode table out as a single block.
59 */
60#define BUF_BLOCKS 32
61
62errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
63{
64 unsigned int group, left, c, d;
65 char *buf, *cp;
66 blk_t blk;
67 ssize_t actual;
68 errcode_t retval;
69
70 buf = malloc(fs->blocksize * BUF_BLOCKS);
71 if (!buf)
72 return ENOMEM;
73
74 for (group = 0; group < fs->group_desc_count; group++) {
75 blk = fs->group_desc[(unsigned)group].bg_inode_table;
76 if (!blk)
77 return EXT2_ET_MISSING_INODE_TABLE;
78 left = fs->inode_blocks_per_group;
79 while (left) {
80 c = BUF_BLOCKS;
81 if (c > left)
82 c = left;
83 retval = io_channel_read_blk(fs->io, blk, c, buf);
84 if (retval)
85 goto errout;
86 cp = buf;
87 while (c) {
88 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
89 d = c;
90 goto skip_sparse;
91 }
92 /* Skip zero blocks */
93 if (check_zero_block(cp, fs->blocksize)) {
94 c--;
95 blk++;
96 left--;
97 cp += fs->blocksize;
98 lseek(fd, fs->blocksize, SEEK_CUR);
99 continue;
100 }
101 /* Find non-zero blocks */
102 for (d=1; d < c; d++) {
103 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
104 break;
105 }
106 skip_sparse:
107 actual = write(fd, cp, fs->blocksize * d);
108 if (actual == -1) {
109 errno = retval;
110 goto errout;
111 }
112 if (actual != fs->blocksize * d) {
113 retval = EXT2_ET_SHORT_WRITE;
114 goto errout;
115 }
116 blk += d;
117 left -= d;
118 cp += fs->blocksize * d;
119 c -= d;
120 }
121 }
122 }
123 retval = 0;
124
125errout:
126 free(buf);
127 return retval;
128}
129
130/*
131 * Read in the inode table and stuff it into place
132 */
133errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags)
134{
135 unsigned int group, i, 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 return EXT2_ET_MISSING_INODE_TABLE;
149 left = fs->inode_blocks_per_group;
150 while (left) {
151 c = BUF_BLOCKS;
152 if (c > left)
153 c = left;
154 actual = read(fd, buf, fs->blocksize * c);
155 if (actual == -1) {
156 errno = retval;
157 goto errout;
158 }
159 if (actual != fs->blocksize * c) {
160 retval = EXT2_ET_SHORT_READ;
161 goto errout;
162 }
163 retval = io_channel_write_blk(fs->io, blk, c, buf);
164 if (retval)
165 goto errout;
166
167 blk += c;
168 left -= c;
169 }
170 }
171 retval = ext2fs_flush_icache(fs);
172
173errout:
174 free(buf);
175 return retval;
176}
177
178/*
179 * Write out superblock and group descriptors
180 */
181errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags)
182{
183 unsigned int i;
184 char *buf, *cp;
185 blk_t blk;
186 ssize_t actual;
187 errcode_t retval;
188
189 buf = malloc(fs->blocksize);
190 if (!buf)
191 return ENOMEM;
192
193 /*
194 * Write out the superblock
195 */
196 memset(buf, 0, fs->blocksize);
197 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
198 actual = write(fd, buf, fs->blocksize);
199 if (actual == -1) {
200 errno = retval;
201 goto errout;
202 }
203 if (actual != fs->blocksize) {
204 retval = EXT2_ET_SHORT_WRITE;
205 goto errout;
206 }
207
208 /*
209 * Now write out the block group descriptors
210 */
211 cp = (char *) fs->group_desc;
212 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
213 if (actual == -1) {
214 errno = retval;
215 goto errout;
216 }
217 if (actual != fs->blocksize * fs->desc_blocks) {
218 retval = EXT2_ET_SHORT_WRITE;
219 goto errout;
220 }
221
222 retval = 0;
223
224errout:
225 free(buf);
226 return retval;
227}
228
229/*
230 * Read the superblock and group descriptors and overwrite them.
231 */
232errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags)
233{
234 unsigned int i;
235 char *buf, *cp;
236 blk_t blk;
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 errno = retval;
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)+7) / 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
302 actual = write(fd, ptr, size);
303 if (actual == -1) {
304 errno = retval;
305 goto errout;
306 }
307 if (actual != size) {
308 retval = EXT2_ET_SHORT_WRITE;
309 goto errout;
310 }
311 size = size % fs->blocksize;
312 memset(zero_buf, 0, sizeof(zero_buf));
313 if (size) {
314 size = fs->blocksize - size;
315 while (size) {
316 c = size;
317 if (c > sizeof(zero_buf))
318 c = sizeof(zero_buf);
319 actual = write(fd, zero_buf, c);
320 if (actual == -1) {
321 errno = retval;
322 goto errout;
323 }
324 if (actual != c) {
325 retval = EXT2_ET_SHORT_WRITE;
326 goto errout;
327 }
328 size -= c;
329 }
330 }
331 retval = 0;
332errout:
333 return (retval);
334}
335
336
337/*
338 * Read the block/inode bitmaps.
339 */
340errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
341{
342 char *ptr, *buf = 0;
343 int c, size;
344 char zero_buf[1024];
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)+7) / 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
366 buf = malloc(size);
367 if (!buf)
368 return ENOMEM;
369
370 actual = read(fd, buf, size);
371 if (actual == -1) {
372 errno = retval;
373 goto errout;
374 }
375 if (actual != size) {
376 retval = EXT2_ET_SHORT_WRITE;
377 goto errout;
378 }
379 memcpy(ptr, buf, size);
380
381 retval = 0;
382errout:
383 if (buf)
384 free(buf);
385 return (retval);
386}