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