+/* Return true if this type of file needs encryption */
+static int needs_encryption(e2fsck_t ctx, const struct ext2_dir_entry *dirent)
+{
+ int filetype = ext2fs_dirent_file_type(dirent);
+ ext2_ino_t ino = dirent->inode;
+ struct ext2_inode inode;
+
+ if (filetype != EXT2_FT_UNKNOWN)
+ return filetype == EXT2_FT_REG_FILE ||
+ filetype == EXT2_FT_DIR ||
+ filetype == EXT2_FT_SYMLINK;
+
+ if (ext2fs_test_inode_bitmap2(ctx->inode_reg_map, ino) ||
+ ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino))
+ return 1;
+
+ e2fsck_read_inode(ctx, ino, &inode, "check_encryption_policy");
+ return LINUX_S_ISREG(inode.i_mode) ||
+ LINUX_S_ISDIR(inode.i_mode) ||
+ LINUX_S_ISLNK(inode.i_mode);
+}
+
+/*
+ * All regular files, directories, and symlinks in encrypted directories must be
+ * encrypted using the same encryption policy as their directory.
+ *
+ * Returns 1 if the dirent should be cleared, otherwise 0.
+ */
+static int check_encryption_policy(e2fsck_t ctx,
+ const struct ext2_dir_entry *dirent,
+ __u32 dir_encpolicy_id,
+ struct problem_context *pctx)
+{
+ __u32 file_encpolicy_id = find_encryption_policy(ctx, dirent->inode);
+
+ /* Same policy or both UNRECOGNIZED_ENCRYPTION_POLICY? */
+ if (file_encpolicy_id == dir_encpolicy_id)
+ return 0;
+
+ if (file_encpolicy_id == NO_ENCRYPTION_POLICY) {
+ if (!needs_encryption(ctx, dirent))
+ return 0;
+ return fix_problem(ctx, PR_2_UNENCRYPTED_FILE, pctx);
+ }
+
+ return fix_problem(ctx, PR_2_INCONSISTENT_ENCRYPTION_POLICY, pctx);
+}
+
+/*
+ * Check an encrypted directory entry.
+ *
+ * Returns 1 if the dirent should be cleared, otherwise 0.
+ */
+static int check_encrypted_dirent(e2fsck_t ctx,
+ const struct ext2_dir_entry *dirent,
+ __u32 dir_encpolicy_id,
+ struct problem_context *pctx)
+{
+ if (encrypted_check_name(ctx, dirent, pctx))
+ return 1;
+ if (check_encryption_policy(ctx, dirent, dir_encpolicy_id, pctx))
+ return 1;
+ return 0;
+}
+
+static int check_dir_block2(ext2_filsys fs,
+ struct ext2_db_entry2 *db,
+ void *priv_data)
+{
+ int err;
+ struct check_dir_struct *cd = priv_data;
+
+ if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) {
+ err = e2fsck_readahead_dblist(fs,
+ E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT,
+ fs->dblist,
+ cd->list_offset + cd->ra_entries / 8,
+ cd->ra_entries);
+ if (err)
+ cd->ra_entries = 0;
+ cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8);
+ }
+
+ err = check_dir_block(fs, db, priv_data);
+ cd->list_offset++;
+ return err;
+}
+