/*static char *SCCSID = "@(#)adl.c	6.2 92/01/31";*/
#include <os2def.h>
#include <bse.h>

#include "heap.h"
#include "const.h"
#include "misc.h"
#include "chain.h"
#include "buf.h"
#include "dir.h"
#include "storage.h"
#include "volume.h"
#include "tables.h"
#include "pb_ifs.h"
#include "superb.h"
#include "lw.h"
#include "frame.h"
#include "fsdata.h"

#include "pr_DIR.h"
#include "pr_HEAP.h"
#include "pr_MISC.h"
#include "pr_debug.h"


/*
 ***	ADL - Add To Directory Lookaside
 *
 *	ADL adds a new entry to the front of the directory lookaside
 *	cache.  Since ADL is called after someone has failed to
 *	find the entry in the lookaside buffer and has read the
 *	disk to find the entry, it's possible that a race condition
 *	can add the same directory twice to the lookaside
 *	structure.  If this should happen, the first one in the list
 *	will get moved to the front as it gets touched, and the
 *	second one will then age off the end of the list, so
 *	a rare duplicate is not a problem.
 *
 *	ENTRY	pcpPath = path name string
 *		psbdDirToAdd = address of SBDIR structure
 *
 *	EXIT	returns a pointer to the newly added DIRLOOK struct
 *		returns NULL if not enough memory.
 */

PDIRLOOK
ADL (pcpPath, psbdDirToAdd, pfrm)
PCRACKEDPATH	pcpPath;	/* path name string */
PSUBDIR		psbdDirToAdd;	/* address of SUBDIR struct */
PFRAME		pfrm;
{
	UINT cbName;		/*  # of bytes to copy in cracked path */
	PDIRLOOK pdlCur;	/*  Pointer to the entry we will modify	 */

	/*  We will reuse the last one in the chain, since he (or she)
	    is the least recently used.
	 */
	pdlCur = dcpDLHead.pBak;

	pdlCur->psbdDir = psbdDirToAdd;
	pdlCur->ulVolBits = (psbdDirToAdd->scpTopDirBlkHint.lsn) & ~SECMASK;
	cbName = pcpPath->cbPath + sizeof(pcpPath->hVPB);

	/* volume is already in the pcp! no need to xor it in to the checksum */
	pdlCur->cks = CAS((PCHAR)pcpPath, cbName);

	/*  Set up the name entry:  release the heap space for
	    the old name, if necessary;	 get heap space for the
	    new name; and copy the name parameter (pcpPath) to
	    the heap space we just got.
	 */
	if (pdlCur->pcpName != NULL)
	    RetHeap (pdlCur->pcpName);

	if ((pdlCur->pcpName = GHS(cbName,pfrm)) == NULL) {
#ifdef DEBUG
	    dprintf ("ADL: GHS returned NULL");
#endif
	    return(NULL);
	}

	BYTE_COPY (pcpPath, pdlCur->pcpName, cbName);

	/*  Since dcpDLHead, the dummy head node, is actually in
	    the chain, it is necessary to invoke MakeFirst to move
	    *pdlCur to the other side of dcpDLHead, to make it the
	    first in the list.
	 */
	MakeFirst ((PDOUBLYCHAINEDNEARPTRS)(dcpDLHead.pFwd),
		   (PDOUBLYCHAINEDNEARPTRS)(pdlCur));

	return (pdlCur);
}
