Whamcloud - gitweb
e2fsck: add support for dirdata feature
[tools/e2fsprogs.git] / e2fsck / rehash.c
index 204ff7d..2048678 100644 (file)
@@ -86,6 +86,8 @@ struct fill_dir_struct {
        int compress;
        ext2_ino_t parent;
        ext2_ino_t dir;
+       struct ext2_dir_entry *dot_de;
+       struct ext2_dir_entry *dotdot_de;
 };
 
 struct hash_entry {
@@ -187,11 +189,14 @@ static int fill_dir_block(ext2_filsys fs,
                        return BLOCK_ABORT;
                }
                if (!fd->compress && (name_len == 1) &&
-                   (dirent->name[0] == '.'))
+                   (dirent->name[0] == '.')) {
+                       fd->dot_de = dirent;
                        continue;
+               }
                if (!fd->compress && (name_len == 2) &&
                    (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
                        fd->parent = dirent->inode;
+                       fd->dotdot_de = dirent;
                        continue;
                }
                if (fd->num_array >= fd->max_array) {
@@ -209,7 +214,7 @@ static int fill_dir_block(ext2_filsys fs,
                }
                ent = fd->harray + fd->num_array++;
                ent->dir = dirent;
-               fd->dir_size += ext2fs_dir_rec_len(name_len, extended);
+               fd->dir_size += ext2fs_dirdata_rec_len(dirent, extended);
                ent->ino = dirent->inode;
                if (extended) {
                        ent->hash = EXT2_DIRENT_HASH(dirent);
@@ -585,8 +590,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
                ent = fd->harray + i;
                if (ent->dir->inode == 0)
                        continue;
-               rec_len = ext2fs_dir_rec_len(ext2fs_dirent_name_len(ent->dir),
-                                            hash_in_entry);
+               rec_len = ext2fs_dirdata_rec_len(ent->dir, hash_in_entry);
                if (rec_len > left) {
                        if (left) {
                                left += prev_rec_len;
@@ -621,8 +625,7 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
                if (retval)
                        return retval;
                prev_rec_len = rec_len;
-               memcpy(dirent->name, ent->dir->name,
-                      ext2fs_dirent_name_len(dirent));
+               memcpy(dirent->name, ent->dir->name, rec_len);
                if (hash_in_entry) {
                        EXT2_DIRENT_HASHES(dirent)->hash = ext2fs_cpu_to_le32(ent->hash);
                        EXT2_DIRENT_HASHES(dirent)->minor_hash =
@@ -653,47 +656,52 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
 
 static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
                                    ext2_ino_t ino, ext2_ino_t parent,
+                                   struct ext2_dir_entry *dot_de,
+                                   struct ext2_dir_entry *dotdot_de,
                                    struct ext2_inode *inode)
 {
-       struct ext2_dir_entry           *dir;
-       struct ext2_dx_root_info        *root;
+       struct ext2_dir_entry           *dirent;
+       struct ext2_dx_root_info        *root;
        struct ext2_dx_countlimit       *limits;
-       int                             filetype = 0;
        int                             csum_size = 0;
-
-       if (ext2fs_has_feature_filetype(fs->super))
-               filetype = EXT2_FT_DIR;
+       int                             offset;
+       int                             rec_len;
 
        memset(buf, 0, fs->blocksize);
-       dir = (struct ext2_dir_entry *) buf;
-       dir->inode = ino;
-       dir->name[0] = '.';
-       ext2fs_dirent_set_name_len(dir, 1);
-       ext2fs_dirent_set_file_type(dir, filetype);
-       dir->rec_len = 12;
-       dir = (struct ext2_dir_entry *) (buf + 12);
-       dir->inode = parent;
-       dir->name[0] = '.';
-       dir->name[1] = '.';
-       ext2fs_dirent_set_name_len(dir, 2);
-       ext2fs_dirent_set_file_type(dir, filetype);
-       dir->rec_len = fs->blocksize - 12;
-
-       root = (struct ext2_dx_root_info *) (buf+24);
+       dirent = (struct ext2_dir_entry *) buf;
+       dirent->inode = ino;
+
+       dirent->name_len = dot_de->name_len;
+       offset = rec_len = dirent->rec_len = dot_de->rec_len;
+       memcpy(dirent->name, dot_de->name, rec_len);
+
+       dirent = EXT2_NEXT_DIRENT(dirent);
+       /* set to jump over the index block */
+
+       dirent->inode = parent;
+
+       dirent->name_len = dotdot_de->name_len;
+       dirent->rec_len = fs->blocksize - rec_len;
+       rec_len = EXT2_DIR_REC_LEN(dotdot_de);
+       memcpy(dirent->name, dotdot_de->name, rec_len);
+       offset += rec_len;
+
+       root = (struct ext2_dx_root_info *)(buf + offset);
        root->reserved_zero = 0;
        if (ext4_hash_in_dirent(inode))
                root->hash_version = EXT2_HASH_SIPHASH;
        else
                root->hash_version = fs->super->s_def_hash_version;
-       root->info_length = 8;
+       root->info_length = sizeof(*root);
        root->indirect_levels = 0;
        root->unused_flags = 0;
+       offset += root->info_length;
 
        if (ext2fs_has_feature_metadata_csum(fs->super))
                csum_size = sizeof(struct ext2_dx_tail);
 
-       limits = (struct ext2_dx_countlimit *) (buf+32);
-       limits->limit = (fs->blocksize - (32 + csum_size)) /
+       limits = (struct ext2_dx_countlimit *) (buf + offset);
+       limits->limit = (fs->blocksize - (offset + csum_size)) /
                        sizeof(struct ext2_dx_entry);
        limits->count = 0;
 
@@ -771,6 +779,8 @@ static errcode_t calculate_tree(ext2_filsys fs,
                                struct out_dir *outdir,
                                ext2_ino_t ino,
                                ext2_ino_t parent,
+                               struct ext2_dir_entry *dot_de,
+                               struct ext2_dir_entry *dotdot_de,
                                struct ext2_inode *inode)
 {
        struct ext2_dx_root_info        *root_info;
@@ -780,7 +790,9 @@ static errcode_t calculate_tree(ext2_filsys fs,
        int                             i, c1, c2, c3, nblks;
        int                             limit_offset, int_offset, root_offset;
 
-       root_info = set_root_node(fs, outdir->buf, ino, parent, inode);
+       root_info = set_root_node(fs, outdir->buf, ino, parent, dot_de,
+                                 dotdot_de, inode);
+
        root_offset = limit_offset = ((char *) root_info - outdir->buf) +
                root_info->info_length;
        root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
@@ -1083,11 +1095,10 @@ resort:
        if (retval)
                goto errout;
 
-       free(dir_buf); dir_buf = 0;
-
        if (!fd.compress) {
                /* Calculate the interior nodes */
-               retval = calculate_tree(fs, &outdir, ino, fd.parent, fd.inode);
+               retval = calculate_tree(fs, &outdir, ino, fd.parent,
+                                       fd.dot_de, fd.dotdot_de, fd.inode);
                if (retval)
                        goto errout;
        }