162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  linux/fs/hpfs/anode.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  handling HPFS anode tree that contains file allocation info
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "hpfs_fn.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/* Find a sector in allocation tree */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cisecno hpfs_bplus_lookup(struct super_block *s, struct inode *inode,
1562306a36Sopenharmony_ci		   struct bplus_header *btree, unsigned sec,
1662306a36Sopenharmony_ci		   struct buffer_head *bh)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	anode_secno a = -1;
1962306a36Sopenharmony_ci	struct anode *anode;
2062306a36Sopenharmony_ci	int i;
2162306a36Sopenharmony_ci	int c1, c2 = 0;
2262306a36Sopenharmony_ci	go_down:
2362306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1;
2462306a36Sopenharmony_ci	if (bp_internal(btree)) {
2562306a36Sopenharmony_ci		for (i = 0; i < btree->n_used_nodes; i++)
2662306a36Sopenharmony_ci			if (le32_to_cpu(btree->u.internal[i].file_secno) > sec) {
2762306a36Sopenharmony_ci				a = le32_to_cpu(btree->u.internal[i].down);
2862306a36Sopenharmony_ci				brelse(bh);
2962306a36Sopenharmony_ci				if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
3062306a36Sopenharmony_ci				btree = &anode->btree;
3162306a36Sopenharmony_ci				goto go_down;
3262306a36Sopenharmony_ci			}
3362306a36Sopenharmony_ci		hpfs_error(s, "sector %08x not found in internal anode %08x", sec, a);
3462306a36Sopenharmony_ci		brelse(bh);
3562306a36Sopenharmony_ci		return -1;
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci	for (i = 0; i < btree->n_used_nodes; i++)
3862306a36Sopenharmony_ci		if (le32_to_cpu(btree->u.external[i].file_secno) <= sec &&
3962306a36Sopenharmony_ci		    le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) > sec) {
4062306a36Sopenharmony_ci			a = le32_to_cpu(btree->u.external[i].disk_secno) + sec - le32_to_cpu(btree->u.external[i].file_secno);
4162306a36Sopenharmony_ci			if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, a, 1, "data")) {
4262306a36Sopenharmony_ci				brelse(bh);
4362306a36Sopenharmony_ci				return -1;
4462306a36Sopenharmony_ci			}
4562306a36Sopenharmony_ci			if (inode) {
4662306a36Sopenharmony_ci				struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
4762306a36Sopenharmony_ci				hpfs_inode->i_file_sec = le32_to_cpu(btree->u.external[i].file_secno);
4862306a36Sopenharmony_ci				hpfs_inode->i_disk_sec = le32_to_cpu(btree->u.external[i].disk_secno);
4962306a36Sopenharmony_ci				hpfs_inode->i_n_secs = le32_to_cpu(btree->u.external[i].length);
5062306a36Sopenharmony_ci			}
5162306a36Sopenharmony_ci			brelse(bh);
5262306a36Sopenharmony_ci			return a;
5362306a36Sopenharmony_ci		}
5462306a36Sopenharmony_ci	hpfs_error(s, "sector %08x not found in external anode %08x", sec, a);
5562306a36Sopenharmony_ci	brelse(bh);
5662306a36Sopenharmony_ci	return -1;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Add a sector to tree */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cisecno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsigned fsecno)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	struct bplus_header *btree;
6462306a36Sopenharmony_ci	struct anode *anode = NULL, *ranode = NULL;
6562306a36Sopenharmony_ci	struct fnode *fnode;
6662306a36Sopenharmony_ci	anode_secno a, na = -1, ra, up = -1;
6762306a36Sopenharmony_ci	secno se;
6862306a36Sopenharmony_ci	struct buffer_head *bh, *bh1, *bh2;
6962306a36Sopenharmony_ci	int n;
7062306a36Sopenharmony_ci	unsigned fs;
7162306a36Sopenharmony_ci	int c1, c2 = 0;
7262306a36Sopenharmony_ci	if (fnod) {
7362306a36Sopenharmony_ci		if (!(fnode = hpfs_map_fnode(s, node, &bh))) return -1;
7462306a36Sopenharmony_ci		btree = &fnode->btree;
7562306a36Sopenharmony_ci	} else {
7662306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, node, &bh))) return -1;
7762306a36Sopenharmony_ci		btree = &anode->btree;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	a = node;
8062306a36Sopenharmony_ci	go_down:
8162306a36Sopenharmony_ci	if ((n = btree->n_used_nodes - 1) < -!!fnod) {
8262306a36Sopenharmony_ci		hpfs_error(s, "anode %08x has no entries", a);
8362306a36Sopenharmony_ci		brelse(bh);
8462306a36Sopenharmony_ci		return -1;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci	if (bp_internal(btree)) {
8762306a36Sopenharmony_ci		a = le32_to_cpu(btree->u.internal[n].down);
8862306a36Sopenharmony_ci		btree->u.internal[n].file_secno = cpu_to_le32(-1);
8962306a36Sopenharmony_ci		mark_buffer_dirty(bh);
9062306a36Sopenharmony_ci		brelse(bh);
9162306a36Sopenharmony_ci		if (hpfs_sb(s)->sb_chk)
9262306a36Sopenharmony_ci			if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_add_sector_to_btree #1")) return -1;
9362306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
9462306a36Sopenharmony_ci		btree = &anode->btree;
9562306a36Sopenharmony_ci		goto go_down;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci	if (n >= 0) {
9862306a36Sopenharmony_ci		if (le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length) != fsecno) {
9962306a36Sopenharmony_ci			hpfs_error(s, "allocated size %08x, trying to add sector %08x, %cnode %08x",
10062306a36Sopenharmony_ci				le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length), fsecno,
10162306a36Sopenharmony_ci				fnod?'f':'a', node);
10262306a36Sopenharmony_ci			brelse(bh);
10362306a36Sopenharmony_ci			return -1;
10462306a36Sopenharmony_ci		}
10562306a36Sopenharmony_ci		if (hpfs_alloc_if_possible(s, se = le32_to_cpu(btree->u.external[n].disk_secno) + le32_to_cpu(btree->u.external[n].length))) {
10662306a36Sopenharmony_ci			le32_add_cpu(&btree->u.external[n].length, 1);
10762306a36Sopenharmony_ci			mark_buffer_dirty(bh);
10862306a36Sopenharmony_ci			brelse(bh);
10962306a36Sopenharmony_ci			return se;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci	} else {
11262306a36Sopenharmony_ci		if (fsecno) {
11362306a36Sopenharmony_ci			hpfs_error(s, "empty file %08x, trying to add sector %08x", node, fsecno);
11462306a36Sopenharmony_ci			brelse(bh);
11562306a36Sopenharmony_ci			return -1;
11662306a36Sopenharmony_ci		}
11762306a36Sopenharmony_ci		se = !fnod ? node : (node + 16384) & ~16383;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	if (!(se = hpfs_alloc_sector(s, se, 1, fsecno*ALLOC_M>ALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_M<ALLOC_FWD_MIN ? ALLOC_FWD_MIN : fsecno*ALLOC_M))) {
12062306a36Sopenharmony_ci		brelse(bh);
12162306a36Sopenharmony_ci		return -1;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci	fs = n < 0 ? 0 : le32_to_cpu(btree->u.external[n].file_secno) + le32_to_cpu(btree->u.external[n].length);
12462306a36Sopenharmony_ci	if (!btree->n_free_nodes) {
12562306a36Sopenharmony_ci		up = a != node ? le32_to_cpu(anode->up) : -1;
12662306a36Sopenharmony_ci		if (!(anode = hpfs_alloc_anode(s, a, &na, &bh1))) {
12762306a36Sopenharmony_ci			brelse(bh);
12862306a36Sopenharmony_ci			hpfs_free_sectors(s, se, 1);
12962306a36Sopenharmony_ci			return -1;
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci		if (a == node && fnod) {
13262306a36Sopenharmony_ci			anode->up = cpu_to_le32(node);
13362306a36Sopenharmony_ci			anode->btree.flags |= BP_fnode_parent;
13462306a36Sopenharmony_ci			anode->btree.n_used_nodes = btree->n_used_nodes;
13562306a36Sopenharmony_ci			anode->btree.first_free = btree->first_free;
13662306a36Sopenharmony_ci			anode->btree.n_free_nodes = 40 - anode->btree.n_used_nodes;
13762306a36Sopenharmony_ci			memcpy(&anode->u, &btree->u, btree->n_used_nodes * 12);
13862306a36Sopenharmony_ci			btree->flags |= BP_internal;
13962306a36Sopenharmony_ci			btree->n_free_nodes = 11;
14062306a36Sopenharmony_ci			btree->n_used_nodes = 1;
14162306a36Sopenharmony_ci			btree->first_free = cpu_to_le16((char *)&(btree->u.internal[1]) - (char *)btree);
14262306a36Sopenharmony_ci			btree->u.internal[0].file_secno = cpu_to_le32(-1);
14362306a36Sopenharmony_ci			btree->u.internal[0].down = cpu_to_le32(na);
14462306a36Sopenharmony_ci			mark_buffer_dirty(bh);
14562306a36Sopenharmony_ci		} else if (!(ranode = hpfs_alloc_anode(s, /*a*/0, &ra, &bh2))) {
14662306a36Sopenharmony_ci			brelse(bh);
14762306a36Sopenharmony_ci			brelse(bh1);
14862306a36Sopenharmony_ci			hpfs_free_sectors(s, se, 1);
14962306a36Sopenharmony_ci			hpfs_free_sectors(s, na, 1);
15062306a36Sopenharmony_ci			return -1;
15162306a36Sopenharmony_ci		}
15262306a36Sopenharmony_ci		brelse(bh);
15362306a36Sopenharmony_ci		bh = bh1;
15462306a36Sopenharmony_ci		btree = &anode->btree;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci	btree->n_free_nodes--; n = btree->n_used_nodes++;
15762306a36Sopenharmony_ci	le16_add_cpu(&btree->first_free, 12);
15862306a36Sopenharmony_ci	btree->u.external[n].disk_secno = cpu_to_le32(se);
15962306a36Sopenharmony_ci	btree->u.external[n].file_secno = cpu_to_le32(fs);
16062306a36Sopenharmony_ci	btree->u.external[n].length = cpu_to_le32(1);
16162306a36Sopenharmony_ci	mark_buffer_dirty(bh);
16262306a36Sopenharmony_ci	brelse(bh);
16362306a36Sopenharmony_ci	if ((a == node && fnod) || na == -1) return se;
16462306a36Sopenharmony_ci	c2 = 0;
16562306a36Sopenharmony_ci	while (up != (anode_secno)-1) {
16662306a36Sopenharmony_ci		struct anode *new_anode;
16762306a36Sopenharmony_ci		if (hpfs_sb(s)->sb_chk)
16862306a36Sopenharmony_ci			if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1;
16962306a36Sopenharmony_ci		if (up != node || !fnod) {
17062306a36Sopenharmony_ci			if (!(anode = hpfs_map_anode(s, up, &bh))) return -1;
17162306a36Sopenharmony_ci			btree = &anode->btree;
17262306a36Sopenharmony_ci		} else {
17362306a36Sopenharmony_ci			if (!(fnode = hpfs_map_fnode(s, up, &bh))) return -1;
17462306a36Sopenharmony_ci			btree = &fnode->btree;
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci		if (btree->n_free_nodes) {
17762306a36Sopenharmony_ci			btree->n_free_nodes--; n = btree->n_used_nodes++;
17862306a36Sopenharmony_ci			le16_add_cpu(&btree->first_free, 8);
17962306a36Sopenharmony_ci			btree->u.internal[n].file_secno = cpu_to_le32(-1);
18062306a36Sopenharmony_ci			btree->u.internal[n].down = cpu_to_le32(na);
18162306a36Sopenharmony_ci			btree->u.internal[n-1].file_secno = cpu_to_le32(fs);
18262306a36Sopenharmony_ci			mark_buffer_dirty(bh);
18362306a36Sopenharmony_ci			brelse(bh);
18462306a36Sopenharmony_ci			brelse(bh2);
18562306a36Sopenharmony_ci			hpfs_free_sectors(s, ra, 1);
18662306a36Sopenharmony_ci			if ((anode = hpfs_map_anode(s, na, &bh))) {
18762306a36Sopenharmony_ci				anode->up = cpu_to_le32(up);
18862306a36Sopenharmony_ci				if (up == node && fnod)
18962306a36Sopenharmony_ci					anode->btree.flags |= BP_fnode_parent;
19062306a36Sopenharmony_ci				else
19162306a36Sopenharmony_ci					anode->btree.flags &= ~BP_fnode_parent;
19262306a36Sopenharmony_ci				mark_buffer_dirty(bh);
19362306a36Sopenharmony_ci				brelse(bh);
19462306a36Sopenharmony_ci			}
19562306a36Sopenharmony_ci			return se;
19662306a36Sopenharmony_ci		}
19762306a36Sopenharmony_ci		up = up != node ? le32_to_cpu(anode->up) : -1;
19862306a36Sopenharmony_ci		btree->u.internal[btree->n_used_nodes - 1].file_secno = cpu_to_le32(/*fs*/-1);
19962306a36Sopenharmony_ci		mark_buffer_dirty(bh);
20062306a36Sopenharmony_ci		brelse(bh);
20162306a36Sopenharmony_ci		a = na;
20262306a36Sopenharmony_ci		if ((new_anode = hpfs_alloc_anode(s, a, &na, &bh))) {
20362306a36Sopenharmony_ci			anode = new_anode;
20462306a36Sopenharmony_ci			/*anode->up = cpu_to_le32(up != -1 ? up : ra);*/
20562306a36Sopenharmony_ci			anode->btree.flags |= BP_internal;
20662306a36Sopenharmony_ci			anode->btree.n_used_nodes = 1;
20762306a36Sopenharmony_ci			anode->btree.n_free_nodes = 59;
20862306a36Sopenharmony_ci			anode->btree.first_free = cpu_to_le16(16);
20962306a36Sopenharmony_ci			anode->btree.u.internal[0].down = cpu_to_le32(a);
21062306a36Sopenharmony_ci			anode->btree.u.internal[0].file_secno = cpu_to_le32(-1);
21162306a36Sopenharmony_ci			mark_buffer_dirty(bh);
21262306a36Sopenharmony_ci			brelse(bh);
21362306a36Sopenharmony_ci			if ((anode = hpfs_map_anode(s, a, &bh))) {
21462306a36Sopenharmony_ci				anode->up = cpu_to_le32(na);
21562306a36Sopenharmony_ci				mark_buffer_dirty(bh);
21662306a36Sopenharmony_ci				brelse(bh);
21762306a36Sopenharmony_ci			}
21862306a36Sopenharmony_ci		} else na = a;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci	if ((anode = hpfs_map_anode(s, na, &bh))) {
22162306a36Sopenharmony_ci		anode->up = cpu_to_le32(node);
22262306a36Sopenharmony_ci		if (fnod)
22362306a36Sopenharmony_ci			anode->btree.flags |= BP_fnode_parent;
22462306a36Sopenharmony_ci		mark_buffer_dirty(bh);
22562306a36Sopenharmony_ci		brelse(bh);
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci	if (!fnod) {
22862306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, node, &bh))) {
22962306a36Sopenharmony_ci			brelse(bh2);
23062306a36Sopenharmony_ci			return -1;
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci		btree = &anode->btree;
23362306a36Sopenharmony_ci	} else {
23462306a36Sopenharmony_ci		if (!(fnode = hpfs_map_fnode(s, node, &bh))) {
23562306a36Sopenharmony_ci			brelse(bh2);
23662306a36Sopenharmony_ci			return -1;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci		btree = &fnode->btree;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci	ranode->up = cpu_to_le32(node);
24162306a36Sopenharmony_ci	memcpy(&ranode->btree, btree, le16_to_cpu(btree->first_free));
24262306a36Sopenharmony_ci	if (fnod)
24362306a36Sopenharmony_ci		ranode->btree.flags |= BP_fnode_parent;
24462306a36Sopenharmony_ci	ranode->btree.n_free_nodes = (bp_internal(&ranode->btree) ? 60 : 40) - ranode->btree.n_used_nodes;
24562306a36Sopenharmony_ci	if (bp_internal(&ranode->btree)) for (n = 0; n < ranode->btree.n_used_nodes; n++) {
24662306a36Sopenharmony_ci		struct anode *unode;
24762306a36Sopenharmony_ci		if ((unode = hpfs_map_anode(s, le32_to_cpu(ranode->u.internal[n].down), &bh1))) {
24862306a36Sopenharmony_ci			unode->up = cpu_to_le32(ra);
24962306a36Sopenharmony_ci			unode->btree.flags &= ~BP_fnode_parent;
25062306a36Sopenharmony_ci			mark_buffer_dirty(bh1);
25162306a36Sopenharmony_ci			brelse(bh1);
25262306a36Sopenharmony_ci		}
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	btree->flags |= BP_internal;
25562306a36Sopenharmony_ci	btree->n_free_nodes = fnod ? 10 : 58;
25662306a36Sopenharmony_ci	btree->n_used_nodes = 2;
25762306a36Sopenharmony_ci	btree->first_free = cpu_to_le16((char *)&btree->u.internal[2] - (char *)btree);
25862306a36Sopenharmony_ci	btree->u.internal[0].file_secno = cpu_to_le32(fs);
25962306a36Sopenharmony_ci	btree->u.internal[0].down = cpu_to_le32(ra);
26062306a36Sopenharmony_ci	btree->u.internal[1].file_secno = cpu_to_le32(-1);
26162306a36Sopenharmony_ci	btree->u.internal[1].down = cpu_to_le32(na);
26262306a36Sopenharmony_ci	mark_buffer_dirty(bh);
26362306a36Sopenharmony_ci	brelse(bh);
26462306a36Sopenharmony_ci	mark_buffer_dirty(bh2);
26562306a36Sopenharmony_ci	brelse(bh2);
26662306a36Sopenharmony_ci	return se;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci/*
27062306a36Sopenharmony_ci * Remove allocation tree. Recursion would look much nicer but
27162306a36Sopenharmony_ci * I want to avoid it because it can cause stack overflow.
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_civoid hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct bplus_header *btree1 = btree;
27762306a36Sopenharmony_ci	struct anode *anode = NULL;
27862306a36Sopenharmony_ci	anode_secno ano = 0, oano;
27962306a36Sopenharmony_ci	struct buffer_head *bh;
28062306a36Sopenharmony_ci	int level = 0;
28162306a36Sopenharmony_ci	int pos = 0;
28262306a36Sopenharmony_ci	int i;
28362306a36Sopenharmony_ci	int c1, c2 = 0;
28462306a36Sopenharmony_ci	int d1, d2;
28562306a36Sopenharmony_ci	go_down:
28662306a36Sopenharmony_ci	d2 = 0;
28762306a36Sopenharmony_ci	while (bp_internal(btree1)) {
28862306a36Sopenharmony_ci		ano = le32_to_cpu(btree1->u.internal[pos].down);
28962306a36Sopenharmony_ci		if (level) brelse(bh);
29062306a36Sopenharmony_ci		if (hpfs_sb(s)->sb_chk)
29162306a36Sopenharmony_ci			if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1"))
29262306a36Sopenharmony_ci				return;
29362306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, ano, &bh))) return;
29462306a36Sopenharmony_ci		btree1 = &anode->btree;
29562306a36Sopenharmony_ci		level++;
29662306a36Sopenharmony_ci		pos = 0;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	for (i = 0; i < btree1->n_used_nodes; i++)
29962306a36Sopenharmony_ci		hpfs_free_sectors(s, le32_to_cpu(btree1->u.external[i].disk_secno), le32_to_cpu(btree1->u.external[i].length));
30062306a36Sopenharmony_ci	go_up:
30162306a36Sopenharmony_ci	if (!level) return;
30262306a36Sopenharmony_ci	brelse(bh);
30362306a36Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
30462306a36Sopenharmony_ci		if (hpfs_stop_cycles(s, ano, &c1, &c2, "hpfs_remove_btree #2")) return;
30562306a36Sopenharmony_ci	hpfs_free_sectors(s, ano, 1);
30662306a36Sopenharmony_ci	oano = ano;
30762306a36Sopenharmony_ci	ano = le32_to_cpu(anode->up);
30862306a36Sopenharmony_ci	if (--level) {
30962306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, ano, &bh))) return;
31062306a36Sopenharmony_ci		btree1 = &anode->btree;
31162306a36Sopenharmony_ci	} else btree1 = btree;
31262306a36Sopenharmony_ci	for (i = 0; i < btree1->n_used_nodes; i++) {
31362306a36Sopenharmony_ci		if (le32_to_cpu(btree1->u.internal[i].down) == oano) {
31462306a36Sopenharmony_ci			if ((pos = i + 1) < btree1->n_used_nodes)
31562306a36Sopenharmony_ci				goto go_down;
31662306a36Sopenharmony_ci			else
31762306a36Sopenharmony_ci				goto go_up;
31862306a36Sopenharmony_ci		}
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci	hpfs_error(s,
32162306a36Sopenharmony_ci		   "reference to anode %08x not found in anode %08x "
32262306a36Sopenharmony_ci		   "(probably bad up pointer)",
32362306a36Sopenharmony_ci		   oano, level ? ano : -1);
32462306a36Sopenharmony_ci	if (level)
32562306a36Sopenharmony_ci		brelse(bh);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/* Just a wrapper around hpfs_bplus_lookup .. used for reading eas */
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic secno anode_lookup(struct super_block *s, anode_secno a, unsigned sec)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct anode *anode;
33362306a36Sopenharmony_ci	struct buffer_head *bh;
33462306a36Sopenharmony_ci	if (!(anode = hpfs_map_anode(s, a, &bh))) return -1;
33562306a36Sopenharmony_ci	return hpfs_bplus_lookup(s, NULL, &anode->btree, sec, bh);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ciint hpfs_ea_read(struct super_block *s, secno a, int ano, unsigned pos,
33962306a36Sopenharmony_ci	    unsigned len, char *buf)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct buffer_head *bh;
34262306a36Sopenharmony_ci	char *data;
34362306a36Sopenharmony_ci	secno sec;
34462306a36Sopenharmony_ci	unsigned l;
34562306a36Sopenharmony_ci	while (len) {
34662306a36Sopenharmony_ci		if (ano) {
34762306a36Sopenharmony_ci			if ((sec = anode_lookup(s, a, pos >> 9)) == -1)
34862306a36Sopenharmony_ci				return -1;
34962306a36Sopenharmony_ci		} else sec = a + (pos >> 9);
35062306a36Sopenharmony_ci		if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, sec, 1, "ea #1")) return -1;
35162306a36Sopenharmony_ci		if (!(data = hpfs_map_sector(s, sec, &bh, (len - 1) >> 9)))
35262306a36Sopenharmony_ci			return -1;
35362306a36Sopenharmony_ci		l = 0x200 - (pos & 0x1ff); if (l > len) l = len;
35462306a36Sopenharmony_ci		memcpy(buf, data + (pos & 0x1ff), l);
35562306a36Sopenharmony_ci		brelse(bh);
35662306a36Sopenharmony_ci		buf += l; pos += l; len -= l;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci	return 0;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ciint hpfs_ea_write(struct super_block *s, secno a, int ano, unsigned pos,
36262306a36Sopenharmony_ci	     unsigned len, const char *buf)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct buffer_head *bh;
36562306a36Sopenharmony_ci	char *data;
36662306a36Sopenharmony_ci	secno sec;
36762306a36Sopenharmony_ci	unsigned l;
36862306a36Sopenharmony_ci	while (len) {
36962306a36Sopenharmony_ci		if (ano) {
37062306a36Sopenharmony_ci			if ((sec = anode_lookup(s, a, pos >> 9)) == -1)
37162306a36Sopenharmony_ci				return -1;
37262306a36Sopenharmony_ci		} else sec = a + (pos >> 9);
37362306a36Sopenharmony_ci		if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, sec, 1, "ea #2")) return -1;
37462306a36Sopenharmony_ci		if (!(data = hpfs_map_sector(s, sec, &bh, (len - 1) >> 9)))
37562306a36Sopenharmony_ci			return -1;
37662306a36Sopenharmony_ci		l = 0x200 - (pos & 0x1ff); if (l > len) l = len;
37762306a36Sopenharmony_ci		memcpy(data + (pos & 0x1ff), buf, l);
37862306a36Sopenharmony_ci		mark_buffer_dirty(bh);
37962306a36Sopenharmony_ci		brelse(bh);
38062306a36Sopenharmony_ci		buf += l; pos += l; len -= l;
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci	return 0;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_civoid hpfs_ea_remove(struct super_block *s, secno a, int ano, unsigned len)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct anode *anode;
38862306a36Sopenharmony_ci	struct buffer_head *bh;
38962306a36Sopenharmony_ci	if (ano) {
39062306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, a, &bh))) return;
39162306a36Sopenharmony_ci		hpfs_remove_btree(s, &anode->btree);
39262306a36Sopenharmony_ci		brelse(bh);
39362306a36Sopenharmony_ci		hpfs_free_sectors(s, a, 1);
39462306a36Sopenharmony_ci	} else hpfs_free_sectors(s, a, (len + 511) >> 9);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci/* Truncate allocation tree. Doesn't join anodes - I hope it doesn't matter */
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_civoid hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct fnode *fnode;
40262306a36Sopenharmony_ci	struct anode *anode;
40362306a36Sopenharmony_ci	struct buffer_head *bh;
40462306a36Sopenharmony_ci	struct bplus_header *btree;
40562306a36Sopenharmony_ci	anode_secno node = f;
40662306a36Sopenharmony_ci	int i, j, nodes;
40762306a36Sopenharmony_ci	int c1, c2 = 0;
40862306a36Sopenharmony_ci	if (fno) {
40962306a36Sopenharmony_ci		if (!(fnode = hpfs_map_fnode(s, f, &bh))) return;
41062306a36Sopenharmony_ci		btree = &fnode->btree;
41162306a36Sopenharmony_ci	} else {
41262306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, f, &bh))) return;
41362306a36Sopenharmony_ci		btree = &anode->btree;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci	if (!secs) {
41662306a36Sopenharmony_ci		hpfs_remove_btree(s, btree);
41762306a36Sopenharmony_ci		if (fno) {
41862306a36Sopenharmony_ci			btree->n_free_nodes = 8;
41962306a36Sopenharmony_ci			btree->n_used_nodes = 0;
42062306a36Sopenharmony_ci			btree->first_free = cpu_to_le16(8);
42162306a36Sopenharmony_ci			btree->flags &= ~BP_internal;
42262306a36Sopenharmony_ci			mark_buffer_dirty(bh);
42362306a36Sopenharmony_ci		} else hpfs_free_sectors(s, f, 1);
42462306a36Sopenharmony_ci		brelse(bh);
42562306a36Sopenharmony_ci		return;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci	while (bp_internal(btree)) {
42862306a36Sopenharmony_ci		nodes = btree->n_used_nodes + btree->n_free_nodes;
42962306a36Sopenharmony_ci		for (i = 0; i < btree->n_used_nodes; i++)
43062306a36Sopenharmony_ci			if (le32_to_cpu(btree->u.internal[i].file_secno) >= secs) goto f;
43162306a36Sopenharmony_ci		brelse(bh);
43262306a36Sopenharmony_ci		hpfs_error(s, "internal btree %08x doesn't end with -1", node);
43362306a36Sopenharmony_ci		return;
43462306a36Sopenharmony_ci		f:
43562306a36Sopenharmony_ci		for (j = i + 1; j < btree->n_used_nodes; j++)
43662306a36Sopenharmony_ci			hpfs_ea_remove(s, le32_to_cpu(btree->u.internal[j].down), 1, 0);
43762306a36Sopenharmony_ci		btree->n_used_nodes = i + 1;
43862306a36Sopenharmony_ci		btree->n_free_nodes = nodes - btree->n_used_nodes;
43962306a36Sopenharmony_ci		btree->first_free = cpu_to_le16(8 + 8 * btree->n_used_nodes);
44062306a36Sopenharmony_ci		mark_buffer_dirty(bh);
44162306a36Sopenharmony_ci		if (btree->u.internal[i].file_secno == cpu_to_le32(secs)) {
44262306a36Sopenharmony_ci			brelse(bh);
44362306a36Sopenharmony_ci			return;
44462306a36Sopenharmony_ci		}
44562306a36Sopenharmony_ci		node = le32_to_cpu(btree->u.internal[i].down);
44662306a36Sopenharmony_ci		brelse(bh);
44762306a36Sopenharmony_ci		if (hpfs_sb(s)->sb_chk)
44862306a36Sopenharmony_ci			if (hpfs_stop_cycles(s, node, &c1, &c2, "hpfs_truncate_btree"))
44962306a36Sopenharmony_ci				return;
45062306a36Sopenharmony_ci		if (!(anode = hpfs_map_anode(s, node, &bh))) return;
45162306a36Sopenharmony_ci		btree = &anode->btree;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci	nodes = btree->n_used_nodes + btree->n_free_nodes;
45462306a36Sopenharmony_ci	for (i = 0; i < btree->n_used_nodes; i++)
45562306a36Sopenharmony_ci		if (le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) >= secs) goto ff;
45662306a36Sopenharmony_ci	brelse(bh);
45762306a36Sopenharmony_ci	return;
45862306a36Sopenharmony_ci	ff:
45962306a36Sopenharmony_ci	if (secs <= le32_to_cpu(btree->u.external[i].file_secno)) {
46062306a36Sopenharmony_ci		hpfs_error(s, "there is an allocation error in file %08x, sector %08x", f, secs);
46162306a36Sopenharmony_ci		if (i) i--;
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	else if (le32_to_cpu(btree->u.external[i].file_secno) + le32_to_cpu(btree->u.external[i].length) > secs) {
46462306a36Sopenharmony_ci		hpfs_free_sectors(s, le32_to_cpu(btree->u.external[i].disk_secno) + secs -
46562306a36Sopenharmony_ci			le32_to_cpu(btree->u.external[i].file_secno), le32_to_cpu(btree->u.external[i].length)
46662306a36Sopenharmony_ci			- secs + le32_to_cpu(btree->u.external[i].file_secno)); /* I hope gcc optimizes this :-) */
46762306a36Sopenharmony_ci		btree->u.external[i].length = cpu_to_le32(secs - le32_to_cpu(btree->u.external[i].file_secno));
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci	for (j = i + 1; j < btree->n_used_nodes; j++)
47062306a36Sopenharmony_ci		hpfs_free_sectors(s, le32_to_cpu(btree->u.external[j].disk_secno), le32_to_cpu(btree->u.external[j].length));
47162306a36Sopenharmony_ci	btree->n_used_nodes = i + 1;
47262306a36Sopenharmony_ci	btree->n_free_nodes = nodes - btree->n_used_nodes;
47362306a36Sopenharmony_ci	btree->first_free = cpu_to_le16(8 + 12 * btree->n_used_nodes);
47462306a36Sopenharmony_ci	mark_buffer_dirty(bh);
47562306a36Sopenharmony_ci	brelse(bh);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/* Remove file or directory and it's eas - note that directory must
47962306a36Sopenharmony_ci   be empty when this is called. */
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_civoid hpfs_remove_fnode(struct super_block *s, fnode_secno fno)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct buffer_head *bh;
48462306a36Sopenharmony_ci	struct fnode *fnode;
48562306a36Sopenharmony_ci	struct extended_attribute *ea;
48662306a36Sopenharmony_ci	struct extended_attribute *ea_end;
48762306a36Sopenharmony_ci	if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return;
48862306a36Sopenharmony_ci	if (!fnode_is_dir(fnode)) hpfs_remove_btree(s, &fnode->btree);
48962306a36Sopenharmony_ci	else hpfs_remove_dtree(s, le32_to_cpu(fnode->u.external[0].disk_secno));
49062306a36Sopenharmony_ci	ea_end = fnode_end_ea(fnode);
49162306a36Sopenharmony_ci	for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea))
49262306a36Sopenharmony_ci		if (ea_indirect(ea))
49362306a36Sopenharmony_ci			hpfs_ea_remove(s, ea_sec(ea), ea_in_anode(ea), ea_len(ea));
49462306a36Sopenharmony_ci	hpfs_ea_ext_remove(s, le32_to_cpu(fnode->ea_secno), fnode_in_anode(fnode), le32_to_cpu(fnode->ea_size_l));
49562306a36Sopenharmony_ci	brelse(bh);
49662306a36Sopenharmony_ci	hpfs_free_sectors(s, fno, 1);
49762306a36Sopenharmony_ci}
498