Whamcloud - gitweb
libext2fs: precompute FS UUID checksum seed
[tools/e2fsprogs.git] / lib / ext2fs / openfs.c
index 283daee..3675518 100644 (file)
@@ -9,6 +9,7 @@
  * %End-Header%
  */
 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #if HAVE_UNISTD_H
@@ -22,6 +23,9 @@
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
 
 #include "ext2_fs.h"
 
@@ -82,6 +86,9 @@ errcode_t ext2fs_open(const char *name, int flags, int superblock,
  *     EXT2_FLAG_FORCE - Open the filesystem even if some of the
  *                             features aren't supported.
  *     EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
+ *     EXT2_FLAG_SKIP_MMP - Open without multi-mount protection check.
+ *     EXT2_FLAG_64BITS - Allow 64-bit bitfields (needed for large
+ *                             filesystems)
  */
 errcode_t ext2fs_open2(const char *name, const char *io_options,
                       int flags, int superblock,
@@ -92,7 +99,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
        errcode_t       retval;
        unsigned long   i, first_meta_bg;
        __u32           features;
-       int             groups_per_block, blocks_per_group, io_flags;
+       unsigned int    groups_per_block, blocks_per_group, io_flags;
        blk64_t         group_block, blk;
        char            *dest, *cp;
 #ifdef WORDS_BIGENDIAN
@@ -137,7 +144,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                goto cleanup;
        fs->image_io = fs->io;
        fs->io->app_data = fs;
-       retval = ext2fs_get_memalign(SUPERBLOCK_SIZE, 512, &fs->super);
+       retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
        if (retval)
                goto cleanup;
        if (flags & EXT2_FLAG_IMAGE_FILE) {
@@ -214,7 +221,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                features = fs->super->s_feature_incompat;
 #ifdef EXT2_LIB_SOFTSUPP_INCOMPAT
                if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
-                       features &= !EXT2_LIB_SOFTSUPP_INCOMPAT;
+                       features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT;
 #endif
                if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
                        retval = EXT2_ET_UNSUPP_FEATURE;
@@ -224,7 +231,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                features = fs->super->s_feature_ro_compat;
 #ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT
                if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
-                       features &= !EXT2_LIB_SOFTSUPP_RO_COMPAT;
+                       features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT;
 #endif
                if ((flags & EXT2_FLAG_RW) &&
                    (features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
@@ -251,11 +258,26 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                retval = EXT2_ET_CORRUPT_SUPERBLOCK;
                goto cleanup;
        }
-       fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
+       fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
        if (EXT2_INODE_SIZE(fs->super) < EXT2_GOOD_OLD_INODE_SIZE) {
                retval = EXT2_ET_CORRUPT_SUPERBLOCK;
                goto cleanup;
        }
+
+       /* Enforce the block group descriptor size */
+       if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) {
+               if (fs->super->s_desc_size != EXT2_MIN_DESC_SIZE_64BIT) {
+                       retval = EXT2_ET_BAD_DESC_SIZE;
+                       goto cleanup;
+               }
+       } else {
+               if (fs->super->s_desc_size &&
+                   fs->super->s_desc_size != EXT2_MIN_DESC_SIZE) {
+                       retval = EXT2_ET_BAD_DESC_SIZE;
+                       goto cleanup;
+               }
+       }
+
        fs->cluster_ratio_bits = fs->super->s_log_cluster_size -
                fs->super->s_log_block_size;
        if (EXT2_BLOCKS_PER_GROUP(fs->super) !=
@@ -293,6 +315,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                retval = EXT2_ET_CORRUPT_SUPERBLOCK;
                goto cleanup;
        }
+       /* Precompute the FS UUID to seed other checksums */
+       ext2fs_init_csum_seed(fs);
 
        /*
         * Read group descriptors
@@ -322,6 +346,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                goto cleanup;
        if (!group_block)
                group_block = fs->super->s_first_data_block;
+       if (group_block == 0 && fs->blocksize == 1024)
+               group_block = 1; /* Deal with 1024 blocksize && bigalloc */
        dest = (char *) fs->group_desc;
        groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
        if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
@@ -349,8 +375,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                        goto cleanup;
 #ifdef WORDS_BIGENDIAN
                for (j=0; j < groups_per_block; j++) {
-                       /* The below happens to work... be careful. */
-                       gdp = ext2fs_group_desc(fs, fs->group_desc, j);
+                       gdp = ext2fs_group_desc(fs, fs->group_desc,
+                                               i * groups_per_block + j);
                        ext2fs_swap_group_desc2(fs, gdp);
                }
 #endif
@@ -371,12 +397,28 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                        ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
                        ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
                        ext2fs_bg_itable_unused_set(fs, group, 0);
+                       /* The checksum will be reset later, but fix it here
+                        * anyway to avoid printing a lot of spurious errors. */
+                       ext2fs_group_desc_csum_set(fs, group);
                }
-               ext2fs_mark_super_dirty(fs);
+               if (fs->flags & EXT2_FLAG_RW)
+                       ext2fs_mark_super_dirty(fs);
        }
 
        fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
        *ret_fs = fs;
+
+       if ((fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) &&
+           !(flags & EXT2_FLAG_SKIP_MMP) &&
+           (flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) {
+               retval = ext2fs_mmp_start(fs);
+               if (retval) {
+                       fs->flags |= EXT2_FLAG_SKIP_MMP; /* just do cleanup */
+                       ext2fs_mmp_stop(fs);
+                       goto cleanup;
+               }
+       }
+
        return 0;
 cleanup:
        if (flags & EXT2_FLAG_NOFREE_ON_ERROR)