Whamcloud - gitweb
tst_libext2fs: Avoid multiple definition of global variables
[tools/e2fsprogs.git] / lib / ext2fs / inode.c
index 08024cb..c4377ee 100644 (file)
@@ -64,7 +64,7 @@ struct ext2_struct_inode_scan {
  */
 errcode_t ext2fs_flush_icache(ext2_filsys fs)
 {
-       int     i;
+       unsigned        i;
 
        if (!fs->icache)
                return 0;
@@ -81,7 +81,7 @@ errcode_t ext2fs_flush_icache(ext2_filsys fs)
  */
 void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
 {
-       int i;
+       unsigned i;
 
        if (--icache->refcount)
                return;
@@ -97,7 +97,7 @@ void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
 
 errcode_t ext2fs_create_inode_cache(ext2_filsys fs, unsigned int cache_size)
 {
-       int             i;
+       unsigned        i;
        errcode_t       retval;
 
        if (fs->icache)
@@ -151,7 +151,7 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
         */
        if (fs->badblocks == 0) {
                /*
-                * Temporarly save fs->get_blocks and set it to zero,
+                * Temporarily save fs->get_blocks and set it to zero,
                 * for compatibility with old e2fsck's.
                 */
                save_get_blocks = fs->get_blocks;
@@ -175,14 +175,26 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
        scan->bytes_left = 0;
        scan->current_group = 0;
        scan->groups_left = fs->group_desc_count - 1;
-       scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
+       scan->inode_buffer_blocks = buffer_blocks ? 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)) {
-               scan->inodes_left -=
-                       ext2fs_bg_itable_unused(fs, scan->current_group);
+               __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
+               if (scan->inodes_left > unused)
+                       scan->inodes_left -= unused;
+               else
+                       scan->inodes_left = 0;
                scan->blocks_left =
                        (scan->inodes_left +
                         (fs->blocksize / scan->inode_size - 1)) *
@@ -274,14 +286,21 @@ static errcode_t get_next_blockgroup(ext2_inode_scan scan)
        scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
        scan->blocks_left = fs->inode_blocks_per_group;
        if (ext2fs_has_group_desc_csum(fs)) {
-               scan->inodes_left -=
-                       ext2fs_bg_itable_unused(fs, scan->current_group);
+               __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
+               if (scan->inodes_left > unused)
+                       scan->inodes_left -= unused;
+               else
+                       scan->inodes_left = 0;
                scan->blocks_left =
                        (scan->inodes_left +
                         (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;
 }
 
@@ -290,6 +309,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);
 }
 
@@ -313,6 +333,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
@@ -403,10 +429,10 @@ static void check_inode_block_sanity(ext2_inode_scan scan, blk64_t num_blocks)
        ext2_ino_t      ino, inodes_to_scan;
        unsigned int    badness, checksum_failures;
        unsigned int    inodes_in_buf, inodes_per_block;
-       void            *p;
+       char            *p;
        struct ext2_inode_large *inode;
        char            *block_status;
-       unsigned int    blk;
+       unsigned int    blk, bad_csum;
 
        if (!(scan->scan_flags & EXT2_SF_WARN_GARBAGE_INODES))
                return;
@@ -416,19 +442,37 @@ static void check_inode_block_sanity(ext2_inode_scan scan, blk64_t num_blocks)
        if (inodes_to_scan > inodes_in_buf)
                inodes_to_scan = inodes_in_buf;
 
-       p = scan->inode_buffer;
+       p = (char *) scan->inode_buffer;
        ino = scan->current_inode + 1;
        checksum_failures = badness = 0;
        block_status = SCAN_BLOCK_STATUS(scan);
        memset(block_status, 0, scan->inode_buffer_blocks);
        inodes_per_block = EXT2_INODES_PER_BLOCK(scan->fs->super);
 
+       if (inodes_per_block < 2)
+               return;
+
+#ifdef WORDS_BIGENDIAN
+       if (ext2fs_get_mem(EXT2_INODE_SIZE(scan->fs->super), &inode))
+               return;
+#endif
+
        while (inodes_to_scan > 0) {
-               blk = (p - (void *)scan->inode_buffer) / scan->fs->blocksize;
-               inode = p;
+               blk = (p - (char *)scan->inode_buffer) / scan->fs->blocksize;
+               bad_csum = ext2fs_inode_csum_verify(scan->fs, ino,
+                               (struct ext2_inode_large *) p) == 0;
+
+#ifdef WORDS_BIGENDIAN
+               ext2fs_swap_inode_full(scan->fs,
+                              (struct ext2_inode_large *) inode,
+                              (struct ext2_inode_large *) p,
+                              0, EXT2_INODE_SIZE(scan->fs->super));
+#else
+               inode = (struct ext2_inode_large *) p;
+#endif
 
                /* Is this inode insane? */
-               if (!ext2fs_inode_csum_verify(scan->fs, ino, inode)) {
+               if (bad_csum) {
                        checksum_failures++;
                        badness++;
                } else if (extent_head_looks_insane(inode) ||
@@ -460,6 +504,10 @@ static void check_inode_block_sanity(ext2_inode_scan scan, blk64_t num_blocks)
                p += scan->inode_size;
                ino++;
        };
+
+#ifdef WORDS_BIGENDIAN
+       ext2fs_free_mem(&inode);
+#endif
 }
 
 /*
@@ -601,7 +649,8 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
         * need to read in more blocks.
         */
        if (scan->bytes_left < scan->inode_size) {
-               memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
+               if (scan->bytes_left)
+                       memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
                extra_bytes = scan->bytes_left;
 
                retval = get_next_blocks(scan);
@@ -698,18 +747,21 @@ 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;
-       int             clen, i, inodes_per_block;
+       unsigned        i;
+       int             clen, inodes_per_block;
        io_channel      io;
        int             length = EXT2_INODE_SIZE(fs->super);
        struct ext2_inode_large *iptr;
-       int             cache_slot;
+       int             cache_slot, fail_csum;
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -739,7 +791,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
        }
        if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
                inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
-               block_nr = fs->image_header->offset_inode / fs->blocksize;
+               block_nr = ext2fs_le32_to_cpu(fs->image_header->offset_inode) / fs->blocksize;
                block_nr += (ino - 1) / inodes_per_block;
                offset = ((ino - 1) % inodes_per_block) *
                        EXT2_INODE_SIZE(fs->super);
@@ -751,10 +803,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);
@@ -787,9 +843,7 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
        length = EXT2_INODE_SIZE(fs->super);
 
        /* Verify the inode checksum. */
-       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
-           !ext2fs_inode_csum_verify(fs, ino, iptr))
-               return EXT2_ET_INODE_CSUM_INVALID;
+       fail_csum = !ext2fs_inode_csum_verify(fs, ino, iptr);
 
 #ifdef WORDS_BIGENDIAN
        ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) iptr,
@@ -798,29 +852,44 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
 #endif
 
        /* Update the inode cache bookkeeping */
-       fs->icache->cache_last = cache_slot;
-       fs->icache->cache[cache_slot].ino = ino;
+       if (!fail_csum) {
+               fs->icache->cache_last = cache_slot;
+               fs->icache->cache[cache_slot].ino = ino;
+       }
        memcpy(inode, iptr, (bufsize > length) ? length : bufsize);
 
+       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;
-       int clen, i;
+       unsigned i;
+       int clen;
        int length = EXT2_INODE_SIZE(fs->super);
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -841,12 +910,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;
+               retval = ext2fs_read_inode2(fs, ino,
+                                           (struct ext2_inode *)w_inode,
+                                           length, READ_INODE_NOCSUM);
                if (retval)
                        goto errout;
        }
@@ -876,19 +942,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);
 
@@ -928,11 +1003,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);
 }
 
 /*