/*static char *SCCSID = "@(#)updir.c	6.2 92/01/31";*/
#define BSWAP2 BSWAP2
#define INCL_DOSERRORS
#include <os2.h>
#include "api.h"
#include "const.h"
#include "chain.h"
#include "misc.h"
#include "buf.h"
#include "dir.h"
#include "find.h"
#include "storage.h"
#include "volume.h"
#include "frame.h"
#include "tables.h"
#include "pb_ifs.h"
#include "ea.h"
#include "assert.h"
#include "pr_FIND.h"
#include "pr_CACHE.h"
#include "pr_debug.h"

/*
 ***	UpDir - Go Up a Directory Level
 *
 *	UpDir is called by folks who are sequentially stepping through
 *	a directory and they reach the end entry.  UpDir reads the
 *	parent dirblk, if there is one, and finds the entry which
 *	directly (lexically) follows the last entry in that lower
 *	directory block
 *
 *	ENTRY	ppdb = pointer to address of directory block
 *		ppde = pointer to address of end dir entry
 *		ppbuf = address of ptr to buffer header for dir block
 *
 *	EXIT	Returns
 *		  NO_ERROR		- if we find an entry
 *		    *ppdb = address of directory block
 *		    *ppde = address of entry
 *		    *ppbuf = address of buffer block for dir block
 *		  ERROR_NO_MORE_FILES	- if we reach the end of the directory
 *		  ERROR_READ_FAULT	- if error reading
 */

USHORT far
UpDir (
    PDIRBLK far	 *ppdb,	    /* ptr to ptr to dir block */
    PDIRENT far	 *ppde,	    /* ptr to ptr to dir entry */
    PBUFNODE far *ppbuf,    /* ptr to ptr to buffer header */
    PFRAME	  pfrm)
{
    PDIRBLK	pdb = *ppdb;	/* temp for fast access */
    PDIRENT	pde = *ppde;	/* temp for fast access */
    LSN		lsnChildDir;	/* lsn of child dir block */

    do {
	if ( IS_TOP_DIRBLOCK(pdb) )
	    return ERROR_NO_MORE_FILES;	  /* we are at the top */

	/*
	 * save the lsn of current dir block
	 */
	lsnChildDir = pdb->lsnThisDir;

	/*
	 * read the parent dir block
	 */
	if ((pdb = RdBuf(pdb->lsnParent, BP_KEEP, ppbuf, pfrm)) == NULL) {
#ifdef DEBUG
	    dprintf ("UpDir: RdBuf returned NULL\n");
#endif
	    return ERROR_READ_FAULT;
	}
	ASSERT_DB (pdb);

	/*
	 * find the dir entry where the btree downpointer (lsn)
	 * matches the lsn of the child dir block
	 */
	pde = (PDIRENT) &pdb->bFirst;
	while ( BTP(pde) != lsnChildDir ) {
	    if (pde->fFlags & DF_END) {
#ifdef DEBUG
		dprintf("UpDir: Failed to find BTP pdb=%p, ",pdb);
		dprintf("lsn=%ld, ",lsnChildDir);
		dprintf("parent pdb=%p\n",*ppdb);
		Int3();
#endif
		return ERROR_READ_FAULT;
	    }
	    pde = NEXT_ENTRY(pde);
	}
	*ppdb = pdb;
	*ppde = pde;

    } while ( pde->fFlags & DF_END );	/* continue up the btree */

    return NO_ERROR;	/* next dir entry is found */
}
