Coverage Report

Created: 2024-05-05 06:22

/src/e2fsprogs/lib/ext2fs/openfs.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * openfs.c --- open an ext2 filesystem
3
 *
4
 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
5
 *
6
 * %Begin-Header%
7
 * This file may be redistributed under the terms of the GNU Library
8
 * General Public License, version 2.
9
 * %End-Header%
10
 */
11
12
#include "config.h"
13
#include <stdio.h>
14
#include <string.h>
15
#if HAVE_UNISTD_H
16
#include <unistd.h>
17
#endif
18
#include <fcntl.h>
19
#include <time.h>
20
#if HAVE_SYS_STAT_H
21
#include <sys/stat.h>
22
#endif
23
#if HAVE_SYS_TYPES_H
24
#include <sys/types.h>
25
#endif
26
#ifdef HAVE_ERRNO_H
27
#include <errno.h>
28
#endif
29
30
#include "ext2_fs.h"
31
32
#include "ext2fs.h"
33
#include "e2image.h"
34
35
blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, blk64_t group_block,
36
             dgrp_t i)
37
14.7M
{
38
14.7M
  int bg;
39
14.7M
  int has_super = 0, group_zero_adjust = 0;
40
14.7M
  blk64_t ret_blk;
41
42
  /*
43
   * On a bigalloc FS with 1K blocks, block 0 is reserved for non-ext4
44
   * stuff, so adjust for that if we're being asked for group 0.
45
   */
46
14.7M
  if (i == 0 && fs->blocksize == 1024 && EXT2FS_CLUSTER_RATIO(fs) > 1)
47
0
    group_zero_adjust = 1;
48
49
14.7M
  if (!ext2fs_has_feature_meta_bg(fs->super) ||
50
14.7M
      (i < fs->super->s_first_meta_bg))
51
0
    return group_block + i + 1 + group_zero_adjust;
52
53
14.7M
  bg = EXT2_DESC_PER_BLOCK(fs->super) * i;
54
14.7M
  if (ext2fs_bg_has_super(fs, bg))
55
695
    has_super = 1;
56
14.7M
  ret_blk = ext2fs_group_first_block2(fs, bg);
57
  /*
58
   * If group_block is not the normal value, we're trying to use
59
   * the backup group descriptors and superblock --- so use the
60
   * alternate location of the second block group in the
61
   * metablock group.  Ideally we should be testing each bg
62
   * descriptor block individually for correctness, but we don't
63
   * have the infrastructure in place to do that.
64
   */
65
14.7M
  if (group_block != fs->super->s_first_data_block &&
66
14.7M
      ((ret_blk + has_super + fs->super->s_blocks_per_group) <
67
0
       ext2fs_blocks_count(fs->super))) {
68
0
    ret_blk += fs->super->s_blocks_per_group;
69
70
    /*
71
     * If we're going to jump forward a block group, make sure
72
     * that we adjust has_super to account for the next group's
73
     * backup superblock (or lack thereof).
74
     */
75
0
    if (ext2fs_bg_has_super(fs, bg + 1))
76
0
      has_super = 1;
77
0
    else
78
0
      has_super = 0;
79
0
  }
80
14.7M
  return ret_blk + has_super + group_zero_adjust;
81
14.7M
}
82
83
blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
84
0
{
85
0
  return ext2fs_descriptor_block_loc2(fs, group_block, i);
86
0
}
87
88
errcode_t ext2fs_open(const char *name, int flags, int superblock,
89
          unsigned int block_size, io_manager manager,
90
          ext2_filsys *ret_fs)
91
1.23k
{
92
1.23k
  return ext2fs_open2(name, 0, flags, superblock, block_size,
93
1.23k
          manager, ret_fs);
94
1.23k
}
95
96
static void block_sha_map_free_entry(void *data)
97
0
{
98
0
  free(data);
99
0
  return;
100
0
}
101
102
/*
103
 *  Note: if superblock is non-zero, block-size must also be non-zero.
104
 *  Superblock and block_size can be zero to use the default size.
105
 *
106
 * Valid flags for ext2fs_open()
107
 *
108
 *  EXT2_FLAG_RW  - Open the filesystem for read/write.
109
 *  EXT2_FLAG_FORCE - Open the filesystem even if some of the
110
 *        features aren't supported.
111
 *  EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
112
 *  EXT2_FLAG_SKIP_MMP - Open without multi-mount protection check.
113
 *  EXT2_FLAG_64BITS - Allow 64-bit bitfields (needed for large
114
 *        filesystems)
115
 */
116
errcode_t ext2fs_open2(const char *name, const char *io_options,
117
           int flags, int superblock,
118
           unsigned int block_size, io_manager manager,
119
           ext2_filsys *ret_fs)
120
1.23k
{
121
1.23k
  ext2_filsys fs;
122
1.23k
  errcode_t retval;
123
1.23k
  unsigned long i, first_meta_bg;
124
1.23k
  __u32   features;
125
1.23k
  unsigned int  blocks_per_group, io_flags;
126
1.23k
  blk64_t   group_block, blk;
127
1.23k
  char    *dest, *cp;
128
1.23k
  int   group_zero_adjust = 0;
129
1.23k
  unsigned int  inode_size;
130
1.23k
  __u64   groups_cnt;
131
#ifdef WORDS_BIGENDIAN
132
  unsigned int  groups_per_block;
133
  struct ext2_group_desc *gdp;
134
  int   j;
135
#endif
136
1.23k
  char    *time_env;
137
1.23k
  int   csum_retries = 0;
138
139
1.23k
  EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
140
141
1.23k
  retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
142
1.23k
  if (retval)
143
0
    return retval;
144
145
1.23k
  memset(fs, 0, sizeof(struct struct_ext2_filsys));
146
1.23k
  fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
147
1.23k
  fs->flags = flags;
148
  /* don't overwrite sb backups unless flag is explicitly cleared */
149
1.23k
  fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
150
1.23k
  fs->umask = 022;
151
152
1.23k
  time_env = ext2fs_safe_getenv("SOURCE_DATE_EPOCH");
153
1.23k
  if (time_env) {
154
0
    fs->now = strtoul(time_env, NULL, 0);
155
0
    fs->flags2 |= EXT2_FLAG2_USE_FAKE_TIME;
156
1.23k
  } else {
157
1.23k
    time_env = ext2fs_safe_getenv("E2FSPROGS_FAKE_TIME");
158
1.23k
    if (time_env)
159
0
      fs->now = strtoul(time_env, NULL, 0);
160
1.23k
  }
161
162
1.23k
  retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
163
1.23k
  if (retval)
164
0
    goto cleanup;
165
1.23k
  strcpy(fs->device_name, name);
166
1.23k
  cp = strchr(fs->device_name, '?');
167
1.23k
  if (!io_options && cp) {
168
0
    *cp++ = 0;
169
0
    io_options = cp;
170
0
  }
171
172
1.23k
  io_flags = 0;
173
1.23k
  if (flags & EXT2_FLAG_RW)
174
0
    io_flags |= IO_FLAG_RW;
175
1.23k
  if (flags & EXT2_FLAG_EXCLUSIVE)
176
0
    io_flags |= IO_FLAG_EXCLUSIVE;
177
1.23k
  if (flags & EXT2_FLAG_DIRECT_IO)
178
0
    io_flags |= IO_FLAG_DIRECT_IO;
179
1.23k
  if (flags & EXT2_FLAG_THREADS)
180
0
    io_flags |= IO_FLAG_THREADS;
181
1.23k
  retval = manager->open(fs->device_name, io_flags, &fs->io);
182
1.23k
  if (retval)
183
0
    goto cleanup;
184
1.23k
  if (io_options &&
185
1.23k
      (retval = io_channel_set_options(fs->io, io_options)))
186
0
    goto cleanup;
187
1.23k
  fs->image_io = fs->io;
188
1.23k
  fs->io->app_data = fs;
189
1.23k
  retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
190
1.23k
  if (retval)
191
0
    goto cleanup;
192
1.23k
  if (flags & EXT2_FLAG_IMAGE_FILE) {
193
0
    retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
194
0
          &fs->image_header);
195
0
    if (retval)
196
0
      goto cleanup;
197
0
    retval = io_channel_read_blk(fs->io, 0,
198
0
               -(int)sizeof(struct ext2_image_hdr),
199
0
               fs->image_header);
200
0
    if (retval)
201
0
      goto cleanup;
202
0
    if (ext2fs_le32_to_cpu(fs->image_header->magic_number) != EXT2_ET_MAGIC_E2IMAGE)
203
0
      return EXT2_ET_MAGIC_E2IMAGE;
204
0
    superblock = 1;
205
0
    block_size = ext2fs_le32_to_cpu(fs->image_header->fs_blocksize);
206
0
  }
207
208
  /*
209
   * If the user specifies a specific block # for the
210
   * superblock, then he/she must also specify the block size!
211
   * Otherwise, read the master superblock located at offset
212
   * SUPERBLOCK_OFFSET from the start of the partition.
213
   *
214
   * Note: we only save a backup copy of the superblock if we
215
   * are reading the superblock from the primary superblock location.
216
   */
217
1.23k
  if (superblock) {
218
0
    if (!block_size) {
219
0
      retval = EXT2_ET_INVALID_ARGUMENT;
220
0
      goto cleanup;
221
0
    }
222
0
    io_channel_set_blksize(fs->io, block_size);
223
0
    group_block = superblock;
224
0
    fs->orig_super = 0;
225
1.23k
  } else {
226
1.23k
    io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
227
1.23k
    superblock = 1;
228
1.23k
    group_block = 0;
229
1.23k
    retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
230
1.23k
    if (retval)
231
0
      goto cleanup;
232
1.23k
  }
233
1.23k
retry:
234
1.23k
  retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
235
1.23k
             fs->super);
236
1.23k
  if (retval)
237
19
    goto cleanup;
238
1.21k
  if (fs->orig_super)
239
1.21k
    memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
240
241
1.21k
  if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
242
0
    retval = 0;
243
0
    if (!ext2fs_verify_csum_type(fs, fs->super))
244
0
      retval = EXT2_ET_UNKNOWN_CSUM;
245
0
    if (!ext2fs_superblock_csum_verify(fs, fs->super)) {
246
0
      if (csum_retries++ < 3)
247
0
        goto retry;
248
0
      retval = EXT2_ET_SB_CSUM_INVALID;
249
0
    }
250
0
  }
251
252
#ifdef WORDS_BIGENDIAN
253
  fs->flags |= EXT2_FLAG_SWAP_BYTES;
254
  ext2fs_swap_super(fs->super);
255
#else
256
1.21k
  if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
257
0
    retval = EXT2_ET_UNIMPLEMENTED;
258
0
    goto cleanup;
259
0
  }
260
1.21k
#endif
261
262
1.21k
  if (fs->super->s_magic != EXT2_SUPER_MAGIC)
263
36
    retval = EXT2_ET_BAD_MAGIC;
264
1.21k
  if (retval)
265
36
    goto cleanup;
266
267
1.17k
  if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
268
39
    retval = EXT2_ET_REV_TOO_HIGH;
269
39
    goto cleanup;
270
39
  }
271
272
  /*
273
   * Check for feature set incompatibility
274
   */
275
1.14k
  if (!(flags & EXT2_FLAG_FORCE)) {
276
1.14k
    features = fs->super->s_feature_incompat;
277
1.14k
#ifdef EXT2_LIB_SOFTSUPP_INCOMPAT
278
1.14k
    if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
279
0
      features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT;
280
1.14k
#endif
281
1.14k
    if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
282
24
      retval = EXT2_ET_UNSUPP_FEATURE;
283
24
      goto cleanup;
284
24
    }
285
286
1.11k
    features = fs->super->s_feature_ro_compat;
287
1.11k
#ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT
288
1.11k
    if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
289
0
      features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT;
290
1.11k
#endif
291
1.11k
    if ((flags & EXT2_FLAG_RW) &&
292
1.11k
        (features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
293
0
      retval = EXT2_ET_RO_UNSUPP_FEATURE;
294
0
      goto cleanup;
295
0
    }
296
297
1.11k
    if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
298
1.11k
        ext2fs_has_feature_journal_dev(fs->super)) {
299
1
      retval = EXT2_ET_UNSUPP_FEATURE;
300
1
      goto cleanup;
301
1
    }
302
1.11k
  }
303
304
1.11k
  if ((fs->super->s_log_block_size >
305
1.11k
       (unsigned) (EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) ||
306
1.11k
      (fs->super->s_log_cluster_size >
307
1.08k
       (unsigned) (EXT2_MAX_CLUSTER_LOG_SIZE - EXT2_MIN_CLUSTER_LOG_SIZE)) ||
308
1.11k
      (fs->super->s_log_block_size > fs->super->s_log_cluster_size) ||
309
1.11k
      (fs->super->s_log_groups_per_flex > 31)) {
310
60
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
311
60
    goto cleanup;
312
60
  }
313
314
  /*
315
   * bigalloc requires cluster-aware bitfield operations, which at the
316
   * moment means we need EXT2_FLAG_64BITS.
317
   */
318
1.05k
  if (ext2fs_has_feature_bigalloc(fs->super) &&
319
1.05k
      !(flags & EXT2_FLAG_64BITS)) {
320
1
    retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS;
321
1
    goto cleanup;
322
1
  }
323
324
1.05k
  if (!ext2fs_has_feature_bigalloc(fs->super) &&
325
1.05k
      (fs->super->s_log_block_size != fs->super->s_log_cluster_size)) {
326
4
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
327
4
    goto cleanup;
328
4
  }
329
1.05k
  fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
330
1.05k
  inode_size = EXT2_INODE_SIZE(fs->super);
331
1.05k
  if ((inode_size < EXT2_GOOD_OLD_INODE_SIZE) ||
332
1.05k
      (inode_size > fs->blocksize) ||
333
1.05k
      (inode_size & (inode_size - 1))) {
334
26
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
335
26
    goto cleanup;
336
26
  }
337
338
  /* Enforce the block group descriptor size */
339
1.02k
  if (ext2fs_has_feature_64bit(fs->super)) {
340
357
    unsigned desc_size = fs->super->s_desc_size;
341
342
357
    if (desc_size == 0 ||
343
357
        (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS) &&
344
356
         ((desc_size > EXT2_MAX_DESC_SIZE) ||
345
356
          (desc_size < EXT2_MIN_DESC_SIZE_64BIT) ||
346
356
          (desc_size & (desc_size - 1)) != 0))) {
347
27
      retval = EXT2_ET_BAD_DESC_SIZE;
348
27
      goto cleanup;
349
27
    }
350
357
  }
351
352
997
  fs->cluster_ratio_bits = fs->super->s_log_cluster_size -
353
997
    fs->super->s_log_block_size;
354
997
  if (EXT2_BLOCKS_PER_GROUP(fs->super) !=
355
997
      EXT2_CLUSTERS_PER_GROUP(fs->super) << fs->cluster_ratio_bits) {
356
45
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
357
45
    goto cleanup;
358
45
  }
359
952
  fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) *
360
952
               EXT2_INODE_SIZE(fs->super) +
361
952
               EXT2_BLOCK_SIZE(fs->super) - 1) /
362
952
              EXT2_BLOCK_SIZE(fs->super));
363
952
  if (block_size) {
364
0
    if (block_size != fs->blocksize) {
365
0
      retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
366
0
      goto cleanup;
367
0
    }
368
0
  }
369
  /*
370
   * Set the blocksize to the filesystem's blocksize.
371
   */
372
952
  io_channel_set_blksize(fs->io, fs->blocksize);
373
374
  /*
375
   * If this is an external journal device, don't try to read
376
   * the group descriptors, because they're not there.
377
   */
378
952
  if (ext2fs_has_feature_journal_dev(fs->super)) {
379
0
    fs->group_desc_count = 0;
380
0
    *ret_fs = fs;
381
0
    return 0;
382
0
  }
383
384
952
  if (EXT2_INODES_PER_GROUP(fs->super) == 0) {
385
1
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
386
1
    goto cleanup;
387
1
  }
388
  /* Precompute the FS UUID to seed other checksums */
389
951
  ext2fs_init_csum_seed(fs);
390
391
  /*
392
   * Read group descriptors
393
   */
394
951
  blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
395
951
  if (blocks_per_group < 8 ||
396
951
      blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
397
951
      fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super) ||
398
951
           EXT2_DESC_PER_BLOCK(fs->super) == 0 ||
399
951
           fs->super->s_first_data_block >= ext2fs_blocks_count(fs->super)) {
400
34
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
401
34
    goto cleanup;
402
34
  }
403
917
  groups_cnt = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) -
404
917
               fs->super->s_first_data_block,
405
917
               blocks_per_group);
406
917
  if (groups_cnt >> 32) {
407
57
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
408
57
    goto cleanup;
409
57
  }
410
860
  fs->group_desc_count =  groups_cnt;
411
860
  if (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS) &&
412
860
      (__u64)fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) !=
413
860
      fs->super->s_inodes_count) {
414
89
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
415
89
    goto cleanup;
416
89
  }
417
771
  fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
418
771
            EXT2_DESC_PER_BLOCK(fs->super));
419
771
  if (ext2fs_has_feature_meta_bg(fs->super) &&
420
771
      (fs->super->s_first_meta_bg > fs->desc_blocks) &&
421
771
      !(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) {
422
28
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
423
28
    goto cleanup;
424
28
  }
425
743
  if (flags & EXT2_FLAG_SUPER_ONLY)
426
0
    goto skip_read_bg;
427
743
  retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
428
743
        &fs->group_desc);
429
743
  if (retval)
430
0
    goto cleanup;
431
743
  if (!group_block)
432
743
    group_block = fs->super->s_first_data_block;
433
  /*
434
   * On a FS with a 1K blocksize, block 0 is reserved for bootloaders
435
   * so we must increment block numbers to any group 0 items.
436
   *
437
   * However, we cannot touch group_block directly because in the meta_bg
438
   * case, the ext2fs_descriptor_block_loc2() function will interpret
439
   * group_block != s_first_data_block to mean that we want to access the
440
   * backup group descriptors.  This is not what we want if the caller
441
   * set superblock == 0 (i.e. auto-detect the superblock), which is
442
   * what's going on here.
443
   */
444
743
  if (group_block == 0 && fs->blocksize == 1024)
445
272
    group_zero_adjust = 1;
446
743
  dest = (char *) fs->group_desc;
447
#ifdef WORDS_BIGENDIAN
448
  groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
449
#endif
450
743
  if (ext2fs_has_feature_meta_bg(fs->super) &&
451
743
      !(flags & EXT2_FLAG_IMAGE_FILE)) {
452
136
    first_meta_bg = fs->super->s_first_meta_bg;
453
136
    if (first_meta_bg > fs->desc_blocks)
454
0
      first_meta_bg = fs->desc_blocks;
455
136
  } else
456
607
    first_meta_bg = fs->desc_blocks;
457
743
  if (first_meta_bg) {
458
642
    retval = io_channel_read_blk(fs->io, group_block +
459
642
               group_zero_adjust + 1,
460
642
               first_meta_bg, dest);
461
642
    if (retval)
462
39
      goto cleanup;
463
#ifdef WORDS_BIGENDIAN
464
    gdp = (struct ext2_group_desc *) dest;
465
    for (j=0; j < groups_per_block*first_meta_bg; j++) {
466
      gdp = ext2fs_group_desc(fs, fs->group_desc, j);
467
      if (gdp)
468
        ext2fs_swap_group_desc2(fs, gdp);
469
    }
470
#endif
471
603
    dest += fs->blocksize*first_meta_bg;
472
603
  }
473
474
14.7M
  for (i = first_meta_bg ; i < fs->desc_blocks; i++) {
475
14.7M
    blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
476
14.7M
    io_channel_cache_readahead(fs->io, blk, 1);
477
14.7M
  }
478
479
1.28k
  for (i=first_meta_bg ; i < fs->desc_blocks; i++) {
480
614
    blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
481
614
    retval = io_channel_read_blk64(fs->io, blk, 1, dest);
482
614
    if (retval)
483
29
      goto cleanup;
484
#ifdef WORDS_BIGENDIAN
485
    for (j=0; j < groups_per_block; j++) {
486
      gdp = ext2fs_group_desc(fs, fs->group_desc,
487
            i * groups_per_block + j);
488
      if (gdp)
489
        ext2fs_swap_group_desc2(fs, gdp);
490
    }
491
#endif
492
585
    dest += fs->blocksize;
493
585
  }
494
495
675
  fs->stride = fs->super->s_raid_stride;
496
497
  /*
498
   * If recovery is from backup superblock, Clear _UNININT flags &
499
   * reset bg_itable_unused to zero
500
   */
501
675
  if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
502
0
    dgrp_t group;
503
504
0
    for (group = 0; group < fs->group_desc_count; group++) {
505
0
      ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
506
0
      ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
507
0
      ext2fs_bg_itable_unused_set(fs, group, 0);
508
      /* The checksum will be reset later, but fix it here
509
       * anyway to avoid printing a lot of spurious errors. */
510
0
      ext2fs_group_desc_csum_set(fs, group);
511
0
    }
512
0
    if (fs->flags & EXT2_FLAG_RW)
513
0
      ext2fs_mark_super_dirty(fs);
514
0
  }
515
675
skip_read_bg:
516
675
  if (ext2fs_has_feature_mmp(fs->super) &&
517
675
      !(flags & EXT2_FLAG_SKIP_MMP) &&
518
675
      (flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) {
519
0
    retval = ext2fs_mmp_start(fs);
520
0
    if (retval) {
521
0
      fs->flags |= EXT2_FLAG_SKIP_MMP; /* just do cleanup */
522
0
      ext2fs_mmp_stop(fs);
523
0
      goto cleanup;
524
0
    }
525
0
  }
526
527
675
  if (fs->flags & EXT2_FLAG_SHARE_DUP) {
528
0
    fs->block_sha_map = ext2fs_hashmap_create(ext2fs_djb2_hash,
529
0
          block_sha_map_free_entry, 4096);
530
0
    if (!fs->block_sha_map) {
531
0
      retval = EXT2_ET_NO_MEMORY;
532
0
      goto cleanup;
533
0
    }
534
0
    ext2fs_set_feature_shared_blocks(fs->super);
535
0
  }
536
537
675
  if (ext2fs_has_feature_casefold(fs->super))
538
47
    fs->encoding = ext2fs_load_nls_table(fs->super->s_encoding);
539
540
675
  fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
541
675
  *ret_fs = fs;
542
543
675
  return 0;
544
559
cleanup:
545
559
  if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) {
546
559
    ext2fs_free(fs);
547
559
    fs = NULL;
548
559
  }
549
559
  *ret_fs = fs;
550
559
  return retval;
551
675
}
552
553
/*
554
 * Set/get the filesystem data I/O channel.
555
 *
556
 * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
557
 */
558
errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
559
0
{
560
0
  if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
561
0
    return EXT2_ET_NOT_IMAGE_FILE;
562
0
  if (old_io) {
563
0
    *old_io = (fs->image_io == fs->io) ? 0 : fs->io;
564
0
  }
565
0
  return 0;
566
0
}
567
568
errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
569
0
{
570
0
  if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
571
0
    return EXT2_ET_NOT_IMAGE_FILE;
572
0
  fs->io = new_io ? new_io : fs->image_io;
573
0
  return 0;
574
0
}
575
576
errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
577
0
{
578
0
  errcode_t err;
579
580
0
  if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
581
0
    return EXT2_ET_NOT_IMAGE_FILE;
582
0
  err = io_channel_set_blksize(new_io, fs->blocksize);
583
0
  if (err)
584
0
    return err;
585
0
  if ((new_io == fs->image_io) || (new_io == fs->io))
586
0
    return 0;
587
0
  if ((fs->image_io != fs->io) &&
588
0
      fs->image_io)
589
0
    io_channel_close(fs->image_io);
590
0
  if (fs->io)
591
0
    io_channel_close(fs->io);
592
0
  fs->io = fs->image_io = new_io;
593
0
  fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
594
0
    EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
595
0
  fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
596
0
  return 0;
597
0
}