Coverage Report

Created: 2023-09-25 06:05

/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
19.7M
{
38
19.7M
  int bg;
39
19.7M
  int has_super = 0, group_zero_adjust = 0;
40
19.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
19.7M
  if (i == 0 && fs->blocksize == 1024 && EXT2FS_CLUSTER_RATIO(fs) > 1)
47
0
    group_zero_adjust = 1;
48
49
19.7M
  if (!ext2fs_has_feature_meta_bg(fs->super) ||
50
19.7M
      (i < fs->super->s_first_meta_bg))
51
0
    return group_block + i + 1 + group_zero_adjust;
52
53
19.7M
  bg = EXT2_DESC_PER_BLOCK(fs->super) * i;
54
19.7M
  if (ext2fs_bg_has_super(fs, bg))
55
2.09M
    has_super = 1;
56
19.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
19.7M
  if (group_block != fs->super->s_first_data_block &&
66
19.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
19.7M
  return ret_blk + has_super + group_zero_adjust;
81
19.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
885
{
92
885
  return ext2fs_open2(name, 0, flags, superblock, block_size,
93
885
          manager, ret_fs);
94
885
}
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
885
{
121
885
  ext2_filsys fs;
122
885
  errcode_t retval;
123
885
  unsigned long i, first_meta_bg;
124
885
  __u32   features;
125
885
  unsigned int  blocks_per_group, io_flags;
126
885
  blk64_t   group_block, blk;
127
885
  char    *dest, *cp;
128
885
  int   group_zero_adjust = 0;
129
885
  unsigned int  inode_size;
130
885
  __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
885
  char    *time_env;
137
885
  int   csum_retries = 0;
138
139
885
  EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
140
141
885
  retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
142
885
  if (retval)
143
0
    return retval;
144
145
885
  memset(fs, 0, sizeof(struct struct_ext2_filsys));
146
885
  fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
147
885
  fs->flags = flags;
148
  /* don't overwrite sb backups unless flag is explicitly cleared */
149
885
  fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
150
885
  fs->umask = 022;
151
152
885
  time_env = getenv("E2FSPROGS_FAKE_TIME");
153
885
  if (time_env)
154
0
    fs->now = strtoul(time_env, NULL, 0);
155
156
885
  retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
157
885
  if (retval)
158
0
    goto cleanup;
159
885
  strcpy(fs->device_name, name);
160
885
  cp = strchr(fs->device_name, '?');
161
885
  if (!io_options && cp) {
162
0
    *cp++ = 0;
163
0
    io_options = cp;
164
0
  }
165
166
885
  io_flags = 0;
167
885
  if (flags & EXT2_FLAG_RW)
168
0
    io_flags |= IO_FLAG_RW;
169
885
  if (flags & EXT2_FLAG_EXCLUSIVE)
170
0
    io_flags |= IO_FLAG_EXCLUSIVE;
171
885
  if (flags & EXT2_FLAG_DIRECT_IO)
172
0
    io_flags |= IO_FLAG_DIRECT_IO;
173
885
  if (flags & EXT2_FLAG_THREADS)
174
0
    io_flags |= IO_FLAG_THREADS;
175
885
  retval = manager->open(fs->device_name, io_flags, &fs->io);
176
885
  if (retval)
177
0
    goto cleanup;
178
885
  if (io_options &&
179
885
      (retval = io_channel_set_options(fs->io, io_options)))
180
0
    goto cleanup;
181
885
  fs->image_io = fs->io;
182
885
  fs->io->app_data = fs;
183
885
  retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
184
885
  if (retval)
185
0
    goto cleanup;
186
885
  if (flags & EXT2_FLAG_IMAGE_FILE) {
187
0
    retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
188
0
          &fs->image_header);
189
0
    if (retval)
190
0
      goto cleanup;
191
0
    retval = io_channel_read_blk(fs->io, 0,
192
0
               -(int)sizeof(struct ext2_image_hdr),
193
0
               fs->image_header);
194
0
    if (retval)
195
0
      goto cleanup;
196
0
    if (ext2fs_le32_to_cpu(fs->image_header->magic_number) != EXT2_ET_MAGIC_E2IMAGE)
197
0
      return EXT2_ET_MAGIC_E2IMAGE;
198
0
    superblock = 1;
199
0
    block_size = ext2fs_le32_to_cpu(fs->image_header->fs_blocksize);
200
0
  }
201
202
  /*
203
   * If the user specifies a specific block # for the
204
   * superblock, then he/she must also specify the block size!
205
   * Otherwise, read the master superblock located at offset
206
   * SUPERBLOCK_OFFSET from the start of the partition.
207
   *
208
   * Note: we only save a backup copy of the superblock if we
209
   * are reading the superblock from the primary superblock location.
210
   */
211
885
  if (superblock) {
212
0
    if (!block_size) {
213
0
      retval = EXT2_ET_INVALID_ARGUMENT;
214
0
      goto cleanup;
215
0
    }
216
0
    io_channel_set_blksize(fs->io, block_size);
217
0
    group_block = superblock;
218
0
    fs->orig_super = 0;
219
885
  } else {
220
885
    io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
221
885
    superblock = 1;
222
885
    group_block = 0;
223
885
    retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
224
885
    if (retval)
225
0
      goto cleanup;
226
885
  }
227
885
retry:
228
885
  retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
229
885
             fs->super);
230
885
  if (retval)
231
1
    goto cleanup;
232
884
  if (fs->orig_super)
233
884
    memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
234
235
884
  if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
236
0
    retval = 0;
237
0
    if (!ext2fs_verify_csum_type(fs, fs->super))
238
0
      retval = EXT2_ET_UNKNOWN_CSUM;
239
0
    if (!ext2fs_superblock_csum_verify(fs, fs->super)) {
240
0
      if (csum_retries++ < 3)
241
0
        goto retry;
242
0
      retval = EXT2_ET_SB_CSUM_INVALID;
243
0
    }
244
0
  }
245
246
#ifdef WORDS_BIGENDIAN
247
  fs->flags |= EXT2_FLAG_SWAP_BYTES;
248
  ext2fs_swap_super(fs->super);
249
#else
250
884
  if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
251
0
    retval = EXT2_ET_UNIMPLEMENTED;
252
0
    goto cleanup;
253
0
  }
254
884
#endif
255
256
884
  if (fs->super->s_magic != EXT2_SUPER_MAGIC)
257
21
    retval = EXT2_ET_BAD_MAGIC;
258
884
  if (retval)
259
21
    goto cleanup;
260
261
863
  if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
262
5
    retval = EXT2_ET_REV_TOO_HIGH;
263
5
    goto cleanup;
264
5
  }
265
266
  /*
267
   * Check for feature set incompatibility
268
   */
269
858
  if (!(flags & EXT2_FLAG_FORCE)) {
270
858
    features = fs->super->s_feature_incompat;
271
858
#ifdef EXT2_LIB_SOFTSUPP_INCOMPAT
272
858
    if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
273
0
      features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT;
274
858
#endif
275
858
    if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
276
11
      retval = EXT2_ET_UNSUPP_FEATURE;
277
11
      goto cleanup;
278
11
    }
279
280
847
    features = fs->super->s_feature_ro_compat;
281
847
#ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT
282
847
    if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
283
0
      features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT;
284
847
#endif
285
847
    if ((flags & EXT2_FLAG_RW) &&
286
847
        (features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
287
0
      retval = EXT2_ET_RO_UNSUPP_FEATURE;
288
0
      goto cleanup;
289
0
    }
290
291
847
    if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
292
847
        ext2fs_has_feature_journal_dev(fs->super)) {
293
0
      retval = EXT2_ET_UNSUPP_FEATURE;
294
0
      goto cleanup;
295
0
    }
296
847
  }
297
298
847
  if ((fs->super->s_log_block_size >
299
847
       (unsigned) (EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) ||
300
847
      (fs->super->s_log_cluster_size >
301
841
       (unsigned) (EXT2_MAX_CLUSTER_LOG_SIZE - EXT2_MIN_CLUSTER_LOG_SIZE)) ||
302
847
      (fs->super->s_log_block_size > fs->super->s_log_cluster_size) ||
303
847
      (fs->super->s_log_groups_per_flex > 31)) {
304
12
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
305
12
    goto cleanup;
306
12
  }
307
308
  /*
309
   * bigalloc requires cluster-aware bitfield operations, which at the
310
   * moment means we need EXT2_FLAG_64BITS.
311
   */
312
835
  if (ext2fs_has_feature_bigalloc(fs->super) &&
313
835
      !(flags & EXT2_FLAG_64BITS)) {
314
1
    retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS;
315
1
    goto cleanup;
316
1
  }
317
318
834
  if (!ext2fs_has_feature_bigalloc(fs->super) &&
319
834
      (fs->super->s_log_block_size != fs->super->s_log_cluster_size)) {
320
1
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
321
1
    goto cleanup;
322
1
  }
323
833
  fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
324
833
  inode_size = EXT2_INODE_SIZE(fs->super);
325
833
  if ((inode_size < EXT2_GOOD_OLD_INODE_SIZE) ||
326
833
      (inode_size > fs->blocksize) ||
327
833
      (inode_size & (inode_size - 1))) {
328
2
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
329
2
    goto cleanup;
330
2
  }
331
332
  /* Enforce the block group descriptor size */
333
831
  if (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS) &&
334
831
      ext2fs_has_feature_64bit(fs->super)) {
335
282
    unsigned desc_size = fs->super->s_desc_size;
336
337
282
    if ((desc_size < EXT2_MIN_DESC_SIZE_64BIT) ||
338
282
        (desc_size > EXT2_MAX_DESC_SIZE) ||
339
282
        (desc_size & (desc_size - 1)) != 0) {
340
9
      retval = EXT2_ET_BAD_DESC_SIZE;
341
9
      goto cleanup;
342
9
    }
343
282
  }
344
345
822
  fs->cluster_ratio_bits = fs->super->s_log_cluster_size -
346
822
    fs->super->s_log_block_size;
347
822
  if (EXT2_BLOCKS_PER_GROUP(fs->super) !=
348
822
      EXT2_CLUSTERS_PER_GROUP(fs->super) << fs->cluster_ratio_bits) {
349
7
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
350
7
    goto cleanup;
351
7
  }
352
815
  fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) *
353
815
               EXT2_INODE_SIZE(fs->super) +
354
815
               EXT2_BLOCK_SIZE(fs->super) - 1) /
355
815
              EXT2_BLOCK_SIZE(fs->super));
356
815
  if (block_size) {
357
0
    if (block_size != fs->blocksize) {
358
0
      retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
359
0
      goto cleanup;
360
0
    }
361
0
  }
362
  /*
363
   * Set the blocksize to the filesystem's blocksize.
364
   */
365
815
  io_channel_set_blksize(fs->io, fs->blocksize);
366
367
  /*
368
   * If this is an external journal device, don't try to read
369
   * the group descriptors, because they're not there.
370
   */
371
815
  if (ext2fs_has_feature_journal_dev(fs->super)) {
372
0
    fs->group_desc_count = 0;
373
0
    *ret_fs = fs;
374
0
    return 0;
375
0
  }
376
377
815
  if (EXT2_INODES_PER_GROUP(fs->super) == 0) {
378
0
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
379
0
    goto cleanup;
380
0
  }
381
  /* Precompute the FS UUID to seed other checksums */
382
815
  ext2fs_init_csum_seed(fs);
383
384
  /*
385
   * Read group descriptors
386
   */
387
815
  blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
388
815
  if (blocks_per_group < 8 ||
389
815
      blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
390
815
      fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super) ||
391
815
           EXT2_DESC_PER_BLOCK(fs->super) == 0 ||
392
815
           fs->super->s_first_data_block >= ext2fs_blocks_count(fs->super)) {
393
13
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
394
13
    goto cleanup;
395
13
  }
396
802
  groups_cnt = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) -
397
802
               fs->super->s_first_data_block,
398
802
               blocks_per_group);
399
802
  if (groups_cnt >> 32) {
400
10
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
401
10
    goto cleanup;
402
10
  }
403
792
  fs->group_desc_count =  groups_cnt;
404
792
  if (!(flags & EXT2_FLAG_IGNORE_SB_ERRORS) &&
405
792
      (__u64)fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) !=
406
792
      fs->super->s_inodes_count) {
407
20
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
408
20
    goto cleanup;
409
20
  }
410
772
  fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
411
772
            EXT2_DESC_PER_BLOCK(fs->super));
412
772
  if (ext2fs_has_feature_meta_bg(fs->super) &&
413
772
      (fs->super->s_first_meta_bg > fs->desc_blocks) &&
414
772
      !(flags & EXT2_FLAG_IGNORE_SB_ERRORS)) {
415
5
    retval = EXT2_ET_CORRUPT_SUPERBLOCK;
416
5
    goto cleanup;
417
5
  }
418
767
  if (flags & EXT2_FLAG_SUPER_ONLY)
419
0
    goto skip_read_bg;
420
767
  retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
421
767
        &fs->group_desc);
422
767
  if (retval)
423
0
    goto cleanup;
424
767
  if (!group_block)
425
767
    group_block = fs->super->s_first_data_block;
426
  /*
427
   * On a FS with a 1K blocksize, block 0 is reserved for bootloaders
428
   * so we must increment block numbers to any group 0 items.
429
   *
430
   * However, we cannot touch group_block directly because in the meta_bg
431
   * case, the ext2fs_descriptor_block_loc2() function will interpret
432
   * group_block != s_first_data_block to mean that we want to access the
433
   * backup group descriptors.  This is not what we want if the caller
434
   * set superblock == 0 (i.e. auto-detect the superblock), which is
435
   * what's going on here.
436
   */
437
767
  if (group_block == 0 && fs->blocksize == 1024)
438
485
    group_zero_adjust = 1;
439
767
  dest = (char *) fs->group_desc;
440
#ifdef WORDS_BIGENDIAN
441
  groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
442
#endif
443
767
  if (ext2fs_has_feature_meta_bg(fs->super) &&
444
767
      !(flags & EXT2_FLAG_IMAGE_FILE)) {
445
312
    first_meta_bg = fs->super->s_first_meta_bg;
446
312
    if (first_meta_bg > fs->desc_blocks)
447
0
      first_meta_bg = fs->desc_blocks;
448
312
  } else
449
455
    first_meta_bg = fs->desc_blocks;
450
767
  if (first_meta_bg) {
451
582
    retval = io_channel_read_blk(fs->io, group_block +
452
582
               group_zero_adjust + 1,
453
582
               first_meta_bg, dest);
454
582
    if (retval)
455
35
      goto cleanup;
456
#ifdef WORDS_BIGENDIAN
457
    gdp = (struct ext2_group_desc *) dest;
458
    for (j=0; j < groups_per_block*first_meta_bg; j++) {
459
      gdp = ext2fs_group_desc(fs, fs->group_desc, j);
460
      if (gdp)
461
        ext2fs_swap_group_desc2(fs, gdp);
462
    }
463
#endif
464
547
    dest += fs->blocksize*first_meta_bg;
465
547
  }
466
467
19.7M
  for (i = first_meta_bg ; i < fs->desc_blocks; i++) {
468
19.7M
    blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
469
19.7M
    io_channel_cache_readahead(fs->io, blk, 1);
470
19.7M
  }
471
472
1.38k
  for (i=first_meta_bg ; i < fs->desc_blocks; i++) {
473
699
    blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
474
699
    retval = io_channel_read_blk64(fs->io, blk, 1, dest);
475
699
    if (retval)
476
42
      goto cleanup;
477
#ifdef WORDS_BIGENDIAN
478
    for (j=0; j < groups_per_block; j++) {
479
      gdp = ext2fs_group_desc(fs, fs->group_desc,
480
            i * groups_per_block + j);
481
      if (gdp)
482
        ext2fs_swap_group_desc2(fs, gdp);
483
    }
484
#endif
485
657
    dest += fs->blocksize;
486
657
  }
487
488
690
  fs->stride = fs->super->s_raid_stride;
489
490
  /*
491
   * If recovery is from backup superblock, Clear _UNININT flags &
492
   * reset bg_itable_unused to zero
493
   */
494
690
  if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
495
0
    dgrp_t group;
496
497
0
    for (group = 0; group < fs->group_desc_count; group++) {
498
0
      ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
499
0
      ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
500
0
      ext2fs_bg_itable_unused_set(fs, group, 0);
501
      /* The checksum will be reset later, but fix it here
502
       * anyway to avoid printing a lot of spurious errors. */
503
0
      ext2fs_group_desc_csum_set(fs, group);
504
0
    }
505
0
    if (fs->flags & EXT2_FLAG_RW)
506
0
      ext2fs_mark_super_dirty(fs);
507
0
  }
508
690
skip_read_bg:
509
690
  if (ext2fs_has_feature_mmp(fs->super) &&
510
690
      !(flags & EXT2_FLAG_SKIP_MMP) &&
511
690
      (flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) {
512
0
    retval = ext2fs_mmp_start(fs);
513
0
    if (retval) {
514
0
      fs->flags |= EXT2_FLAG_SKIP_MMP; /* just do cleanup */
515
0
      ext2fs_mmp_stop(fs);
516
0
      goto cleanup;
517
0
    }
518
0
  }
519
520
690
  if (fs->flags & EXT2_FLAG_SHARE_DUP) {
521
0
    fs->block_sha_map = ext2fs_hashmap_create(ext2fs_djb2_hash,
522
0
          block_sha_map_free_entry, 4096);
523
0
    if (!fs->block_sha_map) {
524
0
      retval = EXT2_ET_NO_MEMORY;
525
0
      goto cleanup;
526
0
    }
527
0
    ext2fs_set_feature_shared_blocks(fs->super);
528
0
  }
529
530
690
  if (ext2fs_has_feature_casefold(fs->super))
531
43
    fs->encoding = ext2fs_load_nls_table(fs->super->s_encoding);
532
533
690
  fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
534
690
  *ret_fs = fs;
535
536
690
  return 0;
537
195
cleanup:
538
195
  if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) {
539
195
    ext2fs_free(fs);
540
195
    fs = NULL;
541
195
  }
542
195
  *ret_fs = fs;
543
195
  return retval;
544
690
}
545
546
/*
547
 * Set/get the filesystem data I/O channel.
548
 *
549
 * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
550
 */
551
errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
552
0
{
553
0
  if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
554
0
    return EXT2_ET_NOT_IMAGE_FILE;
555
0
  if (old_io) {
556
0
    *old_io = (fs->image_io == fs->io) ? 0 : fs->io;
557
0
  }
558
0
  return 0;
559
0
}
560
561
errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
562
0
{
563
0
  if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
564
0
    return EXT2_ET_NOT_IMAGE_FILE;
565
0
  fs->io = new_io ? new_io : fs->image_io;
566
0
  return 0;
567
0
}
568
569
errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
570
0
{
571
0
  errcode_t err;
572
573
0
  if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
574
0
    return EXT2_ET_NOT_IMAGE_FILE;
575
0
  err = io_channel_set_blksize(new_io, fs->blocksize);
576
0
  if (err)
577
0
    return err;
578
0
  if ((new_io == fs->image_io) || (new_io == fs->io))
579
0
    return 0;
580
0
  if ((fs->image_io != fs->io) &&
581
0
      fs->image_io)
582
0
    io_channel_close(fs->image_io);
583
0
  if (fs->io)
584
0
    io_channel_close(fs->io);
585
0
  fs->io = fs->image_io = new_io;
586
0
  fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
587
0
    EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
588
0
  fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
589
0
  return 0;
590
0
}