windows-nt/Source/XPSP1/NT/net/sfm/afp/server/idindex.h
2020-09-26 16:20:57 +08:00

1541 lines
48 KiB
C

/*
Copyright (c) 1992 Microsoft Corporation
Module Name:
idindex.h
Abstract:
This module contains the file and directory id structures.
Author:
Jameel Hyder (microsoft!jameelh)
Revision History:
25 Apr 1992 Initial Version
Notes: Tab stop: 4
--*/
#ifndef _IDINDEX_
#define _IDINDEX_
// AFP_IDDBHDR_VERSION2 was an experimental version.
#define AFP_IDDBHDR_VERSION1 0x00010000
#define AFP_IDDBHDR_VERSION2 0x00020000
#define AFP_IDDBHDR_VERSION3 0x00030000
#define AFP_IDDBHDR_VERSION4 0x00040000
#define AFP_IDDBHDR_VERSION5 0x00050000
#define AFP_IDDBHDR_VERSION AFP_IDDBHDR_VERSION5
typedef struct _IdDbHeader // Database header
{
DWORD idh_Signature; // Signature
DWORD idh_Version; // Version number
DWORD idh_LastId; // Highest id that is assigned
AFPTIME idh_CreateTime; // Creation time for this volume
AFPTIME idh_ModifiedTime; // Modified time for this volume
AFPTIME idh_BackupTime; // Backup time for this volume
} IDDBHDR, *PIDDBHDR;
// IdDb header is followed by a ULONG count of entries, then the DISKENTRies
#define VALID_DFE(pDfe) ((pDfe) != NULL)
struct _DfeBlock;
struct _DirFileEntry;
#define MAX_CHILD_HASH_BUCKETS 6
typedef struct _DirEntry
{
// NOTE: Keep the ChildDir and ChildFile entries together and in this order
// The code in AfpAddDfEntry depends on this to efficiently zero it out
// Also de_ChildDir is accessed as de_ChildFile[-1] !!!
struct _DirFileEntry * de_ChildDir; // First child in the dir list
struct _DirFileEntry * de_ChildFile[MAX_CHILD_HASH_BUCKETS];
// File 'children' are hashed for faster lookup
DWORD de_Access; // Combined access bits
#ifdef AGE_DFES
AFPTIME de_LastAccessTime; // Time when this DFE was last accessed
// Valid for directories only
LONG de_ChildForkOpenCount;// Count of open forks within this directory
#endif
} DIRENTRY, *PDIRENTRY;
// Owner access mask (SFI vs. SFO)
#define DE_OWNER_ACCESS(_pDE) *((PBYTE)(&(_pDE)->de_Access) + 0)
// Group access mask (SFI vs. SFO)
#define DE_GROUP_ACCESS(_pDE) *((PBYTE)(&(_pDE)->de_Access) + 1)
// World access mask (SFI vs. SFO)
#define DE_WORLD_ACCESS(_pDE) *((PBYTE)(&(_pDE)->de_Access) + 2)
typedef struct _DirFileEntry
{
// The dfe_Overflow is overloaded with dfe_NextFree for use by the block
// allocation package for the DFEs.
#define dfe_NextFree dfe_NextOverflow
struct _DirFileEntry * dfe_NextOverflow; // Overflow links
struct _DirFileEntry ** dfe_PrevOverflow; // Overflow links
struct _DirFileEntry * dfe_NextSibling; // Next sibling.
struct _DirFileEntry ** dfe_PrevSibling; // Previous sibling.
struct _DirFileEntry * dfe_Parent; // Parent entry
DWORD dfe_AfpId; // Afp FileId or DirId (from AfpInfo)
AFPTIME dfe_BackupTime; // Backup time for the file/dir (from AfpInfo)
// (Volume backup time is stored
// in the AFP_IdIndex stream)
AFPTIME dfe_CreateTime; // Creation time
TIME dfe_LastModTime; // Last modify time (as a LARGE_INTEGER)
SHORT dfe_DirDepth; // Parent of root at -1, root at 0
USHORT dfe_Flags; // file, dir or file with id
USHORT dfe_NtAttr; // NT Attributes (FILE_ATTRIBUTE_VALID_FLAGS)
USHORT dfe_AfpAttr; // Attributes mask (From AfpInfo)
union
{
// File specific information
struct // For Files Only
{
DWORD dfe_DataLen; // Data fork length
DWORD dfe_RescLen; // Resource fork length
};
// Directory specific information
struct // For Directories Only
{
DWORD dfe_DirOffspring; // count of dir offspring
DWORD dfe_FileOffspring; // count of file offspring
};
};
FINDERINFO dfe_FinderInfo; // Finder Info (32 bytes) (from AfpInfo)
// NOTE: When Dfes are copied as a structure, the fields below are NOT TO BE COPIED.
// The fields above should be.
#define dfe_CopyUpto dfe_UnicodeName
UNICODE_STRING dfe_UnicodeName; // 'Munged' Unicode Name of the entity
DWORD dfe_NameHash; // Hash value for the upcased munged Unicode name
// For directories, the DirEntry structure follows this structure. The space for
// this is allocated immediately after the DFENTRY structure and before the space
// for the name strings. For files it is NULL. This pointer should not be copied
// as well !!!
PDIRENTRY dfe_pDirEntry; // Directory related fields
// NULL for files
} DFENTRY, *PDFENTRY;
// Owner access mask (SFI vs. SFO)
#define DFE_OWNER_ACCESS(_pDFE) *((PBYTE)(&(_pDFE)->dfe_pDirEntry->de_Access) + 0)
// Group access mask (SFI vs. SFO)
#define DFE_GROUP_ACCESS(_pDFE) *((PBYTE)(&(_pDFE)->dfe_pDirEntry->de_Access) + 1)
// World access mask (SFI vs. SFO)
#define DFE_WORLD_ACCESS(_pDFE) *((PBYTE)(&(_pDFE)->dfe_pDirEntry->de_Access) + 2)
typedef struct _EnumIdAndType
{
DWORD eit_Id;
DWORD eit_Flags;
} EIT, *PEIT;
// There is the result of enumeration of a directory for this session and is stored
// within the connection descriptor. This is purely for performance reasons. This is
// deleted whenever an api other than AfpEnumerate is called and a result is around.
typedef struct _EnumDir
{
DWORD ed_ParentDirId; // Anchor point
DWORD ed_Bitmap; // Combination of file & dir bitmaps
LONG ed_ChildCount; // Count of children of the dir being enumerated
AFPTIME ed_TimeStamp; // Time at which created
PEIT ed_pEit; // list of actual entries
ANSI_STRING ed_PathName; // This is the name as passed by the client
// and is not normalised.
USHORT ed_BadCount; // Count of failed entities
BYTE ed_PathType; // Long name or short name
} ENUMDIR, *PENUMDIR;
typedef struct _CatSearchSpec
{
BYTE __StructLength;
BYTE __FillerOrFileDir;
// The rest of the parameters follow
} CATSEARCHSPEC, *PCATSEARCHSPEC;
// Must be 16 bytes as per AfpCatSearch API
typedef struct _CatalogPosition
{
USHORT cp_Flags; // if zero, then start search from beginning
USHORT cp_usPad1;
DWORD cp_CurParentId;
DWORD cp_NextFileId;
AFPTIME cp_TimeStamp;
} CATALOGPOSITION, *PCATALOGPOSITION;
#define CATFLAGS_SEARCHING_FILES 0x0001
#define CATFLAGS_SEARCHING_DIRCHILD 0x0002
#define CATFLAGS_SEARCHING_SIBLING 0x0004
#define CATFLAGS_WRITELOCK_REQUIRED 0x0008
#define CATFLAGS_VALID (CATFLAGS_SEARCHING_FILES | \
CATFLAGS_SEARCHING_DIRCHILD | \
CATFLAGS_SEARCHING_SIBLING | \
CATFLAGS_WRITELOCK_REQUIRED)
// Maximum time that a mac can hold onto a catsearch position and still
// have the search pickup from there instead of the beginning of the catalog
#define MAX_CATSEARCH_TIME 3600 // In seconds
// DFE_FLAGS_xxxx values for dfe_Flags field of DFENTRY structure
#define DFE_FLAGS_FILE_WITH_ID 0x0100
#define DFE_FLAGS_FILE_NO_ID 0x0200
#define DFE_FLAGS_DIR 0x0400
#define DFE_FLAGS_DFBITS (DFE_FLAGS_FILE_WITH_ID | \
DFE_FLAGS_FILE_NO_ID | \
DFE_FLAGS_DIR | \
DFE_FLAGS_HAS_COMMENT)
#define DFE_FLAGS_HAS_COMMENT 0x0800
#define DFE_FLAGS_INIT_COMPLETED 0x20
#define DFE_FLAGS_ENUMERATED 0x8000
// Encode the child and sibling pointers
#define DFE_FLAGS_HAS_CHILD 0x1000 // Used for reading in IdDb from disk
#define DFE_FLAGS_HAS_SIBLING 0x2000 // Used for reading in IdDb from disk
#define DFE_FLAGS_CSENCODEDBITS (DFE_FLAGS_HAS_CHILD | DFE_FLAGS_HAS_SIBLING | DFE_FLAGS_HAS_COMMENT)
#define DFE_FLAGS_NAMELENBITS 0x001F // Encodes the length of the longname
// which is 31 *characters* max
#define DFE_FLAGS_VALID_DSKBITS (DFE_FLAGS_CSENCODEDBITS | \
DFE_FLAGS_NAMELENBITS | \
DFE_FLAGS_HAS_COMMENT)
// Valid only for directories when their files have been enumerated from disk
// and now all have cached DFEs in the IDDB tree structure
#define DFE_FLAGS_FILES_CACHED 0x4000
// DAlreadyOpen and RAlreadyOpen flags for a File
#define DFE_FLAGS_R_ALREADYOPEN 0x0040
#define DFE_FLAGS_D_ALREADYOPEN 0x0080
#define DFE_FLAGS_OPEN_BITS (DFE_FLAGS_D_ALREADYOPEN | \
DFE_FLAGS_R_ALREADYOPEN)
typedef struct _DiskEntry
{
DWORD dsk_AfpId;
AFPTIME dsk_CreateTime; // File Creation time
TIME dsk_LastModTime; // Last modify time
FINDERINFO dsk_FinderInfo; // Finder Info (32 bytes) (from AfpInfo)
AFPTIME dsk_BackupTime; // Backup time for the file/dir (from AfpInfo)
// (Volume backup time is stored
// in the AFP_IdIndex stream)
union
{
DWORD dsk_DataLen; // Data fork length
DWORD dsk_Access; // Combined access rights
};
DWORD dsk_RescLen; // Resource fork length
USHORT dsk_Flags; // DFE_FLAGS_XXXX
USHORT dsk_AfpAttr; // Attributes mask (From AfpInfo)
USHORT dsk_NtAttr; // From FileAttributes
USHORT dsk_Signature; // AFP_DISKENTRY_SIGNATURE
WCHAR dsk_Name[2]; // Longname in 'munged' Unicode will follow and be padded
// out, if necessary, to DWORD boundry (max 64 bytes)
} DISKENTRY, *PDISKENTRY;
#define AFP_DISKENTRY_SIGNATURE *(PUSHORT)"::" // illegal name character
// size of buffer used to read-in/write-out the IdDb entries from/to disk
#define IDDB_UPDATE_BUFLEN (16*1024)
// Round the length to 4*N
#define DWLEN(_b) (((_b) + sizeof(DWORD) - 1) & ~(sizeof(DWORD) - 1))
// #define DFE_IS_DIRECTORY(_pDFE) (((_pDFE)->dfe_Flags & DFE_FLAGS_DIR) ? True : False)
#define DFE_IS_DIRECTORY(_pDFE) ((_pDFE)->dfe_pDirEntry != NULL)
// #define DFE_IS_FILE(_pDFE) (((_pDFE)->dfe_Flags & (DFE_FLAGS_FILE_NO_ID | DFE_FLAGS_FILE_WITH_ID)) ? True : False)
#define DFE_IS_FILE(_pDFE) ((_pDFE)->dfe_pDirEntry == NULL)
#define DFE_IS_FILE_WITH_ID(_pDFE) (((_pDFE)->dfe_Flags & DFE_FLAGS_FILE_WITH_ID) ? True : False)
#define DFE_IS_ROOT(_pDFE) ((_pDFE)->dfe_AfpId == AFP_ID_ROOT)
#define DFE_IS_PARENT_OF_ROOT(_pDFE) ((_pDFE)->dfe_AfpId == AFP_ID_PARENT_OF_ROOT)
#define DFE_IS_NWTRASH(_pDFE) ((_pDFE)->dfe_AfpId == AFP_ID_NETWORK_TRASH)
#define DFE_SET_DIRECTORY(_pDFE, _ParentDepth) \
{ \
((_pDFE)->dfe_DirDepth = _ParentDepth + 1); \
((_pDFE)->dfe_Flags |= DFE_FLAGS_DIR); \
}
#define DFE_SET_FILE(_pDFE) ((_pDFE)->dfe_Flags |= DFE_FLAGS_FILE_NO_ID)
#define DFE_SET_FILE_ID(_pDFE) ((_pDFE)->dfe_Flags |= DFE_FLAGS_FILE_WITH_ID)
#define DFE_CLR_FILE_ID(_pDFE) ((_pDFE)->dfe_Flags &= ~DFE_FLAGS_FILE_WITH_ID)
// update just the AFPinfo in the dfentry
#define DFE_UPDATE_CACHED_AFPINFO(_pDFE, pAfpInfo) \
{ \
(_pDFE)->dfe_BackupTime = (pAfpInfo)->afpi_BackupTime; \
(_pDFE)->dfe_FinderInfo = (pAfpInfo)->afpi_FinderInfo; \
(_pDFE)->dfe_AfpAttr = (pAfpInfo)->afpi_Attributes; \
if ((_pDFE)->dfe_Flags & DFE_FLAGS_DIR) \
{ \
DFE_OWNER_ACCESS(_pDFE) = (pAfpInfo)->afpi_AccessOwner; \
DFE_GROUP_ACCESS(_pDFE) = (pAfpInfo)->afpi_AccessGroup; \
DFE_WORLD_ACCESS(_pDFE) = (pAfpInfo)->afpi_AccessWorld; \
} \
}
#define DFE_SET_COMMENT(_pDFE) ((_pDFE)->dfe_Flags |= DFE_FLAGS_HAS_COMMENT)
#define DFE_CLR_COMMENT(_pDFE) ((_pDFE)->dfe_Flags &= ~DFE_FLAGS_HAS_COMMENT)
// Check to see if this entry was enumerated on an NTFS directory
#define DFE_HAS_BEEN_SEEN(_pDFE) ((_pDFE)->dfe_Flags & DFE_FLAGS_ENUMERATED)
#define DFE_MARK_UNSEEN(_pDFE) ((_pDFE)->dfe_Flags &= ~DFE_FLAGS_ENUMERATED)
#define DFE_MARK_AS_SEEN(_pDFE) ((_pDFE)->dfe_Flags |= DFE_FLAGS_ENUMERATED)
// Directories only
#define DFE_CHILDREN_ARE_PRESENT(_pDFE) ((_pDFE)->dfe_Flags & DFE_FLAGS_FILES_CACHED)
// Directories only
#define DFE_MARK_CHILDREN_PRESENT(_pDFE) ((_pDFE)->dfe_Flags |= DFE_FLAGS_FILES_CACHED)
#define DFE_FILE_HAS_SIBLING(_pDFE, _fbi, _pfHasSibling) \
{ \
DWORD _i; \
PDIRENTRY _pDirEntry; \
\
*(_pfHasSibling) = False; \
if (((_pDFE)->dfe_NextSibling != NULL) || \
((_pDFE)->dfe_Parent->dfe_pDirEntry->de_ChildDir != NULL)) \
{ \
*(_pfHasSibling) = True; \
} \
else \
{ \
_pDirEntry = (_pDFE)->dfe_Parent->dfe_pDirEntry; \
ASSERT(_pDirEntry != NULL); \
for (_i = (_fbi) + 1; \
_i < MAX_CHILD_HASH_BUCKETS; \
_i++) \
{ \
if (_pDirEntry->de_ChildFile[_i] != NULL) \
{ \
*(_pfHasSibling) = True; \
break; \
} \
} \
} \
}
#define HASH_DIR_ID(Id, _pVolDesc) ((Id) & ((_pVolDesc)->vds_DirHashTableSize-1))
#define HASH_FILE_ID(Id, _pVolDesc) ((Id) & ((_pVolDesc)->vds_FileHashTableSize-1))
#define HASH_CACHE_ID(Id) ((Id) & (IDINDEX_CACHE_ENTRIES-1))
#define QUAD_SIZED(_X_) (((_X_) % 8) == 0)
// Values for access checking
#define ACCESS_READ 1
#define ACCESS_WRITE 2
extern
NTSTATUS
AfpDfeInit(
VOID
);
extern
VOID
AfpDfeDeInit(
VOID
);
extern
PDFENTRY
AfpFindDfEntryById(
IN struct _VolDesc * pVolDesc,
IN DWORD Id,
IN DWORD EntityMask
);
extern
PDFENTRY
AfpFindEntryByUnicodeName(
IN struct _VolDesc * pVolDesc,
IN PUNICODE_STRING pName,
IN DWORD PathType,
IN PDFENTRY pDfeParent,
IN DWORD EntityMask
);
extern
PDFENTRY
AfpAddDfEntry(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDfeParent,
IN PUNICODE_STRING pUName,
IN BOOLEAN Directory,
IN DWORD AfpId OPTIONAL
);
extern
PDFENTRY
AfpRenameDfEntry(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDfEntry,
IN PUNICODE_STRING pNewName
);
extern
PDFENTRY
AfpMoveDfEntry(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDfEntry,
IN PDFENTRY pNewParentDfE,
IN PUNICODE_STRING pNewName OPTIONAL
);
extern
VOID FASTCALL
AfpDeleteDfEntry(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDfE
);
extern
VOID
AfpExchangeIdEntries(
IN struct _VolDesc * pVolDesc,
IN DWORD AfpId1,
IN DWORD AfpId2
);
extern
VOID FASTCALL
AfpPruneIdDb(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDfeTarget
);
extern
NTSTATUS FASTCALL
AfpInitIdDb(
IN struct _VolDesc * pVolDesc,
OUT BOOLEAN * pfNewVolume,
OUT BOOLEAN * pfVerifyIndex
);
extern
VOID FASTCALL
AfpFreeIdIndexTables(
IN struct _VolDesc * pVolDesc
);
extern
AFPSTATUS
AfpEnumerate(
IN struct _ConnDesc * pConnDesc,
IN DWORD ParentDirId,
IN PANSI_STRING pPath,
IN DWORD BitmapF,
IN DWORD BitmapD,
IN BYTE PathType,
IN DWORD DFFlags,
OUT PENUMDIR * ppEnumDir
);
extern
AFPSTATUS
AfpSetDFFileFlags(
IN struct _VolDesc * pVolDesc,
IN DWORD AfpId,
IN DWORD FlagSet OPTIONAL,
IN BOOLEAN SetFileId,
IN BOOLEAN ClrFileId
);
extern
VOID
AfpChangeNotifyThread(
IN PVOID pContext
);
extern
VOID FASTCALL
AfpProcessChangeNotify(
IN struct _VolumeNotify * pVolNotify
);
extern
VOID
AfpQueuePrivateChangeNotify(
IN struct _VolDesc * pVolDesc,
IN PUNICODE_STRING pName,
IN PUNICODE_STRING pPath,
IN DWORD ParentId
);
extern
BOOLEAN FASTCALL
AfpShouldWeIgnoreThisNotification(
IN struct _VolumeNotify * pVolNotify
);
extern
VOID
AfpQueueOurChange(
IN struct _VolDesc * pVolDesc,
IN DWORD Action,
IN PUNICODE_STRING pPath,
IN PUNICODE_STRING pParentPath OPTIONAL
);
extern
VOID
AfpDequeueOurChange(
IN struct _VolDesc * pVolDesc,
IN DWORD Action,
IN PUNICODE_STRING pPath,
IN PUNICODE_STRING pParentPath OPTIONAL
);
extern
NTSTATUS FASTCALL
AddToDelayedNotifyList(
IN struct _VolDesc * pVolDesc,
IN PUNICODE_STRING pUName
);
extern
NTSTATUS
RemoveFromDelayedNotifyList(
IN struct _VolDesc * pVolDesc,
IN PUNICODE_STRING pUName,
IN PFILE_NOTIFY_INFORMATION pFNInfo
);
extern
NTSTATUS
CheckAndProcessDelayedNotify(
IN struct _VolDesc * pVolDesc,
IN PUNICODE_STRING pUName,
IN PUNICODE_STRING pUNewname,
IN PUNICODE_STRING pUParent
);
extern
VOID
AfpCacheParentModTime(
IN struct _VolDesc * pVolDesc,
IN PFILESYSHANDLE pHandle OPTIONAL, // if pPath not supplied
IN PUNICODE_STRING pPath OPTIONAL, // if pHandle not supplied
IN PDFENTRY pDfeParent OPTIONAL, // if ParentId not supplied
IN DWORD ParentId OPTIONAL // if pDfeParent not supplied
);
extern
AFPSTATUS
AfpCatSearch(
IN struct _ConnDesc * pConnDesc,
IN PCATALOGPOSITION pCatPosition,
IN DWORD Bitmap,
IN DWORD FileBitmap,
IN DWORD DirBitmap,
IN struct _FileDirParms * pFDParm1,
IN struct _FileDirParms * pFDParm2,
IN PUNICODE_STRING pMatchString OPTIONAL,
IN OUT PDWORD pCount,
IN SHORT Buflen,
OUT PSHORT pSizeLeft,
OUT PBYTE pResults,
OUT PCATALOGPOSITION pNewCatPosition
);
#ifdef AGE_DFES
extern
VOID FASTCALL
AfpAgeDfEntries(
IN struct _VolDesc * pVolDesc
);
#endif
#define REENUMERATE 0x0001
#define GETDIRSKELETON 0x0002
#define GETFILES 0x0004
#define GETENTIRETREE 0x0008
extern
NTSTATUS
AfpCacheDirectoryTree(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDFETreeRoot,
IN DWORD Method,
IN PFILESYSHANDLE phRootDir OPTIONAL,
IN PUNICODE_STRING pDirPath OPTIONAL
);
extern
AFPSTATUS FASTCALL
AfpOurChangeScavenger(
IN struct _VolDesc * pVolDesc
);
extern
VOID FASTCALL
AfpFlushIdDb(
IN struct _VolDesc * pVolDesc,
IN PFILESYSHANDLE phIdDb
);
extern
VOID
AfpGetDirFileHashSizes(
IN struct _VolDesc * pVolDesc,
OUT PDWORD pdwDirHashSz,
OUT PDWORD pdwFileHashSz
);
#ifdef IDINDEX_LOCALS
#define afpConvertBasicToBothDirInfo(_pFBasInfo, _pFBDInfo) \
{ \
(_pFBDInfo)->CreationTime = (_pFBasInfo)->CreationTime; \
(_pFBDInfo)->LastWriteTime = (_pFBasInfo)->LastWriteTime; \
(_pFBDInfo)->ChangeTime = (_pFBasInfo)->ChangeTime; \
(_pFBDInfo)->FileAttributes = (_pFBasInfo)->FileAttributes; \
(_pFBDInfo)->EndOfFile.QuadPart = 0; \
}
#undef EQU
#ifdef _IDDB_GLOBALS_
#define IDDBGLOBAL
#define EQU =
#else
#define IDDBGLOBAL extern
#define EQU ; / ## /
#endif
// This bit on a Notify action indicates it is a simulated notify. Volume
// modified time is not updated when such a notify comes in
#define AFP_ACTION_PRIVATE 0x80000000
// DFEs come in four sizes. This helps in efficiently managing them in a block
// package (see later). THESE SIZES NEED TO BE 4*N, else we run into alignment
// faults on architectures that require it.
#define DFE_INDEX_TINY 0
#define DFE_INDEX_SMALL 1
#define DFE_INDEX_MEDIUM 2
#define DFE_INDEX_LARGE 3
//
// Make sure each of the sizes below (XXX_U) are multiple of 8
//
#define DFE_SIZE_TINY 8 // These are lengths for ANSI names
#define DFE_SIZE_SMALL 12 // - ditto -
#define DFE_SIZE_MEDIUM 20 // - ditto -
#define DFE_SIZE_LARGE 32 // - ditto - corres. to AFP_FILENAME_LEN
#define DFE_SIZE_TINY_U DFE_SIZE_TINY*sizeof(WCHAR) // These are lengths for UNICODE names
#define DFE_SIZE_SMALL_U DFE_SIZE_SMALL*sizeof(WCHAR) // - ditto -
#define DFE_SIZE_MEDIUM_U DFE_SIZE_MEDIUM*sizeof(WCHAR) // - ditto -
#define DFE_SIZE_LARGE_U DFE_SIZE_LARGE*sizeof(WCHAR) // - ditto - corres. to AFP_FILENAME_LEN
#define ASIZE_TO_INDEX(_Size) \
(((_Size) <= DFE_SIZE_TINY) ? DFE_INDEX_TINY : \
(((_Size) <= DFE_SIZE_SMALL) ? DFE_INDEX_SMALL : \
(((_Size) <= DFE_SIZE_MEDIUM) ? DFE_INDEX_MEDIUM : DFE_INDEX_LARGE)))
#define USIZE_TO_INDEX(_Size) \
(((_Size) <= DFE_SIZE_TINY_U) ? DFE_INDEX_TINY : \
(((_Size) <= DFE_SIZE_SMALL_U) ? DFE_INDEX_SMALL : \
(((_Size) <= DFE_SIZE_MEDIUM_U) ? DFE_INDEX_MEDIUM : DFE_INDEX_LARGE)))
#define ALLOC_DFE(Index, fDir) afpAllocDfe(Index, fDir)
#define FREE_DFE(pDfEntry) afpFreeDfe(pDfEntry)
LOCAL DWORD FASTCALL
afpGetNextId(
IN struct _VolDesc * pVolDesc
);
LOCAL
NTSTATUS FASTCALL
afpSeedIdDb(
IN struct _VolDesc * pVolDesc
);
LOCAL
VOID
afpPackSearchParms(
IN PDFENTRY pDfe,
IN DWORD Bitmap,
IN PBYTE pBuf
);
LOCAL
NTSTATUS FASTCALL
afpReadIdDb(
IN struct _VolDesc * pVolDesc,
IN PFILESYSHANDLE pfshIdDb,
OUT BOOLEAN * pfVerifyIndex
);
VOID
afpAddDfEntryAndCacheInfo(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDfeParent,
IN PUNICODE_STRING pUName, // munged unicode name
IN PFILESYSHANDLE pfshParentDir, // open handle to parent directory
IN PFILE_BOTH_DIR_INFORMATION pFBDInfo, // from enumerate
IN PUNICODE_STRING pNotifyPath, // to filter out our own AFP_AfpInfo change notifies
IN PDFENTRY * ppDfEntry,
IN BOOLEAN CheckDuplicate
);
VOID
afpVerifyDFE(
IN struct _VolDesc * pVolDesc,
IN PDFENTRY pDfeParent,
IN PUNICODE_STRING pUName, // munged unicode name
IN PFILESYSHANDLE pfshParentDir, // open handle to parent directory
IN PFILE_BOTH_DIR_INFORMATION pFBDInfo, // from enumerate
IN PUNICODE_STRING pNotifyPath, // to filter out our own AFP_AfpInfo change notifies
IN PDFENTRY * ppDfEntry
);
PDFENTRY
afpFindEntryByNtPath(
IN struct _VolDesc * pVolDesc,
IN DWORD ChangeAction, // if ADDED then lookup parent DFE
IN PUNICODE_STRING pPath,
OUT PUNICODE_STRING pParent,
OUT PUNICODE_STRING pTail
);
PDFENTRY
afpFindEntryByNtName(
IN struct _VolDesc * pVolDesc,
IN PUNICODE_STRING pName,
IN PDFENTRY pDfeParent // pointer to parent DFENTRY
);
VOID FASTCALL
afpProcessPrivateNotify(
IN struct _VolumeNotify * pVolNotify
);
VOID FASTCALL
afpActivateVolume(
IN struct _VolDesc * pVolDesc
);
VOID
afpRenameInvalidWin32Name(
IN PFILESYSHANDLE phRootDir,
IN BOOLEAN IsDir,
IN PUNICODE_STRING pName
);
#define afpInitializeIdDb(_pVolDesc) \
{ \
AFPTIME CurrentTime; \
PDFENTRY pDfEntry; \
\
/* RO volumes don't use the network trash folder at all */ \
(_pVolDesc)->vds_LastId = AFP_ID_NETWORK_TRASH; \
\
AfpGetCurrentTimeInMacFormat(&CurrentTime); \
(_pVolDesc)->vds_CreateTime = CurrentTime; \
(_pVolDesc)->vds_ModifiedTime = CurrentTime; \
(_pVolDesc)->vds_BackupTime = BEGINNING_OF_TIME; \
\
/* Create a DFE for the root directory */ \
afpCreateParentOfRoot(_pVolDesc, &pDfEntry); \
}
#ifdef AGE_DFES
#define afpCreateParentOfRoot(_pVolDesc, _ppDfEntry) \
{ \
PDFENTRY pDFE; \
struct _DirFileEntry ** _DfeDirBucketStart; \
\
/* \
* add the parent of root to the id index. \
* This has to be done here \
* (i.e. cannot call AfpAddDfEntry for parentofroot). \
*/ \
\
if ((*(_ppDfEntry) = ALLOC_DFE(0, True)) != NULL) \
{ \
pDFE = *(_ppDfEntry); \
\
(_pVolDesc)->vds_NumFileDfEntries = 0; \
(_pVolDesc)->vds_NumDirDfEntries = 0; \
pDFE->dfe_Flags = DFE_FLAGS_DIR | DFE_FLAGS_FILES_CACHED; \
pDFE->dfe_DirDepth = -1; \
pDFE->dfe_Parent = NULL; \
pDFE->dfe_NextOverflow = NULL; \
\
/* Initialize the DirEntry for ParentOfRoot */ \
ASSERT((FIELD_OFFSET(DIRENTRY, de_ChildFile) - \
FIELD_OFFSET(DIRENTRY, de_ChildDir)) == sizeof(PVOID));\
\
/* These fields are relevant to directories only */ \
pDFE->dfe_pDirEntry->de_LastAccessTime = BEGINNING_OF_TIME; \
pDFE->dfe_pDirEntry->de_ChildForkOpenCount = 0; \
\
/* \
* The parent of root has no siblings and this should \
* never be referenced \
*/ \
pDFE->dfe_NameHash = 0; \
pDFE->dfe_NextSibling = NULL; \
pDFE->dfe_PrevSibling = NULL; \
pDFE->dfe_AfpId = AFP_ID_PARENT_OF_ROOT; \
pDFE->dfe_DirOffspring = pDFE->dfe_FileOffspring = 0; \
\
/* link it into the hash buckets */ \
_DfeDirBucketStart = (_pVolDesc)->vds_pDfeDirBucketStart; \
AfpLinkDoubleAtHead(_DfeDirBucketStart[HASH_DIR_ID(AFP_ID_PARENT_OF_ROOT,_pVolDesc)],\
pDFE, \
dfe_NextOverflow, \
dfe_PrevOverflow); \
} \
}
#else
#define afpCreateParentOfRoot(_pVolDesc, _ppDfEntry) \
{ \
PDFENTRY pDfEntry; \
struct _DirFileEntry ** _DfeDirBucketStart; \
\
/* \
* add the parent of root to the id index. \
* This has to be done here \
* (i.e. cannot call AfpAddDfEntry for parentofroot). \
*/ \
\
if ((*(_ppDfEntry) = ALLOC_DFE(0, True)) != NULL) \
{ \
pDfEntry = *(_ppDfEntry); \
\
(_pVolDesc)->vds_NumFileDfEntries = 0; \
(_pVolDesc)->vds_NumDirDfEntries = 0; \
pDfEntry->dfe_Flags = DFE_FLAGS_DIR | DFE_FLAGS_FILES_CACHED;\
pDfEntry->dfe_DirDepth = -1; \
pDfEntry->dfe_Parent = NULL; \
pDfEntry->dfe_NextOverflow = NULL; \
\
/* Initialize the DirEntry for ParentOfRoot */ \
ASSERT((FIELD_OFFSET(DIRENTRY, de_ChildFile) - \
FIELD_OFFSET(DIRENTRY, de_ChildDir)) == sizeof(PVOID));\
\
/* The parent of root has no siblings and this should never be referenced */ \
pDfEntry->dfe_NameHash = 0; \
pDfEntry->dfe_NextSibling = NULL; \
pDfEntry->dfe_PrevSibling = NULL; \
pDfEntry->dfe_AfpId = AFP_ID_PARENT_OF_ROOT; \
pDfEntry->dfe_DirOffspring = pDfEntry->dfe_FileOffspring = 0;\
\
/* link it into the hash buckets */ \
_DfeDirBucketStart = (_pVolDesc)->vds_pDfeDirBucketStart; \
AfpLinkDoubleAtHead(_DfeDirBucketStart[HASH_DIR_ID(AFP_ID_PARENT_OF_ROOT,_pVolDesc)],\
pDfEntry, \
dfe_NextOverflow, \
dfe_PrevOverflow); \
} \
}
#endif
#define afpHashUnicodeName(_pUnicodeName, _pHashValue) \
{ \
DWORD j; \
UNICODE_STRING upcaseName; \
WCHAR buffer[AFP_LONGNAME_LEN+1]; \
PDWORD pbuf = NULL; \
\
AfpSetEmptyUnicodeString(&upcaseName, sizeof(buffer), buffer); \
RtlUpcaseUnicodeString(&upcaseName, _pUnicodeName, False); \
j = upcaseName.Length/sizeof(WCHAR); \
buffer[j] = UNICODE_NULL; \
pbuf = (PDWORD)buffer; \
j /= (sizeof(DWORD)/sizeof(WCHAR)); \
\
for (*(_pHashValue) = 0; j > 0; j--, pbuf++) \
{ \
*(_pHashValue) = (*(_pHashValue) << 3) + *pbuf; \
} \
}
#ifdef SORT_DFE_BY_HASH
#define afpFindDFEByUnicodeNameInSiblingList(_pVolDesc, _pDfeParent, _pName, _ppDfEntry, _EntityMask) \
{ \
DWORD NameHash; \
PDFENTRY pD, pF; \
BOOLEAN Found, fFiles; \
\
afpHashUnicodeName(_pName, &NameHash); \
\
pD = (_pDfeParent)->dfe_pDirEntry->de_ChildDir; \
if (((_EntityMask) & (DFE_ANY | DFE_DIR)) == 0) \
pD = NULL; \
\
pF = NULL; \
if ((_EntityMask) & (DFE_ANY | DFE_FILE)) \
pF = (_pDfeParent)->dfe_pDirEntry->de_ChildFile[NameHash % MAX_CHILD_HASH_BUCKETS];\
\
*(_ppDfEntry) = pD; \
Found = fFiles = False; \
do \
{ \
for (NOTHING; \
*(_ppDfEntry) != NULL; \
*(_ppDfEntry) = (*(_ppDfEntry))->dfe_NextSibling) \
{ \
if ((*(_ppDfEntry))->dfe_NameHash < NameHash) \
{ \
*(_ppDfEntry) = NULL; \
break; \
} \
\
if (((*(_ppDfEntry))->dfe_NameHash == NameHash) && \
EQUAL_UNICODE_STRING(&((*(_ppDfEntry))->dfe_UnicodeName), \
_pName, \
True)) \
{ \
afpUpdateDfeAccessTime(_pVolDesc, *(_ppDfEntry)); \
Found = True; \
break; \
} \
} \
if (Found) \
break; \
\
fFiles ^= True; \
if (fFiles) \
{ \
*(_ppDfEntry) = pF; \
} \
} while (fFiles); \
}
#define afpFindDFEByUnicodeNameInSiblingList_CS(_pVolDesc, _pDfeParent, _pName, _ppDfEntry, _EntityMask) \
{ \
DWORD NameHash; \
PDFENTRY pD, pF; \
BOOLEAN Found, fFiles; \
\
afpHashUnicodeName(_pName, &NameHash); \
\
pD = (_pDfeParent)->dfe_pDirEntry->de_ChildDir; \
if (((_EntityMask) & (DFE_ANY | DFE_DIR)) == 0) \
pD = NULL; \
\
pF = NULL; \
if ((_EntityMask) & (DFE_ANY | DFE_FILE)) \
pF = (_pDfeParent)->dfe_pDirEntry->de_ChildFile[NameHash % MAX_CHILD_HASH_BUCKETS];\
\
*(_ppDfEntry) = pD; \
Found = fFiles = False; \
do \
{ \
for (NOTHING; \
*(_ppDfEntry) != NULL; \
*(_ppDfEntry) = (*(_ppDfEntry))->dfe_NextSibling) \
{ \
if ((*(_ppDfEntry))->dfe_NameHash < NameHash) \
{ \
*(_ppDfEntry) = NULL; \
break; \
} \
\
if (((*(_ppDfEntry))->dfe_NameHash == NameHash) && \
EQUAL_UNICODE_STRING_CS(&((*(_ppDfEntry))->dfe_UnicodeName), _pName)) \
{ \
afpUpdateDfeAccessTime(_pVolDesc, *(_ppDfEntry)); \
Found = True; \
break; \
} \
} \
if (Found) \
break; \
\
fFiles ^= True; \
if (fFiles) \
{ \
*(_ppDfEntry) = pF; \
} \
} while (fFiles); \
}
#else
#define afpFindDFEByUnicodeNameInSiblingList(_pVolDesc, _pDfeParent, _pName, _ppDfEntry, _EntityMask) \
{ \
DWORD NameHash; \
PDFENTRY pD, pF; \
BOOLEAN Found, fFiles; \
\
afpHashUnicodeName(_pName, &NameHash); \
\
pD = (_pDfeParent)->dfe_pDirEntry->de_ChildDir; \
if (((_EntityMask) & (DFE_ANY | DFE_DIR)) == 0) \
pD = NULL; \
\
pF = NULL; \
if ((_EntityMask) & (DFE_ANY | DFE_FILE)) \
pF = (_pDfeParent)->dfe_pDirEntry->de_ChildFile[NameHash % MAX_CHILD_HASH_BUCKETS];\
\
*(_ppDfEntry) = pD; \
Found = fFiles = False; \
do \
{ \
for (NOTHING; \
*(_ppDfEntry) != NULL; \
*(_ppDfEntry) = (*(_ppDfEntry))->dfe_NextSibling) \
{ \
if (((*(_ppDfEntry))->dfe_NameHash == NameHash) && \
EQUAL_UNICODE_STRING(&((*(_ppDfEntry))->dfe_UnicodeName), \
_pName, \
True)) \
{ \
afpUpdateDfeAccessTime(_pVolDesc, *(_ppDfEntry)); \
Found = True; \
break; \
} \
} \
if (Found) \
break; \
\
fFiles ^= True; \
if (fFiles) \
{ \
*(_ppDfEntry) = pF; \
} \
} while (fFiles); \
}
#define afpFindDFEByUnicodeNameInSiblingList_CS(_pVolDesc, _pDfeParent, _pName, _ppDfEntry, _EntityMask) \
{ \
DWORD NameHash; \
PDFENTRY pD, pF; \
BOOLEAN Found, fFiles; \
\
afpHashUnicodeName(_pName, &NameHash); \
\
pD = (_pDfeParent)->dfe_pDirEntry->de_ChildDir; \
if (((_EntityMask) & (DFE_ANY | DFE_DIR)) == 0) \
pD = NULL; \
\
pF = NULL; \
if ((_EntityMask) & (DFE_ANY | DFE_FILE)) \
pF = (_pDfeParent)->dfe_pDirEntry->de_ChildFile[NameHash % MAX_CHILD_HASH_BUCKETS];\
\
*(_ppDfEntry) = pD; \
Found = fFiles = False; \
do \
{ \
for (NOTHING; \
*(_ppDfEntry) != NULL; \
*(_ppDfEntry) = (*(_ppDfEntry))->dfe_NextSibling) \
{ \
if (((*(_ppDfEntry))->dfe_NameHash == NameHash) && \
EQUAL_UNICODE_STRING_CS(&((*(_ppDfEntry))->dfe_UnicodeName), _pName)) \
{ \
afpUpdateDfeAccessTime(_pVolDesc, *(_ppDfEntry)); \
Found = True; \
break; \
} \
} \
if (Found) \
break; \
\
fFiles ^= True; \
if (fFiles) \
{ \
*(_ppDfEntry) = pF; \
} \
} while (fFiles); \
}
#endif
#define afpInsertDFEInSiblingList(_pDfeParent, _pDfEntry, _fDirectory) \
{ \
if (fDirectory) \
{ \
afpInsertDirDFEInSiblingList(_pDfeParent, _pDfEntry); \
} \
else \
{ \
afpInsertFileDFEInSiblingList(_pDfeParent, _pDfEntry); \
} \
}
#define afpInsertFileDFEInSiblingList(_pDfeParent, _pDfEntry) \
{ \
DWORD Index; \
PDFENTRY * ppDfEntry; \
\
Index = (_pDfEntry)->dfe_NameHash % MAX_CHILD_HASH_BUCKETS; \
ppDfEntry = &(_pDfeParent)->dfe_pDirEntry->de_ChildFile[Index]; \
afpInsertInSiblingList(ppDfEntry, \
(_pDfEntry)); \
}
#define afpInsertDirDFEInSiblingList(_pDfeParent, _pDfEntry) \
{ \
PDFENTRY * ppDfEntry; \
\
ppDfEntry = &(_pDfeParent)->dfe_pDirEntry->de_ChildDir; \
afpInsertInSiblingList(ppDfEntry, \
(_pDfEntry)); \
}
#ifdef SORT_DFE_BY_HASH
#define afpInsertInSiblingList(_ppHead, _pDfEntry) \
{ \
for (NOTHING; \
*(_ppHead) != NULL; \
(_ppHead) = &(*(_ppHead))->dfe_NextSibling) \
{ \
if ((_pDfEntry)->dfe_NameHash > (*(_ppHead))->dfe_NameHash) \
{ \
break; \
} \
} \
if (*(_ppHead) != NULL) \
{ \
AfpInsertDoubleBefore(_pDfEntry, \
*(_ppHead), \
dfe_NextSibling, \
dfe_PrevSibling); \
} \
else \
{ \
*(_ppHead) = (_pDfEntry); \
(_pDfEntry)->dfe_NextSibling = NULL; \
(_pDfEntry)->dfe_PrevSibling = (_ppHead); \
} \
}
#else
#define afpInsertInSiblingList(_ppHead, _pDfEntry) \
{ \
AfpLinkDoubleAtHead(*(_ppHead), \
(_pDfEntry), \
dfe_NextSibling, \
dfe_PrevSibling); \
}
#endif
#define afpInsertDFEInHashBucket(_pVolDesc, _pDfEntry, _fDirectory, _pfS)\
{ \
PDFENTRY *ppTmp; \
struct _DirFileEntry ** _DfeDirBucketStart; \
struct _DirFileEntry ** _DfeFileBucketStart; \
\
afpUpdateDfeAccessTime(_pVolDesc, _pDfEntry); \
*(_pfS) = True; /* Assume success */ \
\
retry: \
\
if (_fDirectory) \
{ \
_DfeDirBucketStart = (_pVolDesc)->vds_pDfeDirBucketStart; \
ppTmp = &_DfeDirBucketStart[HASH_DIR_ID((_pDfEntry)->dfe_AfpId,_pVolDesc)]; \
} \
else \
{ \
_DfeFileBucketStart = (_pVolDesc)->vds_pDfeFileBucketStart; \
ppTmp = &_DfeFileBucketStart[HASH_FILE_ID((_pDfEntry)->dfe_AfpId,_pVolDesc)]; \
} \
\
for (NOTHING; \
*ppTmp != NULL; \
ppTmp = &(*ppTmp)->dfe_NextOverflow) \
{ \
ASSERT(VALID_DFE(*ppTmp)); \
if ((_pDfEntry)->dfe_AfpId > (*ppTmp)->dfe_AfpId) \
{ \
/* Found our slot */ \
break; \
} \
if ((_pDfEntry)->dfe_AfpId == (*ppTmp)->dfe_AfpId) \
{ \
/* Found a collision. Assign a new id and proceed */ \
(_pDfEntry)->dfe_AfpId = afpGetNextId(_pVolDesc); \
if ((_pDfEntry)->dfe_AfpId == 0) \
{ \
/* Uh-oh */ \
*(_pfS) = False; \
DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_ERR, \
("afpInsertDFEInHashBucket: Collision & Id Overflow\n"));\
break; \
} \
/* Write back the afpinfo stream with the new id */ \
AfpUpdateIdInAfpInfo(_pVolDesc, _pDfEntry); \
goto retry; \
} \
} \
if (*(_pfS)) \
{ \
if (*ppTmp != NULL) \
{ \
AfpInsertDoubleBefore((_pDfEntry), \
*ppTmp, \
dfe_NextOverflow, \
dfe_PrevOverflow); \
} \
else \
{ \
*ppTmp = _pDfEntry; \
(_pDfEntry)->dfe_PrevOverflow = ppTmp; \
} \
(_pVolDesc)->vds_pDfeCache[HASH_CACHE_ID((_pDfEntry)->dfe_AfpId)] = (_pDfEntry); \
} \
}
#define afpValidateDFEType(_pDfEntry, _EntityMask) \
{ \
if (((_EntityMask) & DFE_ANY) || \
(((_EntityMask) & DFE_DIR) && DFE_IS_DIRECTORY(_pDfEntry)) || \
(((_EntityMask) & DFE_FILE) && DFE_IS_FILE(_pDfEntry))) \
NOTHING; \
else \
{ \
_pDfEntry = NULL; \
} \
}
/*** afpCheckDfEntry
*
* When enumerating the disk during volume add, if a file/directory
* has an AfpId associated with it, then it is validated to see if it is
* within range as well as unique. If there is a collision between AFPIds,
* a PC user must have copied (or restored) something from
* this volume, or a different volume (or server) that had the same AFPId,
* in which case we will give the new entity a different AFP Id;
* If there is not a collision between AFPIds, and the Id is larger than the
* last Id we know we assigned, then the new entity gets added with a new
* AFPId; else if the Id is within the range, we will just use its existing
* Id.
*
* Discovered AFPId is: Action for discovered entity in IdDb is:
* -------------------- ----------------------------------------
* 1) > last Id Add a new entry, assign a new AFPId
*
* 2) Collides with existing Id:
* * Host copy occurred Add a new entry, assign a new AFPId
*
* 3) < last Id Insert this entity using same AFPId
*
*
* LOCKS_ASSUMED: vds_idDbAccessLock (SWMR, Exclusive)
* VOID
* afpCheckDfEntry(
* IN PVOLDESC pVolDesc,
* IN PAFPINFO pAfpInfo, // AFP Info of the discovered entity
* IN PUNICODE_STRING pUName, // Munged unicode name
* IN BOOLEAN IsDir, // is this thing a file or a directory?
* IN PDFENTRY pParent, // parent DFE of the discovered thing
* OUT PDFENTRY * ppDfEntry
* );
*/
#define afpCheckDfEntry(_pVolDesc, _AfpId, _pUName, _IsDir, _pParent, _ppDfEntry) \
{ \
PDFENTRY pDfeNew; \
\
if (((_AfpId) > (_pVolDesc)->vds_LastId) || \
((_AfpId) <= AFP_ID_NETWORK_TRASH) || \
(AfpFindDfEntryById(_pVolDesc, _AfpId, DFE_ANY) != NULL)) \
{ \
/* add the item to the DB but assign it a new AFP Id */ \
_AfpId = 0; \
} \
\
pDfeNew = AfpAddDfEntry(_pVolDesc, \
_pParent, \
_pUName, \
_IsDir, \
_AfpId); \
\
*(_ppDfEntry) = pDfeNew; \
}
#ifdef AGE_DFES
#define afpUpdateDfeAccessTime(_pVolDesc, _pDfEntry) \
{ \
if (IS_VOLUME_AGING_DFES(_pVolDesc)) \
{ \
if (DFE_IS_DIRECTORY(_pDfEntry)) \
AfpGetCurrentTimeInMacFormat(&(_pDfEntry)->dfe_pDirEntry->de_LastAccessTime);\
else AfpGetCurrentTimeInMacFormat(&(_pDfEntry)->dfe_Parent->dfe_pDirEntry->de_LastAccessTime);\
} \
}
#else
#define afpUpdateDfeAccessTime(pVolDesc, pDfEntry)
#endif
#define afpMarkAllChildrenUnseen(_pDFETree) \
{ \
LONG i = -1; \
PDFENTRY pDFE; \
\
/* \
* Even if this dir has not had its file children cached in \
* yet, we still want to prune out any dead directory children \
*/ \
for (pDFE = (_pDFETree)->dfe_pDirEntry->de_ChildDir; \
True; \
pDFE = (_pDFETree)->dfe_pDirEntry->de_ChildFile[i]) \
{ \
for (NOTHING; \
pDFE != NULL; \
pDFE = pDFE->dfe_NextSibling) \
{ \
DFE_MARK_UNSEEN(pDFE); \
} \
if (++i == MAX_CHILD_HASH_BUCKETS) \
break; \
} \
}
#define afpPruneUnseenChildren(_pVolDesc, _pDFETree) \
{ \
PDFENTRY pDFE, *ppDfEntry; \
LONG i; \
\
/* \
* Go thru the list of children for this parent, and if there \
* are any left that are not marked as seen, get rid of them. \
*/ \
ppDfEntry = &(_pDFETree)->dfe_pDirEntry->de_ChildDir; \
i = -1; \
while (True) \
{ \
while ((pDFE = *ppDfEntry) != NULL) \
{ \
if (!DFE_HAS_BEEN_SEEN(pDFE)) \
{ \
DBGPRINT(DBG_COMP_IDINDEX, DBG_LEVEL_INFO, \
("afpPruneUnseenChildren: deleting nonexistant IdDb entry\n")); \
\
AfpDeleteDfEntry(_pVolDesc, pDFE); \
continue; /* make sure we don't skip any */ \
} \
ppDfEntry = &pDFE->dfe_NextSibling; \
} \
if (++i == MAX_CHILD_HASH_BUCKETS) \
{ \
break; \
} \
ppDfEntry = &(_pDFETree)->dfe_pDirEntry->de_ChildFile[i]; \
} \
}
#define afpUpdateDfeWithSavedData(_pDfe, _pDiskEnt) \
{ \
(_pDfe)->dfe_Flags |= (_pDiskEnt)->dsk_Flags & DFE_FLAGS_CSENCODEDBITS;\
(_pDfe)->dfe_AfpAttr = (_pDiskEnt)->dsk_AfpAttr; \
(_pDfe)->dfe_NtAttr = (_pDiskEnt)->dsk_NtAttr; \
(_pDfe)->dfe_CreateTime = (_pDiskEnt)->dsk_CreateTime; \
(_pDfe)->dfe_LastModTime = (_pDiskEnt)->dsk_LastModTime; \
(_pDfe)->dfe_BackupTime = (_pDiskEnt)->dsk_BackupTime; \
(_pDfe)->dfe_FinderInfo = (_pDiskEnt)->dsk_FinderInfo; \
if (DFE_IS_DIRECTORY((_pDfe))) \
{ \
(_pDfe)->dfe_pDirEntry->de_Access = (_pDiskEnt)->dsk_Access;\
} \
else \
{ \
(_pDfe)->dfe_DataLen = (_pDiskEnt)->dsk_DataLen; \
(_pDfe)->dfe_RescLen = (_pDiskEnt)->dsk_RescLen; \
} \
}
#define afpSaveDfeData(_pDfe, _pDiskEnt) \
{ \
/* Write a signature for sanity checking */ \
(_pDiskEnt)->dsk_Signature = AFP_DISKENTRY_SIGNATURE; \
\
(_pDiskEnt)->dsk_AfpId = (_pDfe)->dfe_AfpId; \
(_pDiskEnt)->dsk_AfpAttr = (_pDfe)->dfe_AfpAttr; \
(_pDiskEnt)->dsk_NtAttr = (_pDfe)->dfe_NtAttr; \
(_pDiskEnt)->dsk_BackupTime = (_pDfe)->dfe_BackupTime; \
(_pDiskEnt)->dsk_CreateTime = (_pDfe)->dfe_CreateTime; \
(_pDiskEnt)->dsk_LastModTime = (_pDfe)->dfe_LastModTime; \
(_pDiskEnt)->dsk_FinderInfo = (_pDfe)->dfe_FinderInfo; \
\
/* Encode the number of characters (not bytes) in the name */ \
(_pDiskEnt)->dsk_Flags = \
((_pDfe)->dfe_Flags & DFE_FLAGS_DFBITS) | \
((_pDfe)->dfe_UnicodeName.Length/sizeof(WCHAR)); \
\
/* Copy the name over */ \
RtlCopyMemory(&(_pDiskEnt)->dsk_Name[0], \
(_pDfe)->dfe_UnicodeName.Buffer, \
(_pDfe)->dfe_UnicodeName.Length); \
}
// File DFEs are aged after MAX_BLOCK_AGE*FILE_BLOCK_AGE_TIME seconds (currently 2 mins)
// File DFEs are aged after MAX_BLOCK_AGE*DIR_BLOCK_AGE_TIME seconds (currently 6 mins)
#define MAX_BLOCK_AGE 6
#define FILE_BLOCK_AGE_TIME 600 // # of seconds
#define DIR_BLOCK_AGE_TIME 3600 // # of seconds
#define BLOCK_64K_ALLOC 64*1024 // Virtual mem allocates 64K chunks
#define MAX_BLOCK_TYPE 4 // For TINY, SMALL, MEDIUM & LARGE
#define VALID_DFB(pDfeBlock) ((pDfeBlock) != NULL)
typedef struct _Block64K
{
struct _Block64K *b64_Next;
PBYTE b64_BaseAddress;
DWORD b64_PagesFree;
BYTE b64_PageInUse[BLOCK_64K_ALLOC/PAGE_SIZE];
} BLOCK64K, *PBLOCK64K;
typedef struct _DfeBlock
{
struct _DfeBlock * dfb_Next; // Link to next
struct _DfeBlock ** dfb_Prev; // Link to previous
USHORT dfb_NumFree; // # of free DFEs in this block
BYTE dfb_Age; // Age of the Block if all are free
BOOLEAN dfb_fDir; // TRUE if it is a Dir DFB - else a file DFB
PDFENTRY dfb_FreeHead; // Head of the list of free DFEs
} DFEBLOCK, *PDFEBLOCK, **PPDFEBLOCK;
LOCAL PDFENTRY FASTCALL
afpAllocDfe(
IN LONG Index,
IN BOOLEAN fDir
);
LOCAL VOID FASTCALL
afpFreeDfe(
IN PDFENTRY pDfEntry
);
LOCAL AFPSTATUS FASTCALL
afpDfeBlockAge(
IN PPDFEBLOCK pBlockHead
);
#if DBG
VOID FASTCALL
afpDisplayDfe(
IN PDFENTRY pDfEntry
);
NTSTATUS FASTCALL
afpDumpDfeTree(
IN PVOID Context
);
#endif
IDDBGLOBAL PBLOCK64K afp64kBlockHead EQU NULL;
IDDBGLOBAL PDFEBLOCK afpDirDfeFreeBlockHead[MAX_BLOCK_TYPE] EQU { NULL, NULL, NULL };
IDDBGLOBAL PDFEBLOCK afpDirDfePartialBlockHead[MAX_BLOCK_TYPE] EQU { NULL, NULL, NULL };
IDDBGLOBAL PDFEBLOCK afpDirDfeUsedBlockHead[MAX_BLOCK_TYPE] EQU { NULL, NULL, NULL };
IDDBGLOBAL PDFEBLOCK afpFileDfeFreeBlockHead[MAX_BLOCK_TYPE] EQU { NULL, NULL, NULL };
IDDBGLOBAL PDFEBLOCK afpFileDfePartialBlockHead[MAX_BLOCK_TYPE] EQU { NULL, NULL, NULL };
IDDBGLOBAL PDFEBLOCK afpFileDfeUsedBlockHead[MAX_BLOCK_TYPE] EQU { NULL, NULL, NULL };
IDDBGLOBAL USHORT afpDfeUnicodeBufSize[MAX_BLOCK_TYPE] EQU \
{ \
DFE_SIZE_TINY_U, DFE_SIZE_SMALL_U, \
DFE_SIZE_MEDIUM_U, DFE_SIZE_LARGE_U \
};
IDDBGLOBAL USHORT afpDfeFileBlockSize[MAX_BLOCK_TYPE] EQU \
{ \
sizeof(DFENTRY) + DFE_SIZE_TINY_U, \
sizeof(DFENTRY) + DFE_SIZE_SMALL_U, \
sizeof(DFENTRY) + DFE_SIZE_MEDIUM_U, \
sizeof(DFENTRY) + DFE_SIZE_LARGE_U \
};
IDDBGLOBAL USHORT afpDfeDirBlockSize[MAX_BLOCK_TYPE] EQU \
{ \
(USHORT)(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_TINY_U), \
(USHORT)(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_SMALL_U), \
(USHORT)(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_MEDIUM_U), \
(USHORT)(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_LARGE_U) \
};
IDDBGLOBAL USHORT afpDfeNumFileBlocks[MAX_BLOCK_TYPE] EQU \
{ \
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + DFE_SIZE_TINY_U), \
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + DFE_SIZE_SMALL_U), \
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + DFE_SIZE_MEDIUM_U), \
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + DFE_SIZE_LARGE_U) \
};
IDDBGLOBAL USHORT afpDfeNumDirBlocks[MAX_BLOCK_TYPE] EQU \
{ \
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_TINY_U), \
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_SMALL_U),\
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_MEDIUM_U),\
(PAGE_SIZE - sizeof(DFEBLOCK))/ \
(sizeof(DFENTRY) + sizeof(DIRENTRY) + DFE_SIZE_LARGE_U) \
};
IDDBGLOBAL SWMR afpDfeBlockLock EQU { 0 };
#if DBG
IDDBGLOBAL LONG afpDfeAllocCount EQU 0;
IDDBGLOBAL LONG afpDfbAllocCount EQU 0;
IDDBGLOBAL LONG afpDfe64kBlockCount EQU 0;
IDDBGLOBAL BOOLEAN afpDumpDfeTreeFlag EQU 0;
IDDBGLOBAL PDFENTRY afpDfeStack[4096] EQU { 0 };
#endif
#undef EQU
#ifdef _GLOBALS_
#define EQU =
#else
#define EQU ; / ## /
#endif
#endif // IDINDEX_LOCALS
#endif // _IDINDEX_