Coverage Report

Created: 2026-08-31 06:58

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