]>
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 | { | |
8c6b6483 | 50 | fprintf(stderr, _("Usage: %s [-r] device image_file\n"), program_name); |
72ed1264 TT |
51 | exit (1); |
52 | } | |
53 | ||
095b459d | 54 | static void write_header(int fd, struct ext2_image_hdr *hdr, int blocksize) |
72ed1264 | 55 | { |
095b459d | 56 | char *header_buf; |
72ed1264 TT |
57 | int actual; |
58 | ||
095b459d TT |
59 | header_buf = malloc(blocksize); |
60 | if (!header_buf) { | |
54434927 | 61 | fputs(_("Couldn't allocate header buffer\n"), stderr); |
095b459d TT |
62 | exit(1); |
63 | } | |
64 | ||
72ed1264 TT |
65 | if (lseek(fd, 0, SEEK_SET) < 0) { |
66 | perror("lseek while writing header"); | |
67 | exit(1); | |
68 | } | |
095b459d | 69 | memset(header_buf, 0, blocksize); |
72ed1264 TT |
70 | |
71 | if (hdr) | |
72 | memcpy(header_buf, hdr, sizeof(struct ext2_image_hdr)); | |
73 | ||
095b459d | 74 | actual = write(fd, header_buf, blocksize); |
72ed1264 TT |
75 | if (actual < 0) { |
76 | perror("write header"); | |
77 | exit(1); | |
78 | } | |
095b459d | 79 | if (actual != blocksize) { |
ddc32a04 | 80 | fprintf(stderr, _("short write (only %d bytes) for " |
72ed1264 TT |
81 | "writing image header"), actual); |
82 | exit(1); | |
83 | } | |
095b459d | 84 | free(header_buf); |
72ed1264 TT |
85 | } |
86 | ||
6304baf2 | 87 | static void write_image_file(ext2_filsys fs, int fd) |
72ed1264 | 88 | { |
6304baf2 TT |
89 | struct ext2_image_hdr hdr; |
90 | struct stat st; | |
91 | errcode_t retval; | |
72ed1264 | 92 | |
095b459d | 93 | write_header(fd, NULL, fs->blocksize); |
72ed1264 | 94 | memset(&hdr, 0, sizeof(struct ext2_image_hdr)); |
6304baf2 | 95 | |
72ed1264 TT |
96 | hdr.offset_super = lseek(fd, 0, SEEK_CUR); |
97 | retval = ext2fs_image_super_write(fs, fd, 0); | |
98 | if (retval) { | |
99 | com_err(program_name, retval, _("while writing superblock")); | |
100 | exit(1); | |
101 | } | |
102 | ||
103 | hdr.offset_inode = lseek(fd, 0, SEEK_CUR); | |
6304baf2 TT |
104 | retval = ext2fs_image_inode_write(fs, fd, |
105 | (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0); | |
72ed1264 TT |
106 | if (retval) { |
107 | com_err(program_name, retval, _("while writing inode table")); | |
108 | exit(1); | |
109 | } | |
110 | ||
111 | hdr.offset_blockmap = lseek(fd, 0, SEEK_CUR); | |
112 | retval = ext2fs_image_bitmap_write(fs, fd, 0); | |
113 | if (retval) { | |
114 | com_err(program_name, retval, _("while writing block bitmap")); | |
115 | exit(1); | |
116 | } | |
117 | ||
118 | hdr.offset_inodemap = lseek(fd, 0, SEEK_CUR); | |
119 | retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP); | |
120 | if (retval) { | |
121 | com_err(program_name, retval, _("while writing inode bitmap")); | |
122 | exit(1); | |
123 | } | |
c5423c5b TT |
124 | |
125 | hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE; | |
126 | strcpy(hdr.magic_descriptor, "Ext2 Image 1.0"); | |
127 | gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname)); | |
095b459d TT |
128 | strncat(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)); |
129 | hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0; | |
130 | hdr.fs_blocksize = fs->blocksize; | |
131 | ||
c5423c5b TT |
132 | if (stat(device_name, &st) == 0) |
133 | hdr.fs_device = st.st_rdev; | |
134 | ||
135 | if (fstat(fd, &st) == 0) { | |
136 | hdr.image_device = st.st_dev; | |
137 | hdr.image_inode = st.st_ino; | |
138 | } | |
139 | memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid)); | |
140 | ||
141 | hdr.image_time = time(0); | |
095b459d | 142 | write_header(fd, &hdr, fs->blocksize); |
6304baf2 TT |
143 | } |
144 | ||
145 | /* | |
146 | * These set of functions are used to write a RAW image file. | |
147 | */ | |
148 | ext2fs_block_bitmap meta_block_map; | |
149 | ||
150 | struct process_block_struct { | |
151 | ext2_ino_t ino; | |
152 | }; | |
153 | ||
154 | /* | |
155 | * These subroutines short circuits ext2fs_get_blocks and | |
156 | * ext2fs_check_directory; we use them since we already have the inode | |
157 | * structure, so there's no point in letting the ext2fs library read | |
158 | * the inode again. | |
159 | */ | |
160 | static ino_t stashed_ino = 0; | |
161 | static struct ext2_inode *stashed_inode; | |
162 | ||
54434927 TT |
163 | static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)), |
164 | ext2_ino_t ino, | |
165 | blk_t *blocks) | |
6304baf2 TT |
166 | { |
167 | int i; | |
168 | ||
169 | if ((ino != stashed_ino) || !stashed_inode) | |
170 | return EXT2_ET_CALLBACK_NOTHANDLED; | |
171 | ||
172 | for (i=0; i < EXT2_N_BLOCKS; i++) | |
173 | blocks[i] = stashed_inode->i_block[i]; | |
174 | return 0; | |
175 | } | |
176 | ||
54434927 TT |
177 | static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)), |
178 | ext2_ino_t ino) | |
4ea7bd04 TT |
179 | { |
180 | if ((ino != stashed_ino) || !stashed_inode) | |
181 | return EXT2_ET_CALLBACK_NOTHANDLED; | |
182 | ||
183 | if (!LINUX_S_ISDIR(stashed_inode->i_mode)) | |
184 | return EXT2_ET_NO_DIRECTORY; | |
185 | return 0; | |
186 | } | |
187 | ||
54434927 TT |
188 | static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)), |
189 | ext2_ino_t ino, | |
6304baf2 TT |
190 | struct ext2_inode *inode) |
191 | { | |
192 | if ((ino != stashed_ino) || !stashed_inode) | |
193 | return EXT2_ET_CALLBACK_NOTHANDLED; | |
194 | *inode = *stashed_inode; | |
195 | return 0; | |
196 | } | |
197 | ||
4ea7bd04 TT |
198 | static void use_inode_shortcuts(ext2_filsys fs, int bool) |
199 | { | |
200 | if (bool) { | |
201 | fs->get_blocks = meta_get_blocks; | |
202 | fs->check_directory = meta_check_directory; | |
203 | fs->read_inode = meta_read_inode; | |
204 | stashed_ino = 0; | |
205 | } else { | |
206 | fs->get_blocks = 0; | |
207 | fs->check_directory = 0; | |
208 | fs->read_inode = 0; | |
209 | } | |
210 | } | |
211 | ||
54434927 TT |
212 | static int process_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)), |
213 | blk_t *block_nr, | |
214 | e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), | |
215 | blk_t ref_block EXT2FS_ATTR((unused)), | |
216 | int ref_offset EXT2FS_ATTR((unused)), | |
217 | void *priv_data EXT2FS_ATTR((unused))) | |
6304baf2 TT |
218 | { |
219 | ext2fs_mark_block_bitmap(meta_block_map, *block_nr); | |
220 | return 0; | |
221 | } | |
222 | ||
54434927 TT |
223 | static int process_file_block(ext2_filsys fs EXT2FS_ATTR((unused)), |
224 | blk_t *block_nr, | |
225 | e2_blkcnt_t blockcnt, | |
226 | blk_t ref_block EXT2FS_ATTR((unused)), | |
227 | int ref_offset EXT2FS_ATTR((unused)), | |
228 | void *priv_data EXT2FS_ATTR((unused))) | |
6304baf2 TT |
229 | { |
230 | if (blockcnt < 0) { | |
231 | ext2fs_mark_block_bitmap(meta_block_map, *block_nr); | |
232 | } | |
233 | return 0; | |
234 | } | |
235 | ||
236 | static void mark_table_blocks(ext2_filsys fs) | |
237 | { | |
238 | blk_t block, b; | |
54434927 | 239 | unsigned int i,j; |
6304baf2 TT |
240 | |
241 | block = fs->super->s_first_data_block; | |
242 | /* | |
243 | * Mark primary superblock | |
244 | */ | |
245 | ext2fs_mark_block_bitmap(meta_block_map, block); | |
246 | ||
247 | /* | |
248 | * Mark the primary superblock descriptors | |
249 | */ | |
250 | for (j = 0; j < fs->desc_blocks; j++) { | |
251 | ext2fs_mark_block_bitmap(meta_block_map, | |
c046ac7f | 252 | ext2fs_descriptor_block_loc(fs, block, j)); |
6304baf2 TT |
253 | } |
254 | ||
255 | for (i = 0; i < fs->group_desc_count; i++) { | |
256 | /* | |
257 | * Mark the blocks used for the inode table | |
258 | */ | |
259 | if (fs->group_desc[i].bg_inode_table) { | |
260 | for (j = 0, b = fs->group_desc[i].bg_inode_table; | |
54434927 | 261 | j < (unsigned) fs->inode_blocks_per_group; |
6304baf2 TT |
262 | j++, b++) |
263 | ext2fs_mark_block_bitmap(meta_block_map, b); | |
264 | } | |
265 | ||
266 | /* | |
267 | * Mark block used for the block bitmap | |
268 | */ | |
269 | if (fs->group_desc[i].bg_block_bitmap) { | |
270 | ext2fs_mark_block_bitmap(meta_block_map, | |
271 | fs->group_desc[i].bg_block_bitmap); | |
272 | } | |
273 | ||
274 | /* | |
275 | * Mark block used for the inode bitmap | |
276 | */ | |
277 | if (fs->group_desc[i].bg_inode_bitmap) { | |
278 | ext2fs_mark_block_bitmap(meta_block_map, | |
279 | fs->group_desc[i].bg_inode_bitmap); | |
280 | } | |
281 | block += fs->super->s_blocks_per_group; | |
282 | } | |
283 | } | |
284 | ||
285 | /* | |
286 | * This function returns 1 if the specified block is all zeros | |
287 | */ | |
288 | static int check_zero_block(char *buf, int blocksize) | |
289 | { | |
290 | char *cp = buf; | |
291 | int left = blocksize; | |
292 | ||
293 | while (left > 0) { | |
294 | if (*cp++) | |
295 | return 0; | |
296 | left--; | |
297 | } | |
298 | return 1; | |
299 | } | |
300 | ||
e3ef3502 TT |
301 | static void write_block(int fd, char *buf, int sparse_offset, |
302 | int blocksize, blk_t block) | |
6304baf2 TT |
303 | { |
304 | int count; | |
305 | errcode_t err; | |
306 | ||
e3ef3502 TT |
307 | if (sparse_offset) { |
308 | #ifdef HAVE_LSEEK64 | |
309 | if (lseek64(fd, sparse_offset, SEEK_CUR) < 0) | |
310 | perror("lseek"); | |
311 | #else | |
312 | if (lseek(fd, sparse_offset, SEEK_CUR) < 0) | |
313 | perror("lseek"); | |
314 | #endif | |
315 | } | |
316 | if (blocksize) { | |
317 | count = write(fd, buf, blocksize); | |
318 | if (count != blocksize) { | |
319 | if (count == -1) | |
320 | err = errno; | |
321 | else | |
322 | err = 0; | |
323 | com_err(program_name, err, "error writing block %d", | |
324 | block); | |
325 | } | |
6304baf2 TT |
326 | } |
327 | } | |
328 | ||
4ea7bd04 | 329 | static void output_meta_data_blocks(ext2_filsys fs, int fd) |
6304baf2 TT |
330 | { |
331 | errcode_t retval; | |
332 | blk_t blk; | |
333 | char buf[8192], zero_buf[8192]; | |
e3ef3502 | 334 | int sparse = 0; |
6304baf2 TT |
335 | |
336 | memset(zero_buf, 0, sizeof(zero_buf)); | |
337 | for (blk = 0; blk < fs->super->s_blocks_count; blk++) { | |
338 | if ((blk >= fs->super->s_first_data_block) && | |
339 | ext2fs_test_block_bitmap(meta_block_map, blk)) { | |
340 | retval = io_channel_read_blk(fs->io, blk, 1, buf); | |
341 | if (retval) { | |
342 | com_err(program_name, retval, | |
343 | "error reading block %d", blk); | |
344 | } | |
345 | if ((fd != 1) && check_zero_block(buf, fs->blocksize)) | |
346 | goto sparse_write; | |
e3ef3502 TT |
347 | write_block(fd, buf, sparse, fs->blocksize, blk); |
348 | sparse = 0; | |
6304baf2 TT |
349 | } else { |
350 | sparse_write: | |
351 | if (fd == 1) { | |
e3ef3502 TT |
352 | write_block(fd, zero_buf, 0, |
353 | fs->blocksize, blk); | |
6304baf2 TT |
354 | continue; |
355 | } | |
e3ef3502 TT |
356 | sparse += fs->blocksize; |
357 | if (sparse >= 1024*1024) { | |
358 | write_block(fd, 0, sparse, 0, 0); | |
359 | sparse = 0; | |
360 | } | |
6304baf2 TT |
361 | } |
362 | } | |
e3ef3502 | 363 | write_block(fd, zero_buf, sparse, 1, -1); |
6304baf2 TT |
364 | } |
365 | ||
366 | static void write_raw_image_file(ext2_filsys fs, int fd) | |
367 | { | |
368 | struct process_block_struct pb; | |
369 | struct ext2_inode inode; | |
370 | ext2_inode_scan scan; | |
371 | ext2_ino_t ino; | |
372 | errcode_t retval; | |
373 | char * block_buf; | |
374 | ||
375 | retval = ext2fs_allocate_block_bitmap(fs, "in-use block map", | |
376 | &meta_block_map); | |
377 | if (retval) { | |
378 | com_err(program_name, retval, "while allocating block bitmap"); | |
379 | exit(1); | |
380 | } | |
381 | ||
382 | mark_table_blocks(fs); | |
383 | ||
384 | retval = ext2fs_open_inode_scan(fs, 0, &scan); | |
385 | if (retval) { | |
386 | com_err(program_name, retval, _("while opening inode scan")); | |
387 | exit(1); | |
388 | } | |
389 | ||
390 | block_buf = malloc(fs->blocksize * 3); | |
391 | if (!block_buf) { | |
392 | com_err(program_name, 0, "Can't allocate block buffer"); | |
393 | exit(1); | |
394 | } | |
395 | ||
4ea7bd04 | 396 | use_inode_shortcuts(fs, 1); |
6304baf2 TT |
397 | stashed_inode = &inode; |
398 | while (1) { | |
399 | retval = ext2fs_get_next_inode(scan, &ino, &inode); | |
3432a916 TT |
400 | if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) |
401 | continue; | |
6304baf2 TT |
402 | if (retval) { |
403 | com_err(program_name, retval, | |
404 | _("while getting next inode")); | |
405 | exit(1); | |
406 | } | |
407 | if (ino == 0) | |
408 | break; | |
ed909bbe TT |
409 | if (!inode.i_links_count) |
410 | continue; | |
411 | if (inode.i_file_acl) { | |
412 | ext2fs_mark_block_bitmap(meta_block_map, | |
413 | inode.i_file_acl); | |
414 | } | |
415 | if (!ext2fs_inode_has_valid_blocks(&inode)) | |
6304baf2 TT |
416 | continue; |
417 | ||
418 | stashed_ino = ino; | |
1c1e0049 | 419 | if (LINUX_S_ISDIR(inode.i_mode) || |
eca53e3c TT |
420 | (LINUX_S_ISLNK(inode.i_mode) && |
421 | ext2fs_inode_has_valid_blocks(&inode)) || | |
1c1e0049 | 422 | ino == fs->super->s_journal_inum) { |
6304baf2 TT |
423 | retval = ext2fs_block_iterate2(fs, ino, 0, |
424 | block_buf, process_dir_block, &pb); | |
425 | if (retval) { | |
426 | com_err(program_name, retval, | |
427 | "while iterating over inode %d", | |
428 | ino); | |
429 | exit(1); | |
430 | } | |
431 | } else { | |
432 | if (inode.i_block[EXT2_IND_BLOCK] || | |
433 | inode.i_block[EXT2_DIND_BLOCK] || | |
434 | inode.i_block[EXT2_TIND_BLOCK]) { | |
435 | retval = ext2fs_block_iterate2(fs, | |
436 | ino, 0, block_buf, | |
437 | process_file_block, &pb); | |
438 | if (retval) { | |
439 | com_err(program_name, retval, | |
440 | "while iterating over %d", ino); | |
441 | exit(1); | |
442 | } | |
443 | } | |
6304baf2 TT |
444 | } |
445 | } | |
4ea7bd04 | 446 | use_inode_shortcuts(fs, 0); |
6304baf2 TT |
447 | output_meta_data_blocks(fs, fd); |
448 | } | |
449 | ||
8c6b6483 TT |
450 | void install_image(char *device_name, char *image_fn, int raw_flag) |
451 | { | |
452 | int c; | |
453 | errcode_t retval; | |
454 | ext2_filsys fs; | |
455 | int open_flag = EXT2_FLAG_IMAGE_FILE; | |
456 | int fd = 0; | |
457 | io_manager io_ptr; | |
458 | io_channel io, image_io; | |
459 | ||
460 | if (raw_flag) { | |
461 | com_err(program_name, 0, "Raw images cannot be installed"); | |
462 | exit(1); | |
463 | } | |
464 | ||
465 | #ifdef CONFIG_TESTIO_DEBUG | |
466 | io_ptr = test_io_manager; | |
467 | test_io_backing_manager = unix_io_manager; | |
468 | #else | |
469 | io_ptr = unix_io_manager; | |
470 | #endif | |
471 | ||
472 | retval = ext2fs_open (image_fn, open_flag, 0, 0, | |
473 | io_ptr, &fs); | |
474 | if (retval) { | |
475 | com_err (program_name, retval, _("while trying to open %s"), | |
476 | image_fn); | |
477 | exit(1); | |
478 | } | |
479 | ||
480 | retval = ext2fs_read_bitmaps (fs); | |
481 | if (retval) { | |
482 | com_err(program_name, retval, "error reading bitmaps"); | |
483 | exit(1); | |
484 | } | |
485 | ||
486 | ||
487 | fd = open(image_fn, O_RDONLY); | |
488 | if (fd < 0) { | |
489 | perror(image_fn); | |
490 | exit(1); | |
491 | } | |
492 | ||
493 | retval = io_ptr->open(device_name, IO_FLAG_RW, &io); | |
494 | if (retval) { | |
495 | com_err(device_name, 0, "while opening device file"); | |
496 | exit(1); | |
497 | } | |
498 | ||
499 | image_io = fs->io; | |
500 | ||
501 | ext2fs_rewrite_to_io(fs, io); | |
502 | ||
503 | if (lseek(fd, fs->image_header->offset_inode, SEEK_SET) < 0) { | |
504 | perror("lseek"); | |
505 | exit(1); | |
506 | } | |
507 | ||
508 | retval = ext2fs_image_inode_read(fs, fd, 0); | |
509 | if (retval) { | |
510 | com_err(image_fn, 0, "while restoring the image table"); | |
511 | exit(1); | |
512 | } | |
513 | ||
514 | ext2fs_close (fs); | |
515 | exit (0); | |
516 | } | |
517 | ||
6304baf2 TT |
518 | int main (int argc, char ** argv) |
519 | { | |
520 | int c; | |
521 | errcode_t retval; | |
522 | ext2_filsys fs; | |
8c6b6483 | 523 | char *image_fn; |
6304baf2 TT |
524 | int open_flag = 0; |
525 | int raw_flag = 0; | |
8c6b6483 | 526 | int install_flag = 0; |
6304baf2 TT |
527 | int fd = 0; |
528 | ||
529 | #ifdef ENABLE_NLS | |
530 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 531 | setlocale(LC_CTYPE, ""); |
6304baf2 TT |
532 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
533 | textdomain(NLS_CAT_NAME); | |
534 | #endif | |
0f8973fb TT |
535 | fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION, |
536 | E2FSPROGS_DATE); | |
6304baf2 TT |
537 | if (argc && *argv) |
538 | program_name = *argv; | |
539 | initialize_ext2_error_table(); | |
8c6b6483 | 540 | while ((c = getopt (argc, argv, "rI")) != EOF) |
6304baf2 TT |
541 | switch (c) { |
542 | case 'r': | |
543 | raw_flag++; | |
544 | break; | |
8c6b6483 TT |
545 | case 'I': |
546 | install_flag++; | |
547 | break; | |
6304baf2 TT |
548 | default: |
549 | usage(); | |
550 | } | |
551 | if (optind != argc - 2 ) | |
552 | usage(); | |
553 | device_name = argv[optind]; | |
8c6b6483 TT |
554 | image_fn = argv[optind+1]; |
555 | ||
556 | if (install_flag) { | |
557 | install_image(device_name, image_fn, raw_flag); | |
558 | return; | |
559 | } | |
560 | ||
6304baf2 TT |
561 | retval = ext2fs_open (device_name, open_flag, 0, 0, |
562 | unix_io_manager, &fs); | |
563 | if (retval) { | |
564 | com_err (program_name, retval, _("while trying to open %s"), | |
565 | device_name); | |
54434927 | 566 | fputs(_("Couldn't find valid filesystem superblock.\n"), stdout); |
6304baf2 TT |
567 | exit(1); |
568 | } | |
569 | ||
8c6b6483 | 570 | if (strcmp(image_fn, "-") == 0) |
1c1e0049 TT |
571 | fd = 1; |
572 | else { | |
6304baf2 | 573 | #ifdef HAVE_OPEN64 |
8c6b6483 | 574 | fd = open64(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600); |
6304baf2 | 575 | #else |
8c6b6483 | 576 | fd = open(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600); |
6304baf2 | 577 | #endif |
1c1e0049 TT |
578 | if (fd < 0) { |
579 | com_err(program_name, errno, | |
580 | _("while trying to open %s"), argv[optind+1]); | |
581 | exit(1); | |
582 | } | |
6304baf2 TT |
583 | } |
584 | ||
585 | if (raw_flag) | |
586 | write_raw_image_file(fs, fd); | |
587 | else | |
588 | write_image_file(fs, fd); | |
c5423c5b | 589 | |
72ed1264 TT |
590 | ext2fs_close (fs); |
591 | exit (0); | |
592 | } |