]>
Commit | Line | Data |
---|---|---|
72ed1264 TT |
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 | |
efc6f628 | 8 | * functions in this library. So sue me. |
72ed1264 TT |
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 | ||
72ed1264 | 33 | #include "ext2_fs.h" |
72ed1264 TT |
34 | #include "ext2fs.h" |
35 | ||
fff45483 TT |
36 | #ifndef HAVE_TYPE_SSIZE_T |
37 | typedef int ssize_t; | |
38 | #endif | |
39 | ||
72ed1264 TT |
40 | /* |
41 | * This function returns 1 if the specified block is all zeros | |
42 | */ | |
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 | ||
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; | |
efc6f628 | 72 | |
72ed1264 TT |
73 | for (group = 0; group < fs->group_desc_count; group++) { |
74 | blk = fs->group_desc[(unsigned)group].bg_inode_table; | |
f93625b2 BB |
75 | if (!blk) { |
76 | retval = EXT2_ET_MISSING_INODE_TABLE; | |
77 | goto errout; | |
78 | } | |
72ed1264 TT |
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) { | |
b94bd81a | 110 | retval = errno; |
72ed1264 TT |
111 | goto errout; |
112 | } | |
54434927 | 113 | if (actual != (ssize_t) (fs->blocksize * d)) { |
72ed1264 TT |
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 | */ | |
efc6f628 | 134 | errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, |
54434927 | 135 | int flags EXT2FS_ATTR((unused))) |
72ed1264 | 136 | { |
b94bd81a | 137 | unsigned int group, c, left; |
72ed1264 TT |
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; | |
efc6f628 | 146 | |
72ed1264 TT |
147 | for (group = 0; group < fs->group_desc_count; group++) { |
148 | blk = fs->group_desc[(unsigned)group].bg_inode_table; | |
b94bd81a TT |
149 | if (!blk) { |
150 | retval = EXT2_ET_MISSING_INODE_TABLE; | |
151 | goto errout; | |
152 | } | |
72ed1264 TT |
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) { | |
b94bd81a | 160 | retval = errno; |
72ed1264 TT |
161 | goto errout; |
162 | } | |
54434927 | 163 | if (actual != (ssize_t) (fs->blocksize * c)) { |
72ed1264 TT |
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; | |
efc6f628 | 170 | |
72ed1264 TT |
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 | */ | |
efc6f628 | 185 | errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, |
54434927 | 186 | int flags EXT2FS_ATTR((unused))) |
72ed1264 | 187 | { |
72ed1264 | 188 | char *buf, *cp; |
72ed1264 TT |
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) { | |
b94bd81a | 203 | retval = errno; |
72ed1264 TT |
204 | goto errout; |
205 | } | |
54434927 | 206 | if (actual != (ssize_t) fs->blocksize) { |
72ed1264 TT |
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) { | |
b94bd81a | 217 | retval = errno; |
72ed1264 TT |
218 | goto errout; |
219 | } | |
54434927 | 220 | if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) { |
72ed1264 TT |
221 | retval = EXT2_ET_SHORT_WRITE; |
222 | goto errout; | |
223 | } | |
efc6f628 | 224 | |
72ed1264 TT |
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 | */ | |
efc6f628 | 235 | errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, |
54434927 | 236 | int flags EXT2FS_ATTR((unused))) |
72ed1264 | 237 | { |
b94bd81a | 238 | char *buf; |
72ed1264 TT |
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) { | |
b94bd81a | 252 | retval = errno; |
72ed1264 TT |
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 | */ | |
278 | errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags) | |
279 | { | |
f1f115a7 TT |
280 | ext2fs_generic_bitmap bmap; |
281 | errcode_t err, retval; | |
282 | ssize_t actual; | |
283 | __u32 itr, cnt, size; | |
284 | int c, total_size; | |
285 | char buf[1024]; | |
72ed1264 TT |
286 | |
287 | if (flags & IMAGER_FLAG_INODEMAP) { | |
288 | if (!fs->inode_map) { | |
289 | retval = ext2fs_read_inode_bitmap(fs); | |
290 | if (retval) | |
291 | return retval; | |
292 | } | |
f1f115a7 TT |
293 | bmap = fs->inode_map; |
294 | err = EXT2_ET_MAGIC_INODE_BITMAP; | |
295 | itr = 1; | |
296 | cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; | |
a78926ef | 297 | size = (EXT2_INODES_PER_GROUP(fs->super) / 8); |
72ed1264 TT |
298 | } else { |
299 | if (!fs->block_map) { | |
300 | retval = ext2fs_read_block_bitmap(fs); | |
301 | if (retval) | |
302 | return retval; | |
303 | } | |
f1f115a7 TT |
304 | bmap = fs->block_map; |
305 | err = EXT2_ET_MAGIC_BLOCK_BITMAP; | |
306 | itr = fs->super->s_first_data_block; | |
307 | cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count; | |
72ed1264 TT |
308 | size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; |
309 | } | |
f1f115a7 TT |
310 | total_size = size * fs->group_desc_count; |
311 | ||
312 | while (cnt > 0) { | |
313 | size = sizeof(buf); | |
314 | if (size > (cnt >> 3)) | |
315 | size = (cnt >> 3); | |
316 | ||
efc6f628 | 317 | retval = ext2fs_get_generic_bitmap_range(bmap, |
f1f115a7 TT |
318 | err, itr, size << 3, buf); |
319 | if (retval) | |
320 | return retval; | |
321 | ||
322 | actual = write(fd, buf, size); | |
323 | if (actual == -1) | |
324 | return errno; | |
325 | if (actual != (int) size) | |
326 | return EXT2_ET_SHORT_READ; | |
efc6f628 | 327 | |
f1f115a7 TT |
328 | itr += size << 3; |
329 | cnt -= size << 3; | |
72ed1264 | 330 | } |
f1f115a7 TT |
331 | |
332 | size = total_size % fs->blocksize; | |
333 | memset(buf, 0, sizeof(buf)); | |
72ed1264 TT |
334 | if (size) { |
335 | size = fs->blocksize - size; | |
336 | while (size) { | |
337 | c = size; | |
f1f115a7 TT |
338 | if (c > (int) sizeof(buf)) |
339 | c = sizeof(buf); | |
340 | actual = write(fd, buf, c); | |
341 | if (actual == -1) | |
342 | return errno; | |
343 | if (actual != c) | |
344 | return EXT2_ET_SHORT_WRITE; | |
72ed1264 TT |
345 | size -= c; |
346 | } | |
347 | } | |
f1f115a7 | 348 | return 0; |
72ed1264 TT |
349 | } |
350 | ||
351 | ||
352 | /* | |
353 | * Read the block/inode bitmaps. | |
354 | */ | |
355 | errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags) | |
356 | { | |
f1f115a7 TT |
357 | ext2fs_generic_bitmap bmap; |
358 | errcode_t err, retval; | |
359 | __u32 itr, cnt; | |
360 | char buf[1024]; | |
361 | unsigned int size; | |
362 | ssize_t actual; | |
72ed1264 TT |
363 | |
364 | if (flags & IMAGER_FLAG_INODEMAP) { | |
365 | if (!fs->inode_map) { | |
366 | retval = ext2fs_read_inode_bitmap(fs); | |
367 | if (retval) | |
368 | return retval; | |
369 | } | |
f1f115a7 TT |
370 | bmap = fs->inode_map; |
371 | err = EXT2_ET_MAGIC_INODE_BITMAP; | |
372 | itr = 1; | |
373 | cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; | |
a78926ef | 374 | size = (EXT2_INODES_PER_GROUP(fs->super) / 8); |
72ed1264 TT |
375 | } else { |
376 | if (!fs->block_map) { | |
377 | retval = ext2fs_read_block_bitmap(fs); | |
378 | if (retval) | |
379 | return retval; | |
380 | } | |
f1f115a7 TT |
381 | bmap = fs->block_map; |
382 | err = EXT2_ET_MAGIC_BLOCK_BITMAP; | |
383 | itr = fs->super->s_first_data_block; | |
384 | cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count; | |
72ed1264 TT |
385 | size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; |
386 | } | |
387 | ||
f1f115a7 TT |
388 | while (cnt > 0) { |
389 | size = sizeof(buf); | |
390 | if (size > (cnt >> 3)) | |
391 | size = (cnt >> 3); | |
72ed1264 | 392 | |
f1f115a7 TT |
393 | actual = read(fd, buf, size); |
394 | if (actual == -1) | |
395 | return errno; | |
396 | if (actual != (int) size) | |
397 | return EXT2_ET_SHORT_READ; | |
398 | ||
efc6f628 | 399 | retval = ext2fs_set_generic_bitmap_range(bmap, |
f1f115a7 TT |
400 | err, itr, size << 3, buf); |
401 | if (retval) | |
402 | return retval; | |
403 | ||
404 | itr += size << 3; | |
405 | cnt -= size << 3; | |
72ed1264 | 406 | } |
f1f115a7 | 407 | return 0; |
72ed1264 | 408 | } |