/* 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_