Whamcloud - gitweb
e2fsck: handle encrypted directories which are indexed using htree
authorTheodore Ts'o <tytso@mit.edu>
Sun, 8 Mar 2015 23:09:52 +0000 (19:09 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 8 Mar 2015 23:09:52 +0000 (19:09 -0400)
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/pass2.c
e2fsck/rehash.c

index b895f1e..e0a9239 100644 (file)
@@ -482,6 +482,10 @@ extern void e2fsck_intercept_block_allocations(e2fsck_t ctx);
 /* pass2.c */
 extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
                                    ext2_ino_t ino, char *buf);
+extern int get_filename_hash(ext2_filsys fs, int encrypted, int version,
+                            const char *name, int len,
+                            ext2_dirhash_t *ret_hash,
+                            ext2_dirhash_t *ret_minor_hash);
 
 /* pass3.c */
 extern int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
index 78a4c71..319d23b 100644 (file)
@@ -178,6 +178,7 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
        ext2_extent_handle_t    handle;
        struct ext2_extent_info info;
        struct ext2fs_extent    extent;
+       int encrypted = 0;
 
        if ((inode->i_size_high || inode->i_size == 0) ||
            (inode->i_flags & EXT2_INDEX_FL))
@@ -235,7 +236,11 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
                if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf))
                        return 0;
 
-               len = strnlen(buf, fs->blocksize);
+               if (inode->i_flags & EXT4_ENCRYPT_FL) {
+                       len = ext2fs_le32_to_cpu(*((__u32 *)buf)) + 4;
+               } else {
+                       len = strnlen(buf, fs->blocksize);
+               }
                if (len == fs->blocksize)
                        return 0;
        } else if (inode->i_flags & EXT4_INLINE_DATA_FL) {
@@ -268,7 +273,8 @@ exit_inline:
                        return 0;
        }
        if (len != inode->i_size)
-               return 0;
+               if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0)
+                       return 0;
        return 1;
 }
 
index a6624f4..94665c6 100644 (file)
@@ -464,23 +464,15 @@ static int check_dotdot(e2fsck_t ctx,
 static int check_name(e2fsck_t ctx,
                      struct ext2_dir_entry *dirent,
                      ext2_ino_t dir_ino,
-                     int *encrypted,
                      struct problem_context *pctx)
 {
        int     i;
        int     fixup = -1;
        int     ret = 0;
 
-       if (*encrypted > 0)
-               return 0;
        for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) {
                if (dirent->name[i] != '/' && dirent->name[i] != '\0')
                        continue;
-               if (*encrypted < 0 && ctx->encrypted_dirs)
-                       *encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs,
-                                                         dir_ino);
-               if (*encrypted > 0)
-                       return 0;
                if (fixup < 0)
                        fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
                if (fixup == 0)
@@ -850,6 +842,32 @@ err:
        return retval;
 }
 
+int get_filename_hash(ext2_filsys fs, int encrypted, int version,
+                     const char *name, int len, ext2_dirhash_t *ret_hash,
+                     ext2_dirhash_t *ret_minor_hash)
+{
+       char    buf[2*EXT2FS_DIGEST_SIZE];
+       int     buf_len;
+
+       if (!encrypted)
+               return ext2fs_dirhash(version, name, len,
+                                     fs->super->s_hash_seed,
+                                     ret_hash, ret_minor_hash);
+
+       if (len <= EXT2FS_DIGEST_SIZE)
+               buf_len = ext2fs_digest_encode(name, len, buf);
+       else {
+               ext2fs_sha256(name, len, buf + EXT2FS_DIGEST_SIZE);
+               buf[0] = 'I';
+               buf_len = ext2fs_digest_encode(buf + EXT2FS_DIGEST_SIZE,
+                                              EXT2FS_DIGEST_SIZE, buf + 1);
+               buf_len++;
+       }
+       return ext2fs_dirhash(version, buf, buf_len,
+                             fs->super->s_hash_seed,
+                             ret_hash, ret_minor_hash);
+}
+
 static int check_dir_block(ext2_filsys fs,
                           struct ext2_db_entry2 *db,
                           void *priv_data)
@@ -883,7 +901,7 @@ static int check_dir_block(ext2_filsys fs,
        int     is_leaf = 1;
        size_t  inline_data_size = 0;
        int     filetype = 0;
-       int     encrypted = -1;
+       int     encrypted = 0;
        size_t  max_block_size;
 
        cd = (struct check_dir_struct *) priv_data;
@@ -1095,6 +1113,9 @@ skip_checksum:
        } else
                max_block_size = fs->blocksize - de_csum_size;
 
+       if (ctx->encrypted_dirs)
+               encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino);
+
        dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
        prev = 0;
        do {
@@ -1357,7 +1378,7 @@ skip_checksum:
                        }
                }
 
-               if (check_name(ctx, dirent, ino, &encrypted, &cd->pctx))
+               if (!encrypted && check_name(ctx, dirent, ino, &cd->pctx))
                        dir_modified++;
 
                if (check_filetype(ctx, dirent, ino, &cd->pctx))
@@ -1365,9 +1386,10 @@ skip_checksum:
 
 #ifdef ENABLE_HTREE
                if (dx_db) {
-                       ext2fs_dirhash(dx_dir->hashversion, dirent->name,
-                                      ext2fs_dirent_name_len(dirent),
-                                      fs->super->s_hash_seed, &hash, 0);
+                       get_filename_hash(fs, encrypted, dx_dir->hashversion,
+                                         dirent->name,
+                                         ext2fs_dirent_name_len(dirent),
+                                         &hash, 0);
                        if (hash < dx_db->min_hash)
                                dx_db->min_hash = hash;
                        if (hash > dx_db->max_hash)
index e37e871..66e6786 100644 (file)
@@ -74,6 +74,7 @@ int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino)
 struct fill_dir_struct {
        char *buf;
        struct ext2_inode *inode;
+       ext2_ino_t ino;
        errcode_t err;
        e2fsck_t ctx;
        struct hash_entry *harray;
@@ -111,6 +112,9 @@ static int fill_dir_block(ext2_filsys fs,
        char                    *dir;
        unsigned int            offset, dir_offset, rec_len, name_len;
        int                     hash_alg;
+       int                     encrypted = 0;
+       char                    processed_filename[2*EXT2FS_DIGEST_SIZE];
+       int                     processed_filename_len;
 
        if (blockcnt < 0)
                return 0;
@@ -120,6 +124,12 @@ static int fill_dir_block(ext2_filsys fs,
                fd->err = EXT2_ET_DIR_CORRUPTED;
                return BLOCK_ABORT;
        }
+
+       /* Determine if the directory is encrypted */
+       if (fd->ctx->encrypted_dirs)
+               encrypted = ext2fs_u32_list_test(fd->ctx->encrypted_dirs,
+                                               fd->ino);
+
        dir = (fd->buf+offset);
        if (HOLE_BLKADDR(*block_nr)) {
                memset(dir, 0, fs->blocksize);
@@ -180,10 +190,10 @@ static int fill_dir_block(ext2_filsys fs,
                if (fd->compress)
                        ent->hash = ent->minor_hash = 0;
                else {
-                       fd->err = ext2fs_dirhash(hash_alg, dirent->name,
-                                                name_len,
-                                                fs->super->s_hash_seed,
-                                                &ent->hash, &ent->minor_hash);
+                       fd->err = get_filename_hash(fs, encrypted,
+                                       hash_alg, dirent->name,
+                                       ext2fs_dirent_name_len(dirent),
+                                       &ent->hash, &ent->minor_hash);
                        if (fd->err)
                                return BLOCK_ABORT;
                }
@@ -368,6 +378,9 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
        char                    new_name[256];
        unsigned int            new_len;
        int                     hash_alg;
+       int                     encrypted = 0;
+       char                    processed_filename[2*EXT2FS_DIGEST_SIZE];
+       int                     processed_filename_len;
 
        clear_problem_context(&pctx);
        pctx.ino = ino;
@@ -377,6 +390,10 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
            (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
                hash_alg += 3;
 
+       /* Determine if the directory is encrypted */
+       if (fd->ctx->encrypted_dirs)
+               encrypted = ext2fs_u32_list_test(fd->ctx->encrypted_dirs,
+                                               fd->ino);
        for (i=1; i < fd->num_array; i++) {
                ent = fd->harray + i;
                prev = ent - 1;
@@ -412,9 +429,9 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
                if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
                        memcpy(ent->dir->name, new_name, new_len);
                        ext2fs_dirent_set_name_len(ent->dir, new_len);
-                       ext2fs_dirhash(hash_alg, ent->dir->name, new_len,
-                                      fs->super->s_hash_seed,
-                                      &ent->hash, &ent->minor_hash);
+                       get_filename_hash(fs, encrypted,
+                                         hash_alg, new_name, new_len,
+                                         &ent->hash, &ent->minor_hash);
                        fixed++;
                }
        }
@@ -817,6 +834,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
        fd.ctx = ctx;
        fd.buf = dir_buf;
        fd.inode = &inode;
+       fd.ino = ino;
        fd.err = 0;
        fd.dir_size = 0;
        fd.compress = 0;