/*static char *SCCSID = "@(#)wipesbdr.c	6.1 90/11/18";*/
/*static char *SCCSID = "@(#)wipesbdr.c	13.3 90/02/23";*/
#include <os2.h>
#include "api.h"
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "fnode.h"
#include "volume.h"
#include "tables.h"
#include "pb_ifs.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"

#include "pr_MOVE.h"
#include "pr_DEL.h"
#include "pr_MISC.h"

/*
 ***	WipeSBDIR - Remove references from SBDIR tree.
 *
 *
 *	When we move a directory we remove it's entry, and all of it's
 *	descendents, from the SBDIR tree.  Sure, this is wasteful -
 *	ideally we'd move the subtree over, renaming the top field, etc.
 *
 *	In practice, directory renames are really rare, so we'll just
 *	prune the sucker and relearn it when it's referenced.
 *
 *	We know that this guy can't be the root because that's a special
 *	directory and such clever requests have been rejected by now.
 *
 *	Algorithm:
 *		We don't want to recurse in case some practical joker has
 *		a super deep tree and blows our stack.	Instead, we'll brute
 *		force it by scanning down towards a leaf, removing a sibling
 *		chain there, and then repeating as necessary.  This is like
 *		a recursive algorithm only when we need to go back up we
 *		start scanning from the top again instead of returning
 *		to a recursive caller.
 *
 *		If we find a SBDIR which has a "solo pending" on it then
 *		it's probably being RMDIRed.  We waste some time by forcing
 *		a disk hit and then repeat as necessary.  This will be super
 *		rare.
 *
 *		This algo isn't very efficient, but these sbdir trees are
 *		nearly always shallow and this operation is rare, so sue me.
 *
 *	BUGBUG - time me worst case to make sure we're acceptable
 *
 *	ENTRY	lsnFNode (eax) = fnode of guy moved
 *		tdbSBDIR points to dir holding guy moved
 *	EXIT	none
 *	USES	all but EBP
 *
 *	HISTORY
 *	    23-Feb-1990 by JR (John Rogers, JohnRo@Microsoft)
 *		- PTR B788262: fix FS_DoPageIO probs (e.g. nested swap).
 */
void
WipeSBDIR (lsnFNode)
LSN lsnFNode;
{

	PSUBDIR psbdParent;	/*  ptr to Parent of SUBDIR to delete	*/
	PSUBDIR psbdCur;	/*  set to ptr to SUBDIR to delete	*/
	PSUBDIR psbdLeaf;	/*  Used to traverse SUBDIR ring struct */
	PSUBDIR psbdLeafParent;	/*  psbdLeaf's parent			*/
	ULONG i;		/*  Generic index variable		*/

	psbdParent = pfrm->psbd;


	/*
	 *  If the parent SUBDIR doesn't have any children,
	 *  the one we want to remove isn't in memory, and
	 *  we're done.
	 */
	if (psbdParent->cSubDirs == 0) {
		return;
	}


	/*  Go around the sibling ring until we've found the SUBDIR
	 *  we want or we've made a complete circuit.
	 *
	 */
	for (i = 0, psbdCur = psbdParent->psbdKids;
	     (i < psbdParent->cSubDirs) && (psbdCur->lsnFNode != lsnFNode);
	     i++, psbdCur = (PSUBDIR)(psbdCur->dcpSib.pFwd));


	if (psbdCur->lsnFNode != lsnFNode) {

	    /*	The SUBDIR we want to delete isn't in memory--
	     *	less work for us.
	     */
	    return;
	}



	/*
	 *  psbdCur now points to the SUBDIR we want to delete.
	 *  Delete descendants of psbdCur until they have all
	 *  been deleted, along with psbdCur itself.
	 */
	do {

	    /*	Do a depth-first traversal down to a leaf node.
	     *	We have to keep track of who the leaf node's parent
	     *	is for DelSBDIR.
	     */
	    psbdLeaf = psbdCur;
	    psbdLeafParent = psbdParent;
	    while ( psbdLeaf->cSubDirs != 0 ) {
		 psbdLeafParent = psbdLeaf;
		 psbdLeaf = psbdLeaf->psbdKids;
	    }

	    /*	Delete this leaf subdir	 */
	    LOCKSWAP(&swapBSWAP1);
	    DelSBDIR (psbdLeaf, psbdLeafParent);
	    UNLOCKSWAP(&swapBSWAP1);

	} while (psbdLeaf != psbdCur);
}
