//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1992 - 1992.
//
//  File:       prefix.hxx
//
//  Contents:   PREFIX table definition
//
//  History:    SethuR -- Implemented
//
//  Notes:      The DFS prefix table data structure consists of three
//              entities and methods to manipulate them. They are the
//              DFS_PREFIX_TABLE_ENTRY,DFS_PREFIX_TABLE_BUCKET and the
//              DFS_PREFIX_TABLE.
//
//              The DFS_PREFIX_TABLE is a hash table of DFS_PREFIX_TABLE_ENTRY's
//              wherein collisions are resolved through linear chaining. The
//              hash table is organized as an array of collision lists
//              (DFS_PREFIX_TABLE_BUCKET). A brief description with each of
//              these entities is attached to the declaration.
//
//              There are certain characterstics that distinguish this
//              hash table from other hash tables. These are the extensions
//              provided to accomodate the special operations.
//
//--------------------------------------------------------------------------

#ifndef __PREFIX_HXX__
#define __PREFIX_HXX__

//+---------------------------------------------------------------------
//
// Struct:  DFS_PREFIX_TABLE_ENTRY
//
// History:
//
// Notes:   Each DFS_PREFIX_TABLE entry is in reality a member of two linked
//          lists -- a doubly linked list chaining the entries in a bucket
//          and a singly linked list establishing the path from any entry to
//          the root of the name space. In addition we have the data associated
//          with each entry, viz., the name and the data (pData). We also
//          keep track of the number of children of each entry. It can also
//          be defined as the number of paths to the root of which this entry
//          is a member.
//
//----------------------------------------------------------------------

typedef struct _DFS_PREFIX_TABLE_ENTRY_
{
   struct _DFS_PREFIX_TABLE_ENTRY_  *pParentEntry;
   struct _DFS_PREFIX_TABLE_ENTRY_  *pNextEntry;
   struct _DFS_PREFIX_TABLE_ENTRY_  *pPrevEntry;

   //
   // pFirstChildEntry and pSiblingEntry are used purely for enumeration
   //
   struct _DFS_PREFIX_TABLE_ENTRY_  *pFirstChildEntry;
   struct _DFS_PREFIX_TABLE_ENTRY_  *pSiblingEntry;

   ULONG                             NoOfChildren;

   UNICODE_STRING                    PathSegment;
   PVOID                             pData;
} DFS_PREFIX_TABLE_ENTRY, *PDFS_PREFIX_TABLE_ENTRY;

//+---------------------------------------------------------------------
//
// Struct:  DFS_PREFIX_TABLE_BUCKET
//
// History:
//
// Notes:   The DFS_PREFIX_TABLE_BUCKET is a doubly linked list of
//          DFS_PREFIX_TABLE_ENTRY's. The current implementation employs
//          the notion of a sentinel entry associated with each bucket. The
//          end pointers are never null but are always looped back to the
//          sentinel entry. The reason we employ such an organization is that
//          it considerably simplifies the list manipulation routines. The
//          reason this needs to be a doubly linked list is that we would like
//          to have the ability of deleting entries without having to traverse
//          the buckets from beginning.
//
//          The following inline methods ( macro defns. ) are provided for
//          inserting, deleting and looking up an entry in the bucket.
//
//----------------------------------------------------------------------

typedef struct _PREFIX_TABLE_BUCKET_
{
   ULONG                  NoOfEntries;   // High water mark for entries hashing to the bkt.
   DFS_PREFIX_TABLE_ENTRY SentinelEntry;
} PREFIX_TABLE_BUCKET, *PPREFIX_TABLE_BUCKET;

//+---------------------------------------------------------------------
//
// Struct:  NAME_PAGE
//
// History:
//
// Notes:   The name segments associated with the various entries are all
//          stored together in a name page. This allows us to amortize the
//          memory allocation costs over a number of entries and also allows
//          us to speed up traversal ( for details see DFS_PREFIX_TABLE
//          definition ).
//
//----------------------------------------------------------------------

#define FREESPACE_IN_NAME_PAGE ((PAGE_SIZE - sizeof(ULONG) - sizeof(PVOID)) / sizeof(WCHAR))

typedef struct _NAME_PAGE_
{
   struct _NAME_PAGE_  *pNextPage;
   LONG                cFreeSpace; // free space avilable in WCHAR's
   WCHAR               Names[FREESPACE_IN_NAME_PAGE];
} NAME_PAGE, *PNAME_PAGE;

typedef struct _NAME_PAGE_LIST_
{
   PNAME_PAGE  pFirstPage;
} NAME_PAGE_LIST, *PNAME_PAGE_LIST;

//+---------------------------------------------------------------------
//
// Struct:  DFS_PREFIX_TABLE
//
// History:
//
// Notes:   The DFS_PREFIX_TABLE is a hashed collection of DFS_PREFIX_TABLE_ENTRY
//          organized in the form of buckets. In addition one other space
//          conserving measure is adopted. There is only one copy of each
//          name segment stored in the table. As an example consider the
//          two pathnames \foo\bar and \bar\foo. We only store one copy of foo
//          and bar eventhough we accomdate both these paths. A beneficial
//          side effect of storing single copies is that our traversal of the
//          collision chain is considerably speeded up since once we have
//          located the pointer to the name, subsequent comparisons need merely
//          compare pointers as opposed to strings.
//
//----------------------------------------------------------------------

#define NO_OF_HASH_BUCKETS 57

typedef struct _DFS_PREFIX_TABLE
{
   BOOLEAN             CaseSensitive;
   NAME_PAGE_LIST      NamePageList;
   //
   // NextEntry is used purely for enumeration
   //
   PDFS_PREFIX_TABLE_ENTRY NextEntry;
   DFS_PREFIX_TABLE_ENTRY RootEntry;
   PREFIX_TABLE_BUCKET Buckets[NO_OF_HASH_BUCKETS];

#ifdef KERNEL_MODE

   // Zone for allocating DFS_PREFIX_TABLE entries .....

   ZONE_HEADER         PrefixTableEntryZone;

#else

   // A DFS_PREFIX_TABLE is part of DS_DATA. We need to make the sizes of
   // these structures identical in user and kernel mode, so that user-mode
   // utilities like dfsdump can work.

   CHAR                UnusedBuffer[sizeof(ZONE_HEADER)];

#endif
} DFS_PREFIX_TABLE, *PDFS_PREFIX_TABLE;

//+---------------------------------------------------------------------
//
// Struct:  DFS_PREFIX_TABLE API.
//
// History:
//
// Notes:   The following API's are provided for manipulating the
//          DFS_PREFIX_TABLE.
//
//----------------------------------------------------------------------

extern
NTSTATUS DfsInitializePrefixTable(PDFS_PREFIX_TABLE pTable,
                                  BOOLEAN           fCaseSensitive);

extern
NTSTATUS DfsFreePrefixTable(PDFS_PREFIX_TABLE pTable);

extern
NTSTATUS DfsInsertInPrefixTable(PDFS_PREFIX_TABLE pTable,
                                PUNICODE_STRING   pPath,
                                PVOID             pData);
extern
NTSTATUS DfsLookupPrefixTable(PDFS_PREFIX_TABLE   pTable,
                              PUNICODE_STRING     pPath,
                              PUNICODE_STRING     pSuffix,
                              PVOID               *ppData);

extern
NTSTATUS DfsRemoveFromPrefixTable(PDFS_PREFIX_TABLE pTable,
                                  PUNICODE_STRING pPath);

//
// The RTL Prefix Table function signatures are slightly different.
// For now we will define a mapping between them to ease the porting
// effort. Subsequently we will change our signatures to confirm to
// the RTL routine.
//

#define DfsInitializeUnicodePrefix(pTable) \
        (DfsInitializePrefixTable(pTable,FALSE) == STATUS_SUCCESS)

#define DfsRemoveUnicodePrefix(pTable,pPath)  \
        (DfsRemoveFromPrefixTable(pTable,pPath) == STATUS_SUCCESS)

#define DfsInsertUnicodePrefix(pTable,pPath,pData) \
        (DfsInsertInPrefixTable(pTable,pPath,pData) == STATUS_SUCCESS)

PVOID    DfsFindUnicodePrefix(PDFS_PREFIX_TABLE   pTable,
                              PUNICODE_STRING     pPath,
                              PUNICODE_STRING     pSuffix);

PVOID   DfsNextUnicodePrefix(PDFS_PREFIX_TABLE    pTable,
                             BOOLEAN              fRestart);

PVOID   DfsNextUnicodePrefixChild(PDFS_PREFIX_TABLE pTable,
                                  PUNICODE_STRING   pPath,
                                  PVOID             *ppCookie);

#endif // __PREFIX_HXX__
