blob: 38dc7d80ded086c2d13d3522d9c7d6349870b6e6 [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) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000109 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000110 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{
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000135 unsigned int group, c, left;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000136 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;
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000147 if (!blk) {
148 retval = EXT2_ET_MISSING_INODE_TABLE;
149 goto errout;
150 }
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000151 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) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000158 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000159 goto errout;
160 }
161 if (actual != 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, int flags)
184{
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000185 char *buf, *cp;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000186 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) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000200 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000201 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) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000214 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000215 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{
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000234 char *buf;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000235 ssize_t actual, size;
236 errcode_t retval;
237
238 size = fs->blocksize * (fs->group_desc_count + 1);
239 buf = malloc(size);
240 if (!buf)
241 return ENOMEM;
242
243 /*
244 * Read it all in.
245 */
246 actual = read(fd, buf, size);
247 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000248 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000249 goto errout;
250 }
251 if (actual != size) {
252 retval = EXT2_ET_SHORT_READ;
253 goto errout;
254 }
255
256 /*
257 * Now copy in the superblock and group descriptors
258 */
259 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
260
261 memcpy(fs->group_desc, buf + fs->blocksize,
262 fs->blocksize * fs->group_desc_count);
263
264 retval = 0;
265
266errout:
267 free(buf);
268 return retval;
269}
270
271/*
272 * Write the block/inode bitmaps.
273 */
274errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
275{
276 char *ptr;
277 int c, size;
278 char zero_buf[1024];
279 ssize_t actual;
280 errcode_t retval;
281
282 if (flags & IMAGER_FLAG_INODEMAP) {
283 if (!fs->inode_map) {
284 retval = ext2fs_read_inode_bitmap(fs);
285 if (retval)
286 return retval;
287 }
288 ptr = fs->inode_map->bitmap;
289 size = ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
290 } else {
291 if (!fs->block_map) {
292 retval = ext2fs_read_block_bitmap(fs);
293 if (retval)
294 return retval;
295 }
296 ptr = fs->block_map->bitmap;
297 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
298 }
299
300 actual = write(fd, ptr, size);
301 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000302 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000303 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) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000319 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000320 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;
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000341 int size;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000342 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)+7) / 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
363 buf = malloc(size);
364 if (!buf)
365 return ENOMEM;
366
367 actual = read(fd, buf, size);
368 if (actual == -1) {
Theodore Ts'ob94bd812001-01-12 17:26:05 +0000369 retval = errno;
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000370 goto errout;
371 }
372 if (actual != size) {
373 retval = EXT2_ET_SHORT_WRITE;
374 goto errout;
375 }
376 memcpy(ptr, buf, size);
377
378 retval = 0;
379errout:
380 if (buf)
381 free(buf);
382 return (retval);
383}