blob: a7fc9b5d6c232a84152134d7c026aa56f6c31eb3 [file] [log] [blame]
Theodore Ts'o72ed1262000-11-12 19:32:20 +00001/*
2 * e2image.c --- Program which writes an image file backing up
3 * critical metadata for the filesystem.
4 *
Theodore Ts'oa3827952001-05-03 16:24:57 +00005 * Copyright 2000, 2001 by Theodore Ts'o.
Theodore Ts'o72ed1262000-11-12 19:32:20 +00006 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
Theodore Ts'o6304baf2001-08-09 05:41:29 -040013#define _LARGEFILE_SOURCE
14#define _LARGEFILE64_SOURCE
15
Theodore Ts'o72ed1262000-11-12 19:32:20 +000016#include <fcntl.h>
17#include <grp.h>
18#ifdef HAVE_GETOPT_H
19#include <getopt.h>
20#else
21extern char *optarg;
22extern 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
Theodore Ts'o54c637d2001-05-14 11:45:38 +000035#include "ext2fs/ext2_fs.h"
Theodore Ts'o72ed1262000-11-12 19:32:20 +000036#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
Theodore Ts'o3e377db2000-12-09 02:37:33 +000045const char * program_name = "e2image";
Theodore Ts'o72ed1262000-11-12 19:32:20 +000046char * device_name = NULL;
47
48static void usage(void)
49{
Theodore Ts'od851ed32005-01-19 00:26:43 -050050 fprintf(stderr, _("Usage: %s [-rsI] device image_file\n"),
51 program_name);
Theodore Ts'o72ed1262000-11-12 19:32:20 +000052 exit (1);
53}
54
Theodore Ts'o095b4592001-05-03 13:33:11 +000055static void write_header(int fd, struct ext2_image_hdr *hdr, int blocksize)
Theodore Ts'o72ed1262000-11-12 19:32:20 +000056{
Theodore Ts'o095b4592001-05-03 13:33:11 +000057 char *header_buf;
Theodore Ts'o72ed1262000-11-12 19:32:20 +000058 int actual;
59
Theodore Ts'o095b4592001-05-03 13:33:11 +000060 header_buf = malloc(blocksize);
61 if (!header_buf) {
Theodore Ts'o54434922003-12-07 01:28:50 -050062 fputs(_("Couldn't allocate header buffer\n"), stderr);
Theodore Ts'o095b4592001-05-03 13:33:11 +000063 exit(1);
64 }
65
Theodore Ts'o72ed1262000-11-12 19:32:20 +000066 if (lseek(fd, 0, SEEK_SET) < 0) {
67 perror("lseek while writing header");
68 exit(1);
69 }
Theodore Ts'o095b4592001-05-03 13:33:11 +000070 memset(header_buf, 0, blocksize);
Theodore Ts'o72ed1262000-11-12 19:32:20 +000071
72 if (hdr)
73 memcpy(header_buf, hdr, sizeof(struct ext2_image_hdr));
74
Theodore Ts'o095b4592001-05-03 13:33:11 +000075 actual = write(fd, header_buf, blocksize);
Theodore Ts'o72ed1262000-11-12 19:32:20 +000076 if (actual < 0) {
77 perror("write header");
78 exit(1);
79 }
Theodore Ts'o095b4592001-05-03 13:33:11 +000080 if (actual != blocksize) {
Theodore Ts'oddc32a02003-05-03 18:45:55 -040081 fprintf(stderr, _("short write (only %d bytes) for "
Theodore Ts'o72ed1262000-11-12 19:32:20 +000082 "writing image header"), actual);
83 exit(1);
84 }
Theodore Ts'o095b4592001-05-03 13:33:11 +000085 free(header_buf);
Theodore Ts'o72ed1262000-11-12 19:32:20 +000086}
87
Theodore Ts'o6304baf2001-08-09 05:41:29 -040088static void write_image_file(ext2_filsys fs, int fd)
Theodore Ts'o72ed1262000-11-12 19:32:20 +000089{
Theodore Ts'o6304baf2001-08-09 05:41:29 -040090 struct ext2_image_hdr hdr;
91 struct stat st;
92 errcode_t retval;
Theodore Ts'o72ed1262000-11-12 19:32:20 +000093
Theodore Ts'o095b4592001-05-03 13:33:11 +000094 write_header(fd, NULL, fs->blocksize);
Theodore Ts'o72ed1262000-11-12 19:32:20 +000095 memset(&hdr, 0, sizeof(struct ext2_image_hdr));
Theodore Ts'o6304baf2001-08-09 05:41:29 -040096
Theodore Ts'o72ed1262000-11-12 19:32:20 +000097 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);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400105 retval = ext2fs_image_inode_write(fs, fd,
106 (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000107 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 }
Theodore Ts'oc5423c52001-02-08 05:45:17 +0000125
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));
Theodore Ts'o095b4592001-05-03 13:33:11 +0000129 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
Theodore Ts'oc5423c52001-02-08 05:45:17 +0000133 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);
Theodore Ts'o095b4592001-05-03 13:33:11 +0000143 write_header(fd, &hdr, fs->blocksize);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400144}
145
146/*
147 * These set of functions are used to write a RAW image file.
148 */
149ext2fs_block_bitmap meta_block_map;
Theodore Ts'od851ed32005-01-19 00:26:43 -0500150ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400151
152struct process_block_struct {
153 ext2_ino_t ino;
Theodore Ts'od851ed32005-01-19 00:26:43 -0500154 int is_dir;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400155};
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 */
163static ino_t stashed_ino = 0;
164static struct ext2_inode *stashed_inode;
165
Theodore Ts'o54434922003-12-07 01:28:50 -0500166static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
167 ext2_ino_t ino,
168 blk_t *blocks)
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400169{
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
Theodore Ts'o54434922003-12-07 01:28:50 -0500180static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)),
181 ext2_ino_t ino)
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500182{
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
Theodore Ts'o54434922003-12-07 01:28:50 -0500191static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
192 ext2_ino_t ino,
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400193 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
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500201static 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
Theodore Ts'o54434922003-12-07 01:28:50 -0500215static 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)))
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400221{
Theodore Ts'od851ed32005-01-19 00:26:43 -0500222 struct process_block_struct *p;
223
224 p = (struct process_block_struct *) priv_data;
225
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400226 ext2fs_mark_block_bitmap(meta_block_map, *block_nr);
Theodore Ts'od851ed32005-01-19 00:26:43 -0500227 if (scramble_block_map && p->is_dir && blockcnt >= 0)
228 ext2fs_mark_block_bitmap(scramble_block_map, *block_nr);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400229 return 0;
230}
231
Theodore Ts'o54434922003-12-07 01:28:50 -0500232static 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)))
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400238{
239 if (blockcnt < 0) {
240 ext2fs_mark_block_bitmap(meta_block_map, *block_nr);
241 }
242 return 0;
243}
244
245static void mark_table_blocks(ext2_filsys fs)
246{
247 blk_t block, b;
Theodore Ts'o54434922003-12-07 01:28:50 -0500248 unsigned int i,j;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400249
250 block = fs->super->s_first_data_block;
251 /*
252 * Mark primary superblock
253 */
254 ext2fs_mark_block_bitmap(meta_block_map, block);
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,
Theodore Ts'oc046ac72002-10-20 00:38:57 -0400261 ext2fs_descriptor_block_loc(fs, block, j));
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400262 }
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;
Theodore Ts'o54434922003-12-07 01:28:50 -0500270 j < (unsigned) fs->inode_blocks_per_group;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400271 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 }
290 block += fs->super->s_blocks_per_group;
291 }
292}
293
294/*
295 * This function returns 1 if the specified block is all zeros
296 */
297static int check_zero_block(char *buf, int blocksize)
298{
299 char *cp = buf;
300 int left = blocksize;
301
302 while (left > 0) {
303 if (*cp++)
304 return 0;
305 left--;
306 }
307 return 1;
308}
309
Theodore Ts'oe3ef3502001-11-05 18:57:43 -0500310static void write_block(int fd, char *buf, int sparse_offset,
311 int blocksize, blk_t block)
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400312{
313 int count;
314 errcode_t err;
315
Theodore Ts'oe3ef3502001-11-05 18:57:43 -0500316 if (sparse_offset) {
317#ifdef HAVE_LSEEK64
318 if (lseek64(fd, sparse_offset, SEEK_CUR) < 0)
319 perror("lseek");
320#else
321 if (lseek(fd, sparse_offset, SEEK_CUR) < 0)
322 perror("lseek");
323#endif
324 }
325 if (blocksize) {
326 count = write(fd, buf, blocksize);
327 if (count != blocksize) {
328 if (count == -1)
329 err = errno;
330 else
331 err = 0;
332 com_err(program_name, err, "error writing block %d",
333 block);
334 }
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400335 }
336}
337
Theodore Ts'od851ed32005-01-19 00:26:43 -0500338int name_id[256];
339
340static void scramble_dir_block(ext2_filsys fs, blk_t blk, char *buf)
341{
342 char *p, *end, *cp;
343 struct ext2_dir_entry_2 *dirent;
344 int rec_len, id, len;
345
Theodore Ts'od851ed32005-01-19 00:26:43 -0500346 end = buf + fs->blocksize;
347 for (p = buf; p < end-8; p += rec_len) {
348 dirent = (struct ext2_dir_entry_2 *) p;
349 rec_len = dirent->rec_len;
350#ifdef EXT2FS_ENABLE_SWAPFS
351 if (fs->flags & EXT2_FLAG_SWAP_BYTES)
352 rec_len = ext2fs_swab16(rec_len);
353#endif
354#if 0
355 printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
356#endif
357 if (rec_len < 8 || (rec_len % 4) ||
358 (p+rec_len > end)) {
359 printf("Corrupt directory block %lu: "
360 "bad rec_len (%d)\n", blk, rec_len);
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: "
370 "bad name_len (%d)\n", blk, dirent->name_len);
371 dirent->name_len = rec_len - 8;
372 continue;
373 }
Theodore Ts'od851ed32005-01-19 00:26:43 -0500374 cp = p+8;
Theodore Ts'od851ed32005-01-19 00:26:43 -0500375 len = rec_len - dirent->name_len - 8;
376 if (len > 0)
377 memset(cp+dirent->name_len, 0, len);
Theodore Ts'o79fc2a92005-01-26 11:37:46 -0500378 if (dirent->name_len==1 && cp[0] == '.')
379 continue;
380 if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.')
381 continue;
382
383 memset(cp, 'A', dirent->name_len);
Theodore Ts'od851ed32005-01-19 00:26:43 -0500384 len = dirent->name_len;
385 id = name_id[len]++;
386 while ((len > 0) && (id > 0)) {
387 *cp += id % 26;
388 id = id / 26;
389 cp++;
390 len--;
391 }
392 }
393}
394
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500395static void output_meta_data_blocks(ext2_filsys fs, int fd)
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400396{
397 errcode_t retval;
398 blk_t blk;
Theodore Ts'od851ed32005-01-19 00:26:43 -0500399 char *buf, *zero_buf;
Theodore Ts'oe3ef3502001-11-05 18:57:43 -0500400 int sparse = 0;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400401
Theodore Ts'od851ed32005-01-19 00:26:43 -0500402 buf = malloc(fs->blocksize);
403 if (!buf) {
404 com_err(program_name, ENOMEM, "while allocating buffer");
405 exit(1);
406 }
407 zero_buf = malloc(fs->blocksize);
408 if (!zero_buf) {
409 com_err(program_name, ENOMEM, "while allocating buffer");
410 exit(1);
411 }
412 memset(zero_buf, 0, fs->blocksize);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400413 for (blk = 0; blk < fs->super->s_blocks_count; blk++) {
414 if ((blk >= fs->super->s_first_data_block) &&
415 ext2fs_test_block_bitmap(meta_block_map, blk)) {
416 retval = io_channel_read_blk(fs->io, blk, 1, buf);
417 if (retval) {
418 com_err(program_name, retval,
419 "error reading block %d", blk);
420 }
Theodore Ts'od851ed32005-01-19 00:26:43 -0500421 if (scramble_block_map &&
422 ext2fs_test_block_bitmap(scramble_block_map, blk))
423 scramble_dir_block(fs, blk, buf);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400424 if ((fd != 1) && check_zero_block(buf, fs->blocksize))
425 goto sparse_write;
Theodore Ts'oe3ef3502001-11-05 18:57:43 -0500426 write_block(fd, buf, sparse, fs->blocksize, blk);
427 sparse = 0;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400428 } else {
429 sparse_write:
430 if (fd == 1) {
Theodore Ts'oe3ef3502001-11-05 18:57:43 -0500431 write_block(fd, zero_buf, 0,
432 fs->blocksize, blk);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400433 continue;
434 }
Theodore Ts'oe3ef3502001-11-05 18:57:43 -0500435 sparse += fs->blocksize;
436 if (sparse >= 1024*1024) {
437 write_block(fd, 0, sparse, 0, 0);
438 sparse = 0;
439 }
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400440 }
441 }
Theodore Ts'oe3ef3502001-11-05 18:57:43 -0500442 write_block(fd, zero_buf, sparse, 1, -1);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400443}
444
Theodore Ts'od851ed32005-01-19 00:26:43 -0500445static void write_raw_image_file(ext2_filsys fs, int fd, int scramble_flag)
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400446{
447 struct process_block_struct pb;
448 struct ext2_inode inode;
449 ext2_inode_scan scan;
450 ext2_ino_t ino;
451 errcode_t retval;
452 char * block_buf;
453
454 retval = ext2fs_allocate_block_bitmap(fs, "in-use block map",
455 &meta_block_map);
456 if (retval) {
457 com_err(program_name, retval, "while allocating block bitmap");
458 exit(1);
459 }
Theodore Ts'od851ed32005-01-19 00:26:43 -0500460
461 if (scramble_flag) {
462 retval = ext2fs_allocate_block_bitmap(fs, "scramble block map",
463 &scramble_block_map);
464 if (retval) {
465 com_err(program_name, retval,
466 "while allocating scramble block bitmap");
467 exit(1);
468 }
469 }
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400470
471 mark_table_blocks(fs);
472
473 retval = ext2fs_open_inode_scan(fs, 0, &scan);
474 if (retval) {
475 com_err(program_name, retval, _("while opening inode scan"));
476 exit(1);
477 }
478
479 block_buf = malloc(fs->blocksize * 3);
480 if (!block_buf) {
481 com_err(program_name, 0, "Can't allocate block buffer");
482 exit(1);
483 }
484
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500485 use_inode_shortcuts(fs, 1);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400486 stashed_inode = &inode;
487 while (1) {
488 retval = ext2fs_get_next_inode(scan, &ino, &inode);
Theodore Ts'o3432a912002-10-02 17:47:08 -0400489 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
490 continue;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400491 if (retval) {
492 com_err(program_name, retval,
493 _("while getting next inode"));
494 exit(1);
495 }
496 if (ino == 0)
497 break;
Theodore Ts'oed909bb2002-08-16 17:03:59 -0400498 if (!inode.i_links_count)
499 continue;
500 if (inode.i_file_acl) {
501 ext2fs_mark_block_bitmap(meta_block_map,
502 inode.i_file_acl);
503 }
504 if (!ext2fs_inode_has_valid_blocks(&inode))
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400505 continue;
506
507 stashed_ino = ino;
Theodore Ts'od851ed32005-01-19 00:26:43 -0500508 pb.ino = ino;
509 pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
Theodore Ts'o1c1e0042001-08-09 06:04:32 -0400510 if (LINUX_S_ISDIR(inode.i_mode) ||
Theodore Ts'oeca53e32003-03-14 00:38:45 -0500511 (LINUX_S_ISLNK(inode.i_mode) &&
512 ext2fs_inode_has_valid_blocks(&inode)) ||
Theodore Ts'o1c1e0042001-08-09 06:04:32 -0400513 ino == fs->super->s_journal_inum) {
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400514 retval = ext2fs_block_iterate2(fs, ino, 0,
515 block_buf, process_dir_block, &pb);
516 if (retval) {
517 com_err(program_name, retval,
518 "while iterating over inode %d",
519 ino);
520 exit(1);
521 }
522 } else {
523 if (inode.i_block[EXT2_IND_BLOCK] ||
524 inode.i_block[EXT2_DIND_BLOCK] ||
525 inode.i_block[EXT2_TIND_BLOCK]) {
526 retval = ext2fs_block_iterate2(fs,
527 ino, 0, block_buf,
528 process_file_block, &pb);
529 if (retval) {
530 com_err(program_name, retval,
531 "while iterating over %d", ino);
532 exit(1);
533 }
534 }
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400535 }
536 }
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500537 use_inode_shortcuts(fs, 0);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400538 output_meta_data_blocks(fs, fd);
539}
540
Theodore Ts'o6e82cd72005-01-05 03:02:54 -0500541static void install_image(char *device, char *image_fn, int raw_flag)
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400542{
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400543 errcode_t retval;
544 ext2_filsys fs;
545 int open_flag = EXT2_FLAG_IMAGE_FILE;
546 int fd = 0;
547 io_manager io_ptr;
548 io_channel io, image_io;
549
550 if (raw_flag) {
551 com_err(program_name, 0, "Raw images cannot be installed");
552 exit(1);
553 }
554
555#ifdef CONFIG_TESTIO_DEBUG
556 io_ptr = test_io_manager;
557 test_io_backing_manager = unix_io_manager;
558#else
559 io_ptr = unix_io_manager;
560#endif
561
562 retval = ext2fs_open (image_fn, open_flag, 0, 0,
563 io_ptr, &fs);
564 if (retval) {
565 com_err (program_name, retval, _("while trying to open %s"),
566 image_fn);
567 exit(1);
568 }
569
570 retval = ext2fs_read_bitmaps (fs);
571 if (retval) {
572 com_err(program_name, retval, "error reading bitmaps");
573 exit(1);
574 }
575
576
577 fd = open(image_fn, O_RDONLY);
578 if (fd < 0) {
579 perror(image_fn);
580 exit(1);
581 }
582
Theodore Ts'o6e82cd72005-01-05 03:02:54 -0500583 retval = io_ptr->open(device, IO_FLAG_RW, &io);
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400584 if (retval) {
Theodore Ts'o6e82cd72005-01-05 03:02:54 -0500585 com_err(device, 0, "while opening device file");
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400586 exit(1);
587 }
588
589 image_io = fs->io;
590
591 ext2fs_rewrite_to_io(fs, io);
592
593 if (lseek(fd, fs->image_header->offset_inode, SEEK_SET) < 0) {
594 perror("lseek");
595 exit(1);
596 }
597
598 retval = ext2fs_image_inode_read(fs, fd, 0);
599 if (retval) {
600 com_err(image_fn, 0, "while restoring the image table");
601 exit(1);
602 }
603
604 ext2fs_close (fs);
605 exit (0);
606}
607
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400608int main (int argc, char ** argv)
609{
610 int c;
611 errcode_t retval;
612 ext2_filsys fs;
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400613 char *image_fn;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400614 int open_flag = 0;
615 int raw_flag = 0;
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400616 int install_flag = 0;
Theodore Ts'od851ed32005-01-19 00:26:43 -0500617 int scramble_flag = 0;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400618 int fd = 0;
619
620#ifdef ENABLE_NLS
621 setlocale(LC_MESSAGES, "");
Theodore Ts'o14308a52002-03-05 03:26:52 -0500622 setlocale(LC_CTYPE, "");
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400623 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
624 textdomain(NLS_CAT_NAME);
625#endif
Theodore Ts'o0f8973f2001-08-27 12:44:23 -0400626 fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
627 E2FSPROGS_DATE);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400628 if (argc && *argv)
629 program_name = *argv;
630 initialize_ext2_error_table();
Theodore Ts'od851ed32005-01-19 00:26:43 -0500631 while ((c = getopt (argc, argv, "rsI")) != EOF)
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400632 switch (c) {
633 case 'r':
634 raw_flag++;
635 break;
Theodore Ts'od851ed32005-01-19 00:26:43 -0500636 case 's':
637 scramble_flag++;
638 break;
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400639 case 'I':
640 install_flag++;
641 break;
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400642 default:
643 usage();
644 }
645 if (optind != argc - 2 )
646 usage();
647 device_name = argv[optind];
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400648 image_fn = argv[optind+1];
649
650 if (install_flag) {
651 install_image(device_name, image_fn, raw_flag);
Theodore Ts'o6e82cd72005-01-05 03:02:54 -0500652 exit (0);
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400653 }
654
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400655 retval = ext2fs_open (device_name, open_flag, 0, 0,
656 unix_io_manager, &fs);
657 if (retval) {
658 com_err (program_name, retval, _("while trying to open %s"),
659 device_name);
Theodore Ts'o54434922003-12-07 01:28:50 -0500660 fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400661 exit(1);
662 }
663
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400664 if (strcmp(image_fn, "-") == 0)
Theodore Ts'o1c1e0042001-08-09 06:04:32 -0400665 fd = 1;
666 else {
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400667#ifdef HAVE_OPEN64
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400668 fd = open64(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400669#else
Theodore Ts'o8c6b6482004-07-28 21:07:53 -0400670 fd = open(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400671#endif
Theodore Ts'o1c1e0042001-08-09 06:04:32 -0400672 if (fd < 0) {
673 com_err(program_name, errno,
674 _("while trying to open %s"), argv[optind+1]);
675 exit(1);
676 }
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400677 }
678
679 if (raw_flag)
Theodore Ts'od851ed32005-01-19 00:26:43 -0500680 write_raw_image_file(fs, fd, scramble_flag);
Theodore Ts'o6304baf2001-08-09 05:41:29 -0400681 else
682 write_image_file(fs, fd);
Theodore Ts'oc5423c52001-02-08 05:45:17 +0000683
Theodore Ts'o72ed1262000-11-12 19:32:20 +0000684 ext2fs_close (fs);
685 exit (0);
686}