Coverage Report

Created: 2026-09-04 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/e2fsprogs/lib/ext2fs/openfs.c
Line
Count
Source
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
10.0M
{
38
10.0M
  int bg;
39
10.0M
  int has_super = 0, group_zero_adjust = 0;
40
10.0M
  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
10.0M
  if (i == 0 && fs->blocksize == 1024 && EXT2FS_CLUSTER_RATIO(fs) > 1)
47
0
    group_zero_adjust = 1;
48
49
10.0M
  if (!ext2fs_has_feature_meta_bg(fs->super) ||
50
10.0M
      (i < fs->super->s_first_meta_bg))
51
0
    return group_block + i + 1 + group_zero_adjust;
52
53
10.0M
  bg = EXT2_DESC_PER_BLOCK(fs->super) * i;
54
10.0M
  if (ext2fs_bg_has_super(fs, bg))
55
1.04M
    has_super = 1;
56
10.0M
  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
10.0M
  if (group_block != fs->super->s_first_data_block &&
66
0
      ((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
10.0M
  return ret_blk + has_super + group_zero_adjust;
81
10.0M
}
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
556
{
92
556
  return ext2fs_open2(name, 0, flags, superblock, block_size,
93
556
          manager, ret_fs);
94
556
}
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
556
{
121
556
  ext2_filsys fs;
122
556
  errcode_t retval;
123
556
  unsigned long i, first_meta_bg;
124
556
  __u32   features;
125
556
  unsigned int  blocks_per_group, io_flags;
126
556
  blk64_t   group_block, blk;
127
556
  char    *dest, *cp;
128
556
  int   group_zero_adjust = 0;
129
556
  unsigned int  inode_size;
130
556
  __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
556
  char    *time_env;
137
556
  int   csum_retries = 0;
138
139
556
  EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
140
141
556
  retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
142
556
  if (retval)
143
0
    return retval;
144
145
556
  memset(fs, 0, sizeof(struct struct_ext2_filsys));
146
556
  fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
147
556
  fs->flags = flags;
148
  /* don't overwrite sb backups unless flag is explicitly cleared */
149
556
  fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
150
556
  fs->umask = 022;
151
152
556
  time_env = ext2fs_safe_getenv("SOURCE_DATE_EPOCH");
153
556
  if (time_env) {
154
0
    fs->now = strtoul(time_env, NULL, 0);
155
0
    fs->flags2 |= EXT2_FLAG2_USE_FAKE_TIME;
156
556
  } else {
157
556
    time_env = ext2fs_safe_getenv("E2FSPROGS_FAKE_TIME");
158
556
    if (time_env)
159
0
      fs->now = strtoul(time_env, NULL, 0);
160
556
  }
161
162
556
  retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
163
556
  if (retval)
164
0
    goto cleanup;
165
556
  strcpy(fs->device_name, name);
166
556
  cp = strchr(fs->device_name, '?');
167
556
  if (!io_options && cp) {
168
0
    *cp++ = 0;
169
0
    io_options = cp;
170
0
  }
171
172
556
  io_flags = 0;
173
556
  if (flags & EXT2_FLAG_RW)
174
0
    io_flags |= IO_FLAG_RW;
175
556
  if (flags & EXT2_FLAG_EXCLUSIVE)
176
0
    io_flags |= IO_FLAG_EXCLUSIVE;
177
556
  if (flags & EXT2_FLAG_DIRECT_IO)
178
0
    io_flags |= IO_FLAG_DIRECT_IO;
179
556
  if (flags & EXT2_FLAG_THREADS)
180
0
    io_flags |= IO_FLAG_THREADS;
181
556
  retval = manager->open(fs->device_name, io_flags, &fs->io);
182
556
  if (retval)
183
0
    goto cleanup;
184
556
  if (io_options &&
185
0
      (retval = io_channel_set_options(fs->io, io_options)))
186
0
    goto cleanup;
187
556
  fs->image_io = fs->io;
188
556
  fs->io->app_data = fs;
189
556
  retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
190
556
  if (retval)
191
0
    goto cleanup;
192
556
  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
556
  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
556
  } else {
226
556
    io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
227
556
    superblock = 1;
228
556
    group_block = 0;
229
556
    retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
230
556
    if (retval)
231
0
      goto cleanup;
232
556
  }
233
556
retry:
234
556
  retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
235
556
             fs->super);
236
556
  if (retval)
237
0
    goto cleanup;
238
556
  if (fs->orig_super)
239
556
    memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
240
241
556
  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
556
  if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
257
0
    retval = EXT2_ET_UNIMPLEMENTED;
258
0
    goto cleanup;
259
0
  }
260
556
#endif
261
262
556
  if (fs->super->s_magic != EXT2_SUPER_MAGIC)
263
31
    retval = EXT2_ET_BAD_MAGIC;
264
556
  if (retval)
265
31
    goto cleanup;
266
267
525
  if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
268
0
    retval = EXT2_ET_REV_TOO_HIGH;
269
0
    goto cleanup;
270
0
  }
271
272
  /*
273
   * Check for feature set incompatibility
274
   */
275
525
  if (!(flags & EXT2_FLAG_FORCE)) {
276
525
    features = fs->super->s_feature_incompat;
277
525
#ifdef EXT2_LIB_SOFTSUPP_INCOMPAT
278
525
    if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
279
0
      features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT;
280
525
#endif
281
525
    if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
282
4
      retval = EXT2_ET_UNSUPP_FEATURE;
283
4
      goto cleanup;
284
4
    }
285
286
521
    features = fs->super->s_feature_ro_compat;
287
521
#ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT
288
521
    if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
289
0
      features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT;
290
521
#endif
291
521
    if ((flags & EXT2_FLAG_RW) &&
292
0
        (features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
293
0
      retval = EXT2_ET_RO_UNSUPP_FEATURE;
294
0
      goto cleanup;
295
0
    }
296
297
521
    if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
298
521
        ext2fs_has_feature_journal_dev(fs->super)) {
299
0
      retval = EXT2_ET_UNSUPP_FEATURE;
300
0
      goto cleanup;
301
0
    }
302
521
  }
303
304
521
  if ((fs->super->s_log_block_size >
305
521
       (unsigned) (EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) ||
306
520
      (fs->super->s_log_cluster_size >
307
520
       (unsigned) (EXT2_MAX_CLUSTER_LOG_SIZE - EXT2_MIN_CLUSTER_LOG_SIZE)) ||
308
520
      (fs->super->s_log_block_size > fs->super->s_log_cluster_size) ||
309
520
      (fs->super->s_log_groups_per_flex > 31)) {
310
1
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
311
1
    goto cleanup;
312
1
  }
313
314
  /*
315
   * bigalloc requires cluster-aware bitfield operations, which at the
316
   * moment means we need EXT2_FLAG_64BITS.
317
   */
318
520
  if (ext2fs_has_feature_bigalloc(fs->super) &&
319
0
      !(flags & EXT2_FLAG_64BITS)) {
320
0
    retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS;
321
0
    goto cleanup;
322
0
  }
323
324
520
  if (!ext2fs_has_feature_bigalloc(fs->super) &&
325
520
      (fs->super->s_log_block_size != fs->super->s_log_cluster_size)) {
326
0
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
327
0
    goto cleanup;
328
0
  }
329
520
  fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
330
520
  inode_size = EXT2_INODE_SIZE(fs->super);
331
520
  if ((inode_size < EXT2_GOOD_OLD_INODE_SIZE) ||
332
520
      (inode_size > fs->blocksize) ||
333
520
      (inode_size & (inode_size - 1))) {
334
0
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
335
0
    goto cleanup;
336
0
  }
337
338
  /* Enforce the block group descriptor size */
339
520
  if (ext2fs_has_feature_64bit(fs->super)) {
340
120
    unsigned desc_size = fs->super->s_desc_size;
341
342
120
    if (desc_size == 0 ||
343
120
        (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS) &&
344
120
         ((desc_size > EXT2_MAX_DESC_SIZE) ||
345
120
          (desc_size < EXT2_MIN_DESC_SIZE_64BIT) ||
346
120
          (desc_size & (desc_size - 1)) != 0))) {
347
3
      retval = EXT2_ET_BAD_DESC_SIZE;
348
3
      goto cleanup;
349
3
    }
350
120
  }
351
352
517
  fs->cluster_ratio_bits = fs->super->s_log_cluster_size -
353
517
    fs->super->s_log_block_size;
354
517
  if (EXT2_BLOCKS_PER_GROUP(fs->super) !=
355
517
      EXT2_CLUSTERS_PER_GROUP(fs->super) << fs->cluster_ratio_bits) {
356
0
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
357
0
    goto cleanup;
358
0
  }
359
517
  fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) *
360
517
               EXT2_INODE_SIZE(fs->super) +
361
517
               EXT2_BLOCK_SIZE(fs->super) - 1) /
362
517
              EXT2_BLOCK_SIZE(fs->super));
363
517
  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
517
  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
517
  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
517
  if (EXT2_INODES_PER_GROUP(fs->super) == 0) {
385
0
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
386
0
    goto cleanup;
387
0
  }
388
  /* Precompute the FS UUID to seed other checksums */
389
517
  ext2fs_init_csum_seed(fs);
390
391
  /*
392
   * Read group descriptors
393
   */
394
517
  blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
395
517
  if (blocks_per_group < 8 ||
396
517
      blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
397
517
      fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super) ||
398
517
           EXT2_DESC_PER_BLOCK(fs->super) == 0 ||
399
517
           fs->super->s_first_data_block >= ext2fs_blocks_count(fs->super)) {
400
0
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
401
0
    goto cleanup;
402
0
  }
403
517
  groups_cnt = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) -
404
517
               fs->super->s_first_data_block,
405
517
               blocks_per_group);
406
517
  if (groups_cnt >> 32) {
407
0
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
408
0
    goto cleanup;
409
0
  }
410
517
  fs->group_desc_count =  groups_cnt;
411
517
  if (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS) &&
412
517
      (__u64)fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) !=
413
517
      fs->super->s_inodes_count) {
414
3
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
415
3
    goto cleanup;
416
3
  }
417
514
  fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
418
514
            EXT2_DESC_PER_BLOCK(fs->super));
419
514
  if (ext2fs_has_feature_meta_bg(fs->super) &&
420
154
      (fs->super->s_first_meta_bg > fs->desc_blocks) &&
421
4
      !(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) {
422
4
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
423
4
    goto cleanup;
424
4
  }
425
510
  if (flags & EXT2_FLAG_SUPER_ONLY)
426
0
    goto skip_read_bg;
427
510
  retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
428
510
        &fs->group_desc);
429
510
  if (retval)
430
0
    goto cleanup;
431
510
  if (!group_block)
432
510
    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
510
  if (group_block == 0 && fs->blocksize == 1024)
445
317
    group_zero_adjust = 1;
446
510
  dest = (char *) fs->group_desc;
447
#ifdef WORDS_BIGENDIAN
448
  groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
449
#endif
450
510
  if (ext2fs_has_feature_meta_bg(fs->super) &&
451
150
      !(flags & EXT2_FLAG_IMAGE_FILE)) {
452
150
    first_meta_bg = fs->super->s_first_meta_bg;
453
150
    if (first_meta_bg > fs->desc_blocks)
454
0
      first_meta_bg = fs->desc_blocks;
455
150
  } else
456
360
    first_meta_bg = fs->desc_blocks;
457
510
  if (first_meta_bg) {
458
417
    retval = io_channel_read_blk(fs->io, group_block +
459
417
               group_zero_adjust + 1,
460
417
               first_meta_bg, dest);
461
417
    if (retval)
462
18
      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
399
    dest += fs->blocksize*first_meta_bg;
472
399
  }
473
474
10.0M
  for (i = first_meta_bg ; i < fs->desc_blocks; i++) {
475
10.0M
    blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
476
10.0M
    io_channel_cache_readahead(fs->io, blk, 1);
477
10.0M
  }
478
479
1.12k
  for (i=first_meta_bg ; i < fs->desc_blocks; i++) {
480
659
    blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
481
659
    retval = io_channel_read_blk64(fs->io, blk, 1, dest);
482
659
    if (retval)
483
23
      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
636
    dest += fs->blocksize;
493
636
  }
494
495
469
  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
469
  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
469
skip_read_bg:
516
469
  if (ext2fs_has_feature_mmp(fs->super) &&
517
96
      !(flags & EXT2_FLAG_SKIP_MMP) &&
518
96
      (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
469
  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
469
  if (ext2fs_has_feature_casefold(fs->super))
538
18
    fs->encoding = ext2fs_load_nls_table(fs->super->s_encoding);
539
540
469
  fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
541
469
  *ret_fs = fs;
542
543
469
  return 0;
544
87
cleanup:
545
87
  if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) {
546
87
    ext2fs_free(fs);
547
87
    fs = NULL;
548
87
  }
549
87
  *ret_fs = fs;
550
87
  return retval;
551
469
}
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
}