18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/fs/hpfs/dnode.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  handling directory dnode tree - adding, deleteing & searching for dirents
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "hpfs_fn.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
158c2ecf20Sopenharmony_ci	struct hpfs_dirent *de_end = dnode_end_de(d);
168c2ecf20Sopenharmony_ci	int i = 1;
178c2ecf20Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
188c2ecf20Sopenharmony_ci		if (de == fde) return ((loff_t) le32_to_cpu(d->self) << 4) | (loff_t)i;
198c2ecf20Sopenharmony_ci		i++;
208c2ecf20Sopenharmony_ci	}
218c2ecf20Sopenharmony_ci	pr_info("%s(): not_found\n", __func__);
228c2ecf20Sopenharmony_ci	return ((loff_t)le32_to_cpu(d->self) << 4) | (loff_t)1;
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciint hpfs_add_pos(struct inode *inode, loff_t *pos)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
288c2ecf20Sopenharmony_ci	int i = 0;
298c2ecf20Sopenharmony_ci	loff_t **ppos;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	if (hpfs_inode->i_rddir_off)
328c2ecf20Sopenharmony_ci		for (; hpfs_inode->i_rddir_off[i]; i++)
338c2ecf20Sopenharmony_ci			if (hpfs_inode->i_rddir_off[i] == pos)
348c2ecf20Sopenharmony_ci				return 0;
358c2ecf20Sopenharmony_ci	if (!(i&0x0f)) {
368c2ecf20Sopenharmony_ci		ppos = kmalloc_array(i + 0x11, sizeof(loff_t *), GFP_NOFS);
378c2ecf20Sopenharmony_ci		if (!ppos) {
388c2ecf20Sopenharmony_ci			pr_err("out of memory for position list\n");
398c2ecf20Sopenharmony_ci			return -ENOMEM;
408c2ecf20Sopenharmony_ci		}
418c2ecf20Sopenharmony_ci		if (hpfs_inode->i_rddir_off) {
428c2ecf20Sopenharmony_ci			memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t));
438c2ecf20Sopenharmony_ci			kfree(hpfs_inode->i_rddir_off);
448c2ecf20Sopenharmony_ci		}
458c2ecf20Sopenharmony_ci		hpfs_inode->i_rddir_off = ppos;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	hpfs_inode->i_rddir_off[i] = pos;
488c2ecf20Sopenharmony_ci	hpfs_inode->i_rddir_off[i + 1] = NULL;
498c2ecf20Sopenharmony_ci	return 0;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_civoid hpfs_del_pos(struct inode *inode, loff_t *pos)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
558c2ecf20Sopenharmony_ci	loff_t **i, **j;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (!hpfs_inode->i_rddir_off) goto not_f;
588c2ecf20Sopenharmony_ci	for (i = hpfs_inode->i_rddir_off; *i; i++) if (*i == pos) goto fnd;
598c2ecf20Sopenharmony_ci	goto not_f;
608c2ecf20Sopenharmony_ci	fnd:
618c2ecf20Sopenharmony_ci	for (j = i + 1; *j; j++) ;
628c2ecf20Sopenharmony_ci	*i = *(j - 1);
638c2ecf20Sopenharmony_ci	*(j - 1) = NULL;
648c2ecf20Sopenharmony_ci	if (j - 1 == hpfs_inode->i_rddir_off) {
658c2ecf20Sopenharmony_ci		kfree(hpfs_inode->i_rddir_off);
668c2ecf20Sopenharmony_ci		hpfs_inode->i_rddir_off = NULL;
678c2ecf20Sopenharmony_ci	}
688c2ecf20Sopenharmony_ci	return;
698c2ecf20Sopenharmony_ci	not_f:
708c2ecf20Sopenharmony_ci	/*pr_warn("position pointer %p->%08x not found\n",
718c2ecf20Sopenharmony_ci		  pos, (int)*pos);*/
728c2ecf20Sopenharmony_ci	return;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t),
768c2ecf20Sopenharmony_ci			 loff_t p1, loff_t p2)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
798c2ecf20Sopenharmony_ci	loff_t **i;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (!hpfs_inode->i_rddir_off) return;
828c2ecf20Sopenharmony_ci	for (i = hpfs_inode->i_rddir_off; *i; i++) (*f)(*i, p1, p2);
838c2ecf20Sopenharmony_ci	return;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	if (*p == f) *p = t;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/*void hpfs_hpfs_pos_substd(loff_t *p, loff_t f, loff_t t)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	if ((*p & ~0x3f) == (f & ~0x3f)) *p = (t & ~0x3f) | (*p & 0x3f);
948c2ecf20Sopenharmony_ci}*/
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
998c2ecf20Sopenharmony_ci		int n = (*p & 0x3f) + c;
1008c2ecf20Sopenharmony_ci		if (n > 0x3f)
1018c2ecf20Sopenharmony_ci			pr_err("%s(): %08x + %d\n",
1028c2ecf20Sopenharmony_ci				__func__, (int)*p, (int)c >> 8);
1038c2ecf20Sopenharmony_ci		else
1048c2ecf20Sopenharmony_ci			*p = (*p & ~0x3f) | n;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic void hpfs_pos_del(loff_t *p, loff_t d, loff_t c)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) {
1118c2ecf20Sopenharmony_ci		int n = (*p & 0x3f) - c;
1128c2ecf20Sopenharmony_ci		if (n < 1)
1138c2ecf20Sopenharmony_ci			pr_err("%s(): %08x - %d\n",
1148c2ecf20Sopenharmony_ci				__func__, (int)*p, (int)c >> 8);
1158c2ecf20Sopenharmony_ci		else
1168c2ecf20Sopenharmony_ci			*p = (*p & ~0x3f) | n;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic struct hpfs_dirent *dnode_pre_last_de(struct dnode *d)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct hpfs_dirent *de, *de_end, *dee = NULL, *deee = NULL;
1238c2ecf20Sopenharmony_ci	de_end = dnode_end_de(d);
1248c2ecf20Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
1258c2ecf20Sopenharmony_ci		deee = dee; dee = de;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci	return deee;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic struct hpfs_dirent *dnode_last_de(struct dnode *d)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct hpfs_dirent *de, *de_end, *dee = NULL;
1338c2ecf20Sopenharmony_ci	de_end = dnode_end_de(d);
1348c2ecf20Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
1358c2ecf20Sopenharmony_ci		dee = de;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	return dee;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno ptr)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
1438c2ecf20Sopenharmony_ci	if (!(de = dnode_last_de(d))) {
1448c2ecf20Sopenharmony_ci		hpfs_error(s, "set_last_pointer: empty dnode %08x", le32_to_cpu(d->self));
1458c2ecf20Sopenharmony_ci		return;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	if (hpfs_sb(s)->sb_chk) {
1488c2ecf20Sopenharmony_ci		if (de->down) {
1498c2ecf20Sopenharmony_ci			hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x",
1508c2ecf20Sopenharmony_ci				le32_to_cpu(d->self), de_down_pointer(de));
1518c2ecf20Sopenharmony_ci			return;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci		if (le16_to_cpu(de->length) != 32) {
1548c2ecf20Sopenharmony_ci			hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", le32_to_cpu(d->self));
1558c2ecf20Sopenharmony_ci			return;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci	if (ptr) {
1598c2ecf20Sopenharmony_ci		le32_add_cpu(&d->first_free, 4);
1608c2ecf20Sopenharmony_ci		if (le32_to_cpu(d->first_free) > 2048) {
1618c2ecf20Sopenharmony_ci			hpfs_error(s, "set_last_pointer: too long dnode %08x", le32_to_cpu(d->self));
1628c2ecf20Sopenharmony_ci			le32_add_cpu(&d->first_free, -4);
1638c2ecf20Sopenharmony_ci			return;
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci		de->length = cpu_to_le16(36);
1668c2ecf20Sopenharmony_ci		de->down = 1;
1678c2ecf20Sopenharmony_ci		*(__le32 *)((char *)de + 32) = cpu_to_le32(ptr);
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/* Add an entry to dnode and don't care if it grows over 2048 bytes */
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistruct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d,
1748c2ecf20Sopenharmony_ci				const unsigned char *name,
1758c2ecf20Sopenharmony_ci				unsigned namelen, secno down_ptr)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
1788c2ecf20Sopenharmony_ci	struct hpfs_dirent *de_end = dnode_end_de(d);
1798c2ecf20Sopenharmony_ci	unsigned d_size = de_size(namelen, down_ptr);
1808c2ecf20Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
1818c2ecf20Sopenharmony_ci		int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last);
1828c2ecf20Sopenharmony_ci		if (!c) {
1838c2ecf20Sopenharmony_ci			hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, le32_to_cpu(d->self));
1848c2ecf20Sopenharmony_ci			return NULL;
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci		if (c < 0) break;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci	memmove((char *)de + d_size, de, (char *)de_end - (char *)de);
1898c2ecf20Sopenharmony_ci	memset(de, 0, d_size);
1908c2ecf20Sopenharmony_ci	if (down_ptr) {
1918c2ecf20Sopenharmony_ci		*(__le32 *)((char *)de + d_size - 4) = cpu_to_le32(down_ptr);
1928c2ecf20Sopenharmony_ci		de->down = 1;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci	de->length = cpu_to_le16(d_size);
1958c2ecf20Sopenharmony_ci	de->not_8x3 = hpfs_is_name_long(name, namelen);
1968c2ecf20Sopenharmony_ci	de->namelen = namelen;
1978c2ecf20Sopenharmony_ci	memcpy(de->name, name, namelen);
1988c2ecf20Sopenharmony_ci	le32_add_cpu(&d->first_free, d_size);
1998c2ecf20Sopenharmony_ci	return de;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/* Delete dirent and don't care about its subtree */
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic void hpfs_delete_de(struct super_block *s, struct dnode *d,
2058c2ecf20Sopenharmony_ci			   struct hpfs_dirent *de)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	if (de->last) {
2088c2ecf20Sopenharmony_ci		hpfs_error(s, "attempt to delete last dirent in dnode %08x", le32_to_cpu(d->self));
2098c2ecf20Sopenharmony_ci		return;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci	d->first_free = cpu_to_le32(le32_to_cpu(d->first_free) - le16_to_cpu(de->length));
2128c2ecf20Sopenharmony_ci	memmove(de, de_next_de(de), le32_to_cpu(d->first_free) + (char *)d - (char *)de);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic void fix_up_ptrs(struct super_block *s, struct dnode *d)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
2188c2ecf20Sopenharmony_ci	struct hpfs_dirent *de_end = dnode_end_de(d);
2198c2ecf20Sopenharmony_ci	dnode_secno dno = le32_to_cpu(d->self);
2208c2ecf20Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de))
2218c2ecf20Sopenharmony_ci		if (de->down) {
2228c2ecf20Sopenharmony_ci			struct quad_buffer_head qbh;
2238c2ecf20Sopenharmony_ci			struct dnode *dd;
2248c2ecf20Sopenharmony_ci			if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) {
2258c2ecf20Sopenharmony_ci				if (le32_to_cpu(dd->up) != dno || dd->root_dnode) {
2268c2ecf20Sopenharmony_ci					dd->up = cpu_to_le32(dno);
2278c2ecf20Sopenharmony_ci					dd->root_dnode = 0;
2288c2ecf20Sopenharmony_ci					hpfs_mark_4buffers_dirty(&qbh);
2298c2ecf20Sopenharmony_ci				}
2308c2ecf20Sopenharmony_ci				hpfs_brelse4(&qbh);
2318c2ecf20Sopenharmony_ci			}
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci/* Add an entry to dnode and do dnode splitting if required */
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
2388c2ecf20Sopenharmony_ci			     const unsigned char *name, unsigned namelen,
2398c2ecf20Sopenharmony_ci			     struct hpfs_dirent *new_de, dnode_secno down_ptr)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh, qbh1, qbh2;
2428c2ecf20Sopenharmony_ci	struct dnode *d, *ad, *rd, *nd = NULL;
2438c2ecf20Sopenharmony_ci	dnode_secno adno, rdno;
2448c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
2458c2ecf20Sopenharmony_ci	struct hpfs_dirent nde;
2468c2ecf20Sopenharmony_ci	unsigned char *nname;
2478c2ecf20Sopenharmony_ci	int h;
2488c2ecf20Sopenharmony_ci	int pos;
2498c2ecf20Sopenharmony_ci	struct buffer_head *bh;
2508c2ecf20Sopenharmony_ci	struct fnode *fnode;
2518c2ecf20Sopenharmony_ci	int c1, c2 = 0;
2528c2ecf20Sopenharmony_ci	if (!(nname = kmalloc(256, GFP_NOFS))) {
2538c2ecf20Sopenharmony_ci		pr_err("out of memory, can't add to dnode\n");
2548c2ecf20Sopenharmony_ci		return 1;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci	go_up:
2578c2ecf20Sopenharmony_ci	if (namelen >= 256) {
2588c2ecf20Sopenharmony_ci		hpfs_error(i->i_sb, "%s(): namelen == %d", __func__, namelen);
2598c2ecf20Sopenharmony_ci		kfree(nd);
2608c2ecf20Sopenharmony_ci		kfree(nname);
2618c2ecf20Sopenharmony_ci		return 1;
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci	if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) {
2648c2ecf20Sopenharmony_ci		kfree(nd);
2658c2ecf20Sopenharmony_ci		kfree(nname);
2668c2ecf20Sopenharmony_ci		return 1;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	go_up_a:
2698c2ecf20Sopenharmony_ci	if (hpfs_sb(i->i_sb)->sb_chk)
2708c2ecf20Sopenharmony_ci		if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_to_dnode")) {
2718c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
2728c2ecf20Sopenharmony_ci			kfree(nd);
2738c2ecf20Sopenharmony_ci			kfree(nname);
2748c2ecf20Sopenharmony_ci			return 1;
2758c2ecf20Sopenharmony_ci		}
2768c2ecf20Sopenharmony_ci	if (le32_to_cpu(d->first_free) + de_size(namelen, down_ptr) <= 2048) {
2778c2ecf20Sopenharmony_ci		loff_t t;
2788c2ecf20Sopenharmony_ci		copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de);
2798c2ecf20Sopenharmony_ci		t = get_pos(d, de);
2808c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_ins, t, 1);
2818c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, 4, t);
2828c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, 5, t + 1);
2838c2ecf20Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
2848c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
2858c2ecf20Sopenharmony_ci		kfree(nd);
2868c2ecf20Sopenharmony_ci		kfree(nname);
2878c2ecf20Sopenharmony_ci		return 0;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	if (!nd) if (!(nd = kmalloc(0x924, GFP_NOFS))) {
2908c2ecf20Sopenharmony_ci		/* 0x924 is a max size of dnode after adding a dirent with
2918c2ecf20Sopenharmony_ci		   max name length. We alloc this only once. There must
2928c2ecf20Sopenharmony_ci		   not be any error while splitting dnodes, otherwise the
2938c2ecf20Sopenharmony_ci		   whole directory, not only file we're adding, would
2948c2ecf20Sopenharmony_ci		   be lost. */
2958c2ecf20Sopenharmony_ci		pr_err("out of memory for dnode splitting\n");
2968c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
2978c2ecf20Sopenharmony_ci		kfree(nname);
2988c2ecf20Sopenharmony_ci		return 1;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci	memcpy(nd, d, le32_to_cpu(d->first_free));
3018c2ecf20Sopenharmony_ci	copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de);
3028c2ecf20Sopenharmony_ci	for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1);
3038c2ecf20Sopenharmony_ci	h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10;
3048c2ecf20Sopenharmony_ci	if (!(ad = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &adno, &qbh1))) {
3058c2ecf20Sopenharmony_ci		hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
3068c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
3078c2ecf20Sopenharmony_ci		kfree(nd);
3088c2ecf20Sopenharmony_ci		kfree(nname);
3098c2ecf20Sopenharmony_ci		return 1;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci	i->i_size += 2048;
3128c2ecf20Sopenharmony_ci	i->i_blocks += 4;
3138c2ecf20Sopenharmony_ci	pos = 1;
3148c2ecf20Sopenharmony_ci	for (de = dnode_first_de(nd); (char *)de_next_de(de) - (char *)nd < h; de = de_next_de(de)) {
3158c2ecf20Sopenharmony_ci		copy_de(hpfs_add_de(i->i_sb, ad, de->name, de->namelen, de->down ? de_down_pointer(de) : 0), de);
3168c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, ((loff_t)adno << 4) | pos);
3178c2ecf20Sopenharmony_ci		pos++;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci	copy_de(new_de = &nde, de);
3208c2ecf20Sopenharmony_ci	memcpy(nname, de->name, de->namelen);
3218c2ecf20Sopenharmony_ci	name = nname;
3228c2ecf20Sopenharmony_ci	namelen = de->namelen;
3238c2ecf20Sopenharmony_ci	for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4);
3248c2ecf20Sopenharmony_ci	down_ptr = adno;
3258c2ecf20Sopenharmony_ci	set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0);
3268c2ecf20Sopenharmony_ci	de = de_next_de(de);
3278c2ecf20Sopenharmony_ci	memmove((char *)nd + 20, de, le32_to_cpu(nd->first_free) + (char *)nd - (char *)de);
3288c2ecf20Sopenharmony_ci	le32_add_cpu(&nd->first_free, -((char *)de - (char *)nd - 20));
3298c2ecf20Sopenharmony_ci	memcpy(d, nd, le32_to_cpu(nd->first_free));
3308c2ecf20Sopenharmony_ci	for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos);
3318c2ecf20Sopenharmony_ci	fix_up_ptrs(i->i_sb, ad);
3328c2ecf20Sopenharmony_ci	if (!d->root_dnode) {
3338c2ecf20Sopenharmony_ci		ad->up = d->up;
3348c2ecf20Sopenharmony_ci		dno = le32_to_cpu(ad->up);
3358c2ecf20Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
3368c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
3378c2ecf20Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh1);
3388c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh1);
3398c2ecf20Sopenharmony_ci		goto go_up;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci	if (!(rd = hpfs_alloc_dnode(i->i_sb, le32_to_cpu(d->up), &rdno, &qbh2))) {
3428c2ecf20Sopenharmony_ci		hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted");
3438c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
3448c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh1);
3458c2ecf20Sopenharmony_ci		kfree(nd);
3468c2ecf20Sopenharmony_ci		kfree(nname);
3478c2ecf20Sopenharmony_ci		return 1;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci	i->i_size += 2048;
3508c2ecf20Sopenharmony_ci	i->i_blocks += 4;
3518c2ecf20Sopenharmony_ci	rd->root_dnode = 1;
3528c2ecf20Sopenharmony_ci	rd->up = d->up;
3538c2ecf20Sopenharmony_ci	if (!(fnode = hpfs_map_fnode(i->i_sb, le32_to_cpu(d->up), &bh))) {
3548c2ecf20Sopenharmony_ci		hpfs_free_dnode(i->i_sb, rdno);
3558c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
3568c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh1);
3578c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh2);
3588c2ecf20Sopenharmony_ci		kfree(nd);
3598c2ecf20Sopenharmony_ci		kfree(nname);
3608c2ecf20Sopenharmony_ci		return 1;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci	fnode->u.external[0].disk_secno = cpu_to_le32(rdno);
3638c2ecf20Sopenharmony_ci	mark_buffer_dirty(bh);
3648c2ecf20Sopenharmony_ci	brelse(bh);
3658c2ecf20Sopenharmony_ci	hpfs_i(i)->i_dno = rdno;
3668c2ecf20Sopenharmony_ci	d->up = ad->up = cpu_to_le32(rdno);
3678c2ecf20Sopenharmony_ci	d->root_dnode = ad->root_dnode = 0;
3688c2ecf20Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh);
3698c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
3708c2ecf20Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh1);
3718c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh1);
3728c2ecf20Sopenharmony_ci	qbh = qbh2;
3738c2ecf20Sopenharmony_ci	set_last_pointer(i->i_sb, rd, dno);
3748c2ecf20Sopenharmony_ci	dno = rdno;
3758c2ecf20Sopenharmony_ci	d = rd;
3768c2ecf20Sopenharmony_ci	goto go_up_a;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci/*
3808c2ecf20Sopenharmony_ci * Add an entry to directory btree.
3818c2ecf20Sopenharmony_ci * I hate such crazy directory structure.
3828c2ecf20Sopenharmony_ci * It's easy to read but terrible to write.
3838c2ecf20Sopenharmony_ci * I wrote this directory code 4 times.
3848c2ecf20Sopenharmony_ci * I hope, now it's finally bug-free.
3858c2ecf20Sopenharmony_ci */
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ciint hpfs_add_dirent(struct inode *i,
3888c2ecf20Sopenharmony_ci		    const unsigned char *name, unsigned namelen,
3898c2ecf20Sopenharmony_ci		    struct hpfs_dirent *new_de)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
3928c2ecf20Sopenharmony_ci	struct dnode *d;
3938c2ecf20Sopenharmony_ci	struct hpfs_dirent *de, *de_end;
3948c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh;
3958c2ecf20Sopenharmony_ci	dnode_secno dno;
3968c2ecf20Sopenharmony_ci	int c;
3978c2ecf20Sopenharmony_ci	int c1, c2 = 0;
3988c2ecf20Sopenharmony_ci	dno = hpfs_inode->i_dno;
3998c2ecf20Sopenharmony_ci	down:
4008c2ecf20Sopenharmony_ci	if (hpfs_sb(i->i_sb)->sb_chk)
4018c2ecf20Sopenharmony_ci		if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1;
4028c2ecf20Sopenharmony_ci	if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 1;
4038c2ecf20Sopenharmony_ci	de_end = dnode_end_de(d);
4048c2ecf20Sopenharmony_ci	for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) {
4058c2ecf20Sopenharmony_ci		if (!(c = hpfs_compare_names(i->i_sb, name, namelen, de->name, de->namelen, de->last))) {
4068c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
4078c2ecf20Sopenharmony_ci			return -1;
4088c2ecf20Sopenharmony_ci		}
4098c2ecf20Sopenharmony_ci		if (c < 0) {
4108c2ecf20Sopenharmony_ci			if (de->down) {
4118c2ecf20Sopenharmony_ci				dno = de_down_pointer(de);
4128c2ecf20Sopenharmony_ci				hpfs_brelse4(&qbh);
4138c2ecf20Sopenharmony_ci				goto down;
4148c2ecf20Sopenharmony_ci			}
4158c2ecf20Sopenharmony_ci			break;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
4198c2ecf20Sopenharmony_ci	if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) {
4208c2ecf20Sopenharmony_ci		c = 1;
4218c2ecf20Sopenharmony_ci		goto ret;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0);
4248c2ecf20Sopenharmony_ci	ret:
4258c2ecf20Sopenharmony_ci	return c;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci/*
4298c2ecf20Sopenharmony_ci * Find dirent with higher name in 'from' subtree and move it to 'to' dnode.
4308c2ecf20Sopenharmony_ci * Return the dnode we moved from (to be checked later if it's empty)
4318c2ecf20Sopenharmony_ci */
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	dnode_secno dno, ddno;
4368c2ecf20Sopenharmony_ci	dnode_secno chk_up = to;
4378c2ecf20Sopenharmony_ci	struct dnode *dnode;
4388c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh;
4398c2ecf20Sopenharmony_ci	struct hpfs_dirent *de, *nde;
4408c2ecf20Sopenharmony_ci	int a;
4418c2ecf20Sopenharmony_ci	loff_t t;
4428c2ecf20Sopenharmony_ci	int c1, c2 = 0;
4438c2ecf20Sopenharmony_ci	dno = from;
4448c2ecf20Sopenharmony_ci	while (1) {
4458c2ecf20Sopenharmony_ci		if (hpfs_sb(i->i_sb)->sb_chk)
4468c2ecf20Sopenharmony_ci			if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "move_to_top"))
4478c2ecf20Sopenharmony_ci				return 0;
4488c2ecf20Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0;
4498c2ecf20Sopenharmony_ci		if (hpfs_sb(i->i_sb)->sb_chk) {
4508c2ecf20Sopenharmony_ci			if (le32_to_cpu(dnode->up) != chk_up) {
4518c2ecf20Sopenharmony_ci				hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x",
4528c2ecf20Sopenharmony_ci					dno, chk_up, le32_to_cpu(dnode->up));
4538c2ecf20Sopenharmony_ci				hpfs_brelse4(&qbh);
4548c2ecf20Sopenharmony_ci				return 0;
4558c2ecf20Sopenharmony_ci			}
4568c2ecf20Sopenharmony_ci			chk_up = dno;
4578c2ecf20Sopenharmony_ci		}
4588c2ecf20Sopenharmony_ci		if (!(de = dnode_last_de(dnode))) {
4598c2ecf20Sopenharmony_ci			hpfs_error(i->i_sb, "move_to_top: dnode %08x has no last de", dno);
4608c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
4618c2ecf20Sopenharmony_ci			return 0;
4628c2ecf20Sopenharmony_ci		}
4638c2ecf20Sopenharmony_ci		if (!de->down) break;
4648c2ecf20Sopenharmony_ci		dno = de_down_pointer(de);
4658c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci	while (!(de = dnode_pre_last_de(dnode))) {
4688c2ecf20Sopenharmony_ci		dnode_secno up = le32_to_cpu(dnode->up);
4698c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
4708c2ecf20Sopenharmony_ci		hpfs_free_dnode(i->i_sb, dno);
4718c2ecf20Sopenharmony_ci		i->i_size -= 2048;
4728c2ecf20Sopenharmony_ci		i->i_blocks -= 4;
4738c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, 5);
4748c2ecf20Sopenharmony_ci		if (up == to) return to;
4758c2ecf20Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return 0;
4768c2ecf20Sopenharmony_ci		if (dnode->root_dnode) {
4778c2ecf20Sopenharmony_ci			hpfs_error(i->i_sb, "move_to_top: got to root_dnode while moving from %08x to %08x", from, to);
4788c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
4798c2ecf20Sopenharmony_ci			return 0;
4808c2ecf20Sopenharmony_ci		}
4818c2ecf20Sopenharmony_ci		de = dnode_last_de(dnode);
4828c2ecf20Sopenharmony_ci		if (!de || !de->down) {
4838c2ecf20Sopenharmony_ci			hpfs_error(i->i_sb, "move_to_top: dnode %08x doesn't point down to %08x", up, dno);
4848c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
4858c2ecf20Sopenharmony_ci			return 0;
4868c2ecf20Sopenharmony_ci		}
4878c2ecf20Sopenharmony_ci		le32_add_cpu(&dnode->first_free, -4);
4888c2ecf20Sopenharmony_ci		le16_add_cpu(&de->length, -4);
4898c2ecf20Sopenharmony_ci		de->down = 0;
4908c2ecf20Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
4918c2ecf20Sopenharmony_ci		dno = up;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci	t = get_pos(dnode, de);
4948c2ecf20Sopenharmony_ci	for_all_poss(i, hpfs_pos_subst, t, 4);
4958c2ecf20Sopenharmony_ci	for_all_poss(i, hpfs_pos_subst, t + 1, 5);
4968c2ecf20Sopenharmony_ci	if (!(nde = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) {
4978c2ecf20Sopenharmony_ci		hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted");
4988c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
4998c2ecf20Sopenharmony_ci		return 0;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci	memcpy(nde, de, le16_to_cpu(de->length));
5028c2ecf20Sopenharmony_ci	ddno = de->down ? de_down_pointer(de) : 0;
5038c2ecf20Sopenharmony_ci	hpfs_delete_de(i->i_sb, dnode, de);
5048c2ecf20Sopenharmony_ci	set_last_pointer(i->i_sb, dnode, ddno);
5058c2ecf20Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh);
5068c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
5078c2ecf20Sopenharmony_ci	a = hpfs_add_to_dnode(i, to, nde->name, nde->namelen, nde, from);
5088c2ecf20Sopenharmony_ci	kfree(nde);
5098c2ecf20Sopenharmony_ci	if (a) return 0;
5108c2ecf20Sopenharmony_ci	return dno;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci/*
5148c2ecf20Sopenharmony_ci * Check if a dnode is empty and delete it from the tree
5158c2ecf20Sopenharmony_ci * (chkdsk doesn't like empty dnodes)
5168c2ecf20Sopenharmony_ci */
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic void delete_empty_dnode(struct inode *i, dnode_secno dno)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
5218c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh;
5228c2ecf20Sopenharmony_ci	struct dnode *dnode;
5238c2ecf20Sopenharmony_ci	dnode_secno down, up, ndown;
5248c2ecf20Sopenharmony_ci	int p;
5258c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
5268c2ecf20Sopenharmony_ci	int c1, c2 = 0;
5278c2ecf20Sopenharmony_ci	try_it_again:
5288c2ecf20Sopenharmony_ci	if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return;
5298c2ecf20Sopenharmony_ci	if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return;
5308c2ecf20Sopenharmony_ci	if (le32_to_cpu(dnode->first_free) > 56) goto end;
5318c2ecf20Sopenharmony_ci	if (le32_to_cpu(dnode->first_free) == 52 || le32_to_cpu(dnode->first_free) == 56) {
5328c2ecf20Sopenharmony_ci		struct hpfs_dirent *de_end;
5338c2ecf20Sopenharmony_ci		int root = dnode->root_dnode;
5348c2ecf20Sopenharmony_ci		up = le32_to_cpu(dnode->up);
5358c2ecf20Sopenharmony_ci		de = dnode_first_de(dnode);
5368c2ecf20Sopenharmony_ci		down = de->down ? de_down_pointer(de) : 0;
5378c2ecf20Sopenharmony_ci		if (hpfs_sb(i->i_sb)->sb_chk) if (root && !down) {
5388c2ecf20Sopenharmony_ci			hpfs_error(i->i_sb, "delete_empty_dnode: root dnode %08x is empty", dno);
5398c2ecf20Sopenharmony_ci			goto end;
5408c2ecf20Sopenharmony_ci		}
5418c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
5428c2ecf20Sopenharmony_ci		hpfs_free_dnode(i->i_sb, dno);
5438c2ecf20Sopenharmony_ci		i->i_size -= 2048;
5448c2ecf20Sopenharmony_ci		i->i_blocks -= 4;
5458c2ecf20Sopenharmony_ci		if (root) {
5468c2ecf20Sopenharmony_ci			struct fnode *fnode;
5478c2ecf20Sopenharmony_ci			struct buffer_head *bh;
5488c2ecf20Sopenharmony_ci			struct dnode *d1;
5498c2ecf20Sopenharmony_ci			struct quad_buffer_head qbh1;
5508c2ecf20Sopenharmony_ci			if (hpfs_sb(i->i_sb)->sb_chk)
5518c2ecf20Sopenharmony_ci				if (up != i->i_ino) {
5528c2ecf20Sopenharmony_ci					hpfs_error(i->i_sb,
5538c2ecf20Sopenharmony_ci						   "bad pointer to fnode, dnode %08x, pointing to %08x, should be %08lx",
5548c2ecf20Sopenharmony_ci						   dno, up,
5558c2ecf20Sopenharmony_ci						   (unsigned long)i->i_ino);
5568c2ecf20Sopenharmony_ci					return;
5578c2ecf20Sopenharmony_ci				}
5588c2ecf20Sopenharmony_ci			if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
5598c2ecf20Sopenharmony_ci				d1->up = cpu_to_le32(up);
5608c2ecf20Sopenharmony_ci				d1->root_dnode = 1;
5618c2ecf20Sopenharmony_ci				hpfs_mark_4buffers_dirty(&qbh1);
5628c2ecf20Sopenharmony_ci				hpfs_brelse4(&qbh1);
5638c2ecf20Sopenharmony_ci			}
5648c2ecf20Sopenharmony_ci			if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) {
5658c2ecf20Sopenharmony_ci				fnode->u.external[0].disk_secno = cpu_to_le32(down);
5668c2ecf20Sopenharmony_ci				mark_buffer_dirty(bh);
5678c2ecf20Sopenharmony_ci				brelse(bh);
5688c2ecf20Sopenharmony_ci			}
5698c2ecf20Sopenharmony_ci			hpfs_inode->i_dno = down;
5708c2ecf20Sopenharmony_ci			for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12);
5718c2ecf20Sopenharmony_ci			return;
5728c2ecf20Sopenharmony_ci		}
5738c2ecf20Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return;
5748c2ecf20Sopenharmony_ci		p = 1;
5758c2ecf20Sopenharmony_ci		de_end = dnode_end_de(dnode);
5768c2ecf20Sopenharmony_ci		for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de), p++)
5778c2ecf20Sopenharmony_ci			if (de->down) if (de_down_pointer(de) == dno) goto fnd;
5788c2ecf20Sopenharmony_ci		hpfs_error(i->i_sb, "delete_empty_dnode: pointer to dnode %08x not found in dnode %08x", dno, up);
5798c2ecf20Sopenharmony_ci		goto end;
5808c2ecf20Sopenharmony_ci		fnd:
5818c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p);
5828c2ecf20Sopenharmony_ci		if (!down) {
5838c2ecf20Sopenharmony_ci			de->down = 0;
5848c2ecf20Sopenharmony_ci			le16_add_cpu(&de->length, -4);
5858c2ecf20Sopenharmony_ci			le32_add_cpu(&dnode->first_free, -4);
5868c2ecf20Sopenharmony_ci			memmove(de_next_de(de), (char *)de_next_de(de) + 4,
5878c2ecf20Sopenharmony_ci				(char *)dnode + le32_to_cpu(dnode->first_free) - (char *)de_next_de(de));
5888c2ecf20Sopenharmony_ci		} else {
5898c2ecf20Sopenharmony_ci			struct dnode *d1;
5908c2ecf20Sopenharmony_ci			struct quad_buffer_head qbh1;
5918c2ecf20Sopenharmony_ci			*(dnode_secno *) ((void *) de + le16_to_cpu(de->length) - 4) = down;
5928c2ecf20Sopenharmony_ci			if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) {
5938c2ecf20Sopenharmony_ci				d1->up = cpu_to_le32(up);
5948c2ecf20Sopenharmony_ci				hpfs_mark_4buffers_dirty(&qbh1);
5958c2ecf20Sopenharmony_ci				hpfs_brelse4(&qbh1);
5968c2ecf20Sopenharmony_ci			}
5978c2ecf20Sopenharmony_ci		}
5988c2ecf20Sopenharmony_ci	} else {
5998c2ecf20Sopenharmony_ci		hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, le32_to_cpu(dnode->first_free));
6008c2ecf20Sopenharmony_ci		goto end;
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	if (!de->last) {
6048c2ecf20Sopenharmony_ci		struct hpfs_dirent *de_next = de_next_de(de);
6058c2ecf20Sopenharmony_ci		struct hpfs_dirent *de_cp;
6068c2ecf20Sopenharmony_ci		struct dnode *d1;
6078c2ecf20Sopenharmony_ci		struct quad_buffer_head qbh1;
6088c2ecf20Sopenharmony_ci		if (!de_next->down) goto endm;
6098c2ecf20Sopenharmony_ci		ndown = de_down_pointer(de_next);
6108c2ecf20Sopenharmony_ci		if (!(de_cp = kmalloc(le16_to_cpu(de->length), GFP_NOFS))) {
6118c2ecf20Sopenharmony_ci			pr_err("out of memory for dtree balancing\n");
6128c2ecf20Sopenharmony_ci			goto endm;
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci		memcpy(de_cp, de, le16_to_cpu(de->length));
6158c2ecf20Sopenharmony_ci		hpfs_delete_de(i->i_sb, dnode, de);
6168c2ecf20Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
6178c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
6188c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4);
6198c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1);
6208c2ecf20Sopenharmony_ci		if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) {
6218c2ecf20Sopenharmony_ci			d1->up = cpu_to_le32(ndown);
6228c2ecf20Sopenharmony_ci			hpfs_mark_4buffers_dirty(&qbh1);
6238c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh1);
6248c2ecf20Sopenharmony_ci		}
6258c2ecf20Sopenharmony_ci		hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, de_cp->down ? de_down_pointer(de_cp) : 0);
6268c2ecf20Sopenharmony_ci		/*pr_info("UP-TO-DNODE: %08x (ndown = %08x, down = %08x, dno = %08x)\n",
6278c2ecf20Sopenharmony_ci		  up, ndown, down, dno);*/
6288c2ecf20Sopenharmony_ci		dno = up;
6298c2ecf20Sopenharmony_ci		kfree(de_cp);
6308c2ecf20Sopenharmony_ci		goto try_it_again;
6318c2ecf20Sopenharmony_ci	} else {
6328c2ecf20Sopenharmony_ci		struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode);
6338c2ecf20Sopenharmony_ci		struct hpfs_dirent *de_cp;
6348c2ecf20Sopenharmony_ci		struct dnode *d1;
6358c2ecf20Sopenharmony_ci		struct quad_buffer_head qbh1;
6368c2ecf20Sopenharmony_ci		dnode_secno dlp;
6378c2ecf20Sopenharmony_ci		if (!de_prev) {
6388c2ecf20Sopenharmony_ci			hpfs_error(i->i_sb, "delete_empty_dnode: empty dnode %08x", up);
6398c2ecf20Sopenharmony_ci			hpfs_mark_4buffers_dirty(&qbh);
6408c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
6418c2ecf20Sopenharmony_ci			dno = up;
6428c2ecf20Sopenharmony_ci			goto try_it_again;
6438c2ecf20Sopenharmony_ci		}
6448c2ecf20Sopenharmony_ci		if (!de_prev->down) goto endm;
6458c2ecf20Sopenharmony_ci		ndown = de_down_pointer(de_prev);
6468c2ecf20Sopenharmony_ci		if ((d1 = hpfs_map_dnode(i->i_sb, ndown, &qbh1))) {
6478c2ecf20Sopenharmony_ci			struct hpfs_dirent *del = dnode_last_de(d1);
6488c2ecf20Sopenharmony_ci			dlp = del->down ? de_down_pointer(del) : 0;
6498c2ecf20Sopenharmony_ci			if (!dlp && down) {
6508c2ecf20Sopenharmony_ci				if (le32_to_cpu(d1->first_free) > 2044) {
6518c2ecf20Sopenharmony_ci					if (hpfs_sb(i->i_sb)->sb_chk >= 2) {
6528c2ecf20Sopenharmony_ci						pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n");
6538c2ecf20Sopenharmony_ci						pr_err("terminating balancing operation\n");
6548c2ecf20Sopenharmony_ci					}
6558c2ecf20Sopenharmony_ci					hpfs_brelse4(&qbh1);
6568c2ecf20Sopenharmony_ci					goto endm;
6578c2ecf20Sopenharmony_ci				}
6588c2ecf20Sopenharmony_ci				if (hpfs_sb(i->i_sb)->sb_chk >= 2) {
6598c2ecf20Sopenharmony_ci					pr_err("unbalanced dnode tree, see hpfs.txt 4 more info\n");
6608c2ecf20Sopenharmony_ci					pr_err("goin'on\n");
6618c2ecf20Sopenharmony_ci				}
6628c2ecf20Sopenharmony_ci				le16_add_cpu(&del->length, 4);
6638c2ecf20Sopenharmony_ci				del->down = 1;
6648c2ecf20Sopenharmony_ci				le32_add_cpu(&d1->first_free, 4);
6658c2ecf20Sopenharmony_ci			}
6668c2ecf20Sopenharmony_ci			if (dlp && !down) {
6678c2ecf20Sopenharmony_ci				le16_add_cpu(&del->length, -4);
6688c2ecf20Sopenharmony_ci				del->down = 0;
6698c2ecf20Sopenharmony_ci				le32_add_cpu(&d1->first_free, -4);
6708c2ecf20Sopenharmony_ci			} else if (down)
6718c2ecf20Sopenharmony_ci				*(__le32 *) ((void *) del + le16_to_cpu(del->length) - 4) = cpu_to_le32(down);
6728c2ecf20Sopenharmony_ci		} else goto endm;
6738c2ecf20Sopenharmony_ci		if (!(de_cp = kmalloc(le16_to_cpu(de_prev->length), GFP_NOFS))) {
6748c2ecf20Sopenharmony_ci			pr_err("out of memory for dtree balancing\n");
6758c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh1);
6768c2ecf20Sopenharmony_ci			goto endm;
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh1);
6798c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh1);
6808c2ecf20Sopenharmony_ci		memcpy(de_cp, de_prev, le16_to_cpu(de_prev->length));
6818c2ecf20Sopenharmony_ci		hpfs_delete_de(i->i_sb, dnode, de_prev);
6828c2ecf20Sopenharmony_ci		if (!de_prev->down) {
6838c2ecf20Sopenharmony_ci			le16_add_cpu(&de_prev->length, 4);
6848c2ecf20Sopenharmony_ci			de_prev->down = 1;
6858c2ecf20Sopenharmony_ci			le32_add_cpu(&dnode->first_free, 4);
6868c2ecf20Sopenharmony_ci		}
6878c2ecf20Sopenharmony_ci		*(__le32 *) ((void *) de_prev + le16_to_cpu(de_prev->length) - 4) = cpu_to_le32(ndown);
6888c2ecf20Sopenharmony_ci		hpfs_mark_4buffers_dirty(&qbh);
6898c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
6908c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4);
6918c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1));
6928c2ecf20Sopenharmony_ci		if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) {
6938c2ecf20Sopenharmony_ci			d1->up = cpu_to_le32(ndown);
6948c2ecf20Sopenharmony_ci			hpfs_mark_4buffers_dirty(&qbh1);
6958c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh1);
6968c2ecf20Sopenharmony_ci		}
6978c2ecf20Sopenharmony_ci		hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, dlp);
6988c2ecf20Sopenharmony_ci		dno = up;
6998c2ecf20Sopenharmony_ci		kfree(de_cp);
7008c2ecf20Sopenharmony_ci		goto try_it_again;
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci	endm:
7038c2ecf20Sopenharmony_ci	hpfs_mark_4buffers_dirty(&qbh);
7048c2ecf20Sopenharmony_ci	end:
7058c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci/* Delete dirent from directory */
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ciint hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de,
7128c2ecf20Sopenharmony_ci		       struct quad_buffer_head *qbh, int depth)
7138c2ecf20Sopenharmony_ci{
7148c2ecf20Sopenharmony_ci	struct dnode *dnode = qbh->data;
7158c2ecf20Sopenharmony_ci	dnode_secno down = 0;
7168c2ecf20Sopenharmony_ci	loff_t t;
7178c2ecf20Sopenharmony_ci	if (de->first || de->last) {
7188c2ecf20Sopenharmony_ci		hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno);
7198c2ecf20Sopenharmony_ci		hpfs_brelse4(qbh);
7208c2ecf20Sopenharmony_ci		return 1;
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci	if (de->down) down = de_down_pointer(de);
7238c2ecf20Sopenharmony_ci	if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) {
7248c2ecf20Sopenharmony_ci		if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) {
7258c2ecf20Sopenharmony_ci			hpfs_brelse4(qbh);
7268c2ecf20Sopenharmony_ci			return 2;
7278c2ecf20Sopenharmony_ci		}
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci	for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1);
7308c2ecf20Sopenharmony_ci	hpfs_delete_de(i->i_sb, dnode, de);
7318c2ecf20Sopenharmony_ci	hpfs_mark_4buffers_dirty(qbh);
7328c2ecf20Sopenharmony_ci	hpfs_brelse4(qbh);
7338c2ecf20Sopenharmony_ci	if (down) {
7348c2ecf20Sopenharmony_ci		dnode_secno a = move_to_top(i, down, dno);
7358c2ecf20Sopenharmony_ci		for_all_poss(i, hpfs_pos_subst, 5, t);
7368c2ecf20Sopenharmony_ci		if (a) delete_empty_dnode(i, a);
7378c2ecf20Sopenharmony_ci		return !a;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci	delete_empty_dnode(i, dno);
7408c2ecf20Sopenharmony_ci	return 0;
7418c2ecf20Sopenharmony_ci}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_civoid hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes,
7448c2ecf20Sopenharmony_ci		       int *n_subdirs, int *n_items)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	struct dnode *dnode;
7478c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh;
7488c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
7498c2ecf20Sopenharmony_ci	dnode_secno ptr, odno = 0;
7508c2ecf20Sopenharmony_ci	int c1, c2 = 0;
7518c2ecf20Sopenharmony_ci	int d1, d2 = 0;
7528c2ecf20Sopenharmony_ci	go_down:
7538c2ecf20Sopenharmony_ci	if (n_dnodes) (*n_dnodes)++;
7548c2ecf20Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
7558c2ecf20Sopenharmony_ci		if (hpfs_stop_cycles(s, dno, &c1, &c2, "hpfs_count_dnodes #1")) return;
7568c2ecf20Sopenharmony_ci	ptr = 0;
7578c2ecf20Sopenharmony_ci	go_up:
7588c2ecf20Sopenharmony_ci	if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return;
7598c2ecf20Sopenharmony_ci	if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && le32_to_cpu(dnode->up) != odno)
7608c2ecf20Sopenharmony_ci		hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, le32_to_cpu(dnode->up));
7618c2ecf20Sopenharmony_ci	de = dnode_first_de(dnode);
7628c2ecf20Sopenharmony_ci	if (ptr) while(1) {
7638c2ecf20Sopenharmony_ci		if (de->down) if (de_down_pointer(de) == ptr) goto process_de;
7648c2ecf20Sopenharmony_ci		if (de->last) {
7658c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
7668c2ecf20Sopenharmony_ci			hpfs_error(s, "hpfs_count_dnodes: pointer to dnode %08x not found in dnode %08x, got here from %08x",
7678c2ecf20Sopenharmony_ci				ptr, dno, odno);
7688c2ecf20Sopenharmony_ci			return;
7698c2ecf20Sopenharmony_ci		}
7708c2ecf20Sopenharmony_ci		de = de_next_de(de);
7718c2ecf20Sopenharmony_ci	}
7728c2ecf20Sopenharmony_ci	next_de:
7738c2ecf20Sopenharmony_ci	if (de->down) {
7748c2ecf20Sopenharmony_ci		odno = dno;
7758c2ecf20Sopenharmony_ci		dno = de_down_pointer(de);
7768c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
7778c2ecf20Sopenharmony_ci		goto go_down;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci	process_de:
7808c2ecf20Sopenharmony_ci	if (!de->first && !de->last && de->directory && n_subdirs) (*n_subdirs)++;
7818c2ecf20Sopenharmony_ci	if (!de->first && !de->last && n_items) (*n_items)++;
7828c2ecf20Sopenharmony_ci	if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de;
7838c2ecf20Sopenharmony_ci	ptr = dno;
7848c2ecf20Sopenharmony_ci	dno = le32_to_cpu(dnode->up);
7858c2ecf20Sopenharmony_ci	if (dnode->root_dnode) {
7868c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
7878c2ecf20Sopenharmony_ci		return;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
7908c2ecf20Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
7918c2ecf20Sopenharmony_ci		if (hpfs_stop_cycles(s, ptr, &d1, &d2, "hpfs_count_dnodes #2")) return;
7928c2ecf20Sopenharmony_ci	odno = -1;
7938c2ecf20Sopenharmony_ci	goto go_up;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic struct hpfs_dirent *map_nth_dirent(struct super_block *s, dnode_secno dno, int n,
7978c2ecf20Sopenharmony_ci					  struct quad_buffer_head *qbh, struct dnode **dn)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	int i;
8008c2ecf20Sopenharmony_ci	struct hpfs_dirent *de, *de_end;
8018c2ecf20Sopenharmony_ci	struct dnode *dnode;
8028c2ecf20Sopenharmony_ci	dnode = hpfs_map_dnode(s, dno, qbh);
8038c2ecf20Sopenharmony_ci	if (!dnode) return NULL;
8048c2ecf20Sopenharmony_ci	if (dn) *dn=dnode;
8058c2ecf20Sopenharmony_ci	de = dnode_first_de(dnode);
8068c2ecf20Sopenharmony_ci	de_end = dnode_end_de(dnode);
8078c2ecf20Sopenharmony_ci	for (i = 1; de < de_end; i++, de = de_next_de(de)) {
8088c2ecf20Sopenharmony_ci		if (i == n) {
8098c2ecf20Sopenharmony_ci			return de;
8108c2ecf20Sopenharmony_ci		}
8118c2ecf20Sopenharmony_ci		if (de->last) break;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci	hpfs_brelse4(qbh);
8148c2ecf20Sopenharmony_ci	hpfs_error(s, "map_nth_dirent: n too high; dnode = %08x, requested %08x", dno, n);
8158c2ecf20Sopenharmony_ci	return NULL;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_cidnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh;
8218c2ecf20Sopenharmony_ci	dnode_secno d = dno;
8228c2ecf20Sopenharmony_ci	dnode_secno up = 0;
8238c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
8248c2ecf20Sopenharmony_ci	int c1, c2 = 0;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	again:
8278c2ecf20Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
8288c2ecf20Sopenharmony_ci		if (hpfs_stop_cycles(s, d, &c1, &c2, "hpfs_de_as_down_as_possible"))
8298c2ecf20Sopenharmony_ci			return d;
8308c2ecf20Sopenharmony_ci	if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno;
8318c2ecf20Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
8328c2ecf20Sopenharmony_ci		if (up && le32_to_cpu(((struct dnode *)qbh.data)->up) != up)
8338c2ecf20Sopenharmony_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));
8348c2ecf20Sopenharmony_ci	if (!de->down) {
8358c2ecf20Sopenharmony_ci		hpfs_brelse4(&qbh);
8368c2ecf20Sopenharmony_ci		return d;
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci	up = d;
8398c2ecf20Sopenharmony_ci	d = de_down_pointer(de);
8408c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
8418c2ecf20Sopenharmony_ci	goto again;
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistruct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
8458c2ecf20Sopenharmony_ci				   struct quad_buffer_head *qbh)
8468c2ecf20Sopenharmony_ci{
8478c2ecf20Sopenharmony_ci	loff_t pos;
8488c2ecf20Sopenharmony_ci	unsigned c;
8498c2ecf20Sopenharmony_ci	dnode_secno dno;
8508c2ecf20Sopenharmony_ci	struct hpfs_dirent *de, *d;
8518c2ecf20Sopenharmony_ci	struct hpfs_dirent *up_de;
8528c2ecf20Sopenharmony_ci	struct hpfs_dirent *end_up_de;
8538c2ecf20Sopenharmony_ci	struct dnode *dnode;
8548c2ecf20Sopenharmony_ci	struct dnode *up_dnode;
8558c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh0;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	pos = *posp;
8588c2ecf20Sopenharmony_ci	dno = pos >> 6 << 2;
8598c2ecf20Sopenharmony_ci	pos &= 077;
8608c2ecf20Sopenharmony_ci	if (!(de = map_nth_dirent(inode->i_sb, dno, pos, qbh, &dnode)))
8618c2ecf20Sopenharmony_ci		goto bail;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	/* Going to the next dirent */
8648c2ecf20Sopenharmony_ci	if ((d = de_next_de(de)) < dnode_end_de(dnode)) {
8658c2ecf20Sopenharmony_ci		if (!(++*posp & 077)) {
8668c2ecf20Sopenharmony_ci			hpfs_error(inode->i_sb,
8678c2ecf20Sopenharmony_ci				"map_pos_dirent: pos crossed dnode boundary; pos = %08llx",
8688c2ecf20Sopenharmony_ci				(unsigned long long)*posp);
8698c2ecf20Sopenharmony_ci			goto bail;
8708c2ecf20Sopenharmony_ci		}
8718c2ecf20Sopenharmony_ci		/* We're going down the tree */
8728c2ecf20Sopenharmony_ci		if (d->down) {
8738c2ecf20Sopenharmony_ci			*posp = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, de_down_pointer(d)) << 4) + 1;
8748c2ecf20Sopenharmony_ci		}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci		return de;
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	/* Going up */
8808c2ecf20Sopenharmony_ci	if (dnode->root_dnode) goto bail;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	if (!(up_dnode = hpfs_map_dnode(inode->i_sb, le32_to_cpu(dnode->up), &qbh0)))
8838c2ecf20Sopenharmony_ci		goto bail;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	end_up_de = dnode_end_de(up_dnode);
8868c2ecf20Sopenharmony_ci	c = 0;
8878c2ecf20Sopenharmony_ci	for (up_de = dnode_first_de(up_dnode); up_de < end_up_de;
8888c2ecf20Sopenharmony_ci	     up_de = de_next_de(up_de)) {
8898c2ecf20Sopenharmony_ci		if (!(++c & 077)) hpfs_error(inode->i_sb,
8908c2ecf20Sopenharmony_ci			"map_pos_dirent: pos crossed dnode boundary; dnode = %08x", le32_to_cpu(dnode->up));
8918c2ecf20Sopenharmony_ci		if (up_de->down && de_down_pointer(up_de) == dno) {
8928c2ecf20Sopenharmony_ci			*posp = ((loff_t) le32_to_cpu(dnode->up) << 4) + c;
8938c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh0);
8948c2ecf20Sopenharmony_ci			return de;
8958c2ecf20Sopenharmony_ci		}
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x",
8998c2ecf20Sopenharmony_ci		dno, le32_to_cpu(dnode->up));
9008c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh0);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	bail:
9038c2ecf20Sopenharmony_ci	*posp = 12;
9048c2ecf20Sopenharmony_ci	return de;
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci/* Find a dirent in tree */
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistruct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
9108c2ecf20Sopenharmony_ci			       const unsigned char *name, unsigned len,
9118c2ecf20Sopenharmony_ci			       dnode_secno *dd, struct quad_buffer_head *qbh)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	struct dnode *dnode;
9148c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
9158c2ecf20Sopenharmony_ci	struct hpfs_dirent *de_end;
9168c2ecf20Sopenharmony_ci	int c1, c2 = 0;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n");
9198c2ecf20Sopenharmony_ci	again:
9208c2ecf20Sopenharmony_ci	if (hpfs_sb(inode->i_sb)->sb_chk)
9218c2ecf20Sopenharmony_ci		if (hpfs_stop_cycles(inode->i_sb, dno, &c1, &c2, "map_dirent")) return NULL;
9228c2ecf20Sopenharmony_ci	if (!(dnode = hpfs_map_dnode(inode->i_sb, dno, qbh))) return NULL;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	de_end = dnode_end_de(dnode);
9258c2ecf20Sopenharmony_ci	for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de)) {
9268c2ecf20Sopenharmony_ci		int t = hpfs_compare_names(inode->i_sb, name, len, de->name, de->namelen, de->last);
9278c2ecf20Sopenharmony_ci		if (!t) {
9288c2ecf20Sopenharmony_ci			if (dd) *dd = dno;
9298c2ecf20Sopenharmony_ci			return de;
9308c2ecf20Sopenharmony_ci		}
9318c2ecf20Sopenharmony_ci		if (t < 0) {
9328c2ecf20Sopenharmony_ci			if (de->down) {
9338c2ecf20Sopenharmony_ci				dno = de_down_pointer(de);
9348c2ecf20Sopenharmony_ci				hpfs_brelse4(qbh);
9358c2ecf20Sopenharmony_ci				goto again;
9368c2ecf20Sopenharmony_ci			}
9378c2ecf20Sopenharmony_ci		break;
9388c2ecf20Sopenharmony_ci		}
9398c2ecf20Sopenharmony_ci	}
9408c2ecf20Sopenharmony_ci	hpfs_brelse4(qbh);
9418c2ecf20Sopenharmony_ci	return NULL;
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci/*
9458c2ecf20Sopenharmony_ci * Remove empty directory. In normal cases it is only one dnode with two
9468c2ecf20Sopenharmony_ci * entries, but we must handle also such obscure cases when it's a tree
9478c2ecf20Sopenharmony_ci * of empty dnodes.
9488c2ecf20Sopenharmony_ci */
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_civoid hpfs_remove_dtree(struct super_block *s, dnode_secno dno)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	struct quad_buffer_head qbh;
9538c2ecf20Sopenharmony_ci	struct dnode *dnode;
9548c2ecf20Sopenharmony_ci	struct hpfs_dirent *de;
9558c2ecf20Sopenharmony_ci	dnode_secno d1, d2, rdno = dno;
9568c2ecf20Sopenharmony_ci	while (1) {
9578c2ecf20Sopenharmony_ci		if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return;
9588c2ecf20Sopenharmony_ci		de = dnode_first_de(dnode);
9598c2ecf20Sopenharmony_ci		if (de->last) {
9608c2ecf20Sopenharmony_ci			if (de->down) d1 = de_down_pointer(de);
9618c2ecf20Sopenharmony_ci			else goto error;
9628c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
9638c2ecf20Sopenharmony_ci			hpfs_free_dnode(s, dno);
9648c2ecf20Sopenharmony_ci			dno = d1;
9658c2ecf20Sopenharmony_ci		} else break;
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci	if (!de->first) goto error;
9688c2ecf20Sopenharmony_ci	d1 = de->down ? de_down_pointer(de) : 0;
9698c2ecf20Sopenharmony_ci	de = de_next_de(de);
9708c2ecf20Sopenharmony_ci	if (!de->last) goto error;
9718c2ecf20Sopenharmony_ci	d2 = de->down ? de_down_pointer(de) : 0;
9728c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
9738c2ecf20Sopenharmony_ci	hpfs_free_dnode(s, dno);
9748c2ecf20Sopenharmony_ci	do {
9758c2ecf20Sopenharmony_ci		while (d1) {
9768c2ecf20Sopenharmony_ci			if (!(dnode = hpfs_map_dnode(s, dno = d1, &qbh))) return;
9778c2ecf20Sopenharmony_ci			de = dnode_first_de(dnode);
9788c2ecf20Sopenharmony_ci			if (!de->last) goto error;
9798c2ecf20Sopenharmony_ci			d1 = de->down ? de_down_pointer(de) : 0;
9808c2ecf20Sopenharmony_ci			hpfs_brelse4(&qbh);
9818c2ecf20Sopenharmony_ci			hpfs_free_dnode(s, dno);
9828c2ecf20Sopenharmony_ci		}
9838c2ecf20Sopenharmony_ci		d1 = d2;
9848c2ecf20Sopenharmony_ci		d2 = 0;
9858c2ecf20Sopenharmony_ci	} while (d1);
9868c2ecf20Sopenharmony_ci	return;
9878c2ecf20Sopenharmony_ci	error:
9888c2ecf20Sopenharmony_ci	hpfs_brelse4(&qbh);
9898c2ecf20Sopenharmony_ci	hpfs_free_dnode(s, dno);
9908c2ecf20Sopenharmony_ci	hpfs_error(s, "directory %08x is corrupted or not empty", rdno);
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci/*
9948c2ecf20Sopenharmony_ci * Find dirent for specified fnode. Use truncated 15-char name in fnode as
9958c2ecf20Sopenharmony_ci * a help for searching.
9968c2ecf20Sopenharmony_ci */
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistruct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
9998c2ecf20Sopenharmony_ci				     struct fnode *f, struct quad_buffer_head *qbh)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	unsigned char *name1;
10028c2ecf20Sopenharmony_ci	unsigned char *name2;
10038c2ecf20Sopenharmony_ci	int name1len, name2len;
10048c2ecf20Sopenharmony_ci	struct dnode *d;
10058c2ecf20Sopenharmony_ci	dnode_secno dno, downd;
10068c2ecf20Sopenharmony_ci	struct fnode *upf;
10078c2ecf20Sopenharmony_ci	struct buffer_head *bh;
10088c2ecf20Sopenharmony_ci	struct hpfs_dirent *de, *de_end;
10098c2ecf20Sopenharmony_ci	int c;
10108c2ecf20Sopenharmony_ci	int c1, c2 = 0;
10118c2ecf20Sopenharmony_ci	int d1, d2 = 0;
10128c2ecf20Sopenharmony_ci	name1 = f->name;
10138c2ecf20Sopenharmony_ci	if (!(name2 = kmalloc(256, GFP_NOFS))) {
10148c2ecf20Sopenharmony_ci		pr_err("out of memory, can't map dirent\n");
10158c2ecf20Sopenharmony_ci		return NULL;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci	if (f->len <= 15)
10188c2ecf20Sopenharmony_ci		memcpy(name2, name1, name1len = name2len = f->len);
10198c2ecf20Sopenharmony_ci	else {
10208c2ecf20Sopenharmony_ci		memcpy(name2, name1, 15);
10218c2ecf20Sopenharmony_ci		memset(name2 + 15, 0xff, 256 - 15);
10228c2ecf20Sopenharmony_ci		/*name2[15] = 0xff;*/
10238c2ecf20Sopenharmony_ci		name1len = 15; name2len = 256;
10248c2ecf20Sopenharmony_ci	}
10258c2ecf20Sopenharmony_ci	if (!(upf = hpfs_map_fnode(s, le32_to_cpu(f->up), &bh))) {
10268c2ecf20Sopenharmony_ci		kfree(name2);
10278c2ecf20Sopenharmony_ci		return NULL;
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci	if (!fnode_is_dir(upf)) {
10308c2ecf20Sopenharmony_ci		brelse(bh);
10318c2ecf20Sopenharmony_ci		hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, le32_to_cpu(f->up));
10328c2ecf20Sopenharmony_ci		kfree(name2);
10338c2ecf20Sopenharmony_ci		return NULL;
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci	dno = le32_to_cpu(upf->u.external[0].disk_secno);
10368c2ecf20Sopenharmony_ci	brelse(bh);
10378c2ecf20Sopenharmony_ci	go_down:
10388c2ecf20Sopenharmony_ci	downd = 0;
10398c2ecf20Sopenharmony_ci	go_up:
10408c2ecf20Sopenharmony_ci	if (!(d = hpfs_map_dnode(s, dno, qbh))) {
10418c2ecf20Sopenharmony_ci		kfree(name2);
10428c2ecf20Sopenharmony_ci		return NULL;
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci	de_end = dnode_end_de(d);
10458c2ecf20Sopenharmony_ci	de = dnode_first_de(d);
10468c2ecf20Sopenharmony_ci	if (downd) {
10478c2ecf20Sopenharmony_ci		while (de < de_end) {
10488c2ecf20Sopenharmony_ci			if (de->down) if (de_down_pointer(de) == downd) goto f;
10498c2ecf20Sopenharmony_ci			de = de_next_de(de);
10508c2ecf20Sopenharmony_ci		}
10518c2ecf20Sopenharmony_ci		hpfs_error(s, "pointer to dnode %08x not found in dnode %08x", downd, dno);
10528c2ecf20Sopenharmony_ci		hpfs_brelse4(qbh);
10538c2ecf20Sopenharmony_ci		kfree(name2);
10548c2ecf20Sopenharmony_ci		return NULL;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci	next_de:
10578c2ecf20Sopenharmony_ci	if (le32_to_cpu(de->fnode) == fno) {
10588c2ecf20Sopenharmony_ci		kfree(name2);
10598c2ecf20Sopenharmony_ci		return de;
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ci	c = hpfs_compare_names(s, name1, name1len, de->name, de->namelen, de->last);
10628c2ecf20Sopenharmony_ci	if (c < 0 && de->down) {
10638c2ecf20Sopenharmony_ci		dno = de_down_pointer(de);
10648c2ecf20Sopenharmony_ci		hpfs_brelse4(qbh);
10658c2ecf20Sopenharmony_ci		if (hpfs_sb(s)->sb_chk)
10668c2ecf20Sopenharmony_ci			if (hpfs_stop_cycles(s, dno, &c1, &c2, "map_fnode_dirent #1")) {
10678c2ecf20Sopenharmony_ci				kfree(name2);
10688c2ecf20Sopenharmony_ci				return NULL;
10698c2ecf20Sopenharmony_ci		}
10708c2ecf20Sopenharmony_ci		goto go_down;
10718c2ecf20Sopenharmony_ci	}
10728c2ecf20Sopenharmony_ci	f:
10738c2ecf20Sopenharmony_ci	if (le32_to_cpu(de->fnode) == fno) {
10748c2ecf20Sopenharmony_ci		kfree(name2);
10758c2ecf20Sopenharmony_ci		return de;
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci	c = hpfs_compare_names(s, name2, name2len, de->name, de->namelen, de->last);
10788c2ecf20Sopenharmony_ci	if (c < 0 && !de->last) goto not_found;
10798c2ecf20Sopenharmony_ci	if ((de = de_next_de(de)) < de_end) goto next_de;
10808c2ecf20Sopenharmony_ci	if (d->root_dnode) goto not_found;
10818c2ecf20Sopenharmony_ci	downd = dno;
10828c2ecf20Sopenharmony_ci	dno = le32_to_cpu(d->up);
10838c2ecf20Sopenharmony_ci	hpfs_brelse4(qbh);
10848c2ecf20Sopenharmony_ci	if (hpfs_sb(s)->sb_chk)
10858c2ecf20Sopenharmony_ci		if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) {
10868c2ecf20Sopenharmony_ci			kfree(name2);
10878c2ecf20Sopenharmony_ci			return NULL;
10888c2ecf20Sopenharmony_ci		}
10898c2ecf20Sopenharmony_ci	goto go_up;
10908c2ecf20Sopenharmony_ci	not_found:
10918c2ecf20Sopenharmony_ci	hpfs_brelse4(qbh);
10928c2ecf20Sopenharmony_ci	hpfs_error(s, "dirent for fnode %08x not found", fno);
10938c2ecf20Sopenharmony_ci	kfree(name2);
10948c2ecf20Sopenharmony_ci	return NULL;
10958c2ecf20Sopenharmony_ci}
1096