]>
Commit | Line | Data |
---|---|---|
72ed1264 TT |
1 | /* |
2 | * e2image.c --- Program which writes an image file backing up | |
3 | * critical metadata for the filesystem. | |
4 | * | |
a3827953 | 5 | * Copyright 2000, 2001 by Theodore Ts'o. |
72ed1264 TT |
6 | * |
7 | * %Begin-Header% | |
8 | * This file may be redistributed under the terms of the GNU Public | |
9 | * License. | |
10 | * %End-Header% | |
11 | */ | |
12 | ||
6304baf2 TT |
13 | #define _LARGEFILE_SOURCE |
14 | #define _LARGEFILE64_SOURCE | |
15 | ||
72ed1264 TT |
16 | #include <fcntl.h> |
17 | #include <grp.h> | |
18 | #ifdef HAVE_GETOPT_H | |
19 | #include <getopt.h> | |
20 | #else | |
21 | extern char *optarg; | |
22 | extern int optind; | |
23 | #endif | |
24 | #include <pwd.h> | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
28 | #include <time.h> | |
29 | #include <unistd.h> | |
30 | #include <fcntl.h> | |
31 | #include <errno.h> | |
32 | #include <sys/stat.h> | |
33 | #include <sys/types.h> | |
34 | ||
54c637d4 | 35 | #include "ext2fs/ext2_fs.h" |
72ed1264 TT |
36 | #include "ext2fs/ext2fs.h" |
37 | #include "et/com_err.h" | |
38 | #include "uuid/uuid.h" | |
39 | #include "e2p/e2p.h" | |
40 | #include "ext2fs/e2image.h" | |
41 | ||
42 | #include "../version.h" | |
43 | #include "nls-enable.h" | |
44 | ||
3e377db2 | 45 | const char * program_name = "e2image"; |
72ed1264 TT |
46 | char * device_name = NULL; |
47 | ||
48 | static void usage(void) | |
49 | { | |
d851ed39 TT |
50 | fprintf(stderr, _("Usage: %s [-rsI] device image_file\n"), |
51 | program_name); | |
72ed1264 TT |
52 | exit (1); |
53 | } | |
54 | ||
095b459d | 55 | static void write_header(int fd, struct ext2_image_hdr *hdr, int blocksize) |
72ed1264 | 56 | { |
095b459d | 57 | char *header_buf; |
72ed1264 TT |
58 | int actual; |
59 | ||
095b459d TT |
60 | header_buf = malloc(blocksize); |
61 | if (!header_buf) { | |
54434927 | 62 | fputs(_("Couldn't allocate header buffer\n"), stderr); |
095b459d TT |
63 | exit(1); |
64 | } | |
65 | ||
72ed1264 TT |
66 | if (lseek(fd, 0, SEEK_SET) < 0) { |
67 | perror("lseek while writing header"); | |
68 | exit(1); | |
69 | } | |
095b459d | 70 | memset(header_buf, 0, blocksize); |
72ed1264 TT |
71 | |
72 | if (hdr) | |
73 | memcpy(header_buf, hdr, sizeof(struct ext2_image_hdr)); | |
74 | ||
095b459d | 75 | actual = write(fd, header_buf, blocksize); |
72ed1264 TT |
76 | if (actual < 0) { |
77 | perror("write header"); | |
78 | exit(1); | |
79 | } | |
095b459d | 80 | if (actual != blocksize) { |
ddc32a04 | 81 | fprintf(stderr, _("short write (only %d bytes) for " |
72ed1264 TT |
82 | "writing image header"), actual); |
83 | exit(1); | |
84 | } | |
095b459d | 85 | free(header_buf); |
72ed1264 TT |
86 | } |
87 | ||
6304baf2 | 88 | static void write_image_file(ext2_filsys fs, int fd) |
72ed1264 | 89 | { |
6304baf2 TT |
90 | struct ext2_image_hdr hdr; |
91 | struct stat st; | |
92 | errcode_t retval; | |
72ed1264 | 93 | |
095b459d | 94 | write_header(fd, NULL, fs->blocksize); |
72ed1264 | 95 | memset(&hdr, 0, sizeof(struct ext2_image_hdr)); |
6304baf2 | 96 | |
72ed1264 TT |
97 | hdr.offset_super = lseek(fd, 0, SEEK_CUR); |
98 | retval = ext2fs_image_super_write(fs, fd, 0); | |
99 | if (retval) { | |
100 | com_err(program_name, retval, _("while writing superblock")); | |
101 | exit(1); | |
102 | } | |
103 | ||
104 | hdr.offset_inode = lseek(fd, 0, SEEK_CUR); | |
6304baf2 TT |
105 | retval = ext2fs_image_inode_write(fs, fd, |
106 | (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0); | |
72ed1264 TT |
107 | if (retval) { |
108 | com_err(program_name, retval, _("while writing inode table")); | |
109 | exit(1); | |
110 | } | |
111 | ||
112 | hdr.offset_blockmap = lseek(fd, 0, SEEK_CUR); | |
113 | retval = ext2fs_image_bitmap_write(fs, fd, 0); | |
114 | if (retval) { | |
115 | com_err(program_name, retval, _("while writing block bitmap")); | |
116 | exit(1); | |
117 | } | |
118 | ||
119 | hdr.offset_inodemap = lseek(fd, 0, SEEK_CUR); | |
120 | retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP); | |
121 | if (retval) { | |
122 | com_err(program_name, retval, _("while writing inode bitmap")); | |
123 | exit(1); | |
124 | } | |
c5423c5b TT |
125 | |
126 | hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE; | |
127 | strcpy(hdr.magic_descriptor, "Ext2 Image 1.0"); | |
128 | gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname)); | |
095b459d TT |
129 | strncat(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)); |
130 | hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0; | |
131 | hdr.fs_blocksize = fs->blocksize; | |
132 | ||
c5423c5b TT |
133 | if (stat(device_name, &st) == 0) |
134 | hdr.fs_device = st.st_rdev; | |
135 | ||
136 | if (fstat(fd, &st) == 0) { | |
137 | hdr.image_device = st.st_dev; | |
138 | hdr.image_inode = st.st_ino; | |
139 | } | |
140 | memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid)); | |
141 | ||
142 | hdr.image_time = time(0); | |
095b459d | 143 | write_header(fd, &hdr, fs->blocksize); |
6304baf2 TT |
144 | } |
145 | ||
146 | /* | |
147 | * These set of functions are used to write a RAW image file. | |
148 | */ | |
149 | ext2fs_block_bitmap meta_block_map; | |
d851ed39 | 150 | ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */ |
6304baf2 TT |
151 | |
152 | struct process_block_struct { | |
153 | ext2_ino_t ino; | |
d851ed39 | 154 | int is_dir; |
6304baf2 TT |
155 | }; |
156 | ||
157 | /* | |
158 | * These subroutines short circuits ext2fs_get_blocks and | |
159 | * ext2fs_check_directory; we use them since we already have the inode | |
160 | * structure, so there's no point in letting the ext2fs library read | |
161 | * the inode again. | |
162 | */ | |
163 | static ino_t stashed_ino = 0; | |
164 | static struct ext2_inode *stashed_inode; | |
165 | ||
54434927 TT |
166 | static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)), |
167 | ext2_ino_t ino, | |
168 | blk_t *blocks) | |
6304baf2 TT |
169 | { |
170 | int i; | |
171 | ||
172 | if ((ino != stashed_ino) || !stashed_inode) | |
173 | return EXT2_ET_CALLBACK_NOTHANDLED; | |
174 | ||
175 | for (i=0; i < EXT2_N_BLOCKS; i++) | |
176 | blocks[i] = stashed_inode->i_block[i]; | |
177 | return 0; | |
178 | } | |
179 | ||
54434927 TT |
180 | static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)), |
181 | ext2_ino_t ino) | |
4ea7bd04 TT |
182 | { |
183 | if ((ino != stashed_ino) || !stashed_inode) | |
184 | return EXT2_ET_CALLBACK_NOTHANDLED; | |
185 | ||
186 | if (!LINUX_S_ISDIR(stashed_inode->i_mode)) | |
187 | return EXT2_ET_NO_DIRECTORY; | |
188 | return 0; | |
189 | } | |
190 | ||
54434927 TT |
191 | static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)), |
192 | ext2_ino_t ino, | |
6304baf2 TT |
193 | struct ext2_inode *inode) |
194 | { | |
195 | if ((ino != stashed_ino) || !stashed_inode) | |
196 | return EXT2_ET_CALLBACK_NOTHANDLED; | |
197 | *inode = *stashed_inode; | |
198 | return 0; | |
199 | } | |
200 | ||
4ea7bd04 TT |
201 | static void use_inode_shortcuts(ext2_filsys fs, int bool) |
202 | { | |
203 | if (bool) { | |
204 | fs->get_blocks = meta_get_blocks; | |
205 | fs->check_directory = meta_check_directory; | |
206 | fs->read_inode = meta_read_inode; | |
207 | stashed_ino = 0; | |
208 | } else { | |
209 | fs->get_blocks = 0; | |
210 | fs->check_directory = 0; | |
211 | fs->read_inode = 0; | |
212 | } | |
213 | } | |
214 | ||
54434927 TT |
215 | static int process_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)), |
216 | blk_t *block_nr, | |
217 | e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), | |
218 | blk_t ref_block EXT2FS_ATTR((unused)), | |
219 | int ref_offset EXT2FS_ATTR((unused)), | |
220 | void *priv_data EXT2FS_ATTR((unused))) | |
6304baf2 | 221 | { |
d851ed39 TT |
222 | struct process_block_struct *p; |
223 | ||
224 | p = (struct process_block_struct *) priv_data; | |
225 | ||
6304baf2 | 226 | ext2fs_mark_block_bitmap(meta_block_map, *block_nr); |
d851ed39 TT |
227 | if (scramble_block_map && p->is_dir && blockcnt >= 0) |
228 | ext2fs_mark_block_bitmap(scramble_block_map, *block_nr); | |
6304baf2 TT |
229 | return 0; |
230 | } | |
231 | ||
54434927 TT |
232 | static int process_file_block(ext2_filsys fs EXT2FS_ATTR((unused)), |
233 | blk_t *block_nr, | |
234 | e2_blkcnt_t blockcnt, | |
235 | blk_t ref_block EXT2FS_ATTR((unused)), | |
236 | int ref_offset EXT2FS_ATTR((unused)), | |
237 | void *priv_data EXT2FS_ATTR((unused))) | |
6304baf2 TT |
238 | { |
239 | if (blockcnt < 0) { | |
240 | ext2fs_mark_block_bitmap(meta_block_map, *block_nr); | |
241 | } | |
242 | return 0; | |
243 | } | |
244 | ||
245 | static void mark_table_blocks(ext2_filsys fs) | |
246 | { | |
bb1a46a4 | 247 | blk_t first_block, b; |
54434927 | 248 | unsigned int i,j; |
6304baf2 | 249 | |
bb1a46a4 | 250 | first_block = fs->super->s_first_data_block; |
6304baf2 TT |
251 | /* |
252 | * Mark primary superblock | |
253 | */ | |
bb1a46a4 | 254 | ext2fs_mark_block_bitmap(meta_block_map, first_block); |
6304baf2 TT |
255 | |
256 | /* | |
257 | * Mark the primary superblock descriptors | |
258 | */ | |
259 | for (j = 0; j < fs->desc_blocks; j++) { | |
260 | ext2fs_mark_block_bitmap(meta_block_map, | |
bb1a46a4 | 261 | ext2fs_descriptor_block_loc(fs, first_block, j)); |
6304baf2 TT |
262 | } |
263 | ||
264 | for (i = 0; i < fs->group_desc_count; i++) { | |
265 | /* | |
266 | * Mark the blocks used for the inode table | |
267 | */ | |
268 | if (fs->group_desc[i].bg_inode_table) { | |
269 | for (j = 0, b = fs->group_desc[i].bg_inode_table; | |
54434927 | 270 | j < (unsigned) fs->inode_blocks_per_group; |
6304baf2 TT |
271 | j++, b++) |
272 | ext2fs_mark_block_bitmap(meta_block_map, b); | |
273 | } | |
274 | ||
275 | /* | |
276 | * Mark block used for the block bitmap | |
277 | */ | |
278 | if (fs->group_desc[i].bg_block_bitmap) { | |
279 | ext2fs_mark_block_bitmap(meta_block_map, | |
280 | fs->group_desc[i].bg_block_bitmap); | |
281 | } | |
282 | ||
283 | /* | |
284 | * Mark block used for the inode bitmap | |
285 | */ | |
286 | if (fs->group_desc[i].bg_inode_bitmap) { | |
287 | ext2fs_mark_block_bitmap(meta_block_map, | |
288 | fs->group_desc[i].bg_inode_bitmap); | |
289 | } | |
6304baf2 TT |
290 | } |
291 | } | |
292 | ||
293 | /* | |
294 | * This function returns 1 if the specified block is all zeros | |
295 | */ | |
296 | static int check_zero_block(char *buf, int blocksize) | |
297 | { | |
298 | char *cp = buf; | |
299 | int left = blocksize; | |
300 | ||
301 | while (left > 0) { | |
302 | if (*cp++) | |
303 | return 0; | |
304 | left--; | |
305 | } | |
306 | return 1; | |
307 | } | |
308 | ||
e3ef3502 TT |
309 | static void write_block(int fd, char *buf, int sparse_offset, |
310 | int blocksize, blk_t block) | |
6304baf2 TT |
311 | { |
312 | int count; | |
313 | errcode_t err; | |
314 | ||
e3ef3502 TT |
315 | if (sparse_offset) { |
316 | #ifdef HAVE_LSEEK64 | |
317 | if (lseek64(fd, sparse_offset, SEEK_CUR) < 0) | |
318 | perror("lseek"); | |
319 | #else | |
320 | if (lseek(fd, sparse_offset, SEEK_CUR) < 0) | |
321 | perror("lseek"); | |
322 | #endif | |
323 | } | |
324 | if (blocksize) { | |
325 | count = write(fd, buf, blocksize); | |
326 | if (count != blocksize) { | |
327 | if (count == -1) | |
328 | err = errno; | |
329 | else | |
330 | err = 0; | |
8deb80a5 | 331 | com_err(program_name, err, "error writing block %u", |
e3ef3502 TT |
332 | block); |
333 | } | |
6304baf2 TT |
334 | } |
335 | } | |
336 | ||
d851ed39 TT |
337 | int name_id[256]; |
338 | ||
339 | static void scramble_dir_block(ext2_filsys fs, blk_t blk, char *buf) | |
340 | { | |
341 | char *p, *end, *cp; | |
342 | struct ext2_dir_entry_2 *dirent; | |
343 | int rec_len, id, len; | |
344 | ||
d851ed39 TT |
345 | end = buf + fs->blocksize; |
346 | for (p = buf; p < end-8; p += rec_len) { | |
347 | dirent = (struct ext2_dir_entry_2 *) p; | |
348 | rec_len = dirent->rec_len; | |
349 | #ifdef EXT2FS_ENABLE_SWAPFS | |
350 | if (fs->flags & EXT2_FLAG_SWAP_BYTES) | |
351 | rec_len = ext2fs_swab16(rec_len); | |
352 | #endif | |
353 | #if 0 | |
354 | printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len); | |
355 | #endif | |
356 | if (rec_len < 8 || (rec_len % 4) || | |
357 | (p+rec_len > end)) { | |
358 | printf("Corrupt directory block %lu: " | |
9b9a780f TT |
359 | "bad rec_len (%d)\n", (unsigned long) blk, |
360 | rec_len); | |
d851ed39 TT |
361 | rec_len = end - p; |
362 | #ifdef EXT2FS_ENABLE_SWAPFS | |
363 | if (fs->flags & EXT2_FLAG_SWAP_BYTES) | |
364 | dirent->rec_len = ext2fs_swab16(rec_len); | |
365 | #endif | |
366 | continue; | |
367 | } | |
368 | if (dirent->name_len + 8 > rec_len) { | |
369 | printf("Corrupt directory block %lu: " | |
9b9a780f TT |
370 | "bad name_len (%d)\n", (unsigned long) blk, |
371 | dirent->name_len); | |
d851ed39 TT |
372 | dirent->name_len = rec_len - 8; |
373 | continue; | |
374 | } | |
d851ed39 | 375 | cp = p+8; |
d851ed39 TT |
376 | len = rec_len - dirent->name_len - 8; |
377 | if (len > 0) | |
378 | memset(cp+dirent->name_len, 0, len); | |
79fc2a99 TT |
379 | if (dirent->name_len==1 && cp[0] == '.') |
380 | continue; | |
381 | if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.') | |
382 | continue; | |
383 | ||
384 | memset(cp, 'A', dirent->name_len); | |
d851ed39 TT |
385 | len = dirent->name_len; |
386 | id = name_id[len]++; | |
387 | while ((len > 0) && (id > 0)) { | |
388 | *cp += id % 26; | |
389 | id = id / 26; | |
390 | cp++; | |
391 | len--; | |
392 | } | |
393 | } | |
394 | } | |
395 | ||
4ea7bd04 | 396 | static void output_meta_data_blocks(ext2_filsys fs, int fd) |
6304baf2 TT |
397 | { |
398 | errcode_t retval; | |
399 | blk_t blk; | |
d851ed39 | 400 | char *buf, *zero_buf; |
e3ef3502 | 401 | int sparse = 0; |
6304baf2 | 402 | |
d851ed39 TT |
403 | buf = malloc(fs->blocksize); |
404 | if (!buf) { | |
405 | com_err(program_name, ENOMEM, "while allocating buffer"); | |
406 | exit(1); | |
407 | } | |
408 | zero_buf = malloc(fs->blocksize); | |
409 | if (!zero_buf) { | |
410 | com_err(program_name, ENOMEM, "while allocating buffer"); | |
411 | exit(1); | |
412 | } | |
413 | memset(zero_buf, 0, fs->blocksize); | |
6304baf2 TT |
414 | for (blk = 0; blk < fs->super->s_blocks_count; blk++) { |
415 | if ((blk >= fs->super->s_first_data_block) && | |
416 | ext2fs_test_block_bitmap(meta_block_map, blk)) { | |
417 | retval = io_channel_read_blk(fs->io, blk, 1, buf); | |
418 | if (retval) { | |
419 | com_err(program_name, retval, | |
d0ff90d5 | 420 | "error reading block %u", blk); |
6304baf2 | 421 | } |
d851ed39 TT |
422 | if (scramble_block_map && |
423 | ext2fs_test_block_bitmap(scramble_block_map, blk)) | |
424 | scramble_dir_block(fs, blk, buf); | |
6304baf2 TT |
425 | if ((fd != 1) && check_zero_block(buf, fs->blocksize)) |
426 | goto sparse_write; | |
e3ef3502 TT |
427 | write_block(fd, buf, sparse, fs->blocksize, blk); |
428 | sparse = 0; | |
6304baf2 TT |
429 | } else { |
430 | sparse_write: | |
431 | if (fd == 1) { | |
e3ef3502 TT |
432 | write_block(fd, zero_buf, 0, |
433 | fs->blocksize, blk); | |
6304baf2 TT |
434 | continue; |
435 | } | |
e3ef3502 TT |
436 | sparse += fs->blocksize; |
437 | if (sparse >= 1024*1024) { | |
438 | write_block(fd, 0, sparse, 0, 0); | |
439 | sparse = 0; | |
440 | } | |
6304baf2 TT |
441 | } |
442 | } | |
e3ef3502 | 443 | write_block(fd, zero_buf, sparse, 1, -1); |
248c2f9c BB |
444 | free(zero_buf); |
445 | free(buf); | |
6304baf2 TT |
446 | } |
447 | ||
d851ed39 | 448 | static void write_raw_image_file(ext2_filsys fs, int fd, int scramble_flag) |
6304baf2 TT |
449 | { |
450 | struct process_block_struct pb; | |
451 | struct ext2_inode inode; | |
452 | ext2_inode_scan scan; | |
453 | ext2_ino_t ino; | |
454 | errcode_t retval; | |
455 | char * block_buf; | |
456 | ||
457 | retval = ext2fs_allocate_block_bitmap(fs, "in-use block map", | |
458 | &meta_block_map); | |
459 | if (retval) { | |
460 | com_err(program_name, retval, "while allocating block bitmap"); | |
461 | exit(1); | |
462 | } | |
d851ed39 TT |
463 | |
464 | if (scramble_flag) { | |
465 | retval = ext2fs_allocate_block_bitmap(fs, "scramble block map", | |
466 | &scramble_block_map); | |
467 | if (retval) { | |
468 | com_err(program_name, retval, | |
469 | "while allocating scramble block bitmap"); | |
470 | exit(1); | |
471 | } | |
472 | } | |
6304baf2 TT |
473 | |
474 | mark_table_blocks(fs); | |
475 | ||
476 | retval = ext2fs_open_inode_scan(fs, 0, &scan); | |
477 | if (retval) { | |
478 | com_err(program_name, retval, _("while opening inode scan")); | |
479 | exit(1); | |
480 | } | |
481 | ||
482 | block_buf = malloc(fs->blocksize * 3); | |
483 | if (!block_buf) { | |
484 | com_err(program_name, 0, "Can't allocate block buffer"); | |
485 | exit(1); | |
486 | } | |
487 | ||
4ea7bd04 | 488 | use_inode_shortcuts(fs, 1); |
6304baf2 TT |
489 | stashed_inode = &inode; |
490 | while (1) { | |
491 | retval = ext2fs_get_next_inode(scan, &ino, &inode); | |
3432a916 TT |
492 | if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) |
493 | continue; | |
6304baf2 TT |
494 | if (retval) { |
495 | com_err(program_name, retval, | |
496 | _("while getting next inode")); | |
497 | exit(1); | |
498 | } | |
499 | if (ino == 0) | |
500 | break; | |
ed909bbe TT |
501 | if (!inode.i_links_count) |
502 | continue; | |
503 | if (inode.i_file_acl) { | |
504 | ext2fs_mark_block_bitmap(meta_block_map, | |
505 | inode.i_file_acl); | |
506 | } | |
507 | if (!ext2fs_inode_has_valid_blocks(&inode)) | |
6304baf2 TT |
508 | continue; |
509 | ||
510 | stashed_ino = ino; | |
d851ed39 TT |
511 | pb.ino = ino; |
512 | pb.is_dir = LINUX_S_ISDIR(inode.i_mode); | |
1c1e0049 | 513 | if (LINUX_S_ISDIR(inode.i_mode) || |
eca53e3c TT |
514 | (LINUX_S_ISLNK(inode.i_mode) && |
515 | ext2fs_inode_has_valid_blocks(&inode)) || | |
1c1e0049 | 516 | ino == fs->super->s_journal_inum) { |
6304baf2 TT |
517 | retval = ext2fs_block_iterate2(fs, ino, 0, |
518 | block_buf, process_dir_block, &pb); | |
519 | if (retval) { | |
520 | com_err(program_name, retval, | |
d0ff90d5 | 521 | "while iterating over inode %u", |
6304baf2 TT |
522 | ino); |
523 | exit(1); | |
524 | } | |
525 | } else { | |
526 | if (inode.i_block[EXT2_IND_BLOCK] || | |
527 | inode.i_block[EXT2_DIND_BLOCK] || | |
528 | inode.i_block[EXT2_TIND_BLOCK]) { | |
529 | retval = ext2fs_block_iterate2(fs, | |
530 | ino, 0, block_buf, | |
531 | process_file_block, &pb); | |
532 | if (retval) { | |
533 | com_err(program_name, retval, | |
d0ff90d5 | 534 | "while iterating over inode %u", ino); |
6304baf2 TT |
535 | exit(1); |
536 | } | |
537 | } | |
6304baf2 TT |
538 | } |
539 | } | |
4ea7bd04 | 540 | use_inode_shortcuts(fs, 0); |
6304baf2 | 541 | output_meta_data_blocks(fs, fd); |
d7eee829 | 542 | free(block_buf); |
6304baf2 TT |
543 | } |
544 | ||
6e82cd7e | 545 | static void install_image(char *device, char *image_fn, int raw_flag) |
8c6b6483 | 546 | { |
8c6b6483 TT |
547 | errcode_t retval; |
548 | ext2_filsys fs; | |
549 | int open_flag = EXT2_FLAG_IMAGE_FILE; | |
550 | int fd = 0; | |
551 | io_manager io_ptr; | |
552 | io_channel io, image_io; | |
553 | ||
554 | if (raw_flag) { | |
555 | com_err(program_name, 0, "Raw images cannot be installed"); | |
556 | exit(1); | |
557 | } | |
558 | ||
559 | #ifdef CONFIG_TESTIO_DEBUG | |
560 | io_ptr = test_io_manager; | |
561 | test_io_backing_manager = unix_io_manager; | |
562 | #else | |
563 | io_ptr = unix_io_manager; | |
564 | #endif | |
565 | ||
566 | retval = ext2fs_open (image_fn, open_flag, 0, 0, | |
567 | io_ptr, &fs); | |
568 | if (retval) { | |
569 | com_err (program_name, retval, _("while trying to open %s"), | |
570 | image_fn); | |
571 | exit(1); | |
572 | } | |
573 | ||
574 | retval = ext2fs_read_bitmaps (fs); | |
575 | if (retval) { | |
576 | com_err(program_name, retval, "error reading bitmaps"); | |
577 | exit(1); | |
578 | } | |
579 | ||
580 | ||
581 | fd = open(image_fn, O_RDONLY); | |
582 | if (fd < 0) { | |
583 | perror(image_fn); | |
584 | exit(1); | |
585 | } | |
586 | ||
6e82cd7e | 587 | retval = io_ptr->open(device, IO_FLAG_RW, &io); |
8c6b6483 | 588 | if (retval) { |
6e82cd7e | 589 | com_err(device, 0, "while opening device file"); |
8c6b6483 TT |
590 | exit(1); |
591 | } | |
592 | ||
593 | image_io = fs->io; | |
594 | ||
595 | ext2fs_rewrite_to_io(fs, io); | |
596 | ||
597 | if (lseek(fd, fs->image_header->offset_inode, SEEK_SET) < 0) { | |
598 | perror("lseek"); | |
599 | exit(1); | |
600 | } | |
601 | ||
602 | retval = ext2fs_image_inode_read(fs, fd, 0); | |
603 | if (retval) { | |
604 | com_err(image_fn, 0, "while restoring the image table"); | |
605 | exit(1); | |
606 | } | |
607 | ||
608 | ext2fs_close (fs); | |
609 | exit (0); | |
610 | } | |
611 | ||
6304baf2 TT |
612 | int main (int argc, char ** argv) |
613 | { | |
614 | int c; | |
615 | errcode_t retval; | |
616 | ext2_filsys fs; | |
8c6b6483 | 617 | char *image_fn; |
6304baf2 TT |
618 | int open_flag = 0; |
619 | int raw_flag = 0; | |
8c6b6483 | 620 | int install_flag = 0; |
d851ed39 | 621 | int scramble_flag = 0; |
6304baf2 TT |
622 | int fd = 0; |
623 | ||
624 | #ifdef ENABLE_NLS | |
625 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 626 | setlocale(LC_CTYPE, ""); |
6304baf2 TT |
627 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
628 | textdomain(NLS_CAT_NAME); | |
629 | #endif | |
0f8973fb TT |
630 | fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION, |
631 | E2FSPROGS_DATE); | |
6304baf2 TT |
632 | if (argc && *argv) |
633 | program_name = *argv; | |
a6d8302b | 634 | add_error_table(&et_ext2_error_table); |
d851ed39 | 635 | while ((c = getopt (argc, argv, "rsI")) != EOF) |
6304baf2 TT |
636 | switch (c) { |
637 | case 'r': | |
638 | raw_flag++; | |
639 | break; | |
d851ed39 TT |
640 | case 's': |
641 | scramble_flag++; | |
642 | break; | |
8c6b6483 TT |
643 | case 'I': |
644 | install_flag++; | |
645 | break; | |
6304baf2 TT |
646 | default: |
647 | usage(); | |
648 | } | |
649 | if (optind != argc - 2 ) | |
650 | usage(); | |
651 | device_name = argv[optind]; | |
8c6b6483 TT |
652 | image_fn = argv[optind+1]; |
653 | ||
654 | if (install_flag) { | |
655 | install_image(device_name, image_fn, raw_flag); | |
6e82cd7e | 656 | exit (0); |
8c6b6483 TT |
657 | } |
658 | ||
6304baf2 TT |
659 | retval = ext2fs_open (device_name, open_flag, 0, 0, |
660 | unix_io_manager, &fs); | |
661 | if (retval) { | |
662 | com_err (program_name, retval, _("while trying to open %s"), | |
663 | device_name); | |
54434927 | 664 | fputs(_("Couldn't find valid filesystem superblock.\n"), stdout); |
6304baf2 TT |
665 | exit(1); |
666 | } | |
667 | ||
8c6b6483 | 668 | if (strcmp(image_fn, "-") == 0) |
1c1e0049 TT |
669 | fd = 1; |
670 | else { | |
6304baf2 | 671 | #ifdef HAVE_OPEN64 |
8c6b6483 | 672 | fd = open64(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600); |
6304baf2 | 673 | #else |
8c6b6483 | 674 | fd = open(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600); |
6304baf2 | 675 | #endif |
1c1e0049 TT |
676 | if (fd < 0) { |
677 | com_err(program_name, errno, | |
678 | _("while trying to open %s"), argv[optind+1]); | |
679 | exit(1); | |
680 | } | |
6304baf2 TT |
681 | } |
682 | ||
683 | if (raw_flag) | |
d851ed39 | 684 | write_raw_image_file(fs, fd, scramble_flag); |
6304baf2 TT |
685 | else |
686 | write_image_file(fs, fd); | |
c5423c5b | 687 | |
72ed1264 | 688 | ext2fs_close (fs); |
a6d8302b | 689 | remove_error_table(&et_ext2_error_table); |
72ed1264 TT |
690 | exit (0); |
691 | } |