Home | History | Annotate | Line # | Download | only in ext2fs
ext2fs_htree.c revision 1.2
      1  1.2  christos /*	$NetBSD: ext2fs_htree.c,v 1.2 2016/08/09 07:15:35 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*-
      4  1.1  christos  * Copyright (c) 2010, 2012 Zheng Liu <lz (at) freebsd.org>
      5  1.1  christos  * Copyright (c) 2012, Vyacheslav Matyushin
      6  1.1  christos  * All rights reserved.
      7  1.1  christos  *
      8  1.1  christos  * Redistribution and use in source and binary forms, with or without
      9  1.1  christos  * modification, are permitted provided that the following conditions
     10  1.1  christos  * are met:
     11  1.1  christos  * 1. Redistributions of source code must retain the above copyright
     12  1.1  christos  *    notice, this list of conditions and the following disclaimer.
     13  1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     15  1.1  christos  *    documentation and/or other materials provided with the distribution.
     16  1.1  christos  *
     17  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     18  1.1  christos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  1.1  christos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  1.1  christos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     21  1.1  christos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  1.1  christos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  1.1  christos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  1.1  christos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  1.1  christos  * SUCH DAMAGE.
     28  1.1  christos  *
     29  1.2  christos  * $FreeBSD: head/sys/fs/ext2fs/ext2fs_htree.c 294653 2016-01-24 02:41:49Z pfg $
     30  1.1  christos  */
     31  1.1  christos #include <sys/cdefs.h>
     32  1.2  christos __KERNEL_RCSID(0, "$NetBSD: ext2fs_htree.c,v 1.2 2016/08/09 07:15:35 christos Exp $");
     33  1.1  christos 
     34  1.1  christos #include <sys/param.h>
     35  1.1  christos #include <sys/systm.h>
     36  1.1  christos #include <sys/resourcevar.h>
     37  1.1  christos #include <sys/kernel.h>
     38  1.1  christos #include <sys/file.h>
     39  1.1  christos #include <sys/stat.h>
     40  1.1  christos #include <sys/buf.h>
     41  1.1  christos #include <sys/proc.h>
     42  1.1  christos #include <sys/mount.h>
     43  1.1  christos #include <sys/namei.h>
     44  1.1  christos #include <sys/vnode.h>
     45  1.1  christos #include <sys/lockf.h>
     46  1.1  christos #include <sys/pool.h>
     47  1.1  christos #include <sys/signalvar.h>
     48  1.1  christos #include <sys/kauth.h>
     49  1.2  christos #include <sys/malloc.h>
     50  1.1  christos #include <ufs/ufs/dir.h>
     51  1.1  christos 
     52  1.1  christos #include <ufs/ufs/inode.h>
     53  1.1  christos #include <ufs/ufs/ufsmount.h>
     54  1.1  christos #include <ufs/ext2fs/ext2fs.h>
     55  1.1  christos 
     56  1.1  christos #include <ufs/ext2fs/ext2fs_extern.h>
     57  1.1  christos #include <ufs/ext2fs/ext2fs_dinode.h>
     58  1.1  christos #include <ufs/ext2fs/ext2fs_dir.h>
     59  1.1  christos #include <ufs/ext2fs/ext2fs_htree.h>
     60  1.1  christos #include <ufs/ext2fs/ext2fs_hash.h>
     61  1.1  christos 
     62  1.2  christos static int ext2fs_htree_find_leaf(struct inode *, const char *, int ,
     63  1.2  christos     uint32_t *, uint8_t *, struct ext2fs_htree_lookup_info *);
     64  1.2  christos 
     65  1.1  christos int
     66  1.1  christos ext2fs_htree_has_idx(struct inode *ip)
     67  1.1  christos {
     68  1.2  christos 	/* XXX ip->i_flags should have got checked here for IN_E3INDEX */
     69  1.1  christos 	return EXT2_HAS_COMPAT_FEATURE(ip->i_e2fs, EXT2F_COMPAT_DIRHASHINDEX)
     70  1.1  christos 	    && (ip->i_din.e2fs_din->e2di_flags & EXT2_INDEX);
     71  1.1  christos }
     72  1.1  christos 
     73  1.1  christos static off_t
     74  1.1  christos ext2fs_htree_get_block(struct ext2fs_htree_entry *ep)
     75  1.1  christos {
     76  1.1  christos 	return ep->h_blk & 0x00FFFFFF;
     77  1.1  christos }
     78  1.1  christos 
     79  1.1  christos static void
     80  1.1  christos ext2fs_htree_release(struct ext2fs_htree_lookup_info *info)
     81  1.1  christos {
     82  1.1  christos 	for (u_int i = 0; i < info->h_levels_num; i++) {
     83  1.1  christos 		struct buf *bp = info->h_levels[i].h_bp;
     84  1.1  christos 		if (bp != NULL)
     85  1.1  christos 			brelse(bp, 0);
     86  1.1  christos 	}
     87  1.1  christos }
     88  1.1  christos 
     89  1.1  christos static uint16_t
     90  1.1  christos ext2fs_htree_get_limit(struct ext2fs_htree_entry *ep)
     91  1.1  christos {
     92  1.1  christos 	return ((struct ext2fs_htree_count *)(ep))->h_entries_max;
     93  1.1  christos }
     94  1.1  christos 
     95  1.1  christos static uint32_t
     96  1.1  christos ext2fs_htree_root_limit(struct inode *ip, int len)
     97  1.1  christos {
     98  1.1  christos 	uint32_t space = ip->i_e2fs->e2fs_bsize - EXT2_DIR_REC_LEN(1) -
     99  1.1  christos 	    EXT2_DIR_REC_LEN(2) - len;
    100  1.1  christos 	return space / sizeof(struct ext2fs_htree_entry);
    101  1.1  christos }
    102  1.1  christos 
    103  1.1  christos static uint16_t
    104  1.1  christos ext2fs_htree_get_count(struct ext2fs_htree_entry *ep)
    105  1.1  christos {
    106  1.1  christos 	return ((struct ext2fs_htree_count *)(ep))->h_entries_num;
    107  1.1  christos }
    108  1.1  christos 
    109  1.1  christos static uint32_t
    110  1.1  christos ext2fs_htree_get_hash(struct ext2fs_htree_entry *ep)
    111  1.1  christos {
    112  1.1  christos 	return ep->h_hash;
    113  1.1  christos }
    114  1.1  christos 
    115  1.2  christos 
    116  1.2  christos static void
    117  1.2  christos ext2fs_htree_set_block(struct ext2fs_htree_entry *ep, uint32_t blk)
    118  1.2  christos {
    119  1.2  christos 	ep->h_blk = blk;
    120  1.2  christos }
    121  1.2  christos 
    122  1.2  christos static void
    123  1.2  christos ext2fs_htree_set_count(struct ext2fs_htree_entry *ep, uint16_t cnt)
    124  1.2  christos {
    125  1.2  christos 	((struct ext2fs_htree_count *)(ep))->h_entries_num = cnt;
    126  1.2  christos }
    127  1.2  christos 
    128  1.2  christos static void
    129  1.2  christos ext2fs_htree_set_hash(struct ext2fs_htree_entry *ep, uint32_t hash)
    130  1.2  christos {
    131  1.2  christos 	ep->h_hash = hash;
    132  1.2  christos }
    133  1.2  christos 
    134  1.2  christos static void
    135  1.2  christos ext2fs_htree_set_limit(struct ext2fs_htree_entry *ep, uint16_t limit)
    136  1.2  christos {
    137  1.2  christos 	((struct ext2fs_htree_count *)(ep))->h_entries_max = limit;
    138  1.2  christos }
    139  1.2  christos 
    140  1.2  christos static uint32_t
    141  1.2  christos ext2fs_htree_node_limit(struct inode *ip)
    142  1.2  christos {
    143  1.2  christos 	struct m_ext2fs *fs;
    144  1.2  christos 	uint32_t space;
    145  1.2  christos 
    146  1.2  christos 	fs = ip->i_e2fs;
    147  1.2  christos 	space = fs->e2fs_bsize - EXT2_DIR_REC_LEN(0);
    148  1.2  christos 
    149  1.2  christos 	return space / sizeof(struct ext2fs_htree_entry);
    150  1.2  christos }
    151  1.2  christos 
    152  1.2  christos static int
    153  1.2  christos ext2fs_htree_append_block(struct vnode *vp, char *data,
    154  1.2  christos     struct componentname *cnp, uint32_t blksize)
    155  1.2  christos {
    156  1.2  christos 	struct iovec aiov;
    157  1.2  christos 	struct uio auio;
    158  1.2  christos 	struct inode *dp = VTOI(vp);
    159  1.2  christos 	uint64_t cursize, newsize;
    160  1.2  christos 	int error;
    161  1.2  christos 
    162  1.2  christos 	cursize = roundup(dp->i_size, blksize);
    163  1.2  christos 	newsize = cursize + blksize;
    164  1.2  christos 
    165  1.2  christos 	auio.uio_offset = cursize;
    166  1.2  christos 	auio.uio_resid = blksize;
    167  1.2  christos 	aiov.iov_len = blksize;
    168  1.2  christos 	aiov.iov_base = data;
    169  1.2  christos 	auio.uio_iov = &aiov;
    170  1.2  christos 	auio.uio_iovcnt = 1;
    171  1.2  christos 	auio.uio_rw = UIO_WRITE;
    172  1.2  christos 	auio.uio_vmspace = vmspace_kernel();
    173  1.2  christos 	error = VOP_WRITE(vp, &auio, IO_SYNC, cnp->cn_cred);
    174  1.2  christos 	if (!error)
    175  1.2  christos 		dp->i_size = newsize;
    176  1.2  christos 
    177  1.2  christos 	return error;
    178  1.2  christos }
    179  1.2  christos 
    180  1.2  christos static int
    181  1.2  christos ext2fs_htree_writebuf(struct ext2fs_htree_lookup_info *info)
    182  1.2  christos {
    183  1.2  christos 	int i, error;
    184  1.2  christos 
    185  1.2  christos 	for (i = 0; i < info->h_levels_num; i++) {
    186  1.2  christos 		struct buf *bp = info->h_levels[i].h_bp;
    187  1.2  christos 		error = bwrite(bp);
    188  1.2  christos 		if (error)
    189  1.2  christos 			return error;
    190  1.2  christos 	}
    191  1.2  christos 
    192  1.2  christos 	return 0;
    193  1.2  christos }
    194  1.2  christos 
    195  1.2  christos static void
    196  1.2  christos ext2fs_htree_insert_entry_to_level(struct ext2fs_htree_lookup_level *level,
    197  1.2  christos     uint32_t hash, uint32_t blk)
    198  1.2  christos {
    199  1.2  christos 	struct ext2fs_htree_entry *target;
    200  1.2  christos 	int entries_num;
    201  1.2  christos 
    202  1.2  christos 	target = level->h_entry + 1;
    203  1.2  christos 	entries_num = ext2fs_htree_get_count(level->h_entries);
    204  1.2  christos 
    205  1.2  christos 	memmove(target + 1, target, (char *)(level->h_entries + entries_num) -
    206  1.2  christos 	    (char *)target);
    207  1.2  christos 	ext2fs_htree_set_block(target, blk);
    208  1.2  christos 	ext2fs_htree_set_hash(target, hash);
    209  1.2  christos 	ext2fs_htree_set_count(level->h_entries, entries_num + 1);
    210  1.2  christos }
    211  1.2  christos 
    212  1.2  christos /*
    213  1.2  christos  * Insert an index entry to the index node.
    214  1.2  christos  */
    215  1.2  christos static void
    216  1.2  christos ext2fs_htree_insert_entry(struct ext2fs_htree_lookup_info *info,
    217  1.2  christos     uint32_t hash, uint32_t blk)
    218  1.2  christos {
    219  1.2  christos 	struct ext2fs_htree_lookup_level *level;
    220  1.2  christos 
    221  1.2  christos 	level = &info->h_levels[info->h_levels_num - 1];
    222  1.2  christos 	ext2fs_htree_insert_entry_to_level(level, hash, blk);
    223  1.2  christos }
    224  1.2  christos 
    225  1.2  christos /*
    226  1.2  christos  * Compare two entry sort descriptors by name hash value.
    227  1.2  christos  * This is used together with qsort.
    228  1.2  christos  */
    229  1.2  christos static int
    230  1.2  christos ext2fs_htree_cmp_sort_entry(const void *e1, const void *e2)
    231  1.2  christos {
    232  1.2  christos 	const struct ext2fs_htree_sort_entry *entry1, *entry2;
    233  1.2  christos 
    234  1.2  christos 	entry1 = (const struct ext2fs_htree_sort_entry *)e1;
    235  1.2  christos 	entry2 = (const struct ext2fs_htree_sort_entry *)e2;
    236  1.2  christos 
    237  1.2  christos 	if (entry1->h_hash < entry2->h_hash)
    238  1.2  christos 		return -1;
    239  1.2  christos 	if (entry1->h_hash > entry2->h_hash)
    240  1.2  christos 		return 1;
    241  1.2  christos 	return 0;
    242  1.2  christos }
    243  1.2  christos 
    244  1.2  christos /*
    245  1.2  christos  * Append an entry to the end of the directory block.
    246  1.2  christos  */
    247  1.2  christos static void
    248  1.2  christos ext2fs_append_entry(char *block, uint32_t blksize,
    249  1.2  christos     struct ext2fs_direct *last_entry, struct ext2fs_direct *new_entry)
    250  1.2  christos {
    251  1.2  christos 	uint16_t entry_len;
    252  1.2  christos 
    253  1.2  christos 	entry_len = EXT2_DIR_REC_LEN(last_entry->e2d_namlen);
    254  1.2  christos 	last_entry->e2d_reclen = entry_len;
    255  1.2  christos 	last_entry = (struct ext2fs_direct *)((char *)last_entry + entry_len);
    256  1.2  christos 	new_entry->e2d_reclen = block + blksize - (char *)last_entry;
    257  1.2  christos 	memcpy(last_entry, new_entry, EXT2_DIR_REC_LEN(new_entry->e2d_namlen));
    258  1.2  christos }
    259  1.2  christos 
    260  1.2  christos /*
    261  1.2  christos  * Move half of entries from the old directory block to the new one.
    262  1.2  christos  */
    263  1.2  christos static int
    264  1.2  christos ext2fs_htree_split_dirblock(char *block1, char *block2, uint32_t blksize,
    265  1.2  christos     uint32_t *hash_seed, uint8_t hash_version,
    266  1.2  christos     uint32_t *split_hash, struct ext2fs_direct *entry)
    267  1.2  christos {
    268  1.2  christos 	int entry_cnt = 0;
    269  1.2  christos 	int size = 0;
    270  1.2  christos 	int i, k;
    271  1.2  christos 	uint32_t offset;
    272  1.2  christos 	uint16_t entry_len = 0;
    273  1.2  christos 	uint32_t entry_hash;
    274  1.2  christos 	struct ext2fs_direct *ep, *last;
    275  1.2  christos 	char *dest;
    276  1.2  christos 	struct ext2fs_htree_sort_entry *sort_info, dummy;
    277  1.2  christos 
    278  1.2  christos 	ep = (struct ext2fs_direct *)block1;
    279  1.2  christos 	dest = block2;
    280  1.2  christos 	sort_info = (struct ext2fs_htree_sort_entry *)
    281  1.2  christos 	    ((char *)block2 + blksize);
    282  1.2  christos 
    283  1.2  christos 	/*
    284  1.2  christos 	 * Calculate name hash value for the entry which is to be added.
    285  1.2  christos 	 */
    286  1.2  christos 	ext2fs_htree_hash(entry->e2d_name, entry->e2d_namlen, hash_seed,
    287  1.2  christos 	    hash_version, &entry_hash, NULL);
    288  1.2  christos 
    289  1.2  christos 	/*
    290  1.2  christos 	 * Fill in directory entry sort descriptors.
    291  1.2  christos 	 */
    292  1.2  christos 	while ((char *)ep < block1 + blksize) {
    293  1.2  christos 		if (ep->e2d_ino && ep->e2d_namlen) {
    294  1.2  christos 			entry_cnt++;
    295  1.2  christos 			sort_info--;
    296  1.2  christos 			sort_info->h_size = ep->e2d_reclen;
    297  1.2  christos 			sort_info->h_offset = (char *)ep - block1;
    298  1.2  christos 			ext2fs_htree_hash(ep->e2d_name, ep->e2d_namlen,
    299  1.2  christos 			    hash_seed, hash_version,
    300  1.2  christos 			    &sort_info->h_hash, NULL);
    301  1.2  christos 		}
    302  1.2  christos 		ep = (struct ext2fs_direct *)
    303  1.2  christos 		    ((char *)ep + ep->e2d_reclen);
    304  1.2  christos 	}
    305  1.2  christos 
    306  1.2  christos 	/*
    307  1.2  christos 	 * Sort directory entry descriptors by name hash value.
    308  1.2  christos 	 */
    309  1.2  christos 	kheapsort(sort_info, entry_cnt, sizeof(struct ext2fs_htree_sort_entry),
    310  1.2  christos 	    ext2fs_htree_cmp_sort_entry,&dummy);
    311  1.2  christos 
    312  1.2  christos 	/*
    313  1.2  christos 	 * Count the number of entries to move to directory block 2.
    314  1.2  christos 	 */
    315  1.2  christos 	for (i = entry_cnt - 1; i >= 0; i--) {
    316  1.2  christos 		if (sort_info[i].h_size + size > blksize / 2)
    317  1.2  christos 			break;
    318  1.2  christos 		size += sort_info[i].h_size;
    319  1.2  christos 	}
    320  1.2  christos 
    321  1.2  christos 	*split_hash = sort_info[i + 1].h_hash;
    322  1.2  christos 
    323  1.2  christos 	/*
    324  1.2  christos 	 * Set collision bit.
    325  1.2  christos 	 */
    326  1.2  christos 	if (*split_hash == sort_info[i].h_hash)
    327  1.2  christos 		*split_hash += 1;
    328  1.2  christos 
    329  1.2  christos 	/*
    330  1.2  christos 	 * Move half of directory entries from block 1 to block 2.
    331  1.2  christos 	 */
    332  1.2  christos 	for (k = i + 1; k < entry_cnt; k++) {
    333  1.2  christos 		ep = (struct ext2fs_direct *)((char *)block1 +
    334  1.2  christos 		    sort_info[k].h_offset);
    335  1.2  christos 		entry_len = EXT2_DIR_REC_LEN(ep->e2d_namlen);
    336  1.2  christos 		memcpy(dest, ep, entry_len);
    337  1.2  christos 		((struct ext2fs_direct *)dest)->e2d_reclen = entry_len;
    338  1.2  christos 		/* Mark directory entry as unused. */
    339  1.2  christos 		ep->e2d_ino = 0;
    340  1.2  christos 		dest += entry_len;
    341  1.2  christos 	}
    342  1.2  christos 	dest -= entry_len;
    343  1.2  christos 
    344  1.2  christos 	/* Shrink directory entries in block 1. */
    345  1.2  christos 	last = (struct ext2fs_direct *)block1;
    346  1.2  christos 	entry_len = 0;
    347  1.2  christos 	for (offset = 0; offset < blksize; ) {
    348  1.2  christos 		ep = (struct ext2fs_direct *)(block1 + offset);
    349  1.2  christos 		offset += ep->e2d_reclen;
    350  1.2  christos 		if (ep->e2d_ino) {
    351  1.2  christos 			last = (struct ext2fs_direct *)
    352  1.2  christos 			   ((char *)last + entry_len);
    353  1.2  christos 			entry_len = EXT2_DIR_REC_LEN(ep->e2d_namlen);
    354  1.2  christos 			memcpy((void *)last, (void *)ep, entry_len);
    355  1.2  christos 			last->e2d_reclen = entry_len;
    356  1.2  christos 		}
    357  1.2  christos 	}
    358  1.2  christos 
    359  1.2  christos 	if (entry_hash >= *split_hash) {
    360  1.2  christos 		/* Add entry to block 2. */
    361  1.2  christos 		ext2fs_append_entry(block2, blksize,
    362  1.2  christos 		    (struct ext2fs_direct *)dest, entry);
    363  1.2  christos 
    364  1.2  christos 		/* Adjust length field of last entry of block 1. */
    365  1.2  christos 		last->e2d_reclen = block1 + blksize - (char *)last;
    366  1.2  christos 	} else {
    367  1.2  christos 		/* Add entry to block 1. */
    368  1.2  christos 		ext2fs_append_entry(block1, blksize, last, entry);
    369  1.2  christos 
    370  1.2  christos 		/* Adjust length field of last entry of block 2. */
    371  1.2  christos 		((struct ext2fs_direct *)dest)->e2d_reclen =
    372  1.2  christos 		    block2 + blksize - dest;
    373  1.2  christos 	}
    374  1.2  christos 
    375  1.2  christos 	return 0;
    376  1.2  christos }
    377  1.2  christos 
    378  1.2  christos /*
    379  1.2  christos  * Create an HTree index for a directory having entries which are no more
    380  1.2  christos  * accommodable in a single dir-block.
    381  1.2  christos  */
    382  1.2  christos int
    383  1.2  christos ext2fs_htree_create_index(struct vnode *vp, struct componentname *cnp,
    384  1.2  christos     struct ext2fs_direct *new_entry)
    385  1.2  christos {
    386  1.2  christos 	struct buf *bp = NULL;
    387  1.2  christos 	struct inode *dp;
    388  1.2  christos 	struct ext2fs *fs;
    389  1.2  christos 	struct m_ext2fs *m_fs;
    390  1.2  christos 	struct ext2fs_direct *ep, *dotdot;
    391  1.2  christos 	struct ext2fs_htree_root *root;
    392  1.2  christos 	struct ext2fs_htree_lookup_info info;
    393  1.2  christos 	uint32_t blksize, dirlen, split_hash;
    394  1.2  christos 	uint8_t hash_version;
    395  1.2  christos 	char *buf1 = NULL;
    396  1.2  christos 	char *buf2 = NULL;
    397  1.2  christos 	int error = 0;
    398  1.2  christos 
    399  1.2  christos 	dp = VTOI(vp);
    400  1.2  christos 	fs = &(dp->i_e2fs->e2fs);
    401  1.2  christos 	m_fs = dp->i_e2fs;
    402  1.2  christos 	blksize = m_fs->e2fs_bsize;
    403  1.2  christos 
    404  1.2  christos 	buf1 = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
    405  1.2  christos 	buf2 = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
    406  1.2  christos 
    407  1.2  christos 	if ((error = ext2fs_blkatoff(vp, 0, NULL, &bp)) != 0)
    408  1.2  christos 		goto out;
    409  1.2  christos 
    410  1.2  christos 	root = (struct ext2fs_htree_root *)bp->b_data;
    411  1.2  christos 	dotdot = (struct ext2fs_direct *)((char *)&(root->h_dotdot));
    412  1.2  christos 	ep = (struct ext2fs_direct *)((char *)dotdot + dotdot->e2d_reclen);
    413  1.2  christos 	dirlen = (char *)root + blksize - (char *)ep;
    414  1.2  christos 	memcpy(buf1, ep, dirlen);
    415  1.2  christos 	ep = (struct ext2fs_direct *)buf1;
    416  1.2  christos 	while ((char *)ep < buf1 + dirlen)
    417  1.2  christos 		ep = (struct ext2fs_direct *)((char *)ep + ep->e2d_reclen);
    418  1.2  christos 	ep->e2d_reclen = buf1 + blksize - (char *)ep;
    419  1.2  christos 	/* XXX It should be made dp->i_flag |= IN_E3INDEX; */
    420  1.2  christos 	dp->i_din.e2fs_din->e2di_flags |= EXT2_INDEX;
    421  1.2  christos 
    422  1.2  christos 	/*
    423  1.2  christos 	 * Initialize index root.
    424  1.2  christos 	 */
    425  1.2  christos 	dotdot->e2d_reclen = blksize - EXT2_DIR_REC_LEN(1);
    426  1.2  christos 	memset(&root->h_info, 0, sizeof(root->h_info));
    427  1.2  christos 	root->h_info.h_hash_version = fs->e3fs_def_hash_version;
    428  1.2  christos 	root->h_info.h_info_len = sizeof(root->h_info);
    429  1.2  christos 	ext2fs_htree_set_block(root->h_entries, 1);
    430  1.2  christos 	ext2fs_htree_set_count(root->h_entries, 1);
    431  1.2  christos 	ext2fs_htree_set_limit(root->h_entries,
    432  1.2  christos 	    ext2fs_htree_root_limit(dp, sizeof(root->h_info)));
    433  1.2  christos 
    434  1.2  christos 	memset(&info, 0, sizeof(info));
    435  1.2  christos 	info.h_levels_num = 1;
    436  1.2  christos 	info.h_levels[0].h_entries = root->h_entries;
    437  1.2  christos 	info.h_levels[0].h_entry = root->h_entries;
    438  1.2  christos 
    439  1.2  christos 	hash_version = root->h_info.h_hash_version;
    440  1.2  christos 	if (hash_version <= EXT2_HTREE_TEA)
    441  1.2  christos 		hash_version += m_fs->e2fs_uhash;
    442  1.2  christos 	ext2fs_htree_split_dirblock(buf1, buf2, blksize, fs->e3fs_hash_seed,
    443  1.2  christos 	    hash_version, &split_hash, new_entry);
    444  1.2  christos 	ext2fs_htree_insert_entry(&info, split_hash, 2);
    445  1.2  christos 
    446  1.2  christos 	/*
    447  1.2  christos 	 * Write directory block 0.
    448  1.2  christos 	 */
    449  1.2  christos 	if ( (vp)->v_mount->mnt_iflag & IO_SYNC)
    450  1.2  christos 		(void)bwrite(bp);
    451  1.2  christos 	else
    452  1.2  christos 		bdwrite(bp);
    453  1.2  christos 
    454  1.2  christos 	dp->i_flag |= IN_CHANGE | IN_UPDATE;
    455  1.2  christos 	if (error)
    456  1.2  christos 		goto out;
    457  1.2  christos 
    458  1.2  christos 	/*
    459  1.2  christos 	 * Write directory block 1.
    460  1.2  christos 	 */
    461  1.2  christos 	error = ext2fs_htree_append_block(vp, buf1, cnp, blksize);
    462  1.2  christos 	if (error)
    463  1.2  christos 		goto out1;
    464  1.2  christos 
    465  1.2  christos 	/*
    466  1.2  christos 	 * Write directory block 2.
    467  1.2  christos 	 */
    468  1.2  christos 	error = ext2fs_htree_append_block(vp, buf2, cnp, blksize);
    469  1.2  christos 	goto out1;
    470  1.2  christos out:
    471  1.2  christos 	if (bp != NULL)
    472  1.2  christos 		brelse(bp, 0);
    473  1.2  christos out1:
    474  1.2  christos 	free(buf1, M_TEMP);
    475  1.2  christos 	free(buf2, M_TEMP);
    476  1.2  christos 	return error;
    477  1.2  christos }
    478  1.2  christos 
    479  1.2  christos /*
    480  1.2  christos  * Add an entry to the directory using htree index.
    481  1.2  christos  */
    482  1.2  christos int
    483  1.2  christos ext2fs_htree_add_entry(struct vnode *dvp, struct ext2fs_direct *entry,
    484  1.2  christos     struct componentname *cnp)
    485  1.2  christos {
    486  1.2  christos 	struct ext2fs_htree_entry *entries, *leaf_node;
    487  1.2  christos 	struct ext2fs_htree_lookup_info info;
    488  1.2  christos 	struct buf *bp = NULL;
    489  1.2  christos 	struct ext2fs *fs;
    490  1.2  christos 	struct m_ext2fs *m_fs;
    491  1.2  christos 	struct inode *ip;
    492  1.2  christos 	uint16_t ent_num;
    493  1.2  christos 	uint32_t dirhash, split_hash;
    494  1.2  christos 	uint32_t blksize, blknum;
    495  1.2  christos 	uint64_t cursize, dirsize;
    496  1.2  christos 	uint8_t hash_version;
    497  1.2  christos 	char *newdirblock = NULL;
    498  1.2  christos 	char *newidxblock = NULL;
    499  1.2  christos 	struct ext2fs_htree_node *dst_node;
    500  1.2  christos 	struct ext2fs_htree_entry *dst_entries;
    501  1.2  christos 	struct ext2fs_htree_entry *root_entires;
    502  1.2  christos 	struct buf *dst_bp = NULL;
    503  1.2  christos 	int error, write_bp = 0, write_dst_bp = 0, write_info = 0;
    504  1.2  christos 
    505  1.2  christos 	ip = VTOI(dvp);
    506  1.2  christos 	m_fs = ip->i_e2fs;
    507  1.2  christos 	fs = &(m_fs->e2fs);
    508  1.2  christos 	blksize = m_fs->e2fs_bsize;
    509  1.2  christos 
    510  1.2  christos 	if (ip->i_crap.ulr_count != 0)
    511  1.2  christos 		return ext2fs_add_entry(dvp, entry, &(ip->i_crap) );
    512  1.2  christos 	/* Target directory block is full, split it */
    513  1.2  christos 	memset(&info, 0, sizeof(info));
    514  1.2  christos 	error = ext2fs_htree_find_leaf(ip, entry->e2d_name, entry->e2d_namlen,
    515  1.2  christos 	    &dirhash, &hash_version, &info);
    516  1.2  christos 	if (error)
    517  1.2  christos 		return error;
    518  1.2  christos 	entries = info.h_levels[info.h_levels_num - 1].h_entries;
    519  1.2  christos 	ent_num = ext2fs_htree_get_count(entries);
    520  1.2  christos 	if (ent_num == ext2fs_htree_get_limit(entries)) {
    521  1.2  christos 		/* Split the index node. */
    522  1.2  christos 		root_entires = info.h_levels[0].h_entries;
    523  1.2  christos 		newidxblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
    524  1.2  christos 		dst_node = (struct ext2fs_htree_node *)newidxblock;
    525  1.2  christos 		dst_entries = dst_node->h_entries;
    526  1.2  christos 		memset(&dst_node->h_fake_dirent, 0,
    527  1.2  christos 		    sizeof(dst_node->h_fake_dirent));
    528  1.2  christos 		dst_node->h_fake_dirent.e2d_reclen = blksize;
    529  1.2  christos 
    530  1.2  christos 		cursize = roundup(ip->i_size, blksize);
    531  1.2  christos 		dirsize = cursize + blksize;
    532  1.2  christos 		blknum = dirsize / blksize - 1;
    533  1.2  christos 
    534  1.2  christos 		error = ext2fs_htree_append_block(dvp, newidxblock,
    535  1.2  christos 		    cnp, blksize);
    536  1.2  christos 		if (error)
    537  1.2  christos 			goto finish;
    538  1.2  christos 		error = ext2fs_blkatoff(dvp, cursize, NULL, &dst_bp);
    539  1.2  christos 		if (error)
    540  1.2  christos 			goto finish;
    541  1.2  christos 
    542  1.2  christos 		dst_node = (struct ext2fs_htree_node *)dst_bp->b_data;
    543  1.2  christos 		dst_entries = dst_node->h_entries;
    544  1.2  christos 
    545  1.2  christos 		if (info.h_levels_num == 2) {
    546  1.2  christos 			uint16_t src_ent_num, dst_ent_num;
    547  1.2  christos 
    548  1.2  christos 			if (ext2fs_htree_get_count(root_entires) ==
    549  1.2  christos 			    ext2fs_htree_get_limit(root_entires)) {
    550  1.2  christos 				/* Directory index is full */
    551  1.2  christos 				error = EIO;
    552  1.2  christos 				goto finish;
    553  1.2  christos 			}
    554  1.2  christos 
    555  1.2  christos 			src_ent_num = ent_num / 2;
    556  1.2  christos 			dst_ent_num = ent_num - src_ent_num;
    557  1.2  christos 			split_hash = ext2fs_htree_get_hash(entries + src_ent_num);
    558  1.2  christos 
    559  1.2  christos 			/* Move half of index entries to the new index node */
    560  1.2  christos 			memcpy(dst_entries, entries + src_ent_num,
    561  1.2  christos 			    dst_ent_num * sizeof(struct ext2fs_htree_entry));
    562  1.2  christos 			ext2fs_htree_set_count(entries, src_ent_num);
    563  1.2  christos 			ext2fs_htree_set_count(dst_entries, dst_ent_num);
    564  1.2  christos 			ext2fs_htree_set_limit(dst_entries,
    565  1.2  christos 			    ext2fs_htree_node_limit(ip));
    566  1.2  christos 
    567  1.2  christos 			if (info.h_levels[1].h_entry >= entries + src_ent_num) {
    568  1.2  christos 				struct buf *tmp = info.h_levels[1].h_bp;
    569  1.2  christos 				info.h_levels[1].h_bp = dst_bp;
    570  1.2  christos 				dst_bp = tmp;
    571  1.2  christos 
    572  1.2  christos 				info.h_levels[1].h_entry =
    573  1.2  christos 				    info.h_levels[1].h_entry -
    574  1.2  christos 				    (entries + src_ent_num) +
    575  1.2  christos 				    dst_entries;
    576  1.2  christos 				info.h_levels[1].h_entries = dst_entries;
    577  1.2  christos 			}
    578  1.2  christos 			ext2fs_htree_insert_entry_to_level(&info.h_levels[0],
    579  1.2  christos 			    split_hash, blknum);
    580  1.2  christos 
    581  1.2  christos 			/* Write new index node to disk */
    582  1.2  christos 			error = bwrite(dst_bp);
    583  1.2  christos 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
    584  1.2  christos 			if (error)
    585  1.2  christos 				goto finish;
    586  1.2  christos 
    587  1.2  christos 			write_dst_bp = 1;
    588  1.2  christos 		} else {
    589  1.2  christos 			/* Create second level for htree index */
    590  1.2  christos 
    591  1.2  christos 			struct ext2fs_htree_root *idx_root;
    592  1.2  christos 
    593  1.2  christos 			memcpy(dst_entries, entries,
    594  1.2  christos 			    ent_num * sizeof(struct ext2fs_htree_entry));
    595  1.2  christos 			ext2fs_htree_set_limit(dst_entries,
    596  1.2  christos 			    ext2fs_htree_node_limit(ip));
    597  1.2  christos 
    598  1.2  christos 			idx_root = (struct ext2fs_htree_root *)
    599  1.2  christos 			    info.h_levels[0].h_bp->b_data;
    600  1.2  christos 			idx_root->h_info.h_ind_levels = 1;
    601  1.2  christos 
    602  1.2  christos 			ext2fs_htree_set_count(entries, 1);
    603  1.2  christos 			ext2fs_htree_set_block(entries, blknum);
    604  1.2  christos 
    605  1.2  christos 			info.h_levels_num = 2;
    606  1.2  christos 			info.h_levels[1].h_entries = dst_entries;
    607  1.2  christos 			info.h_levels[1].h_entry = info.h_levels[0].h_entry -
    608  1.2  christos 			    info.h_levels[0].h_entries + dst_entries;
    609  1.2  christos 			info.h_levels[1].h_bp = dst_bp;
    610  1.2  christos 			dst_bp = NULL;
    611  1.2  christos 		}
    612  1.2  christos 	}
    613  1.2  christos 
    614  1.2  christos 	leaf_node = info.h_levels[info.h_levels_num - 1].h_entry;
    615  1.2  christos 	blknum = ext2fs_htree_get_block(leaf_node);
    616  1.2  christos 	error = ext2fs_blkatoff(dvp, blknum * blksize, NULL, &bp);
    617  1.2  christos 	if (error)
    618  1.2  christos 		goto finish;
    619  1.2  christos 
    620  1.2  christos 	/* Split target directory block */
    621  1.2  christos 	newdirblock = malloc(blksize, M_TEMP, M_WAITOK | M_ZERO);
    622  1.2  christos 	ext2fs_htree_split_dirblock((char *)bp->b_data, newdirblock, blksize,
    623  1.2  christos 	    fs->e3fs_hash_seed, hash_version, &split_hash, entry);
    624  1.2  christos 	cursize = roundup(ip->i_size, blksize);
    625  1.2  christos 	dirsize = cursize + blksize;
    626  1.2  christos 	blknum = dirsize / blksize - 1;
    627  1.2  christos 
    628  1.2  christos 	/* Add index entry for the new directory block */
    629  1.2  christos 	ext2fs_htree_insert_entry(&info, split_hash, blknum);
    630  1.2  christos 
    631  1.2  christos 	/* Write the new directory block to the end of the directory */
    632  1.2  christos 	error = ext2fs_htree_append_block(dvp, newdirblock, cnp, blksize);
    633  1.2  christos 
    634  1.2  christos 	if (error)
    635  1.2  christos 		goto finish;
    636  1.2  christos 
    637  1.2  christos 	/* Write the target directory block */
    638  1.2  christos 	error = bwrite(bp);
    639  1.2  christos 	ip->i_flag |= IN_CHANGE | IN_UPDATE;
    640  1.2  christos 
    641  1.2  christos 	if (error)
    642  1.2  christos 		goto finish;
    643  1.2  christos 	write_bp = 1;
    644  1.2  christos 
    645  1.2  christos 	/* Write the index block */
    646  1.2  christos 	error = ext2fs_htree_writebuf(&info);
    647  1.2  christos 	if (!error)
    648  1.2  christos 		write_info = 1;
    649  1.2  christos 
    650  1.2  christos finish:
    651  1.2  christos 	if (dst_bp != NULL && !write_dst_bp)
    652  1.2  christos 		brelse(dst_bp, 0);
    653  1.2  christos 	if (bp != NULL && !write_bp)
    654  1.2  christos 		brelse(bp, 0);
    655  1.2  christos 	if (newdirblock != NULL)
    656  1.2  christos 		free(newdirblock, M_TEMP);
    657  1.2  christos 	if (newidxblock != NULL)
    658  1.2  christos 		free(newidxblock, M_TEMP);
    659  1.2  christos 	if (!write_info)
    660  1.2  christos 		ext2fs_htree_release(&info);
    661  1.2  christos 	return error;
    662  1.2  christos }
    663  1.2  christos 
    664  1.1  christos static int
    665  1.1  christos ext2fs_htree_check_next(struct inode *ip, uint32_t hash, const char *name,
    666  1.1  christos     struct ext2fs_htree_lookup_info *info)
    667  1.1  christos {
    668  1.1  christos 	struct vnode *vp = ITOV(ip);
    669  1.1  christos 	struct ext2fs_htree_lookup_level *level;
    670  1.1  christos 	struct buf *bp;
    671  1.1  christos 	uint32_t next_hash;
    672  1.1  christos 	int idx = info->h_levels_num - 1;
    673  1.1  christos 	int levels = 0;
    674  1.1  christos 
    675  1.1  christos 	for (;;) {
    676  1.1  christos 		level = &info->h_levels[idx];
    677  1.1  christos 		level->h_entry++;
    678  1.1  christos 		if (level->h_entry < level->h_entries +
    679  1.1  christos 		    ext2fs_htree_get_count(level->h_entries))
    680  1.1  christos 			break;
    681  1.1  christos 		if (idx == 0)
    682  1.1  christos 			return 0;
    683  1.1  christos 		idx--;
    684  1.1  christos 		levels++;
    685  1.1  christos 	}
    686  1.1  christos 
    687  1.1  christos 	next_hash = ext2fs_htree_get_hash(level->h_entry);
    688  1.1  christos 	if ((hash & 1) == 0) {
    689  1.1  christos 		if (hash != (next_hash & ~1))
    690  1.1  christos 			return 0;
    691  1.1  christos 	}
    692  1.1  christos 
    693  1.1  christos 	while (levels > 0) {
    694  1.1  christos 		levels--;
    695  1.1  christos 		if (ext2fs_blkatoff(vp, ext2fs_htree_get_block(level->h_entry) *
    696  1.1  christos 		    ip->i_e2fs->e2fs_bsize, NULL, &bp) != 0)
    697  1.1  christos 			return 0;
    698  1.1  christos 		level = &info->h_levels[idx + 1];
    699  1.1  christos 		brelse(level->h_bp, 0);
    700  1.1  christos 		level->h_bp = bp;
    701  1.1  christos 		level->h_entry = level->h_entries =
    702  1.1  christos 		    ((struct ext2fs_htree_node *)bp->b_data)->h_entries;
    703  1.1  christos 	}
    704  1.1  christos 
    705  1.1  christos 	return 1;
    706  1.1  christos }
    707  1.1  christos 
    708  1.1  christos static int
    709  1.1  christos ext2fs_htree_find_leaf(struct inode *ip, const char *name, int namelen,
    710  1.1  christos     uint32_t *hash, uint8_t *hash_ver,
    711  1.1  christos     struct ext2fs_htree_lookup_info *info)
    712  1.1  christos {
    713  1.1  christos 	struct vnode *vp;
    714  1.1  christos 	struct ext2fs *fs;/* F, G, and H are MD4 functions */
    715  1.1  christos 	struct m_ext2fs *m_fs;
    716  1.1  christos 	struct buf *bp = NULL;
    717  1.1  christos 	struct ext2fs_htree_root *rootp;
    718  1.1  christos 	struct ext2fs_htree_entry *entp, *start, *end, *middle, *found;
    719  1.1  christos 	struct ext2fs_htree_lookup_level *level_info;
    720  1.1  christos 	uint32_t hash_major = 0, hash_minor = 0;
    721  1.1  christos 	uint32_t levels, cnt;
    722  1.1  christos 	uint8_t hash_version;
    723  1.1  christos 
    724  1.1  christos 	if (name == NULL || info == NULL)
    725  1.1  christos 		return -1;
    726  1.1  christos 
    727  1.1  christos 	vp = ITOV(ip);
    728  1.1  christos 	fs = &(ip->i_e2fs->e2fs);
    729  1.1  christos 	m_fs = ip->i_e2fs;
    730  1.1  christos 
    731  1.1  christos 	if (ext2fs_blkatoff(vp, 0, NULL, &bp) != 0)
    732  1.1  christos 		return -1;
    733  1.1  christos 
    734  1.1  christos 	info->h_levels_num = 1;
    735  1.1  christos 	info->h_levels[0].h_bp = bp;
    736  1.1  christos 	rootp = (struct ext2fs_htree_root *)bp->b_data;
    737  1.1  christos 	if (rootp->h_info.h_hash_version != EXT2_HTREE_LEGACY &&
    738  1.1  christos 	    rootp->h_info.h_hash_version != EXT2_HTREE_HALF_MD4 &&
    739  1.1  christos 	    rootp->h_info.h_hash_version != EXT2_HTREE_TEA)
    740  1.1  christos 		goto error;
    741  1.1  christos 
    742  1.1  christos 	hash_version = rootp->h_info.h_hash_version;
    743  1.1  christos 	if (hash_version <= EXT2_HTREE_TEA)
    744  1.1  christos 		hash_version += m_fs->e2fs_uhash;
    745  1.1  christos 	*hash_ver = hash_version;
    746  1.1  christos 
    747  1.1  christos 	ext2fs_htree_hash(name, namelen, fs->e3fs_hash_seed,
    748  1.1  christos 	    hash_version, &hash_major, &hash_minor);
    749  1.1  christos 	*hash = hash_major;
    750  1.1  christos 
    751  1.1  christos 	if ((levels = rootp->h_info.h_ind_levels) > 1)
    752  1.1  christos 		goto error;
    753  1.1  christos 
    754  1.1  christos 	entp = (struct ext2fs_htree_entry *)(((char *)&rootp->h_info) +
    755  1.1  christos 	    rootp->h_info.h_info_len);
    756  1.1  christos 
    757  1.1  christos 	if (ext2fs_htree_get_limit(entp) !=
    758  1.1  christos 	    ext2fs_htree_root_limit(ip, rootp->h_info.h_info_len))
    759  1.1  christos 		goto error;
    760  1.1  christos 
    761  1.1  christos 	for (;;) {
    762  1.1  christos 		cnt = ext2fs_htree_get_count(entp);
    763  1.1  christos 		if (cnt == 0 || cnt > ext2fs_htree_get_limit(entp))
    764  1.1  christos 			goto error;
    765  1.1  christos 
    766  1.1  christos 		start = entp + 1;
    767  1.1  christos 		end = entp + cnt - 1;
    768  1.1  christos 		while (start <= end) {
    769  1.1  christos 			middle = start + (end - start) / 2;
    770  1.1  christos 			if (ext2fs_htree_get_hash(middle) > hash_major)
    771  1.1  christos 				end = middle - 1;
    772  1.1  christos 			else
    773  1.1  christos 				start = middle + 1;
    774  1.1  christos 		}
    775  1.1  christos 		found = start - 1;
    776  1.1  christos 
    777  1.1  christos 		level_info = &(info->h_levels[info->h_levels_num - 1]);
    778  1.1  christos 		level_info->h_bp = bp;
    779  1.1  christos 		level_info->h_entries = entp;
    780  1.1  christos 		level_info->h_entry = found;
    781  1.1  christos 		if (levels == 0)
    782  1.1  christos 			return (0);
    783  1.1  christos 		levels--;
    784  1.1  christos 		if (ext2fs_blkatoff(vp,
    785  1.1  christos 		    ext2fs_htree_get_block(found) * m_fs->e2fs_bsize,
    786  1.1  christos 		    NULL, &bp) != 0)
    787  1.1  christos 			goto error;
    788  1.1  christos 		entp = ((struct ext2fs_htree_node *)bp->b_data)->h_entries;
    789  1.1  christos 		info->h_levels_num++;
    790  1.1  christos 		info->h_levels[info->h_levels_num - 1].h_bp = bp;
    791  1.1  christos 	}
    792  1.1  christos 
    793  1.1  christos error:
    794  1.1  christos 	ext2fs_htree_release(info);
    795  1.1  christos 	return -1;
    796  1.1  christos }
    797  1.1  christos 
    798  1.1  christos /*
    799  1.1  christos  * Try to lookup a directory entry in HTree index
    800  1.1  christos  */
    801  1.1  christos int
    802  1.1  christos ext2fs_htree_lookup(struct inode *ip, const char *name, int namelen,
    803  1.1  christos     struct buf **bpp, int *entryoffp, doff_t *offp,
    804  1.1  christos     doff_t *prevoffp, doff_t *endusefulp, struct ext2fs_searchslot *ss)
    805  1.1  christos {
    806  1.1  christos 	struct vnode *vp;
    807  1.1  christos 	struct ext2fs_htree_lookup_info info;
    808  1.1  christos 	struct ext2fs_htree_entry *leaf_node;
    809  1.1  christos 	struct m_ext2fs *m_fs;
    810  1.1  christos 	struct buf *bp;
    811  1.1  christos 	uint32_t blk;
    812  1.1  christos 	uint32_t dirhash;
    813  1.1  christos 	uint32_t bsize;
    814  1.1  christos 	uint8_t hash_version;
    815  1.1  christos 	int search_next;
    816  1.1  christos 
    817  1.1  christos 	m_fs = ip->i_e2fs;
    818  1.1  christos 	bsize = m_fs->e2fs_bsize;
    819  1.1  christos 	vp = ITOV(ip);
    820  1.1  christos 
    821  1.1  christos 	/* TODO: print error msg because we don't lookup '.' and '..' */
    822  1.1  christos 
    823  1.1  christos 	memset(&info, 0, sizeof(info));
    824  1.1  christos 	if (ext2fs_htree_find_leaf(ip, name, namelen, &dirhash,
    825  1.1  christos 	    &hash_version, &info)) {
    826  1.1  christos 		return -1;
    827  1.1  christos 	}
    828  1.1  christos 
    829  1.1  christos 	do {
    830  1.1  christos 		leaf_node = info.h_levels[info.h_levels_num - 1].h_entry;
    831  1.1  christos 		blk = ext2fs_htree_get_block(leaf_node);
    832  1.1  christos 		if (ext2fs_blkatoff(vp, blk * bsize, NULL, &bp) != 0) {
    833  1.1  christos 			ext2fs_htree_release(&info);
    834  1.1  christos 			return -1;
    835  1.1  christos 		}
    836  1.1  christos 
    837  1.1  christos 		*offp = blk * bsize;
    838  1.1  christos 		*entryoffp = 0;
    839  1.1  christos 		*prevoffp = blk * bsize;
    840  1.1  christos 		*endusefulp = blk * bsize;
    841  1.1  christos 
    842  1.1  christos 		if (ss->slotstatus == NONE) {
    843  1.1  christos 			ss->slotoffset = -1;
    844  1.1  christos 			ss->slotfreespace = 0;
    845  1.1  christos 		}
    846  1.1  christos 
    847  1.1  christos 		int found;
    848  1.1  christos 		if (ext2fs_search_dirblock(ip, bp->b_data, &found,
    849  1.1  christos 		    name, namelen, entryoffp, offp, prevoffp,
    850  1.1  christos 		    endusefulp, ss) != 0) {
    851  1.1  christos 			brelse(bp, 0);
    852  1.1  christos 			ext2fs_htree_release(&info);
    853  1.1  christos 			return -1;
    854  1.1  christos 		}
    855  1.1  christos 
    856  1.1  christos 		if (found) {
    857  1.1  christos 			*bpp = bp;
    858  1.1  christos 			ext2fs_htree_release(&info);
    859  1.1  christos 			return 0;
    860  1.1  christos 		}
    861  1.1  christos 
    862  1.1  christos 		brelse(bp,0);
    863  1.1  christos 		search_next = ext2fs_htree_check_next(ip, dirhash, name, &info);
    864  1.1  christos 	} while (search_next);
    865  1.1  christos 
    866  1.1  christos 	ext2fs_htree_release(&info);
    867  1.1  christos 	return ENOENT;
    868  1.1  christos }
    869