xref: /kernel/linux/linux-6.6/fs/hpfs/dnode.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/hpfs/dnode.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  handling directory dnode tree - adding, deleteing & searching for dirents
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "hpfs_fn.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	struct hpfs_dirent *de;
1562306a36Sopenharmony_ci	struct hpfs_dirent *de_end = dnode_end_de(d);
1662306a36Sopenharmony_ci	int i = 1;
1762306a36Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
1862306a36Sopenharmony_ci		if (de == fde) return ((loff_t) le32_to_cpu(d->self) << 4) | (loff_t)i;
1962306a36Sopenharmony_ci		i++;
2062306a36Sopenharmony_ci	}
2162306a36Sopenharmony_ci	pr_info("%s(): not_found\n", __func__);
2262306a36Sopenharmony_ci	return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1;
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciint hpfs_add_pos(struct inode *inode, loff_t *pos)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
2862306a36Sopenharmony_ci	int i = 0;
2962306a36Sopenharmony_ci	loff_t **ppos;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	if (hpfs_inode->i_rddir_off)
3262306a36Sopenharmony_ci		for (; hpfs_inode->i_rddir_off[i]; i++)
3362306a36Sopenharmony_ci			if (hpfs_inode->i_rddir_off[i] == pos)
3462306a36Sopenharmony_ci				return 0;
3562306a36Sopenharmony_ci	if (!(i&0x0f)) {
3662306a36Sopenharmony_ci		ppos = kmalloc_array(i + 0x11, sizeof(loff_t *), GFP_NOFS);
3762306a36Sopenharmony_ci		if (!ppos) {
3862306a36Sopenharmony_ci			pr_err("out of memory for position list\n");
3962306a36Sopenharmony_ci			return -ENOMEM;
4062306a36Sopenharmony_ci		}
4162306a36Sopenharmony_ci		if (hpfs_inode->i_rddir_off) {
4262306a36Sopenharmony_ci			memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t));
4362306a36Sopenharmony_ci			kfree(hpfs_inode->i_rddir_off);
4462306a36Sopenharmony_ci		}
4562306a36Sopenharmony_ci		hpfs_inode->i_rddir_off = ppos;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci	hpfs_inode->i_rddir_off[i] = pos;
4862306a36Sopenharmony_ci	hpfs_inode->i_rddir_off[i + 1] = NULL;
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_civoid hpfs_del_pos(struct inode *inode, loff_t *pos)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
5562306a36Sopenharmony_ci	loff_t **i, **j;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (!hpfs_inode->i_rddir_off) goto not_f;
5862306a36Sopenharmony_ci	for (i = hpfs_inode->i_rddir_off; *i; i++) if (*i == pos) goto fnd;
5962306a36Sopenharmony_ci	goto not_f;
6062306a36Sopenharmony_ci	fnd:
6162306a36Sopenharmony_ci	for (j = i + 1; *j; j++) ;
6262306a36Sopenharmony_ci	*i = *(j - 1);
6362306a36Sopenharmony_ci	*(j - 1) = NULL;
6462306a36Sopenharmony_ci	if (j - 1 == hpfs_inode->i_rddir_off) {
6562306a36Sopenharmony_ci		kfree(hpfs_inode->i_rddir_off);
6662306a36Sopenharmony_ci		hpfs_inode->i_rddir_off = NULL;
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci	return;
6962306a36Sopenharmony_ci	not_f:
7062306a36Sopenharmony_ci	/*pr_warn("position pointer %p->%08x not found\n",
7162306a36Sopenharmony_ci		  pos, (int)*pos);*/
7262306a36Sopenharmony_ci	return;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t),
7662306a36Sopenharmony_ci			 loff_t p1, loff_t p2)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
7962306a36Sopenharmony_ci	loff_t **i;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (!hpfs_inode->i_rddir_off) return;
8262306a36Sopenharmony_ci	for (i = hpfs_inode->i_rddir_off; *i; i++) (*f)(*i, p1, p2);
8362306a36Sopenharmony_ci	return;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	if (*p == f) *p = t;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/*void hpfs_hpfs_pos_substd(loff_t *p, loff_t f, loff_t t)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	if ((*p & ~0x3f) == (f & ~0x3f)) *p = (t & ~0x3f) | (*p & 0x3f);
9462306a36Sopenharmony_ci}*/
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
9962306a36Sopenharmony_ci		int n = (*p & 0x3f) + c;
10062306a36Sopenharmony_ci		if (n > 0x3f)
10162306a36Sopenharmony_ci			pr_err("%s(): %08x + %d\n",
10262306a36Sopenharmony_ci				__func__, (int)*p, (int)c >> 8);
10362306a36Sopenharmony_ci		else
10462306a36Sopenharmony_ci			*p = (*p & ~0x3f) | n;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic void hpfs_pos_del(loff_t *p, loff_t d, loff_t c)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
11162306a36Sopenharmony_ci		int n = (*p & 0x3f) - c;
11262306a36Sopenharmony_ci		if (n < 1)
11362306a36Sopenharmony_ci			pr_err("%s(): %08x - %d\n",
11462306a36Sopenharmony_ci				__func__, (int)*p, (int)c >> 8);
11562306a36Sopenharmony_ci		else
11662306a36Sopenharmony_ci			*p = (*p & ~0x3f) | n;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic struct hpfs_dirent *dnode_pre_last_de(struct dnode *d)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct hpfs_dirent *de, *de_end, *dee = NULL, *deee = NULL;
12362306a36Sopenharmony_ci	de_end = dnode_end_de(d);
12462306a36Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
12562306a36Sopenharmony_ci		deee = dee; dee = de;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci	return deee;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic struct hpfs_dirent *dnode_last_de(struct dnode *d)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct hpfs_dirent *de, *de_end, *dee = NULL;
13362306a36Sopenharmony_ci	de_end = dnode_end_de(d);
13462306a36Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
13562306a36Sopenharmony_ci		dee = de;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	return dee;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno ptr)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct hpfs_dirent *de;
14362306a36Sopenharmony_ci	if (!(de = dnode_last_de(d))) {
14462306a36Sopenharmony_ci		hpfs_error(s, "set_last_pointer: empty dnode %08x", le32_to_cpu(d->self));
14562306a36Sopenharmony_ci		return;
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk) {
14862306a36Sopenharmony_ci		if (de->down) {
14962306a36Sopenharmony_ci			hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x",
15062306a36Sopenharmony_ci				le32_to_cpu(d->self), de_down_pointer(de));
15162306a36Sopenharmony_ci			return;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci		if (le16_to_cpu(de->length) != 32) {
15462306a36Sopenharmony_ci			hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", le32_to_cpu(d->self));
15562306a36Sopenharmony_ci			return;
15662306a36Sopenharmony_ci		}
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	if (ptr) {
15962306a36Sopenharmony_ci		le32_add_cpu(&d->first_free, 4);
16062306a36Sopenharmony_ci		if (le32_to_cpu(d->first_free) > 2048) {
16162306a36Sopenharmony_ci			hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self));
16262306a36Sopenharmony_ci			le32_add_cpu(&d->first_free, -4);
16362306a36Sopenharmony_ci			return;
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci		de->length = cpu_to_le16(36);
16662306a36Sopenharmony_ci		de->down = 1;
16762306a36Sopenharmony_ci		*(__le32 *)((char *)de + 32) = cpu_to_le32(ptr);
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/* Add an entry to dnode and don't care if it grows over 2048 bytes */
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistruct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d,
17462306a36Sopenharmony_ci				const unsigned char *name,
17562306a36Sopenharmony_ci				unsigned namelen, secno down_ptr)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct hpfs_dirent *de;
17862306a36Sopenharmony_ci	struct hpfs_dirent *de_end = dnode_end_de(d);
17962306a36Sopenharmony_ci	unsigned d_size = de_size(namelen, down_ptr);
18062306a36Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
18162306a36Sopenharmony_ci		int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last);
18262306a36Sopenharmony_ci		if (!c) {
18362306a36Sopenharmony_ci			hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, le32_to_cpu(d->self));
18462306a36Sopenharmony_ci			return NULL;
18562306a36Sopenharmony_ci		}
18662306a36Sopenharmony_ci		if (c < 0) break;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci	memmove((char *)de + d_size, de, (char *)de_end - (char *)de);
18962306a36Sopenharmony_ci	memset(de, 0, d_size);
19062306a36Sopenharmony_ci	if (down_ptr) {
19162306a36Sopenharmony_ci		*(__le32 *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr);
19262306a36Sopenharmony_ci		de->down = 1;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci	de->length = cpu_to_le16(d_size);
19562306a36Sopenharmony_ci	de->not_8x3 = hpfs_is_name_long(name, namelen);
19662306a36Sopenharmony_ci	de->namelen = namelen;
19762306a36Sopenharmony_ci	memcpy(de->name, name, namelen);
19862306a36Sopenharmony_ci	le32_add_cpu(&d->first_free, d_size);
19962306a36Sopenharmony_ci	return de;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/* Delete dirent and don't care about its subtree */
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic void hpfs_delete_de(struct super_block *s, struct dnode *d,
20562306a36Sopenharmony_ci			   struct hpfs_dirent *de)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	if (de->last) {
20862306a36Sopenharmony_ci		hpfs_error(s, "attempt to delete last dirent in dnode %08x", le32_to_cpu(d->self));
20962306a36Sopenharmony_ci		return;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - le16_to_cpu(de->length));
21262306a36Sopenharmony_ci	memmove(de, de_next_de(de), le32_to_cpu(d->first_free) + (char *)d - (char *)de);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic void fix_up_ptrs(struct super_block *s, struct dnode *d)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct hpfs_dirent *de;
21862306a36Sopenharmony_ci	struct hpfs_dirent *de_end = dnode_end_de(d);
21962306a36Sopenharmony_ci	dnode_secno dno = le32_to_cpu(d->self);
22062306a36Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de))
22162306a36Sopenharmony_ci		if (de->down) {
22262306a36Sopenharmony_ci			struct quad_buffer_head qbh;
22362306a36Sopenharmony_ci			struct dnode *dd;
22462306a36Sopenharmony_ci			if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) {
22562306a36Sopenharmony_ci				if (le32_to_cpu(dd->up) != dno || dd->root_dnode) {
22662306a36Sopenharmony_ci					dd->up = cpu_to_le32(dno);
22762306a36Sopenharmony_ci					dd->root_dnode = 0;
22862306a36Sopenharmony_ci					hpfs_mark_4buffers_dirty(&qbh);
22962306a36Sopenharmony_ci				}
23062306a36Sopenharmony_ci				hpfs_brelse4(&qbh);
23162306a36Sopenharmony_ci			}
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/* Add an entry to dnode and do dnode splitting if required */
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
23862306a36Sopenharmony_ci			     const unsigned char *name, unsigned namelen,
23962306a36Sopenharmony_ci			     struct hpfs_dirent *new_de, dnode_secno down_ptr)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct quad_buffer_head qbh, qbh1, qbh2;
24262306a36Sopenharmony_ci	struct dnode *d, *ad, *rd, *nd = NULL;
24362306a36Sopenharmony_ci	dnode_secno adno, rdno;
24462306a36Sopenharmony_ci	struct hpfs_dirent *de;
24562306a36Sopenharmony_ci	struct hpfs_dirent nde;
24662306a36Sopenharmony_ci	unsigned char *nname;
24762306a36Sopenharmony_ci	int h;
24862306a36Sopenharmony_ci	int pos;
24962306a36Sopenharmony_ci	struct buffer_head *bh;
25062306a36Sopenharmony_ci	struct fnode *fnode;
25162306a36Sopenharmony_ci	int c1, c2 = 0;
25262306a36Sopenharmony_ci	if (!(nname = kmalloc(256, GFP_NOFS))) {
25362306a36Sopenharmony_ci		pr_err("out of memory, can't add to dnode\n");
25462306a36Sopenharmony_ci		return 1;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	go_up:
25762306a36Sopenharmony_ci	if (namelen >= 256) {
25862306a36Sopenharmony_ci		hpfs_error(i->i_sb, "%s(): namelen == %d", __func__, namelen);
25962306a36Sopenharmony_ci		kfree(nd);
26062306a36Sopenharmony_ci		kfree(nname);
26162306a36Sopenharmony_ci		return 1;
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci	if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) {
26462306a36Sopenharmony_ci		kfree(nd);
26562306a36Sopenharmony_ci		kfree(nname);
26662306a36Sopenharmony_ci		return 1;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	go_up_a:
26962306a36Sopenharmony_ci	if (hpfs_sb(i->i_sb)->sb_chk)
27062306a36Sopenharmony_ci		if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_to_dnode")) {
27162306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
27262306a36Sopenharmony_ci			kfree(nd);
27362306a36Sopenharmony_ci			kfree(nname);
27462306a36Sopenharmony_ci			return 1;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci	if (le32_to_cpu(d->first_free) + de_size(namelen, down_ptr) <= 2048) {
27762306a36Sopenharmony_ci		loff_t t;
27862306a36Sopenharmony_ci		copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de);
27962306a36Sopenharmony_ci		t = get_pos(d, de);
28062306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_ins, t, 1);
28162306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, 4, t);
28262306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, 5, t + 1);
28362306a36Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
28462306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
28562306a36Sopenharmony_ci		kfree(nd);
28662306a36Sopenharmony_ci		kfree(nname);
28762306a36Sopenharmony_ci		return 0;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci	if (!nd) if (!(nd = kmalloc(0x924, GFP_NOFS))) {
29062306a36Sopenharmony_ci		/* 0x924 is a max size of dnode after adding a dirent with
29162306a36Sopenharmony_ci		   max name length. We alloc this only once. There must
29262306a36Sopenharmony_ci		   not be any error while splitting dnodes, otherwise the
29362306a36Sopenharmony_ci		   whole directory, not only file we're adding, would
29462306a36Sopenharmony_ci		   be lost. */
29562306a36Sopenharmony_ci		pr_err("out of memory for dnode splitting\n");
29662306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
29762306a36Sopenharmony_ci		kfree(nname);
29862306a36Sopenharmony_ci		return 1;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	memcpy(nd, d, le32_to_cpu(d->first_free));
30162306a36Sopenharmony_ci	copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de);
30262306a36Sopenharmony_ci	for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1);
30362306a36Sopenharmony_ci	h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10;
30462306a36Sopenharmony_ci	if (!(ad = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &adno, &qbh1))) {
30562306a36Sopenharmony_ci		hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
30662306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
30762306a36Sopenharmony_ci		kfree(nd);
30862306a36Sopenharmony_ci		kfree(nname);
30962306a36Sopenharmony_ci		return 1;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci	i->i_size += 2048;
31262306a36Sopenharmony_ci	i->i_blocks += 4;
31362306a36Sopenharmony_ci	pos = 1;
31462306a36Sopenharmony_ci	for (de = dnode_first_de(nd); (char *)de_next_de(de) - (char *)nd < h; de = de_next_de(de)) {
31562306a36Sopenharmony_ci		copy_de(hpfs_add_de(i->i_sb, ad, de->name, de->namelen, de->down ? de_down_pointer(de) : 0), de);
31662306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, ((loff_t)adno << 4) | pos);
31762306a36Sopenharmony_ci		pos++;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci	copy_de(new_de = &nde, de);
32062306a36Sopenharmony_ci	memcpy(nname, de->name, de->namelen);
32162306a36Sopenharmony_ci	name = nname;
32262306a36Sopenharmony_ci	namelen = de->namelen;
32362306a36Sopenharmony_ci	for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4);
32462306a36Sopenharmony_ci	down_ptr = adno;
32562306a36Sopenharmony_ci	set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0);
32662306a36Sopenharmony_ci	de = de_next_de(de);
32762306a36Sopenharmony_ci	memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de);
32862306a36Sopenharmony_ci	le32_add_cpu(&nd->first_free, -((char *)de - (char *)nd - 20));
32962306a36Sopenharmony_ci	memcpy(d, nd, le32_to_cpu(nd->first_free));
33062306a36Sopenharmony_ci	for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos);
33162306a36Sopenharmony_ci	fix_up_ptrs(i->i_sb, ad);
33262306a36Sopenharmony_ci	if (!d->root_dnode) {
33362306a36Sopenharmony_ci		ad->up = d->up;
33462306a36Sopenharmony_ci		dno = le32_to_cpu(ad->up);
33562306a36Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
33662306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
33762306a36Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh1);
33862306a36Sopenharmony_ci		hpfs_brelse4(&qbh1);
33962306a36Sopenharmony_ci		goto go_up;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci	if (!(rd = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &rdno, &qbh2))) {
34262306a36Sopenharmony_ci		hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
34362306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
34462306a36Sopenharmony_ci		hpfs_brelse4(&qbh1);
34562306a36Sopenharmony_ci		kfree(nd);
34662306a36Sopenharmony_ci		kfree(nname);
34762306a36Sopenharmony_ci		return 1;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci	i->i_size += 2048;
35062306a36Sopenharmony_ci	i->i_blocks += 4;
35162306a36Sopenharmony_ci	rd->root_dnode = 1;
35262306a36Sopenharmony_ci	rd->up = d->up;
35362306a36Sopenharmony_ci	if (!(fnode = hpfs_map_fnode(i->i_sb, le32_to_cpu(d->up), &bh))) {
35462306a36Sopenharmony_ci		hpfs_free_dnode(i->i_sb, rdno);
35562306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
35662306a36Sopenharmony_ci		hpfs_brelse4(&qbh1);
35762306a36Sopenharmony_ci		hpfs_brelse4(&qbh2);
35862306a36Sopenharmony_ci		kfree(nd);
35962306a36Sopenharmony_ci		kfree(nname);
36062306a36Sopenharmony_ci		return 1;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci	fnode->u.external[0].disk_secno = cpu_to_le32(rdno);
36362306a36Sopenharmony_ci	mark_buffer_dirty(bh);
36462306a36Sopenharmony_ci	brelse(bh);
36562306a36Sopenharmony_ci	hpfs_i(i)->i_dno = rdno;
36662306a36Sopenharmony_ci	d->up = ad->up = cpu_to_le32(rdno);
36762306a36Sopenharmony_ci	d->root_dnode = ad->root_dnode = 0;
36862306a36Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh);
36962306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
37062306a36Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh1);
37162306a36Sopenharmony_ci	hpfs_brelse4(&qbh1);
37262306a36Sopenharmony_ci	qbh = qbh2;
37362306a36Sopenharmony_ci	set_last_pointer(i->i_sb, rd, dno);
37462306a36Sopenharmony_ci	dno = rdno;
37562306a36Sopenharmony_ci	d = rd;
37662306a36Sopenharmony_ci	goto go_up_a;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci/*
38062306a36Sopenharmony_ci * Add an entry to directory btree.
38162306a36Sopenharmony_ci * I hate such crazy directory structure.
38262306a36Sopenharmony_ci * It's easy to read but terrible to write.
38362306a36Sopenharmony_ci * I wrote this directory code 4 times.
38462306a36Sopenharmony_ci * I hope, now it's finally bug-free.
38562306a36Sopenharmony_ci */
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ciint hpfs_add_dirent(struct inode *i,
38862306a36Sopenharmony_ci		    const unsigned char *name, unsigned namelen,
38962306a36Sopenharmony_ci		    struct hpfs_dirent *new_de)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
39262306a36Sopenharmony_ci	struct dnode *d;
39362306a36Sopenharmony_ci	struct hpfs_dirent *de, *de_end;
39462306a36Sopenharmony_ci	struct quad_buffer_head qbh;
39562306a36Sopenharmony_ci	dnode_secno dno;
39662306a36Sopenharmony_ci	int c;
39762306a36Sopenharmony_ci	int c1, c2 = 0;
39862306a36Sopenharmony_ci	dno = hpfs_inode->i_dno;
39962306a36Sopenharmony_ci	down:
40062306a36Sopenharmony_ci	if (hpfs_sb(i->i_sb)->sb_chk)
40162306a36Sopenharmony_ci		if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1;
40262306a36Sopenharmony_ci	if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 1;
40362306a36Sopenharmony_ci	de_end = dnode_end_de(d);
40462306a36Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
40562306a36Sopenharmony_ci		if (!(c = hpfs_compare_names(i->i_sb, name, namelen, de->name, de->namelen, de->last))) {
40662306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
40762306a36Sopenharmony_ci			return -1;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci		if (c < 0) {
41062306a36Sopenharmony_ci			if (de->down) {
41162306a36Sopenharmony_ci				dno = de_down_pointer(de);
41262306a36Sopenharmony_ci				hpfs_brelse4(&qbh);
41362306a36Sopenharmony_ci				goto down;
41462306a36Sopenharmony_ci			}
41562306a36Sopenharmony_ci			break;
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
41962306a36Sopenharmony_ci	if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) {
42062306a36Sopenharmony_ci		c = 1;
42162306a36Sopenharmony_ci		goto ret;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci	c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0);
42462306a36Sopenharmony_ci	ret:
42562306a36Sopenharmony_ci	return c;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci/*
42962306a36Sopenharmony_ci * Find dirent with higher name in 'from' subtree and move it to 'to' dnode.
43062306a36Sopenharmony_ci * Return the dnode we moved from (to be checked later if it's empty)
43162306a36Sopenharmony_ci */
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	dnode_secno dno, ddno;
43662306a36Sopenharmony_ci	dnode_secno chk_up = to;
43762306a36Sopenharmony_ci	struct dnode *dnode;
43862306a36Sopenharmony_ci	struct quad_buffer_head qbh;
43962306a36Sopenharmony_ci	struct hpfs_dirent *de, *nde;
44062306a36Sopenharmony_ci	int a;
44162306a36Sopenharmony_ci	loff_t t;
44262306a36Sopenharmony_ci	int c1, c2 = 0;
44362306a36Sopenharmony_ci	dno = from;
44462306a36Sopenharmony_ci	while (1) {
44562306a36Sopenharmony_ci		if (hpfs_sb(i->i_sb)->sb_chk)
44662306a36Sopenharmony_ci			if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "move_to_top"))
44762306a36Sopenharmony_ci				return 0;
44862306a36Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0;
44962306a36Sopenharmony_ci		if (hpfs_sb(i->i_sb)->sb_chk) {
45062306a36Sopenharmony_ci			if (le32_to_cpu(dnode->up) != chk_up) {
45162306a36Sopenharmony_ci				hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x",
45262306a36Sopenharmony_ci					dno, chk_up, le32_to_cpu(dnode->up));
45362306a36Sopenharmony_ci				hpfs_brelse4(&qbh);
45462306a36Sopenharmony_ci				return 0;
45562306a36Sopenharmony_ci			}
45662306a36Sopenharmony_ci			chk_up = dno;
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci		if (!(de = dnode_last_de(dnode))) {
45962306a36Sopenharmony_ci			hpfs_error(i->i_sb, "move_to_top: dnode %08x has no last de", dno);
46062306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
46162306a36Sopenharmony_ci			return 0;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci		if (!de->down) break;
46462306a36Sopenharmony_ci		dno = de_down_pointer(de);
46562306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci	while (!(de = dnode_pre_last_de(dnode))) {
46862306a36Sopenharmony_ci		dnode_secno up = le32_to_cpu(dnode->up);
46962306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
47062306a36Sopenharmony_ci		hpfs_free_dnode(i->i_sb, dno);
47162306a36Sopenharmony_ci		i->i_size -= 2048;
47262306a36Sopenharmony_ci		i->i_blocks -= 4;
47362306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, 5);
47462306a36Sopenharmony_ci		if (up == to) return to;
47562306a36Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return 0;
47662306a36Sopenharmony_ci		if (dnode->root_dnode) {
47762306a36Sopenharmony_ci			hpfs_error(i->i_sb, "move_to_top: got to root_dnode while moving from %08x to %08x", from, to);
47862306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
47962306a36Sopenharmony_ci			return 0;
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci		de = dnode_last_de(dnode);
48262306a36Sopenharmony_ci		if (!de || !de->down) {
48362306a36Sopenharmony_ci			hpfs_error(i->i_sb, "move_to_top: dnode %08x doesn't point down to %08x", up, dno);
48462306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
48562306a36Sopenharmony_ci			return 0;
48662306a36Sopenharmony_ci		}
48762306a36Sopenharmony_ci		le32_add_cpu(&dnode->first_free, -4);
48862306a36Sopenharmony_ci		le16_add_cpu(&de->length, -4);
48962306a36Sopenharmony_ci		de->down = 0;
49062306a36Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
49162306a36Sopenharmony_ci		dno = up;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci	t = get_pos(dnode, de);
49462306a36Sopenharmony_ci	for_all_poss(i, hpfs_pos_subst, t, 4);
49562306a36Sopenharmony_ci	for_all_poss(i, hpfs_pos_subst, t + 1, 5);
49662306a36Sopenharmony_ci	if (!(nde = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) {
49762306a36Sopenharmony_ci		hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted");
49862306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
49962306a36Sopenharmony_ci		return 0;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci	memcpy(nde, de, le16_to_cpu(de->length));
50262306a36Sopenharmony_ci	ddno = de->down ? de_down_pointer(de) : 0;
50362306a36Sopenharmony_ci	hpfs_delete_de(i->i_sb, dnode, de);
50462306a36Sopenharmony_ci	set_last_pointer(i->i_sb, dnode, ddno);
50562306a36Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh);
50662306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
50762306a36Sopenharmony_ci	a = hpfs_add_to_dnode(i, to, nde->name, nde->namelen, nde, from);
50862306a36Sopenharmony_ci	kfree(nde);
50962306a36Sopenharmony_ci	if (a) return 0;
51062306a36Sopenharmony_ci	return dno;
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci/*
51462306a36Sopenharmony_ci * Check if a dnode is empty and delete it from the tree
51562306a36Sopenharmony_ci * (chkdsk doesn't like empty dnodes)
51662306a36Sopenharmony_ci */
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic void delete_empty_dnode(struct inode *i, dnode_secno dno)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
52162306a36Sopenharmony_ci	struct quad_buffer_head qbh;
52262306a36Sopenharmony_ci	struct dnode *dnode;
52362306a36Sopenharmony_ci	dnode_secno down, up, ndown;
52462306a36Sopenharmony_ci	int p;
52562306a36Sopenharmony_ci	struct hpfs_dirent *de;
52662306a36Sopenharmony_ci	int c1, c2 = 0;
52762306a36Sopenharmony_ci	try_it_again:
52862306a36Sopenharmony_ci	if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return;
52962306a36Sopenharmony_ci	if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return;
53062306a36Sopenharmony_ci	if (le32_to_cpu(dnode->first_free) > 56) goto end;
53162306a36Sopenharmony_ci	if (le32_to_cpu(dnode->first_free) == 52 || le32_to_cpu(dnode->first_free) == 56) {
53262306a36Sopenharmony_ci		struct hpfs_dirent *de_end;
53362306a36Sopenharmony_ci		int root = dnode->root_dnode;
53462306a36Sopenharmony_ci		up = le32_to_cpu(dnode->up);
53562306a36Sopenharmony_ci		de = dnode_first_de(dnode);
53662306a36Sopenharmony_ci		down = de->down ? de_down_pointer(de) : 0;
53762306a36Sopenharmony_ci		if (hpfs_sb(i->i_sb)->sb_chk) if (root && !down) {
53862306a36Sopenharmony_ci			hpfs_error(i->i_sb, "delete_empty_dnode: root dnode %08x is empty", dno);
53962306a36Sopenharmony_ci			goto end;
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
54262306a36Sopenharmony_ci		hpfs_free_dnode(i->i_sb, dno);
54362306a36Sopenharmony_ci		i->i_size -= 2048;
54462306a36Sopenharmony_ci		i->i_blocks -= 4;
54562306a36Sopenharmony_ci		if (root) {
54662306a36Sopenharmony_ci			struct fnode *fnode;
54762306a36Sopenharmony_ci			struct buffer_head *bh;
54862306a36Sopenharmony_ci			struct dnode *d1;
54962306a36Sopenharmony_ci			struct quad_buffer_head qbh1;
55062306a36Sopenharmony_ci			if (hpfs_sb(i->i_sb)->sb_chk)
55162306a36Sopenharmony_ci				if (up != i->i_ino) {
55262306a36Sopenharmony_ci					hpfs_error(i->i_sb,
55362306a36Sopenharmony_ci						   "bad pointer to fnode, dnode %08x, pointing to %08x, should be %08lx",
55462306a36Sopenharmony_ci						   dno, up,
55562306a36Sopenharmony_ci						   (unsigned long)i->i_ino);
55662306a36Sopenharmony_ci					return;
55762306a36Sopenharmony_ci				}
55862306a36Sopenharmony_ci			if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
55962306a36Sopenharmony_ci				d1->up = cpu_to_le32(up);
56062306a36Sopenharmony_ci				d1->root_dnode = 1;
56162306a36Sopenharmony_ci				hpfs_mark_4buffers_dirty(&qbh1);
56262306a36Sopenharmony_ci				hpfs_brelse4(&qbh1);
56362306a36Sopenharmony_ci			}
56462306a36Sopenharmony_ci			if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) {
56562306a36Sopenharmony_ci				fnode->u.external[0].disk_secno = cpu_to_le32(down);
56662306a36Sopenharmony_ci				mark_buffer_dirty(bh);
56762306a36Sopenharmony_ci				brelse(bh);
56862306a36Sopenharmony_ci			}
56962306a36Sopenharmony_ci			hpfs_inode->i_dno = down;
57062306a36Sopenharmony_ci			for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12);
57162306a36Sopenharmony_ci			return;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return;
57462306a36Sopenharmony_ci		p = 1;
57562306a36Sopenharmony_ci		de_end = dnode_end_de(dnode);
57662306a36Sopenharmony_ci		for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de), p++)
57762306a36Sopenharmony_ci			if (de->down) if (de_down_pointer(de) == dno) goto fnd;
57862306a36Sopenharmony_ci		hpfs_error(i->i_sb, "delete_empty_dnode: pointer to dnode %08x not found in dnode %08x", dno, up);
57962306a36Sopenharmony_ci		goto end;
58062306a36Sopenharmony_ci		fnd:
58162306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p);
58262306a36Sopenharmony_ci		if (!down) {
58362306a36Sopenharmony_ci			de->down = 0;
58462306a36Sopenharmony_ci			le16_add_cpu(&de->length, -4);
58562306a36Sopenharmony_ci			le32_add_cpu(&dnode->first_free, -4);
58662306a36Sopenharmony_ci			memmove(de_next_de(de), (char *)de_next_de(de) + 4,
58762306a36Sopenharmony_ci				(char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de));
58862306a36Sopenharmony_ci		} else {
58962306a36Sopenharmony_ci			struct dnode *d1;
59062306a36Sopenharmony_ci			struct quad_buffer_head qbh1;
59162306a36Sopenharmony_ci			*(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4) = down;
59262306a36Sopenharmony_ci			if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
59362306a36Sopenharmony_ci				d1->up = cpu_to_le32(up);
59462306a36Sopenharmony_ci				hpfs_mark_4buffers_dirty(&qbh1);
59562306a36Sopenharmony_ci				hpfs_brelse4(&qbh1);
59662306a36Sopenharmony_ci			}
59762306a36Sopenharmony_ci		}
59862306a36Sopenharmony_ci	} else {
59962306a36Sopenharmony_ci		hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, le32_to_cpu(dnode->first_free));
60062306a36Sopenharmony_ci		goto end;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (!de->last) {
60462306a36Sopenharmony_ci		struct hpfs_dirent *de_next = de_next_de(de);
60562306a36Sopenharmony_ci		struct hpfs_dirent *de_cp;
60662306a36Sopenharmony_ci		struct dnode *d1;
60762306a36Sopenharmony_ci		struct quad_buffer_head qbh1;
60862306a36Sopenharmony_ci		if (!de_next->down) goto endm;
60962306a36Sopenharmony_ci		ndown = de_down_pointer(de_next);
61062306a36Sopenharmony_ci		if (!(de_cp = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) {
61162306a36Sopenharmony_ci			pr_err("out of memory for dtree balancing\n");
61262306a36Sopenharmony_ci			goto endm;
61362306a36Sopenharmony_ci		}
61462306a36Sopenharmony_ci		memcpy(de_cp, de, le16_to_cpu(de->length));
61562306a36Sopenharmony_ci		hpfs_delete_de(i->i_sb, dnode, de);
61662306a36Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
61762306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
61862306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4);
61962306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1);
62062306a36Sopenharmony_ci		if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) {
62162306a36Sopenharmony_ci			d1->up = cpu_to_le32(ndown);
62262306a36Sopenharmony_ci			hpfs_mark_4buffers_dirty(&qbh1);
62362306a36Sopenharmony_ci			hpfs_brelse4(&qbh1);
62462306a36Sopenharmony_ci		}
62562306a36Sopenharmony_ci		hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, de_cp->down ? de_down_pointer(de_cp) : 0);
62662306a36Sopenharmony_ci		/*pr_info("UP-TO-DNODE: %08x (ndown = %08x, down = %08x, dno = %08x)\n",
62762306a36Sopenharmony_ci		  up, ndown, down, dno);*/
62862306a36Sopenharmony_ci		dno = up;
62962306a36Sopenharmony_ci		kfree(de_cp);
63062306a36Sopenharmony_ci		goto try_it_again;
63162306a36Sopenharmony_ci	} else {
63262306a36Sopenharmony_ci		struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode);
63362306a36Sopenharmony_ci		struct hpfs_dirent *de_cp;
63462306a36Sopenharmony_ci		struct dnode *d1;
63562306a36Sopenharmony_ci		struct quad_buffer_head qbh1;
63662306a36Sopenharmony_ci		dnode_secno dlp;
63762306a36Sopenharmony_ci		if (!de_prev) {
63862306a36Sopenharmony_ci			hpfs_error(i->i_sb, "delete_empty_dnode: empty dnode %08x", up);
63962306a36Sopenharmony_ci			hpfs_mark_4buffers_dirty(&qbh);
64062306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
64162306a36Sopenharmony_ci			dno = up;
64262306a36Sopenharmony_ci			goto try_it_again;
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci		if (!de_prev->down) goto endm;
64562306a36Sopenharmony_ci		ndown = de_down_pointer(de_prev);
64662306a36Sopenharmony_ci		if ((d1 = hpfs_map_dnode(i->i_sb, ndown, &qbh1))) {
64762306a36Sopenharmony_ci			struct hpfs_dirent *del = dnode_last_de(d1);
64862306a36Sopenharmony_ci			dlp = del->down ? de_down_pointer(del) : 0;
64962306a36Sopenharmony_ci			if (!dlp && down) {
65062306a36Sopenharmony_ci				if (le32_to_cpu(d1->first_free) > 2044) {
65162306a36Sopenharmony_ci					if (hpfs_sb(i->i_sb)->sb_chk >= 2) {
65262306a36Sopenharmony_ci						pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n");
65362306a36Sopenharmony_ci						pr_err("terminating balancing operation\n");
65462306a36Sopenharmony_ci					}
65562306a36Sopenharmony_ci					hpfs_brelse4(&qbh1);
65662306a36Sopenharmony_ci					goto endm;
65762306a36Sopenharmony_ci				}
65862306a36Sopenharmony_ci				if (hpfs_sb(i->i_sb)->sb_chk >= 2) {
65962306a36Sopenharmony_ci					pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n");
66062306a36Sopenharmony_ci					pr_err("goin'on\n");
66162306a36Sopenharmony_ci				}
66262306a36Sopenharmony_ci				le16_add_cpu(&del->length, 4);
66362306a36Sopenharmony_ci				del->down = 1;
66462306a36Sopenharmony_ci				le32_add_cpu(&d1->first_free, 4);
66562306a36Sopenharmony_ci			}
66662306a36Sopenharmony_ci			if (dlp && !down) {
66762306a36Sopenharmony_ci				le16_add_cpu(&del->length, -4);
66862306a36Sopenharmony_ci				del->down = 0;
66962306a36Sopenharmony_ci				le32_add_cpu(&d1->first_free, -4);
67062306a36Sopenharmony_ci			} else if (down)
67162306a36Sopenharmony_ci				*(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down);
67262306a36Sopenharmony_ci		} else goto endm;
67362306a36Sopenharmony_ci		if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) {
67462306a36Sopenharmony_ci			pr_err("out of memory for dtree balancing\n");
67562306a36Sopenharmony_ci			hpfs_brelse4(&qbh1);
67662306a36Sopenharmony_ci			goto endm;
67762306a36Sopenharmony_ci		}
67862306a36Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh1);
67962306a36Sopenharmony_ci		hpfs_brelse4(&qbh1);
68062306a36Sopenharmony_ci		memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length));
68162306a36Sopenharmony_ci		hpfs_delete_de(i->i_sb, dnode, de_prev);
68262306a36Sopenharmony_ci		if (!de_prev->down) {
68362306a36Sopenharmony_ci			le16_add_cpu(&de_prev->length, 4);
68462306a36Sopenharmony_ci			de_prev->down = 1;
68562306a36Sopenharmony_ci			le32_add_cpu(&dnode->first_free, 4);
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci		*(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown);
68862306a36Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
68962306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
69062306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4);
69162306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1));
69262306a36Sopenharmony_ci		if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) {
69362306a36Sopenharmony_ci			d1->up = cpu_to_le32(ndown);
69462306a36Sopenharmony_ci			hpfs_mark_4buffers_dirty(&qbh1);
69562306a36Sopenharmony_ci			hpfs_brelse4(&qbh1);
69662306a36Sopenharmony_ci		}
69762306a36Sopenharmony_ci		hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, dlp);
69862306a36Sopenharmony_ci		dno = up;
69962306a36Sopenharmony_ci		kfree(de_cp);
70062306a36Sopenharmony_ci		goto try_it_again;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci	endm:
70362306a36Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh);
70462306a36Sopenharmony_ci	end:
70562306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci/* Delete dirent from directory */
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ciint hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de,
71262306a36Sopenharmony_ci		       struct quad_buffer_head *qbh, int depth)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct dnode *dnode = qbh->data;
71562306a36Sopenharmony_ci	dnode_secno down = 0;
71662306a36Sopenharmony_ci	loff_t t;
71762306a36Sopenharmony_ci	if (de->first || de->last) {
71862306a36Sopenharmony_ci		hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno);
71962306a36Sopenharmony_ci		hpfs_brelse4(qbh);
72062306a36Sopenharmony_ci		return 1;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci	if (de->down) down = de_down_pointer(de);
72362306a36Sopenharmony_ci	if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) {
72462306a36Sopenharmony_ci		if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) {
72562306a36Sopenharmony_ci			hpfs_brelse4(qbh);
72662306a36Sopenharmony_ci			return 2;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci	for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1);
73062306a36Sopenharmony_ci	hpfs_delete_de(i->i_sb, dnode, de);
73162306a36Sopenharmony_ci	hpfs_mark_4buffers_dirty(qbh);
73262306a36Sopenharmony_ci	hpfs_brelse4(qbh);
73362306a36Sopenharmony_ci	if (down) {
73462306a36Sopenharmony_ci		dnode_secno a = move_to_top(i, down, dno);
73562306a36Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, 5, t);
73662306a36Sopenharmony_ci		if (a) delete_empty_dnode(i, a);
73762306a36Sopenharmony_ci		return !a;
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci	delete_empty_dnode(i, dno);
74062306a36Sopenharmony_ci	return 0;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_civoid hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes,
74462306a36Sopenharmony_ci		       int *n_subdirs, int *n_items)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct dnode *dnode;
74762306a36Sopenharmony_ci	struct quad_buffer_head qbh;
74862306a36Sopenharmony_ci	struct hpfs_dirent *de;
74962306a36Sopenharmony_ci	dnode_secno ptr, odno = 0;
75062306a36Sopenharmony_ci	int c1, c2 = 0;
75162306a36Sopenharmony_ci	int d1, d2 = 0;
75262306a36Sopenharmony_ci	go_down:
75362306a36Sopenharmony_ci	if (n_dnodes) (*n_dnodes)++;
75462306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
75562306a36Sopenharmony_ci		if (hpfs_stop_cycles(s, dno, &c1, &c2, "hpfs_count_dnodes #1")) return;
75662306a36Sopenharmony_ci	ptr = 0;
75762306a36Sopenharmony_ci	go_up:
75862306a36Sopenharmony_ci	if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return;
75962306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && le32_to_cpu(dnode->up) != odno)
76062306a36Sopenharmony_ci		hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, le32_to_cpu(dnode->up));
76162306a36Sopenharmony_ci	de = dnode_first_de(dnode);
76262306a36Sopenharmony_ci	if (ptr) while(1) {
76362306a36Sopenharmony_ci		if (de->down) if (de_down_pointer(de) == ptr) goto process_de;
76462306a36Sopenharmony_ci		if (de->last) {
76562306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
76662306a36Sopenharmony_ci			hpfs_error(s, "hpfs_count_dnodes: pointer to dnode %08x not found in dnode %08x, got here from %08x",
76762306a36Sopenharmony_ci				ptr, dno, odno);
76862306a36Sopenharmony_ci			return;
76962306a36Sopenharmony_ci		}
77062306a36Sopenharmony_ci		de = de_next_de(de);
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	next_de:
77362306a36Sopenharmony_ci	if (de->down) {
77462306a36Sopenharmony_ci		odno = dno;
77562306a36Sopenharmony_ci		dno = de_down_pointer(de);
77662306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
77762306a36Sopenharmony_ci		goto go_down;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci	process_de:
78062306a36Sopenharmony_ci	if (!de->first && !de->last && de->directory && n_subdirs) (*n_subdirs)++;
78162306a36Sopenharmony_ci	if (!de->first && !de->last && n_items) (*n_items)++;
78262306a36Sopenharmony_ci	if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de;
78362306a36Sopenharmony_ci	ptr = dno;
78462306a36Sopenharmony_ci	dno = le32_to_cpu(dnode->up);
78562306a36Sopenharmony_ci	if (dnode->root_dnode) {
78662306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
78762306a36Sopenharmony_ci		return;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
79062306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
79162306a36Sopenharmony_ci		if (hpfs_stop_cycles(s, ptr, &d1, &d2, "hpfs_count_dnodes #2")) return;
79262306a36Sopenharmony_ci	odno = -1;
79362306a36Sopenharmony_ci	goto go_up;
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_cistatic struct hpfs_dirent *map_nth_dirent(struct super_block *s, dnode_secno dno, int n,
79762306a36Sopenharmony_ci					  struct quad_buffer_head *qbh, struct dnode **dn)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	int i;
80062306a36Sopenharmony_ci	struct hpfs_dirent *de, *de_end;
80162306a36Sopenharmony_ci	struct dnode *dnode;
80262306a36Sopenharmony_ci	dnode = hpfs_map_dnode(s, dno, qbh);
80362306a36Sopenharmony_ci	if (!dnode) return NULL;
80462306a36Sopenharmony_ci	if (dn) *dn=dnode;
80562306a36Sopenharmony_ci	de = dnode_first_de(dnode);
80662306a36Sopenharmony_ci	de_end = dnode_end_de(dnode);
80762306a36Sopenharmony_ci	for (i = 1; de < de_end; i++, de = de_next_de(de)) {
80862306a36Sopenharmony_ci		if (i == n) {
80962306a36Sopenharmony_ci			return de;
81062306a36Sopenharmony_ci		}
81162306a36Sopenharmony_ci		if (de->last) break;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci	hpfs_brelse4(qbh);
81462306a36Sopenharmony_ci	hpfs_error(s, "map_nth_dirent: n too high; dnode = %08x, requested %08x", dno, n);
81562306a36Sopenharmony_ci	return NULL;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cidnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct quad_buffer_head qbh;
82162306a36Sopenharmony_ci	dnode_secno d = dno;
82262306a36Sopenharmony_ci	dnode_secno up = 0;
82362306a36Sopenharmony_ci	struct hpfs_dirent *de;
82462306a36Sopenharmony_ci	int c1, c2 = 0;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	again:
82762306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
82862306a36Sopenharmony_ci		if (hpfs_stop_cycles(s, d, &c1, &c2, "hpfs_de_as_down_as_possible"))
82962306a36Sopenharmony_ci			return d;
83062306a36Sopenharmony_ci	if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno;
83162306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
83262306a36Sopenharmony_ci		if (up && le32_to_cpu(((struct dnode *)qbh.data)->up) != up)
83362306a36Sopenharmony_ci			hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, le32_to_cpu(((struct dnode *)qbh.data)->up));
83462306a36Sopenharmony_ci	if (!de->down) {
83562306a36Sopenharmony_ci		hpfs_brelse4(&qbh);
83662306a36Sopenharmony_ci		return d;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci	up = d;
83962306a36Sopenharmony_ci	d = de_down_pointer(de);
84062306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
84162306a36Sopenharmony_ci	goto again;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistruct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
84562306a36Sopenharmony_ci				   struct quad_buffer_head *qbh)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	loff_t pos;
84862306a36Sopenharmony_ci	unsigned c;
84962306a36Sopenharmony_ci	dnode_secno dno;
85062306a36Sopenharmony_ci	struct hpfs_dirent *de, *d;
85162306a36Sopenharmony_ci	struct hpfs_dirent *up_de;
85262306a36Sopenharmony_ci	struct hpfs_dirent *end_up_de;
85362306a36Sopenharmony_ci	struct dnode *dnode;
85462306a36Sopenharmony_ci	struct dnode *up_dnode;
85562306a36Sopenharmony_ci	struct quad_buffer_head qbh0;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	pos = *posp;
85862306a36Sopenharmony_ci	dno = pos >> 6 << 2;
85962306a36Sopenharmony_ci	pos &= 077;
86062306a36Sopenharmony_ci	if (!(de = map_nth_dirent(inode->i_sb, dno, pos, qbh, &dnode)))
86162306a36Sopenharmony_ci		goto bail;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	/* Going to the next dirent */
86462306a36Sopenharmony_ci	if ((d = de_next_de(de)) < dnode_end_de(dnode)) {
86562306a36Sopenharmony_ci		if (!(++*posp & 077)) {
86662306a36Sopenharmony_ci			hpfs_error(inode->i_sb,
86762306a36Sopenharmony_ci				"map_pos_dirent: pos crossed dnode boundary; pos = %08llx",
86862306a36Sopenharmony_ci				(unsigned long long)*posp);
86962306a36Sopenharmony_ci			goto bail;
87062306a36Sopenharmony_ci		}
87162306a36Sopenharmony_ci		/* We're going down the tree */
87262306a36Sopenharmony_ci		if (d->down) {
87362306a36Sopenharmony_ci			*posp = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, de_down_pointer(d)) << 4) + 1;
87462306a36Sopenharmony_ci		}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci		return de;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* Going up */
88062306a36Sopenharmony_ci	if (dnode->root_dnode) goto bail;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (!(up_dnode = hpfs_map_dnode(inode->i_sb, le32_to_cpu(dnode->up), &qbh0)))
88362306a36Sopenharmony_ci		goto bail;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	end_up_de = dnode_end_de(up_dnode);
88662306a36Sopenharmony_ci	c = 0;
88762306a36Sopenharmony_ci	for (up_de = dnode_first_de(up_dnode); up_de < end_up_de;
88862306a36Sopenharmony_ci	     up_de = de_next_de(up_de)) {
88962306a36Sopenharmony_ci		if (!(++c & 077)) hpfs_error(inode->i_sb,
89062306a36Sopenharmony_ci			"map_pos_dirent: pos crossed dnode boundary; dnode = %08x", le32_to_cpu(dnode->up));
89162306a36Sopenharmony_ci		if (up_de->down && de_down_pointer(up_de) == dno) {
89262306a36Sopenharmony_ci			*posp = ((loff_t) le32_to_cpu(dnode->up) << 4) + c;
89362306a36Sopenharmony_ci			hpfs_brelse4(&qbh0);
89462306a36Sopenharmony_ci			return de;
89562306a36Sopenharmony_ci		}
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x",
89962306a36Sopenharmony_ci		dno, le32_to_cpu(dnode->up));
90062306a36Sopenharmony_ci	hpfs_brelse4(&qbh0);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	bail:
90362306a36Sopenharmony_ci	*posp = 12;
90462306a36Sopenharmony_ci	return de;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci/* Find a dirent in tree */
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistruct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
91062306a36Sopenharmony_ci			       const unsigned char *name, unsigned len,
91162306a36Sopenharmony_ci			       dnode_secno *dd, struct quad_buffer_head *qbh)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	struct dnode *dnode;
91462306a36Sopenharmony_ci	struct hpfs_dirent *de;
91562306a36Sopenharmony_ci	struct hpfs_dirent *de_end;
91662306a36Sopenharmony_ci	int c1, c2 = 0;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n");
91962306a36Sopenharmony_ci	again:
92062306a36Sopenharmony_ci	if (hpfs_sb(inode->i_sb)->sb_chk)
92162306a36Sopenharmony_ci		if (hpfs_stop_cycles(inode->i_sb, dno, &c1, &c2, "map_dirent")) return NULL;
92262306a36Sopenharmony_ci	if (!(dnode = hpfs_map_dnode(inode->i_sb, dno, qbh))) return NULL;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	de_end = dnode_end_de(dnode);
92562306a36Sopenharmony_ci	for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de)) {
92662306a36Sopenharmony_ci		int t = hpfs_compare_names(inode->i_sb, name, len, de->name, de->namelen, de->last);
92762306a36Sopenharmony_ci		if (!t) {
92862306a36Sopenharmony_ci			if (dd) *dd = dno;
92962306a36Sopenharmony_ci			return de;
93062306a36Sopenharmony_ci		}
93162306a36Sopenharmony_ci		if (t < 0) {
93262306a36Sopenharmony_ci			if (de->down) {
93362306a36Sopenharmony_ci				dno = de_down_pointer(de);
93462306a36Sopenharmony_ci				hpfs_brelse4(qbh);
93562306a36Sopenharmony_ci				goto again;
93662306a36Sopenharmony_ci			}
93762306a36Sopenharmony_ci		break;
93862306a36Sopenharmony_ci		}
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci	hpfs_brelse4(qbh);
94162306a36Sopenharmony_ci	return NULL;
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci/*
94562306a36Sopenharmony_ci * Remove empty directory. In normal cases it is only one dnode with two
94662306a36Sopenharmony_ci * entries, but we must handle also such obscure cases when it's a tree
94762306a36Sopenharmony_ci * of empty dnodes.
94862306a36Sopenharmony_ci */
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_civoid hpfs_remove_dtree(struct super_block *s, dnode_secno dno)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	struct quad_buffer_head qbh;
95362306a36Sopenharmony_ci	struct dnode *dnode;
95462306a36Sopenharmony_ci	struct hpfs_dirent *de;
95562306a36Sopenharmony_ci	dnode_secno d1, d2, rdno = dno;
95662306a36Sopenharmony_ci	while (1) {
95762306a36Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return;
95862306a36Sopenharmony_ci		de = dnode_first_de(dnode);
95962306a36Sopenharmony_ci		if (de->last) {
96062306a36Sopenharmony_ci			if (de->down) d1 = de_down_pointer(de);
96162306a36Sopenharmony_ci			else goto error;
96262306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
96362306a36Sopenharmony_ci			hpfs_free_dnode(s, dno);
96462306a36Sopenharmony_ci			dno = d1;
96562306a36Sopenharmony_ci		} else break;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci	if (!de->first) goto error;
96862306a36Sopenharmony_ci	d1 = de->down ? de_down_pointer(de) : 0;
96962306a36Sopenharmony_ci	de = de_next_de(de);
97062306a36Sopenharmony_ci	if (!de->last) goto error;
97162306a36Sopenharmony_ci	d2 = de->down ? de_down_pointer(de) : 0;
97262306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
97362306a36Sopenharmony_ci	hpfs_free_dnode(s, dno);
97462306a36Sopenharmony_ci	do {
97562306a36Sopenharmony_ci		while (d1) {
97662306a36Sopenharmony_ci			if (!(dnode = hpfs_map_dnode(s, dno = d1, &qbh))) return;
97762306a36Sopenharmony_ci			de = dnode_first_de(dnode);
97862306a36Sopenharmony_ci			if (!de->last) goto error;
97962306a36Sopenharmony_ci			d1 = de->down ? de_down_pointer(de) : 0;
98062306a36Sopenharmony_ci			hpfs_brelse4(&qbh);
98162306a36Sopenharmony_ci			hpfs_free_dnode(s, dno);
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci		d1 = d2;
98462306a36Sopenharmony_ci		d2 = 0;
98562306a36Sopenharmony_ci	} while (d1);
98662306a36Sopenharmony_ci	return;
98762306a36Sopenharmony_ci	error:
98862306a36Sopenharmony_ci	hpfs_brelse4(&qbh);
98962306a36Sopenharmony_ci	hpfs_free_dnode(s, dno);
99062306a36Sopenharmony_ci	hpfs_error(s, "directory %08x is corrupted or not empty", rdno);
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci/*
99462306a36Sopenharmony_ci * Find dirent for specified fnode. Use truncated 15-char name in fnode as
99562306a36Sopenharmony_ci * a help for searching.
99662306a36Sopenharmony_ci */
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistruct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
99962306a36Sopenharmony_ci				     struct fnode *f, struct quad_buffer_head *qbh)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	unsigned char *name1;
100262306a36Sopenharmony_ci	unsigned char *name2;
100362306a36Sopenharmony_ci	int name1len, name2len;
100462306a36Sopenharmony_ci	struct dnode *d;
100562306a36Sopenharmony_ci	dnode_secno dno, downd;
100662306a36Sopenharmony_ci	struct fnode *upf;
100762306a36Sopenharmony_ci	struct buffer_head *bh;
100862306a36Sopenharmony_ci	struct hpfs_dirent *de, *de_end;
100962306a36Sopenharmony_ci	int c;
101062306a36Sopenharmony_ci	int c1, c2 = 0;
101162306a36Sopenharmony_ci	int d1, d2 = 0;
101262306a36Sopenharmony_ci	name1 = f->name;
101362306a36Sopenharmony_ci	if (!(name2 = kmalloc(256, GFP_NOFS))) {
101462306a36Sopenharmony_ci		pr_err("out of memory, can't map dirent\n");
101562306a36Sopenharmony_ci		return NULL;
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci	if (f->len <= 15)
101862306a36Sopenharmony_ci		memcpy(name2, name1, name1len = name2len = f->len);
101962306a36Sopenharmony_ci	else {
102062306a36Sopenharmony_ci		memcpy(name2, name1, 15);
102162306a36Sopenharmony_ci		memset(name2 + 15, 0xff, 256 - 15);
102262306a36Sopenharmony_ci		/*name2[15] = 0xff;*/
102362306a36Sopenharmony_ci		name1len = 15; name2len = 256;
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci	if (!(upf = hpfs_map_fnode(s, le32_to_cpu(f->up), &bh))) {
102662306a36Sopenharmony_ci		kfree(name2);
102762306a36Sopenharmony_ci		return NULL;
102862306a36Sopenharmony_ci	}
102962306a36Sopenharmony_ci	if (!fnode_is_dir(upf)) {
103062306a36Sopenharmony_ci		brelse(bh);
103162306a36Sopenharmony_ci		hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up));
103262306a36Sopenharmony_ci		kfree(name2);
103362306a36Sopenharmony_ci		return NULL;
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci	dno = le32_to_cpu(upf->u.external[0].disk_secno);
103662306a36Sopenharmony_ci	brelse(bh);
103762306a36Sopenharmony_ci	go_down:
103862306a36Sopenharmony_ci	downd = 0;
103962306a36Sopenharmony_ci	go_up:
104062306a36Sopenharmony_ci	if (!(d = hpfs_map_dnode(s, dno, qbh))) {
104162306a36Sopenharmony_ci		kfree(name2);
104262306a36Sopenharmony_ci		return NULL;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci	de_end = dnode_end_de(d);
104562306a36Sopenharmony_ci	de = dnode_first_de(d);
104662306a36Sopenharmony_ci	if (downd) {
104762306a36Sopenharmony_ci		while (de < de_end) {
104862306a36Sopenharmony_ci			if (de->down) if (de_down_pointer(de) == downd) goto f;
104962306a36Sopenharmony_ci			de = de_next_de(de);
105062306a36Sopenharmony_ci		}
105162306a36Sopenharmony_ci		hpfs_error(s, "pointer to dnode %08x not found in dnode %08x", downd, dno);
105262306a36Sopenharmony_ci		hpfs_brelse4(qbh);
105362306a36Sopenharmony_ci		kfree(name2);
105462306a36Sopenharmony_ci		return NULL;
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci	next_de:
105762306a36Sopenharmony_ci	if (le32_to_cpu(de->fnode) == fno) {
105862306a36Sopenharmony_ci		kfree(name2);
105962306a36Sopenharmony_ci		return de;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci	c = hpfs_compare_names(s, name1, name1len, de->name, de->namelen, de->last);
106262306a36Sopenharmony_ci	if (c < 0 && de->down) {
106362306a36Sopenharmony_ci		dno = de_down_pointer(de);
106462306a36Sopenharmony_ci		hpfs_brelse4(qbh);
106562306a36Sopenharmony_ci		if (hpfs_sb(s)->sb_chk)
106662306a36Sopenharmony_ci			if (hpfs_stop_cycles(s, dno, &c1, &c2, "map_fnode_dirent #1")) {
106762306a36Sopenharmony_ci				kfree(name2);
106862306a36Sopenharmony_ci				return NULL;
106962306a36Sopenharmony_ci		}
107062306a36Sopenharmony_ci		goto go_down;
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci	f:
107362306a36Sopenharmony_ci	if (le32_to_cpu(de->fnode) == fno) {
107462306a36Sopenharmony_ci		kfree(name2);
107562306a36Sopenharmony_ci		return de;
107662306a36Sopenharmony_ci	}
107762306a36Sopenharmony_ci	c = hpfs_compare_names(s, name2, name2len, de->name, de->namelen, de->last);
107862306a36Sopenharmony_ci	if (c < 0 && !de->last) goto not_found;
107962306a36Sopenharmony_ci	if ((de = de_next_de(de)) < de_end) goto next_de;
108062306a36Sopenharmony_ci	if (d->root_dnode) goto not_found;
108162306a36Sopenharmony_ci	downd = dno;
108262306a36Sopenharmony_ci	dno = le32_to_cpu(d->up);
108362306a36Sopenharmony_ci	hpfs_brelse4(qbh);
108462306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
108562306a36Sopenharmony_ci		if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) {
108662306a36Sopenharmony_ci			kfree(name2);
108762306a36Sopenharmony_ci			return NULL;
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci	goto go_up;
109062306a36Sopenharmony_ci	not_found:
109162306a36Sopenharmony_ci	hpfs_brelse4(qbh);
109262306a36Sopenharmony_ci	hpfs_error(s, "dirent for fnode %08x not found", fno);
109362306a36Sopenharmony_ci	kfree(name2);
109462306a36Sopenharmony_ci	return NULL;
109562306a36Sopenharmony_ci}
1096