Whamcloud - gitweb
resize2fs: trim resize to cluster boundary
[tools/e2fsprogs.git] / e2fsck / pass2.c
index e504b30..3b473af 100644 (file)
@@ -332,7 +332,8 @@ static short htree_depth(struct dx_dir_info *dx_dir,
        return depth;
 }
 
-static int dict_de_cmp(const void *cmp_ctx, const void *a, const void *b)
+static int dict_de_cmp(const void *cmp_ctx EXT2FS_ATTR((unused)),
+                      const void *a, const void *b)
 {
        const struct ext2_dir_entry *de_a, *de_b;
        int     a_len, b_len;
@@ -359,8 +360,9 @@ static int dict_de_cf_cmp(const void *cmp_ctx, const void *a, const void *b)
        de_b = (const struct ext2_dir_entry *) b;
        b_len = ext2fs_dirent_name_len(de_b);
 
-       return ext2fs_casefold_cmp(tbl, (unsigned char *) de_a->name, a_len,
-                                  (unsigned char *) de_b->name, b_len);
+       return ext2fs_casefold_cmp(tbl,
+                                  (const unsigned char *) de_a->name, a_len,
+                                  (const unsigned char *) de_b->name, b_len);
 }
 
 /*
@@ -405,6 +407,7 @@ static int check_dot(e2fsck_t ctx,
        int             status = 0;
        int             created = 0;
        problem_t       problem = 0;
+       int             ftype = EXT2_FT_DIR;
 
        if (!dirent->inode)
                problem = PR_2_MISSING_DOT;
@@ -416,12 +419,14 @@ static int check_dot(e2fsck_t ctx,
 
        (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
        if (problem) {
+               if (!ext2fs_has_feature_filetype(ctx->fs->super))
+                       ftype = EXT2_FT_UNKNOWN;
                if (fix_problem(ctx, problem, pctx)) {
                        if (rec_len < 12)
                                rec_len = dirent->rec_len = 12;
                        dirent->inode = ino;
                        ext2fs_dirent_set_name_len(dirent, 1);
-                       ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
+                       ext2fs_dirent_set_file_type(dirent, ftype);
                        dirent->name[0] = '.';
                        dirent->name[1] = '\0';
                        status = 1;
@@ -442,12 +447,24 @@ static int check_dot(e2fsck_t ctx,
                                nextdir = (struct ext2_dir_entry *)
                                        ((char *) dirent + 12);
                                dirent->rec_len = 12;
-                               (void) ext2fs_set_rec_len(ctx->fs, new_len,
-                                                         nextdir);
-                               nextdir->inode = 0;
-                               ext2fs_dirent_set_name_len(nextdir, 0);
-                               ext2fs_dirent_set_file_type(nextdir,
-                                                           EXT2_FT_UNKNOWN);
+                               /* if the next entry looks like "..", leave it
+                                * and let check_dotdot() verify the dirent,
+                                * otherwise zap the following entry. */
+                               if (strncmp(nextdir->name, "..", 3) != 0) {
+                                       (void)ext2fs_set_rec_len(ctx->fs,
+                                                                new_len,
+                                                                nextdir);
+                                       nextdir->inode = 0;
+                                       ext2fs_dirent_set_name_len(nextdir, 0);
+                                       ext2fs_dirent_set_file_type(nextdir,
+                                                                   ftype);
+#ifdef WORDS_BIGENDIAN
+                               } else {
+                                       (void) ext2fs_dirent_swab_in2(ctx->fs,
+                                               (char *) nextdir,
+                                               ctx->fs->blocksize - 12, 0);
+#endif
+                               }
                                status = 1;
                        }
                }
@@ -466,6 +483,7 @@ static int check_dotdot(e2fsck_t ctx,
 {
        problem_t       problem = 0;
        unsigned int    rec_len;
+       int             ftype = EXT2_FT_DIR;
 
        if (!dirent->inode)
                problem = PR_2_MISSING_DOT_DOT;
@@ -478,6 +496,8 @@ static int check_dotdot(e2fsck_t ctx,
 
        (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
        if (problem) {
+               if (!ext2fs_has_feature_filetype(ctx->fs->super))
+                       ftype = EXT2_FT_UNKNOWN;
                if (fix_problem(ctx, problem, pctx)) {
                        if (rec_len < 12)
                                dirent->rec_len = 12;
@@ -488,7 +508,7 @@ static int check_dotdot(e2fsck_t ctx,
                         */
                        dirent->inode = EXT2_ROOT_INO;
                        ext2fs_dirent_set_name_len(dirent, 2);
-                       ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
+                       ext2fs_dirent_set_file_type(dirent, ftype);
                        dirent->name[0] = '.';
                        dirent->name[1] = '.';
                        dirent->name[2] = '\0';
@@ -778,7 +798,7 @@ static void salvage_directory(ext2_filsys fs,
         * Special case of directory entry of size 8: copy what's left
         * of the directory block up to cover up the invalid hole.
         */
-       if ((left >= ext2fs_dir_rec_len(1, hash_in_dirent)) &&
+       if ((left >= (int) ext2fs_dir_rec_len(1, hash_in_dirent)) &&
             (rec_len == EXT2_DIR_ENTRY_HEADER_LEN)) {
                memmove(cp, cp+EXT2_DIR_ENTRY_HEADER_LEN, left);
                memset(cp + left, 0, EXT2_DIR_ENTRY_HEADER_LEN);
@@ -1284,7 +1304,7 @@ skip_checksum:
 
        if (cf_dir) {
                dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cf_cmp);
-               dict_set_cmp_context(&de_dict, (void *)ctx->fs->encoding);
+               dict_set_cmp_context(&de_dict, (const void *)ctx->fs->encoding);
        } else {
                dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
        }
@@ -1300,7 +1320,7 @@ skip_checksum:
                unsigned int name_len;
                /* csum entry is not checked here, so don't worry about it */
                int extended = (dot_state > 1) && hash_in_dirent;
-               int min_dir_len = ext2fs_dir_rec_len(1, extended);
+               unsigned int min_dir_len = ext2fs_dir_rec_len(1, extended);
 
                problem = 0;
                if (!inline_data_size || dot_state > 1) {
@@ -1356,12 +1376,14 @@ skip_checksum:
                                                          hash_in_dirent);
 #ifdef WORDS_BIGENDIAN
                                        if (need_reswab) {
+                                               unsigned int len;
+
                                                (void) ext2fs_get_rec_len(fs,
-                                                       dirent, &rec_len);
-                                               ext2fs_dirent_swab_in2(fs,
-                                                       ((char *)dirent) + offset + rec_len,
-                                                       max_block_size - offset - rec_len,
-                                                       0);
+                                                       dirent, &len);
+                                               len += offset;
+                                               if (max_block_size > len)
+                                                       ext2fs_dirent_swab_in2(fs,
+                               ((char *)dirent) + len, max_block_size - len, 0);
                                        }
 #endif
                                        dir_modified++;
@@ -1419,7 +1441,10 @@ skip_checksum:
                name_len = ext2fs_dirent_name_len(dirent);
                if (((dirent->inode != EXT2_ROOT_INO) &&
                     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
-                   (dirent->inode > fs->super->s_inodes_count)) {
+                   (dirent->inode > fs->super->s_inodes_count) ||
+                   (dirent->inode == fs->super->s_usr_quota_inum) ||
+                   (dirent->inode == fs->super->s_grp_quota_inum) ||
+                   (dirent->inode == fs->super->s_prj_quota_inum)) {
                        problem = PR_2_BAD_INO;
                } else if (ctx->inode_bb_map &&
                           (ext2fs_test_inode_bitmap2(ctx->inode_bb_map,
@@ -1514,6 +1539,7 @@ skip_checksum:
                                        &cd->pctx)){
                                ext2fs_bg_flags_clear(fs, group,
                                                      EXT2_BG_INODE_UNINIT);
+                               ext2fs_group_desc_csum_set(fs, group);
                                ext2fs_mark_super_dirty(fs);
                                ctx->flags |= E2F_FLAG_RESTART_LATER;
                        } else {
@@ -1525,6 +1551,7 @@ skip_checksum:
                        pctx.num = dirent->inode;
                        if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
                                ext2fs_bg_itable_unused_set(fs, group, 0);
+                               ext2fs_group_desc_csum_set(fs, group);
                                ext2fs_mark_super_dirty(fs);
                                ctx->flags |= E2F_FLAG_RESTART_LATER;
                        } else {