Whamcloud - gitweb
lib/{ext2fs,support}: fix 32-bit Windows build
[tools/e2fsprogs.git] / lib / ext2fs / inode.c
index 015cfe4..957d5aa 100644 (file)
@@ -145,6 +145,12 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+       if (ext2fs_has_feature_journal_dev(fs->super))
+               return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
+
+       if (fs->blocksize < 1024)
+               return EXT2_FILSYS_CORRUPTED; /* Should never happen */
+
        /*
         * If fs->badblocks isn't set, then set it --- since the inode
         * scanning functions require it.
@@ -179,6 +185,14 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
                                    EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS;
        scan->current_block = ext2fs_inode_table_loc(scan->fs,
                                                     scan->current_group);
+       if (scan->current_block &&
+           ((scan->current_block < fs->super->s_first_data_block) ||
+            (scan->current_block + fs->inode_blocks_per_group - 1 >=
+             ext2fs_blocks_count(fs->super)))) {
+               ext2fs_free_mem(&scan);
+               return EXT2_ET_GDESC_BAD_INODE_TABLE;
+       }
+
        scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
        scan->blocks_left = scan->fs->inode_blocks_per_group;
        if (ext2fs_has_group_desc_csum(fs)) {
@@ -288,7 +302,11 @@ static errcode_t get_next_blockgroup(ext2_inode_scan scan)
                         (fs->blocksize / scan->inode_size - 1)) *
                        scan->inode_size / fs->blocksize;
        }
-
+       if (scan->current_block &&
+           ((scan->current_block < fs->super->s_first_data_block) ||
+            (scan->current_block + fs->inode_blocks_per_group - 1 >=
+             ext2fs_blocks_count(fs->super))))
+               return EXT2_ET_GDESC_BAD_INODE_TABLE;
        return 0;
 }
 
@@ -297,6 +315,7 @@ errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
 {
        scan->current_group = group - 1;
        scan->groups_left = scan->fs->group_desc_count - group;
+       scan->bad_block_ptr = 0;
        return get_next_blockgroup(scan);
 }
 
@@ -320,6 +339,12 @@ static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
        if (blk == 0)
                return 0;
 
+       /* Make sure bad_block_ptr is still valid */
+       if (scan->bad_block_ptr >= bb->num) {
+               scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
+               return 0;
+       }
+
        /*
         * If the current block is greater than the bad block listed
         * in the bad block list, then advance the pointer until this
@@ -728,11 +753,13 @@ errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
 /*
  * Functions to read and write a single inode.
  */
-errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
-                                struct ext2_inode * inode, int bufsize)
+errcode_t ext2fs_read_inode2(ext2_filsys fs, ext2_ino_t ino,
+                            struct ext2_inode * inode, int bufsize,
+                            int flags)
 {
        blk64_t         block_nr;
-       unsigned long   group, block, offset;
+       dgrp_t          group;
+       unsigned long   block, offset;
        char            *ptr;
        errcode_t       retval;
        unsigned        i;
@@ -744,6 +771,12 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+       if (ext2fs_has_feature_journal_dev(fs->super))
+               return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
+
+       if (fs->blocksize < 1024)
+               return EXT2_FILSYS_CORRUPTED; /* Should never happen */
+
        /* Check to see if user has an override function */
        if (fs->read_inode &&
            ((bufsize == sizeof(struct ext2_inode)) ||
@@ -782,10 +815,14 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
                offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
                        EXT2_INODE_SIZE(fs->super);
                block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
-               if (!ext2fs_inode_table_loc(fs, (unsigned) group))
+               block_nr = ext2fs_inode_table_loc(fs, group);
+               if (!block_nr)
                        return EXT2_ET_MISSING_INODE_TABLE;
-               block_nr = ext2fs_inode_table_loc(fs, group) +
-                       block;
+               if ((block_nr < fs->super->s_first_data_block) ||
+                   (block_nr + fs->inode_blocks_per_group - 1 >=
+                    ext2fs_blocks_count(fs->super)))
+                       return EXT2_ET_GDESC_BAD_INODE_TABLE;
+               block_nr += block;
                io = fs->io;
        }
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
@@ -833,24 +870,33 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
        }
        memcpy(inode, iptr, (bufsize > length) ? length : bufsize);
 
-       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && fail_csum)
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+           !(flags & READ_INODE_NOCSUM) && fail_csum)
                return EXT2_ET_INODE_CSUM_INVALID;
 
        return 0;
 }
 
+errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+                                struct ext2_inode * inode, int bufsize)
+{
+       return ext2fs_read_inode2(fs, ino, inode, bufsize, 0);
+}
+
 errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
                            struct ext2_inode * inode)
 {
-       return ext2fs_read_inode_full(fs, ino, inode,
-                                       sizeof(struct ext2_inode));
+       return ext2fs_read_inode2(fs, ino, inode,
+                                 sizeof(struct ext2_inode), 0);
 }
 
-errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
-                                 struct ext2_inode * inode, int bufsize)
+errcode_t ext2fs_write_inode2(ext2_filsys fs, ext2_ino_t ino,
+                             struct ext2_inode * inode, int bufsize,
+                             int flags)
 {
        blk64_t block_nr;
-       unsigned long group, block, offset;
+       dgrp_t group;
+       unsigned long block, offset;
        errcode_t retval = 0;
        struct ext2_inode_large *w_inode;
        char *ptr;
@@ -860,6 +906,9 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+       if (ext2fs_has_feature_journal_dev(fs->super))
+               return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
+
        /* Check to see if user provided an override function */
        if (fs->write_inode) {
                retval = (fs->write_inode)(fs, ino, inode);
@@ -876,13 +925,9 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
                return retval;
 
        if (bufsize < length) {
-               int old_flags = fs->flags;
-               fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
-               retval = ext2fs_read_inode_full(fs, ino,
-                                               (struct ext2_inode *)w_inode,
-                                               length);
-               fs->flags = (old_flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
-                           (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
+               retval = ext2fs_read_inode2(fs, ino,
+                                           (struct ext2_inode *)w_inode,
+                                           length, READ_INODE_NOCSUM);
                if (retval)
                        goto errout;
        }
@@ -912,19 +957,28 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
        ext2fs_swap_inode_full(fs, w_inode, w_inode, 1, length);
 #endif
 
-       retval = ext2fs_inode_csum_set(fs, ino, w_inode);
-       if (retval)
-               goto errout;
+       if ((flags & WRITE_INODE_NOCSUM) == 0) {
+               retval = ext2fs_inode_csum_set(fs, ino, w_inode);
+               if (retval)
+                       goto errout;
+       }
 
        group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
        offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
                EXT2_INODE_SIZE(fs->super);
        block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
-       if (!ext2fs_inode_table_loc(fs, (unsigned) group)) {
+       block_nr = ext2fs_inode_table_loc(fs, (unsigned) group);
+       if (!block_nr) {
                retval = EXT2_ET_MISSING_INODE_TABLE;
                goto errout;
        }
-       block_nr = ext2fs_inode_table_loc(fs, (unsigned) group) + block;
+       if ((block_nr < fs->super->s_first_data_block) ||
+           (block_nr + fs->inode_blocks_per_group - 1 >=
+            ext2fs_blocks_count(fs->super))) {
+               retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
+               goto errout;
+       }
+       block_nr += block;
 
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
 
@@ -964,11 +1018,17 @@ errout:
        return retval;
 }
 
+errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+                                 struct ext2_inode * inode, int bufsize)
+{
+       return ext2fs_write_inode2(fs, ino, inode, bufsize, 0);
+}
+
 errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
                             struct ext2_inode *inode)
 {
-       return ext2fs_write_inode_full(fs, ino, inode,
-                                      sizeof(struct ext2_inode));
+       return ext2fs_write_inode2(fs, ino, inode,
+                                  sizeof(struct ext2_inode), 0);
 }
 
 /*