~ubuntu-branches/ubuntu/edgy/e2fsprogs/edgy

« back to all changes in this revision

Viewing changes to misc/e2image.c

  • Committer: Bazaar Package Importer
  • Author(s): Yann Dirson
  • Date: 2002-03-21 23:58:48 UTC
  • Revision ID: james.westby@ubuntu.com-20020321235848-cmmy98hy0nihp922
Tags: upstream-1.27
ImportĀ upstreamĀ versionĀ 1.27

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * e2image.c --- Program which writes an image file backing up
 
3
 * critical metadata for the filesystem.
 
4
 *
 
5
 * Copyright 2000, 2001 by Theodore Ts'o.
 
6
 *
 
7
 * %Begin-Header%
 
8
 * This file may be redistributed under the terms of the GNU Public
 
9
 * License.
 
10
 * %End-Header%
 
11
 */
 
12
 
 
13
#define _LARGEFILE_SOURCE
 
14
#define _LARGEFILE64_SOURCE
 
15
 
 
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
 
 
35
#include "ext2fs/ext2_fs.h"
 
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
 
 
45
const char * program_name = "e2image";
 
46
char * device_name = NULL;
 
47
 
 
48
static void usage(void)
 
49
{
 
50
        fprintf(stderr, _("Usage: %s [-r] device file\n"), program_name);
 
51
        exit (1);
 
52
}
 
53
 
 
54
static void write_header(int fd, struct ext2_image_hdr *hdr, int blocksize)
 
55
{
 
56
        char *header_buf;
 
57
        int actual;
 
58
 
 
59
        header_buf = malloc(blocksize);
 
60
        if (!header_buf) {
 
61
                fprintf(stderr, _("Couldn't allocate header buffer\n"));
 
62
                exit(1);
 
63
        }
 
64
 
 
65
        if (lseek(fd, 0, SEEK_SET) < 0) {
 
66
                perror("lseek while writing header");
 
67
                exit(1);
 
68
        }
 
69
        memset(header_buf, 0, blocksize);
 
70
        
 
71
        if (hdr)
 
72
                memcpy(header_buf, hdr, sizeof(struct ext2_image_hdr));
 
73
        
 
74
        actual = write(fd, header_buf, blocksize);
 
75
        if (actual < 0) {
 
76
                perror("write header");
 
77
                exit(1);
 
78
        }
 
79
        if (actual != blocksize) {
 
80
                fprintf(stderr, _("short write (only %d bytes) for"
 
81
                                  "writing image header"), actual);
 
82
                exit(1);
 
83
        }
 
84
        free(header_buf);
 
85
}
 
86
 
 
87
static void write_image_file(ext2_filsys fs, int fd)
 
88
{
 
89
        struct ext2_image_hdr   hdr;
 
90
        struct stat             st;
 
91
        errcode_t               retval;
 
92
 
 
93
        write_header(fd, NULL, fs->blocksize);
 
94
        memset(&hdr, 0, sizeof(struct ext2_image_hdr));
 
95
 
 
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);
 
104
        retval = ext2fs_image_inode_write(fs, fd,
 
105
                                  (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
 
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
        }
 
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));
 
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
        
 
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);
 
142
        write_header(fd, &hdr, fs->blocksize);
 
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
 
 
163
static errcode_t meta_get_blocks(ext2_filsys fs, ext2_ino_t ino,
 
164
                                  blk_t *blocks)
 
165
{
 
166
        int     i;
 
167
        
 
168
        if ((ino != stashed_ino) || !stashed_inode)
 
169
                return EXT2_ET_CALLBACK_NOTHANDLED;
 
170
 
 
171
        for (i=0; i < EXT2_N_BLOCKS; i++)
 
172
                blocks[i] = stashed_inode->i_block[i];
 
173
        return 0;
 
174
}
 
175
 
 
176
static errcode_t meta_check_directory(ext2_filsys fs, ext2_ino_t ino)
 
177
{
 
178
        if ((ino != stashed_ino) || !stashed_inode)
 
179
                return EXT2_ET_CALLBACK_NOTHANDLED;
 
180
 
 
181
        if (!LINUX_S_ISDIR(stashed_inode->i_mode))
 
182
                return EXT2_ET_NO_DIRECTORY;
 
183
        return 0;
 
184
}
 
185
 
 
186
static errcode_t meta_read_inode(ext2_filsys fs, ext2_ino_t ino,
 
187
                                 struct ext2_inode *inode)
 
188
{
 
189
        if ((ino != stashed_ino) || !stashed_inode)
 
190
                return EXT2_ET_CALLBACK_NOTHANDLED;
 
191
        *inode = *stashed_inode;
 
192
        return 0;
 
193
}
 
194
 
 
195
static void use_inode_shortcuts(ext2_filsys fs, int bool)
 
196
{
 
197
        if (bool) {
 
198
                fs->get_blocks = meta_get_blocks;
 
199
                fs->check_directory = meta_check_directory;
 
200
                fs->read_inode = meta_read_inode;
 
201
                stashed_ino = 0;
 
202
        } else {
 
203
                fs->get_blocks = 0;
 
204
                fs->check_directory = 0;
 
205
                fs->read_inode = 0;
 
206
        }
 
207
}
 
208
 
 
209
static int process_dir_block(ext2_filsys fs, blk_t *block_nr,
 
210
                             e2_blkcnt_t blockcnt, blk_t ref_block,
 
211
                             int ref_offset, void *priv_data)
 
212
{
 
213
        ext2fs_mark_block_bitmap(meta_block_map, *block_nr);
 
214
        return 0;
 
215
}
 
216
 
 
217
static int process_file_block(ext2_filsys fs, blk_t *block_nr,
 
218
                             e2_blkcnt_t blockcnt, blk_t ref_block,
 
219
                             int ref_offset, void *priv_data)
 
220
{
 
221
        if (blockcnt < 0) {
 
222
                ext2fs_mark_block_bitmap(meta_block_map, *block_nr);
 
223
        }
 
224
        return 0;
 
225
}
 
226
 
 
227
static void mark_table_blocks(ext2_filsys fs)
 
228
{
 
229
        blk_t   block, b;
 
230
        int     i,j;
 
231
        
 
232
        block = fs->super->s_first_data_block;
 
233
        /*
 
234
         * Mark primary superblock
 
235
         */
 
236
        ext2fs_mark_block_bitmap(meta_block_map, block);
 
237
                        
 
238
        /*
 
239
         * Mark the primary superblock descriptors
 
240
         */
 
241
        for (j = 0; j < fs->desc_blocks; j++) {
 
242
                ext2fs_mark_block_bitmap(meta_block_map,
 
243
                                         block + j + 1);
 
244
        }
 
245
 
 
246
        for (i = 0; i < fs->group_desc_count; i++) {
 
247
                /*
 
248
                 * Mark the blocks used for the inode table
 
249
                 */
 
250
                if (fs->group_desc[i].bg_inode_table) {
 
251
                        for (j = 0, b = fs->group_desc[i].bg_inode_table;
 
252
                             j < fs->inode_blocks_per_group;
 
253
                             j++, b++)
 
254
                                ext2fs_mark_block_bitmap(meta_block_map, b);
 
255
                }
 
256
                            
 
257
                /*
 
258
                 * Mark block used for the block bitmap 
 
259
                 */
 
260
                if (fs->group_desc[i].bg_block_bitmap) {
 
261
                        ext2fs_mark_block_bitmap(meta_block_map,
 
262
                                     fs->group_desc[i].bg_block_bitmap);
 
263
                }
 
264
                
 
265
                /*
 
266
                 * Mark block used for the inode bitmap 
 
267
                 */
 
268
                if (fs->group_desc[i].bg_inode_bitmap) {
 
269
                        ext2fs_mark_block_bitmap(meta_block_map,
 
270
                                 fs->group_desc[i].bg_inode_bitmap);
 
271
                }
 
272
                block += fs->super->s_blocks_per_group;
 
273
        }
 
274
}
 
275
 
 
276
/*
 
277
 * This function returns 1 if the specified block is all zeros
 
278
 */
 
279
static int check_zero_block(char *buf, int blocksize)
 
280
{
 
281
        char    *cp = buf;
 
282
        int     left = blocksize;
 
283
 
 
284
        while (left > 0) {
 
285
                if (*cp++)
 
286
                        return 0;
 
287
                left--;
 
288
        }
 
289
        return 1;
 
290
}
 
291
 
 
292
static void write_block(int fd, char *buf, int sparse_offset,
 
293
                        int blocksize, blk_t block)
 
294
{
 
295
        int             count;
 
296
        errcode_t       err;
 
297
 
 
298
        if (sparse_offset) {
 
299
#ifdef HAVE_LSEEK64
 
300
                if (lseek64(fd, sparse_offset, SEEK_CUR) < 0)
 
301
                        perror("lseek");
 
302
#else
 
303
                if (lseek(fd, sparse_offset, SEEK_CUR) < 0)
 
304
                        perror("lseek");
 
305
#endif
 
306
        }
 
307
        if (blocksize) {
 
308
                count = write(fd, buf, blocksize);
 
309
                if (count != blocksize) {
 
310
                        if (count == -1)
 
311
                                err = errno;
 
312
                        else
 
313
                                err = 0;
 
314
                        com_err(program_name, err, "error writing block %d", 
 
315
                                block);
 
316
                }
 
317
        }
 
318
}
 
319
 
 
320
static void output_meta_data_blocks(ext2_filsys fs, int fd)
 
321
{
 
322
        errcode_t       retval;
 
323
        blk_t           blk;
 
324
        char            buf[8192], zero_buf[8192];
 
325
        int             sparse = 0;
 
326
 
 
327
        memset(zero_buf, 0, sizeof(zero_buf));
 
328
        for (blk = 0; blk < fs->super->s_blocks_count; blk++) {
 
329
                if ((blk >= fs->super->s_first_data_block) &&
 
330
                    ext2fs_test_block_bitmap(meta_block_map, blk)) {
 
331
                        retval = io_channel_read_blk(fs->io, blk, 1, buf);
 
332
                        if (retval) {
 
333
                                com_err(program_name, retval,
 
334
                                        "error reading block %d", blk);
 
335
                        }
 
336
                        if ((fd != 1) && check_zero_block(buf, fs->blocksize))
 
337
                                goto sparse_write;
 
338
                        write_block(fd, buf, sparse, fs->blocksize, blk);
 
339
                        sparse = 0;
 
340
                } else {
 
341
                sparse_write:
 
342
                        if (fd == 1) {
 
343
                                write_block(fd, zero_buf, 0,
 
344
                                            fs->blocksize, blk);
 
345
                                continue;
 
346
                        }
 
347
                        sparse += fs->blocksize;
 
348
                        if (sparse >= 1024*1024) {
 
349
                                write_block(fd, 0, sparse, 0, 0);
 
350
                                sparse = 0;
 
351
                        }
 
352
                }
 
353
        }
 
354
        write_block(fd, zero_buf, sparse, 1, -1);
 
355
}
 
356
 
 
357
static void write_raw_image_file(ext2_filsys fs, int fd)
 
358
{
 
359
        struct process_block_struct     pb;
 
360
        struct ext2_inode               inode;
 
361
        ext2_inode_scan                 scan;
 
362
        ext2_ino_t                      ino;
 
363
        errcode_t                       retval;
 
364
        char *                          block_buf;
 
365
        
 
366
        retval = ext2fs_allocate_block_bitmap(fs, "in-use block map",
 
367
                                              &meta_block_map);
 
368
        if (retval) {
 
369
                com_err(program_name, retval, "while allocating block bitmap");
 
370
                exit(1);
 
371
        }
 
372
        
 
373
        mark_table_blocks(fs);
 
374
 
 
375
        retval = ext2fs_open_inode_scan(fs, 0, &scan);
 
376
        if (retval) {
 
377
                com_err(program_name, retval, _("while opening inode scan"));
 
378
                exit(1);
 
379
        }
 
380
 
 
381
        block_buf = malloc(fs->blocksize * 3);
 
382
        if (!block_buf) {
 
383
                com_err(program_name, 0, "Can't allocate block buffer");
 
384
                exit(1);
 
385
        }
 
386
        
 
387
        use_inode_shortcuts(fs, 1);
 
388
        stashed_inode = &inode;
 
389
        while (1) {
 
390
                retval = ext2fs_get_next_inode(scan, &ino, &inode);
 
391
                if (retval) {
 
392
                        com_err(program_name, retval,
 
393
                                _("while getting next inode"));
 
394
                        exit(1);
 
395
                }
 
396
                if (ino == 0)
 
397
                        break;
 
398
                if (!inode.i_links_count ||
 
399
                    !ext2fs_inode_has_valid_blocks(&inode))
 
400
                        continue;
 
401
                
 
402
                stashed_ino = ino;
 
403
                if (LINUX_S_ISDIR(inode.i_mode) ||
 
404
                    ino == fs->super->s_journal_inum) {
 
405
                        retval = ext2fs_block_iterate2(fs, ino, 0, 
 
406
                                       block_buf, process_dir_block, &pb);
 
407
                        if (retval) {
 
408
                                com_err(program_name, retval,
 
409
                                        "while iterating over inode %d", 
 
410
                                        ino);
 
411
                                exit(1);
 
412
                        }
 
413
                } else {
 
414
                        if (inode.i_block[EXT2_IND_BLOCK] ||
 
415
                            inode.i_block[EXT2_DIND_BLOCK] ||
 
416
                            inode.i_block[EXT2_TIND_BLOCK]) {
 
417
                                retval = ext2fs_block_iterate2(fs,
 
418
                                       ino, 0, block_buf,
 
419
                                       process_file_block, &pb);
 
420
                                if (retval) {
 
421
                                        com_err(program_name, retval,
 
422
                                        "while iterating over %d", ino);
 
423
                                        exit(1);
 
424
                                }
 
425
                        }
 
426
                        if (inode.i_file_acl) {
 
427
                                ext2fs_mark_block_bitmap(meta_block_map,
 
428
                                                         inode.i_file_acl);
 
429
                        }
 
430
                }
 
431
        }
 
432
        use_inode_shortcuts(fs, 0);
 
433
        output_meta_data_blocks(fs, fd);
 
434
}
 
435
 
 
436
int main (int argc, char ** argv)
 
437
{
 
438
        int c;
 
439
        errcode_t retval;
 
440
        ext2_filsys fs;
 
441
        char *outfn;
 
442
        int open_flag = 0;
 
443
        int raw_flag = 0;
 
444
        int fd = 0;
 
445
 
 
446
#ifdef ENABLE_NLS
 
447
        setlocale(LC_MESSAGES, "");
 
448
        setlocale(LC_CTYPE, "");
 
449
        bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
 
450
        textdomain(NLS_CAT_NAME);
 
451
#endif
 
452
        fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
 
453
                 E2FSPROGS_DATE);
 
454
        if (argc && *argv)
 
455
                program_name = *argv;
 
456
        initialize_ext2_error_table();
 
457
        while ((c = getopt (argc, argv, "r")) != EOF)
 
458
                switch (c) {
 
459
                case 'r':
 
460
                        raw_flag++;
 
461
                        break;
 
462
                default:
 
463
                        usage();
 
464
                }
 
465
        if (optind != argc - 2 )
 
466
                usage();
 
467
        device_name = argv[optind];
 
468
        outfn = argv[optind+1];
 
469
        retval = ext2fs_open (device_name, open_flag, 0, 0,
 
470
                              unix_io_manager, &fs);
 
471
        if (retval) {
 
472
                com_err (program_name, retval, _("while trying to open %s"),
 
473
                         device_name);
 
474
                printf(_("Couldn't find valid filesystem superblock.\n"));
 
475
                exit(1);
 
476
        }
 
477
 
 
478
        if (strcmp(outfn, "-") == 0)
 
479
                fd = 1;
 
480
        else {
 
481
#ifdef HAVE_OPEN64
 
482
                fd = open64(outfn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
 
483
#else
 
484
                fd = open(outfn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
 
485
#endif
 
486
                if (fd < 0) {
 
487
                        com_err(program_name, errno,
 
488
                                _("while trying to open %s"), argv[optind+1]);
 
489
                        exit(1);
 
490
                }
 
491
        }
 
492
 
 
493
        if (raw_flag)
 
494
                write_raw_image_file(fs, fd);
 
495
        else
 
496
                write_image_file(fs, fd);
 
497
 
 
498
        ext2fs_close (fs);
 
499
        exit (0);
 
500
}