/*static char *SCCSID = "@(#)remsbdir.c	6.2 92/01/31";*/
#define _BTXT _BTXT
#include <os2.h>

#include "heap.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 "find.h"
#include "pbmacros.h"

#include "pr_DEL.h"
#include "pr_HEAP.h"
#include "pr_MISC.h"


/*
 ***	RemSBDIR - Remove SbDir Entry
 *
 *	RemSBDIR is called to remove the SBDIR entry of a directory
 *	which is about to be deleted.  Folks can find directories via
 *	the SBDIR tree even if a parent directory is locked, so we gotta
 *	remove the SBDIR entry to make sure that when we yield folks
 *	can't manipulate the directory that we're deleting.
 *
 *	Finding the SBDIR entry is easy; our TDB_SBDIR field points
 *	to the parent SBDIR field; we just scan the list of subdirectories
 *	of that parent for our guy.  Our guy might not be in the SBDIR
 *	table..
 *
 *	If the SD_FNDCNT field is non-zero that means that we're in a
 *	find record somewhere.  We gotta locate that record and edit it to
 *	show our absence.
 *
 *	It's ok if we have to abort the RMDIR since a missing SBDIR
 *	can easily be recreated.
 *
 *	Our caller must have locked the parent directory.  RemSBDIR makes
 *	sure that there is no one held, locked, or waiting on this SBDIR.
 *
 *	ENTRY	fnTarget = lsn of directory's fnode
 *		pfrm->psbd points to the parent directory SBDIR
 *
 *	EXIT	TRUE - if successful
 *		FALSE - if SBDIR is still in use
 *
 *	HISTORY
 *	    23-Feb-1990 by JR (John Rogers, JohnRo@Microsoft)
 *		- PTR B788262: fix FS_DoPageIO probs (e.g. nested swap).
 *	    14-Oct-1988 17:11 by Bill McJohn [t-billm]
 *					translated from Oct 13 assembly code
 */

BOOL
RemSBDIR (lsnFNode,pfrm)
LSN lsnFNode;
PFRAME pfrm;
{
    PSUBDIR psbdCur;	    /*	Used to find SUBDIR to delete	      */
    PDIRLOOK pdlCur;	    /*	Used to traverse Directory Lookaside  */
    ULONG i;		    /*	generic index variable		      */


    /*	If the parent subdirectory structure has no child
     *	subdirectories, we don't need to do anything.
     */
    if (pfrm->psbd->cSubDirs == 0)
	    return TRUE;

    /*	Search the parent's children for the one we want.
     */
    psbdCur = pfrm->psbd->psbdKids;
    for (i = 0;
	 (i < pfrm->psbd->cSubDirs) && (lsnFNode != psbdCur->lsnFNode);
	 i++)
	    psbdCur = (PSUBDIR)(psbdCur->dcpSib.pFwd);


    /*	if i == pfrm->psbd->cSubDirs, then we didn't find the
     *	the subdir we're looking for among its parent's children,
     *	so it isn't in memory.  This is fine;  it means less work
     *	for us.
     */
    if ( i == pfrm->psbd->cSubDirs )
	    return TRUE;

    /*	psbdCur now points to the SUBDIR structure for the
     *	directory we plan to delete.
     */

    /*
     * If any opens reference this SBDIR or if
     * there are any children in the directory that we
     * are trying to delete, we can't continue.
     */
    if ((psbdCur->cOpens != 0) ||
	(psbdCur->cSubDirs != 0)) {
	return FALSE;
    }

    /*	Now we need to make sure
     *	psbdCur doesn't appear in the directory-lookaside table.
     *
     *	Check them all, since there's a race condition that
     *	could leave duplicates in the list.
     *
     */
    pdlCur = (PDIRLOOK)(dcpDLHead.pFwd);
    for (i = 0; i < DLCNT; i++) {

	if (pdlCur->psbdDir == psbdCur) {

		/*  Here's a match.  Zero out its checksum and
		 *  name string.
		 */
		pdlCur->cks = 0;
		pdlCur->pcpName->cbPath = 0;
	}

	pdlCur = (PDIRLOOK)(pdlCur->dcpLinks.pFwd);
    }

    /*	Now remove the entry itself.  */
    LOCKSWAP(&swapBSWAP1);
    DelSBDIR (psbdCur, pfrm->psbd,pfrm);
    UNLOCKSWAP(&swapBSWAP1);

    return TRUE;
}
