int compress;
ino_t parent;
ext2_ino_t dir;
+ struct ext2_dir_entry *dot_de;
+ struct ext2_dir_entry *dotdot_de;
};
struct hash_entry {
if (dirent->inode == 0)
continue;
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) {
}
ent = fd->harray + fd->num_array++;
ent->dir = dirent;
- fd->dir_size += EXT2_DIR_REC_LEN(name_len);
+ fd->dir_size += EXT2_DIR_REC_LEN(dirent);
ent->ino = dirent->inode;
if (fd->compress)
ent->hash = ent->minor_hash = 0;
if (min_len > he_b_len)
min_len = he_b_len;
- ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
+ ret = memcmp(he_a->dir->name, he_b->dir->name, min_len);
if (ret == 0) {
if (he_a_len > he_b_len)
ret = 1;
if (!ent->dir->inode ||
(ext2fs_dirent_name_len(ent->dir) !=
ext2fs_dirent_name_len(prev->dir)) ||
- strncmp(ent->dir->name, prev->dir->name,
+ memcmp(ent->dir->name, prev->dir->name,
ext2fs_dirent_name_len(ent->dir)))
continue;
pctx.dirent = ent->dir;
if ((i==j) ||
(new_len !=
(unsigned) ext2fs_dirent_name_len(fd->harray[j].dir)) ||
- strncmp(new_name, fd->harray[j].dir->name, new_len))
+ memcmp(new_name, fd->harray[j].dir->name, new_len))
continue;
mutate_name(new_name, &new_len);
ent = fd->harray + i;
if (ent->dir->inode == 0)
continue;
- rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(ent->dir));
+ rec_len = EXT2_DIR_REC_LEN(ent->dir);
if (rec_len > left) {
if (left) {
left += prev_rec_len;
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);
offset += rec_len;
left -= rec_len;
if (left < slack) {
static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
- ext2_ino_t ino, ext2_ino_t parent)
+ ext2_ino_t ino, ext2_ino_t parent,
+ struct ext2_dir_entry *dot_de,
+ struct ext2_dir_entry *dotdot_de)
{
- 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;
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;
return (struct ext2_dx_entry *) limits;
}
+static int alloc_blocks(ext2_filsys fs,
+ struct ext2_dx_countlimit **limit,
+ struct ext2_dx_entry **prev_ent,
+ struct ext2_dx_entry **next_ent,
+ int *prev_offset, int *next_offset,
+ struct out_dir *outdir, int i,
+ int *prev_count, int *next_count)
+{
+ errcode_t retval;
+ char *block_start;
+
+ if (*limit)
+ (*limit)->limit = (*limit)->count =
+ ext2fs_cpu_to_le16((*limit)->limit);
+ *prev_ent = (struct ext2_dx_entry *) (outdir->buf + *prev_offset);
+ (*prev_ent)->block = ext2fs_cpu_to_le32(outdir->num);
+
+ if (i != 1)
+ (*prev_ent)->hash =
+ ext2fs_cpu_to_le32(outdir->hashes[i]);
+
+ retval = get_next_block(fs, outdir, &block_start);
+ if (retval)
+ return retval;
+
+ *next_ent = set_int_node(fs, block_start);
+ *limit = (struct ext2_dx_countlimit *)(*next_ent);
+ if (next_offset)
+ *next_offset = ((char *) *next_ent - outdir->buf);
+
+ *next_count = (*limit)->limit;
+ (*prev_offset) += sizeof(struct ext2_dx_entry);
+ (*prev_count)--;
+
+ return 0;
+}
+
/*
* This function takes the leaf nodes which have been written in
* outdir, and populates the root node and any necessary interior nodes.
static errcode_t calculate_tree(ext2_filsys fs,
struct out_dir *outdir,
ext2_ino_t ino,
- ext2_ino_t parent)
+ ext2_ino_t parent,
+ struct ext2_dir_entry *dot_de,
+ struct ext2_dir_entry *dotdot_de)
{
- struct ext2_dx_root_info *root_info;
- struct ext2_dx_entry *root, *dx_ent = 0;
- struct ext2_dx_countlimit *root_limit, *limit;
+ struct ext2_dx_root_info *root_info;
+ struct ext2_dx_entry *root, *int_ent, *dx_ent = 0;
+ struct ext2_dx_countlimit *root_limit, *int_limit, *limit;
errcode_t retval;
- char * block_start;
- int i, c1, c2, nblks;
- int limit_offset, root_offset;
+ int i, c1, c2, c3, nblks;
+ int limit_offset, int_offset, root_offset;
+
+ root_info = set_root_node(fs, outdir->buf, ino, parent, dot_de,
+ dotdot_de);
- root_info = set_root_node(fs, outdir->buf, ino, parent);
root_offset = limit_offset = ((char *) root_info - outdir->buf) +
root_info->info_length;
root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
nblks = outdir->num;
/* Write out the pointer blocks */
- if (nblks-1 <= c1) {
+ if (nblks - 1 <= c1) {
/* Just write out the root block, and we're done */
root = (struct ext2_dx_entry *) (outdir->buf + root_offset);
for (i=1; i < nblks; i++) {
root++;
c1--;
}
- } else {
+ } else if (nblks - 1 <= ext2fs_htree_intnode_maxrecs(fs, c1)) {
c2 = 0;
- limit = 0;
+ limit = NULL;
root_info->indirect_levels = 1;
for (i=1; i < nblks; i++) {
- if (c1 == 0)
+ if (c2 == 0 && c1 == 0)
return ENOSPC;
if (c2 == 0) {
- if (limit)
- limit->limit = limit->count =
- ext2fs_cpu_to_le16(limit->limit);
- root = (struct ext2_dx_entry *)
- (outdir->buf + root_offset);
- root->block = ext2fs_cpu_to_le32(outdir->num);
- if (i != 1)
- root->hash =
- ext2fs_cpu_to_le32(outdir->hashes[i]);
- if ((retval = get_next_block(fs, outdir,
- &block_start)))
+ retval = alloc_blocks(fs, &limit, &root,
+ &dx_ent, &root_offset,
+ NULL, outdir, i, &c1,
+ &c2);
+ if (retval)
return retval;
- dx_ent = set_int_node(fs, block_start);
- limit = (struct ext2_dx_countlimit *) dx_ent;
- c2 = limit->limit;
- root_offset += sizeof(struct ext2_dx_entry);
- c1--;
}
dx_ent->block = ext2fs_cpu_to_le32(i);
if (c2 != limit->limit)
}
limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
limit->limit = ext2fs_cpu_to_le16(limit->limit);
+ } else {
+ c2 = 0;
+ c3 = 0;
+ limit = NULL;
+ int_limit = 0;
+ root_info->indirect_levels = 2;
+ for (i = 1; i < nblks; i++) {
+ if (c3 == 0 && c2 == 0 && c1 == 0)
+ return ENOSPC;
+ if (c3 == 0 && c2 == 0) {
+ retval = alloc_blocks(fs, &int_limit, &root,
+ &int_ent, &root_offset,
+ &int_offset, outdir, i,
+ &c1, &c2);
+ if (retval)
+ return retval;
+ }
+ if (c3 == 0) {
+ retval = alloc_blocks(fs, &limit, &int_ent,
+ &dx_ent, &int_offset,
+ NULL, outdir, i, &c2,
+ &c3);
+ if (retval)
+ return retval;
+
+ }
+ dx_ent->block = ext2fs_cpu_to_le32(i);
+ if (c3 != limit->limit)
+ dx_ent->hash =
+ ext2fs_cpu_to_le32(outdir->hashes[i]);
+ dx_ent++;
+ c3--;
+ }
+ int_limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
+ int_limit->limit = ext2fs_cpu_to_le16(limit->limit);
+
+ limit->count = ext2fs_cpu_to_le16(limit->limit - c3);
+ limit->limit = ext2fs_cpu_to_le16(limit->limit);
+
}
root_limit = (struct ext2_dx_countlimit *) (outdir->buf + limit_offset);
root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
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);
+ retval = calculate_tree(fs, &outdir, ino, fd.parent,
+ fd.dot_de, fd.dotdot_de);
if (retval)
goto errout;
}