2 * link.c --- create links in a ext2fs directory
4 * Copyright (C) 1993, 1994 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
23 #define EXT2_DX_ROOT_OFF 24
28 struct ext2_dx_countlimit *head;
29 struct ext2_dx_entry *entries;
30 struct ext2_dx_entry *at;
33 struct dx_lookup_info {
39 struct dx_frame frames[EXT4_HTREE_LEVEL];
42 static errcode_t alloc_dx_frame(ext2_filsys fs, struct dx_frame *frame)
44 return ext2fs_get_mem(fs->blocksize, &frame->buf);
47 static void dx_release(struct dx_lookup_info *info)
51 for (level = 0; level < info->levels; level++) {
52 if (info->frames[level].buf == NULL)
54 ext2fs_free_mem(&(info->frames[level].buf));
59 static void dx_search_entry(struct dx_frame *frame, int count, __u32 hash)
61 struct ext2_dx_entry *p, *q, *m;
63 p = frame->entries + 1;
64 q = frame->entries + count - 1;
67 if (ext2fs_le32_to_cpu(m->hash) > hash)
75 static errcode_t load_logical_dir_block(ext2_filsys fs, ext2_ino_t dir,
76 struct ext2_inode *diri, blk64_t block,
77 blk64_t *pblk, void *buf)
82 errcode = ext2fs_bmap2(fs, dir, diri, NULL, 0, block, &ret_flags,
86 if (ret_flags & BMAP_RET_UNINIT)
87 return EXT2_ET_DIR_CORRUPTED;
88 return ext2fs_read_dir_block4(fs, *pblk, buf, 0, dir);
91 static errcode_t dx_lookup(ext2_filsys fs, ext2_ino_t dir,
92 struct ext2_inode *diri, struct dx_lookup_info *info)
94 struct ext2_dx_root_info *root;
99 int hash_flags = diri->i_flags & EXT4_CASEFOLD_FL;
101 struct dx_frame *frame;
103 errcode = alloc_dx_frame(fs, &(info->frames[0]));
108 errcode = load_logical_dir_block(fs, dir, diri, 0,
109 &(info->frames[0].pblock),
110 info->frames[0].buf);
113 root = info->frames[0].buf + EXT2_DX_ROOT_OFF;
114 hash_alg = root->hash_version;
115 if (hash_alg != EXT2_HASH_TEA && hash_alg != EXT2_HASH_HALF_MD4 &&
116 hash_alg != EXT2_HASH_LEGACY) {
117 errcode = EXT2_ET_DIRHASH_UNSUPP;
120 if (hash_alg <= EXT2_HASH_TEA &&
121 fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)
123 if (root->indirect_levels >= ext2_dir_htree_level(fs)) {
124 errcode = EXT2_ET_DIR_CORRUPTED;
127 info->hash_alg = hash_alg;
129 errcode = ext2fs_dirhash2(hash_alg, info->name, info->namelen,
130 fs->encoding, hash_flags,
131 fs->super->s_hash_seed, &info->hash,
136 for (level = 0; level <= root->indirect_levels; level++) {
137 frame = &(info->frames[level]);
139 errcode = alloc_dx_frame(fs, frame);
144 errcode = load_logical_dir_block(fs, dir, diri,
145 ext2fs_le32_to_cpu(info->frames[level-1].at->block) & 0x0fffffff,
146 &(frame->pblock), frame->buf);
150 errcode = ext2fs_get_dx_countlimit(fs, frame->buf,
151 &(frame->head), NULL);
154 count = ext2fs_le16_to_cpu(frame->head->count);
155 limit = ext2fs_le16_to_cpu(frame->head->limit);
156 frame->entries = (struct ext2_dx_entry *)(frame->head);
157 if (!count || count > limit) {
158 errcode = EXT2_ET_DIR_CORRUPTED;
162 dx_search_entry(frame, count, info->hash);
177 unsigned int blocksize;
179 struct ext2_super_block *sb;
182 static int link_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
183 int entru EXT2FS_ATTR((unused)),
184 struct ext2_dir_entry *dirent,
190 struct link_struct *ls = (struct link_struct *) priv_data;
191 struct ext2_dir_entry *next;
192 unsigned int rec_len, min_rec_len, curr_rec_len;
199 rec_len = EXT2_DIR_REC_LEN(ls->namelen);
201 ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
205 if (ext2fs_has_feature_metadata_csum(ls->fs->super))
206 csum_size = sizeof(struct ext2_dir_entry_tail);
208 * See if the following directory entry (if any) is unused;
209 * if so, absorb it into this one.
211 next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
212 if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) &&
213 (next->inode == 0) &&
214 (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) {
215 curr_rec_len += next->rec_len;
216 ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
219 ret = DIRENT_CHANGED;
223 * If the directory entry is used, see if we can split the
224 * directory entry to make room for the new name. If so,
225 * truncate it and return.
228 min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent));
229 if (curr_rec_len < (min_rec_len + rec_len))
231 rec_len = curr_rec_len - min_rec_len;
232 ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent);
235 next = (struct ext2_dir_entry *) (buf + offset +
238 ext2fs_dirent_set_name_len(next, 0);
239 ext2fs_dirent_set_file_type(next, 0);
240 ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next);
243 return DIRENT_CHANGED;
247 * If we get this far, then the directory entry is not used.
248 * See if we can fit the request entry in. If so, do it.
250 if (curr_rec_len < rec_len)
252 dirent->inode = ls->inode;
253 ext2fs_dirent_set_name_len(dirent, ls->namelen);
254 strncpy(dirent->name, ls->name, ls->namelen);
255 if (ext2fs_has_feature_filetype(ls->sb))
256 ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7);
259 return DIRENT_ABORT|DIRENT_CHANGED;
262 static errcode_t add_dirent_to_buf(ext2_filsys fs, e2_blkcnt_t blockcnt,
263 char *buf, ext2_ino_t dir,
264 struct ext2_inode *diri, const char *name,
265 ext2_ino_t ino, int flags, blk64_t *pblkp)
267 struct dir_context ctx;
268 struct link_struct ls;
271 retval = load_logical_dir_block(fs, dir, diri, blockcnt, pblkp, buf);
275 ctx.func = link_proc;
277 ctx.flags = DIRENT_FLAG_INCLUDE_EMPTY;
283 ls.namelen = strlen(name);
288 ls.blocksize = fs->blocksize;
291 ext2fs_process_dir_block(fs, pblkp, blockcnt, 0, 0, &ctx);
297 return EXT2_ET_DIR_NO_SPACE;
307 static EXT2_QSORT_TYPE dx_hash_map_cmp(const void *ap, const void *bp)
309 const struct dx_hash_map *a = ap, *b = bp;
311 if (a->hash < b->hash)
313 if (a->hash > b->hash)
318 static errcode_t dx_move_dirents(ext2_filsys fs, struct dx_hash_map *map,
319 int count, void *from, void *to)
321 struct ext2_dir_entry *de;
328 if (ext2fs_has_feature_metadata_csum(fs->super))
329 csum_size = sizeof(struct ext2_dir_entry_tail);
331 for (i = 0; i < count; i++) {
332 de = from + map[i].off;
333 rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(de));
334 memcpy(to, de, rec_len);
335 retval = ext2fs_set_rec_len(fs, rec_len, to);
341 * Update rec_len of the last dir entry to stretch to the end of block
344 rec_len = fs->blocksize - (to - base) - csum_size;
345 retval = ext2fs_set_rec_len(fs, rec_len, to);
349 ext2fs_initialize_dirent_tail(fs,
350 EXT2_DIRENT_TAIL(base, fs->blocksize));
354 static errcode_t dx_insert_entry(ext2_filsys fs, ext2_ino_t dir,
355 struct dx_lookup_info *info, int level,
356 __u32 hash, blk64_t lblk)
359 struct ext2_dx_entry *top, *new;
361 pcount = ext2fs_le16_to_cpu(info->frames[level].head->count);
362 top = info->frames[level].entries + pcount;
363 new = info->frames[level].at + 1;
364 memmove(new + 1, new, (char *)top - (char *)new);
365 new->hash = ext2fs_cpu_to_le32(hash);
366 new->block = ext2fs_cpu_to_le32(lblk);
367 info->frames[level].head->count = ext2fs_cpu_to_le16(pcount + 1);
368 return ext2fs_write_dir_block4(fs, info->frames[level].pblock,
369 info->frames[level].buf, 0, dir);
372 static errcode_t dx_split_leaf(ext2_filsys fs, ext2_ino_t dir,
373 struct ext2_inode *diri,
374 struct dx_lookup_info *info, void *buf,
375 blk64_t leaf_pblk, blk64_t new_lblk,
378 int hash_flags = diri->i_flags & EXT4_CASEFOLD_FL;
379 struct ext2_dir_entry *de;
381 errcode_t retval = 0;
382 unsigned int rec_len;
383 unsigned int offset, move_size;
385 struct dx_hash_map *map;
389 retval = ext2fs_get_mem(fs->blocksize, &buf2);
392 retval = ext2fs_get_array(fs->blocksize / 12,
393 sizeof(struct dx_hash_map), &map);
395 ext2fs_free_mem(&buf2);
398 for (offset = 0; offset < fs->blocksize; offset += rec_len) {
400 retval = ext2fs_get_rec_len(fs, de, &rec_len);
403 if (ext2fs_dirent_name_len(de) > 0 && de->inode) {
404 map[count].off = offset;
405 map[count].size = rec_len;
406 retval = ext2fs_dirhash2(info->hash_alg, de->name,
407 ext2fs_dirent_name_len(de),
408 fs->encoding, hash_flags,
409 fs->super->s_hash_seed,
417 qsort(map, count, sizeof(struct dx_hash_map), dx_hash_map_cmp);
419 /* Find place to split block */
420 for (i = count - 1; i >= 0; i--) {
421 if (move_size + map[i].size / 2 > fs->blocksize / 2)
423 move_size += map[i].size;
425 /* Let i be the first entry to move */
427 /* Move selected directory entries to new block */
428 retval = dx_move_dirents(fs, map + i, count - i, buf, buf2);
431 retval = ext2fs_write_dir_block4(fs, new_pblk, buf2, 0, dir);
434 /* Repack remaining entries in the old block */
435 retval = dx_move_dirents(fs, map, i, buf, buf2);
438 retval = ext2fs_write_dir_block4(fs, leaf_pblk, buf2, 0, dir);
441 /* Update parent node */
442 continued = map[i].hash == map[i-1].hash;
443 retval = dx_insert_entry(fs, dir, info, info->levels - 1,
444 map[i].hash + continued, new_lblk);
446 ext2fs_free_mem(&buf2);
447 ext2fs_free_mem(&map);
451 static errcode_t dx_grow_tree(ext2_filsys fs, ext2_ino_t dir,
452 struct ext2_inode *diri,
453 struct dx_lookup_info *info, void *buf,
458 ext2_off64_t size = EXT2_I_SIZE(diri);
460 struct ext2_dir_entry *de;
461 struct ext2_dx_countlimit *head;
465 if (ext2fs_has_feature_metadata_csum(fs->super))
466 csum_size = sizeof(struct ext2_dx_tail);
468 /* Find level which can accommodate new child */
469 for (i = info->levels - 1; i >= 0; i--)
470 if (ext2fs_le16_to_cpu(info->frames[i].head->count) <
471 ext2fs_le16_to_cpu(info->frames[i].head->limit))
473 /* Need to grow tree depth? */
474 if (i < 0 && info->levels >= ext2_dir_htree_level(fs))
475 return EXT2_ET_DIR_NO_SPACE;
476 lblk = size / fs->blocksize;
477 size += fs->blocksize;
478 retval = ext2fs_inode_size_set(fs, diri, size);
481 retval = ext2fs_fallocate(fs,
482 EXT2_FALLOCATE_FORCE_INIT | EXT2_FALLOCATE_ZERO_BLOCKS,
483 dir, diri, 0, lblk, 1);
486 retval = ext2fs_write_inode(fs, dir, diri);
489 retval = ext2fs_bmap2(fs, dir, diri, NULL, 0, lblk, NULL, &pblk);
492 /* Only leaf addition needed? */
493 if (i == info->levels - 1)
494 return dx_split_leaf(fs, dir, diri, info, buf, leaf_pblk,
499 ext2fs_dirent_set_name_len(de, 0);
500 ext2fs_dirent_set_file_type(de, 0);
501 retval = ext2fs_set_rec_len(fs, fs->blocksize, de);
505 count = ext2fs_le16_to_cpu(info->frames[i+1].head->count);
506 /* Growing tree depth? */
508 struct ext2_dx_root_info *root;
510 memcpy(head, info->frames[0].entries,
511 count * sizeof(struct ext2_dx_entry));
512 head->limit = ext2fs_cpu_to_le16(
513 (fs->blocksize - (8 + csum_size)) /
514 sizeof(struct ext2_dx_entry));
515 /* head->count gets set by memcpy above to correct value */
517 /* Now update tree root */
518 info->frames[0].head->count = ext2fs_cpu_to_le16(1);
519 info->frames[0].entries[0].block = ext2fs_cpu_to_le32(lblk);
520 root = info->frames[0].buf + EXT2_DX_ROOT_OFF;
521 root->indirect_levels++;
523 /* Splitting internal node in two */
524 int count1 = count / 2;
525 int count2 = count - count1;
526 __u32 split_hash = ext2fs_le32_to_cpu(info->frames[i+1].entries[count1].hash);
528 memcpy(head, info->frames[i+1].entries + count1,
529 count2 * sizeof(struct ext2_dx_entry));
530 head->count = ext2fs_cpu_to_le16(count2);
531 head->limit = ext2fs_cpu_to_le16(
532 (fs->blocksize - (8 + csum_size)) /
533 sizeof(struct ext2_dx_entry));
534 info->frames[i+1].head->count = ext2fs_cpu_to_le16(count1);
536 /* Update parent node */
537 retval = dx_insert_entry(fs, dir, info, i, split_hash, lblk);
542 /* Writeout split block / updated root */
543 retval = ext2fs_write_dir_block4(fs, info->frames[i+1].pblock,
544 info->frames[i+1].buf, 0, dir);
547 /* Writeout new tree block */
548 retval = ext2fs_write_dir_block4(fs, pblk, buf, 0, dir);
554 static errcode_t dx_link(ext2_filsys fs, ext2_ino_t dir,
555 struct ext2_inode *diri, const char *name,
556 ext2_ino_t ino, int flags)
558 struct dx_lookup_info dx_info;
564 retval = ext2fs_get_mem(fs->blocksize, &blockbuf);
569 dx_info.namelen = strlen(name);
571 retval = dx_lookup(fs, dir, diri, &dx_info);
575 retval = add_dirent_to_buf(fs,
576 ext2fs_le32_to_cpu(dx_info.frames[dx_info.levels-1].at->block) & 0x0fffffff,
577 blockbuf, dir, diri, name, ino, flags, &leaf_pblk);
579 * Success or error other than ENOSPC...? We are done. We may need upto
580 * two tries to add entry. One to split htree node and another to add
583 if (restart >= dx_info.levels || retval != EXT2_ET_DIR_NO_SPACE)
585 retval = dx_grow_tree(fs, dir, diri, &dx_info, blockbuf, leaf_pblk);
588 /* Restart everything now that the tree is larger */
590 dx_release(&dx_info);
593 dx_release(&dx_info);
595 ext2fs_free_mem(&blockbuf);
600 * Note: the low 3 bits of the flags field are used as the directory
606 errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
607 ext2_ino_t ino, int flags)
610 struct link_struct ls;
611 struct ext2_inode inode;
613 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
615 if (!(fs->flags & EXT2_FLAG_RW))
616 return EXT2_ET_RO_FILSYS;
618 if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
621 if (inode.i_flags & EXT2_INDEX_FL)
622 return dx_link(fs, dir, &inode, name, ino, flags);
626 ls.namelen = name ? strlen(name) : 0;
631 ls.blocksize = fs->blocksize;
634 retval = ext2fs_dir_iterate2(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
635 NULL, link_proc, &ls);
642 return EXT2_ET_DIR_NO_SPACE;