]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blobdiff - e2fsck/pass2.c
Fix encoding for rec_len in directories for >= 64k blocksize file systems
[thirdparty/e2fsprogs.git] / e2fsck / pass2.c
index 28badc9a5a8fd920edf369f4363d1e4d10f5a22d..bb3813cd725ed856b23e4af85f09874a6d84e57a 100644 (file)
@@ -101,10 +101,7 @@ void e2fsck_pass2(e2fsck_t ctx)
        problem_t               code;
        int                     bad_dir;
 
-#ifdef RESOURCE_TRACK
        init_resource_track(&rtrack, ctx->fs->io);
-#endif
-
        clear_problem_context(&cd.pctx);
 
 #ifdef MTRACE
@@ -153,6 +150,12 @@ void e2fsck_pass2(e2fsck_t ctx)
                                                &cd);
        if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
                return;
+
+       if (ctx->flags & E2F_FLAG_RESTART_LATER) {
+               ctx->flags |= E2F_FLAG_RESTART;
+               return;
+       }
+
        if (cd.pctx.errcode) {
                fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
                ctx->flags |= E2F_FLAG_ABORT;
@@ -248,6 +251,7 @@ void e2fsck_pass2(e2fsck_t ctx)
                        dx_dir->numblocks = 0;
                }
        }
+       e2fsck_free_dx_dir_info(ctx);
 #endif
        ext2fs_free_mem(&buf);
        ext2fs_free_dblist(fs->dblist);
@@ -278,12 +282,7 @@ void e2fsck_pass2(e2fsck_t ctx)
                }
        }
 
-#ifdef RESOURCE_TRACK
-       if (ctx->options & E2F_OPT_TIME2) {
-               e2fsck_clear_progbar(ctx);
-               print_resource_track(_("Pass 2"), &rtrack, fs->io);
-       }
-#endif
+       print_resource_track(ctx, _("Pass 2"), &rtrack, fs->io);
 }
 
 #define MAX_DEPTH 32000
@@ -353,9 +352,9 @@ static int check_dot(e2fsck_t ctx,
                     ext2_ino_t ino, struct problem_context *pctx)
 {
        struct ext2_dir_entry *nextdir;
+       unsigned int    rec_len, new_len;
        int     status = 0;
        int     created = 0;
-       int     rec_len, new_len;
        int     problem = 0;
 
        if (!dirent->inode)
@@ -366,8 +365,7 @@ static int check_dot(e2fsck_t ctx,
        else if (dirent->name[1] != '\0')
                problem = PR_2_DOT_NULL_TERM;
 
-       rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
-               dirent->rec_len : 65536;
+       (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
        if (problem) {
                if (fix_problem(ctx, problem, pctx)) {
                        if (rec_len < 12)
@@ -394,7 +392,8 @@ static int check_dot(e2fsck_t ctx,
                                nextdir = (struct ext2_dir_entry *)
                                        ((char *) dirent + 12);
                                dirent->rec_len = 12;
-                               nextdir->rec_len = new_len;
+                               (void) ext2fs_set_rec_len(ctx->fs, new_len,
+                                                         nextdir);
                                nextdir->inode = 0;
                                nextdir->name_len = 0;
                                status = 1;
@@ -424,8 +423,7 @@ static int check_dotdot(e2fsck_t ctx,
        else if (dirent->name[2] != '\0')
                problem = PR_2_DOT_DOT_NULL_TERM;
 
-       rec_len = (dirent->rec_len || ctx->fs->blocksize < 65536) ?
-               dirent->rec_len : 65536;
+       (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
        if (problem) {
                if (fix_problem(ctx, problem, pctx)) {
                        if (rec_len < 12)
@@ -648,11 +646,11 @@ static void salvage_directory(ext2_filsys fs,
                              unsigned int *offset)
 {
        char    *cp = (char *) dirent;
-       int     left, rec_len;
+       int left;
+       unsigned int rec_len, prev_rec_len;
        unsigned int name_len = dirent->name_len & 0xFF;
 
-       rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
-               dirent->rec_len : 65536;
+       (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
        left = fs->blocksize - *offset - rec_len;
 
        /*
@@ -670,10 +668,11 @@ static void salvage_directory(ext2_filsys fs,
         * record length.
         */
        if ((left < 0) &&
-           (name_len + 8 <= rec_len + (unsigned) left) &&
+           ((int) rec_len + left > 8) &&
+           (name_len + 8 <= (int) rec_len + left) &&
            dirent->inode <= fs->super->s_inodes_count &&
            strnlen(dirent->name, name_len) == name_len) {
-               dirent->rec_len += left;
+               (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent);
                return;
        }
        /*
@@ -683,7 +682,9 @@ static void salvage_directory(ext2_filsys fs,
         */
        if (prev && rec_len && (rec_len % 4) == 0 &&
            (*offset + rec_len <= fs->blocksize)) {
-               prev->rec_len += rec_len;
+               (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
+               prev_rec_len += rec_len;
+               (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
                *offset += rec_len;
                return;
        }
@@ -694,10 +695,13 @@ static void salvage_directory(ext2_filsys fs,
         * new empty directory entry the rest of the directory block.
         */
        if (prev) {
-               prev->rec_len += fs->blocksize - *offset;
+               (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
+               prev_rec_len += fs->blocksize - *offset;
+               (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
                *offset = fs->blocksize;
        } else {
-               dirent->rec_len = fs->blocksize - *offset;
+               rec_len = fs->blocksize - *offset;
+               (void) ext2fs_set_rec_len(fs, rec_len, dirent);
                dirent->name_len = 0;
                dirent->inode = 0;
        }
@@ -809,8 +813,7 @@ static int check_dir_block(ext2_filsys fs,
                dx_db->max_hash = 0;
 
                dirent = (struct ext2_dir_entry *) buf;
-               rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
-                       dirent->rec_len : 65536;
+               (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
                limit = (struct ext2_dx_countlimit *) (buf+8);
                if (db->blockcnt == 0) {
                        root = (struct ext2_dx_root_info *) (buf + 24);
@@ -848,8 +851,7 @@ out_htree:
 
                problem = 0;
                dirent = (struct ext2_dir_entry *) (buf + offset);
-               rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
-                       dirent->rec_len : 65536;
+               (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
                cd->pctx.dirent = dirent;
                cd->pctx.num = offset;
                if (((offset + rec_len) > fs->blocksize) ||
@@ -988,23 +990,24 @@ out_htree:
                 * newly visible inodes.
                 */
                if (fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT) {
+                       pctx.num = dirent->inode;
                        if (fix_problem(ctx, PR_2_INOREF_BG_INO_UNINIT,
                                        &cd->pctx)){
                                fs->group_desc[group].bg_flags &=
                                        ~EXT2_BG_INODE_UNINIT;
                                ext2fs_mark_super_dirty(fs);
-                               ctx->flags |= E2F_FLAG_RESTART;
+                               ctx->flags |= E2F_FLAG_RESTART_LATER;
                        } else {
                                ext2fs_unmark_valid(fs);
                                if (problem == PR_2_BAD_INO)
                                        goto next;
                        }
                } else if (dirent->inode >= first_unused_inode) {
+                       pctx.num = dirent->inode;
                        if (fix_problem(ctx, PR_2_INOREF_IN_UNUSED, &cd->pctx)){
                                fs->group_desc[group].bg_itable_unused = 0;
                                ext2fs_mark_super_dirty(fs);
-                               ctx->flags |= E2F_FLAG_RESTART;
-                               goto restart_fsck;
+                               ctx->flags |= E2F_FLAG_RESTART_LATER;
                        } else {
                                ext2fs_unmark_valid(fs);
                                if (problem == PR_2_BAD_INO)
@@ -1104,8 +1107,7 @@ out_htree:
        next:
                prev = dirent;
                if (dir_modified)
-                       rec_len = (dirent->rec_len || fs->blocksize < 65536) ?
-                               dirent->rec_len : 65536;
+                       (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
                offset += rec_len;
                dot_state++;
        } while (offset < fs->blocksize);
@@ -1145,7 +1147,6 @@ out_htree:
        return 0;
 abort_free_dict:
        ctx->flags |= E2F_FLAG_ABORT;
-restart_fsck:
        dict_free_nodes(&de_dict);
        return DIRENT_ABORT;
 }
@@ -1353,6 +1354,17 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
                }
        }
 
+       if (!(fs->super->s_feature_incompat & 
+            EXT4_FEATURE_INCOMPAT_64BIT) &&
+           inode.osd2.linux2.l_i_file_acl_high != 0) {
+               pctx.num = inode.osd2.linux2.l_i_file_acl_high;
+               if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {
+                       inode.osd2.linux2.l_i_file_acl_high = 0;
+                       inode_modified++;
+               } else
+                       not_fixed++;
+       }
+
        if (inode.i_file_acl &&
            ((inode.i_file_acl < fs->super->s_first_data_block) ||
             (inode.i_file_acl >= fs->super->s_blocks_count))) {