Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
11 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: fcbsup.c
  6. //
  7. // Contents: Support routines for associating DFS_FCB records with
  8. // file objects, and looking them up again.
  9. //
  10. // Functions: DfsInitFcbs - Initialize the hash table for DFS_FCB lookup
  11. // DfsLookupFcb - Lookup an DFS_FCB associated with a file object
  12. // DfsAttachFcb - Associate an DFS_FCB with a file object
  13. // DfsDetachFcb - Remove the Association between an DFS_FCB and
  14. // a file object
  15. // DfsAllocateFcb - Allocate an FCB
  16. // DfsDestroyFcb - Deallocate an FCB
  17. //
  18. //--------------------------------------------------------------------------
  19. #include "dfsprocs.h"
  20. #include "attach.h"
  21. #include "fcbsup.h"
  22. #define Dbg 0x1000
  23. #define HASH(k,m) (((ULONG_PTR)(k)>>12^(ULONG_PTR)(k)>>2) & m)
  24. #define DEFAULT_HASH_SIZE 16 // default size of hash table
  25. NTSTATUS
  26. DfsInitFcbHashTable(
  27. IN ULONG cHash,
  28. OUT PFCB_HASH_TABLE *ppHashTable);
  29. #ifdef ALLOC_PRAGMA
  30. #pragma alloc_text(INIT, DfsInitFcbs)
  31. #pragma alloc_text(PAGE, DfsUninitFcbs)
  32. #pragma alloc_text(PAGE, DfsInitFcbHashTable)
  33. //
  34. // The following routines are not pageable because they acquire spinlocks.
  35. //
  36. // DfsLookupFcb
  37. // DfsAttachFcb
  38. // DfsDetachFcb
  39. //
  40. #endif
  41. //+-------------------------------------------------------------------------
  42. //
  43. // Function: DfsInitFcbs - Initialize the DFS_FCB lookup hash table
  44. //
  45. // Synopsis: This function initializes data structures which are
  46. // used for looking up an DFS_FCB associated with some open
  47. // file object.
  48. //
  49. // Arguments: [cHash] -- Size of the hash table to be allocated. Must be
  50. // a power of two. If zero, a default size is used.
  51. //
  52. // Returns: NTSTATUS -- STATUS_SUCCESS, unless memory allocation
  53. // fails.
  54. //
  55. // Note: The hash buckets are initialized to zero, then later
  56. // initialized to a list head when used. This is a debugging
  57. // aid to determine if some hash buckets are never used.
  58. //
  59. //--------------------------------------------------------------------------
  60. NTSTATUS
  61. DfsInitFcbHashTable(
  62. IN ULONG cHash,
  63. OUT PFCB_HASH_TABLE *ppHashTable)
  64. {
  65. PFCB_HASH_TABLE pHashTable;
  66. ULONG cbHashTable;
  67. if (cHash == 0) {
  68. cHash = DEFAULT_HASH_SIZE;
  69. }
  70. ASSERT ((cHash & (cHash-1)) == 0); // Assure cHash is a power of two
  71. cbHashTable = sizeof (FCB_HASH_TABLE) + (cHash-1)*sizeof (LIST_ENTRY);
  72. pHashTable = ExAllocatePoolWithTag(NonPagedPool, cbHashTable, ' sfD');
  73. if (pHashTable == NULL) {
  74. return STATUS_NO_MEMORY;
  75. }
  76. pHashTable->NodeTypeCode = DFS_NTC_FCB_HASH;
  77. pHashTable->NodeByteSize = (NODE_BYTE_SIZE) cbHashTable;
  78. pHashTable->HashMask = (cHash-1);
  79. KeInitializeSpinLock( &pHashTable->HashListSpinLock );
  80. RtlZeroMemory(&pHashTable->HashBuckets[0], cHash * sizeof (LIST_ENTRY));
  81. *ppHashTable = pHashTable;
  82. return(STATUS_SUCCESS);
  83. }
  84. NTSTATUS
  85. DfsInitFcbs(
  86. IN ULONG cHash
  87. ) {
  88. NTSTATUS status;
  89. status = DfsInitFcbHashTable( cHash, &DfsData.FcbHashTable );
  90. return status;
  91. }
  92. VOID
  93. DfsUninitFcbs(
  94. VOID
  95. ) {
  96. ExFreePool (DfsData.FcbHashTable);
  97. }
  98. //+-------------------------------------------------------------------------
  99. //
  100. // Function: DfsLookupFcb - Lookup an DFS_FCB in the hash table
  101. //
  102. // Synopsis: This function will lookup the DFS_FCB associated with
  103. // a particular file object.
  104. //
  105. // Arguments: [pFile] -- Pointer to file object for which the DFS_FCB is
  106. // being looked up.
  107. //
  108. // Returns: PVOID -- pointer to the DFS_FCB found, or NULL if none
  109. //
  110. // Algorithm: Knuth would call it hashing with conflict resoulution
  111. // by chaining.
  112. //
  113. // History: 20 Feb 1993 Alanw Created
  114. //
  115. //--------------------------------------------------------------------------
  116. PDFS_FCB
  117. DfsLookupFcb(
  118. IN PFILE_OBJECT pFile
  119. ) {
  120. PLIST_ENTRY pListHead, pLink;
  121. PDFS_FCB pFCB;
  122. KIRQL SavedIrql;
  123. PFCB_HASH_TABLE pHashTable = DfsData.FcbHashTable;
  124. KeAcquireSpinLock( &pHashTable->HashListSpinLock, &SavedIrql );
  125. pListHead = &pHashTable->HashBuckets[ HASH(pFile, pHashTable->HashMask) ];
  126. if ((pListHead->Flink == NULL) || // list not initialized
  127. (pListHead->Flink == pListHead)) { // list empty
  128. KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
  129. return NULL;
  130. }
  131. for (pLink = pListHead->Flink; pLink != pListHead; pLink = pLink->Flink) {
  132. pFCB = CONTAINING_RECORD(pLink, DFS_FCB, HashChain);
  133. if (pFCB->FileObject == pFile) {
  134. KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
  135. return pFCB;
  136. }
  137. }
  138. KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
  139. return NULL;
  140. }
  141. //+-------------------------------------------------------------------------
  142. //
  143. // Function: DfsAttachFcb - Inserts an DFS_FCB into the hash table
  144. //
  145. // Synopsis: This function associates an DFS_FCB to a file object. This
  146. // involves inserting it into the hash table.
  147. //
  148. // Arguments: [pFCB] -- Pointer to the DFS_FCB to be inserted.
  149. // [pFileObj] -- Pointer to the corresponding file object, used
  150. // as the hash key.
  151. //
  152. // Returns: -nothing-
  153. //
  154. //--------------------------------------------------------------------------
  155. VOID
  156. DfsAttachFcb(
  157. IN PFILE_OBJECT pFileObj,
  158. IN PDFS_FCB pFCB
  159. ) {
  160. PFCB_HASH_TABLE pHashTable = (PFCB_HASH_TABLE) DfsData.FcbHashTable;
  161. PLIST_ENTRY pListHead;
  162. KIRQL SavedIrql;
  163. KeAcquireSpinLock( &pHashTable->HashListSpinLock, &SavedIrql );
  164. pListHead = &pHashTable->HashBuckets[ HASH(pFileObj, pHashTable->HashMask) ];
  165. if (pListHead->Flink == NULL) {
  166. InitializeListHead(pListHead);
  167. }
  168. InsertHeadList(pListHead, &pFCB->HashChain);
  169. KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
  170. DebugTrace(0, Dbg, "Attached Fcb %08lx ", pFCB);
  171. DebugTrace(0, Dbg, "For Fileobject %08lx ", pFileObj);
  172. }
  173. //+-------------------------------------------------------------------------
  174. //
  175. // Function: DfsDetachFcb - Detach an DFS_FCB from the lookup hash table
  176. //
  177. // Synopsis: This function detaches an DFS_FCB from the hash table. This
  178. // involves just deleting it from the hash bucket chain.
  179. //
  180. // Arguments: [pFCB] -- Pointer to the DFS_FCB to be detached.
  181. // [pFileObj] -- Pointer to the corresponding file object, used
  182. // for debugging only.
  183. //
  184. // Returns: -nothing-
  185. //
  186. //--------------------------------------------------------------------------
  187. VOID
  188. DfsDetachFcb(
  189. IN PFILE_OBJECT pFileObj,
  190. IN PDFS_FCB pFCB
  191. ) {
  192. PFCB_HASH_TABLE pHashTable = (PFCB_HASH_TABLE) DfsData.FcbHashTable;
  193. KIRQL SavedIrql;
  194. ASSERT(pFCB->FileObject == pFileObj);
  195. ASSERT(DfsLookupFcb(pFCB->FileObject) == pFCB);
  196. KeAcquireSpinLock( &pHashTable->HashListSpinLock, &SavedIrql );
  197. RemoveEntryList(&pFCB->HashChain);
  198. pFCB->FileObject = NULL;
  199. KeReleaseSpinLock( &pHashTable->HashListSpinLock, SavedIrql );
  200. DebugTrace(0, Dbg, "Detached Fcb %08lx ", pFCB);
  201. DebugTrace(0, Dbg, "For Fileobject %08lx ", pFileObj);
  202. }
  203. //+----------------------------------------------------------------------------
  204. //
  205. // Function: DfsAllocateFcb - Allocate an FCB
  206. //
  207. // Synopsis: This function allocates an FCB for a fileObject that is the
  208. // argument of a Create IRP. The most important thing this
  209. // Fcb contains is the full file name of the fileObject,
  210. // normalized for relative opens etc.
  211. //
  212. // Arguments: [DeviceObject] -- The Device on which the file is being
  213. // opened.
  214. // [FileObject] -- The file object for which the FCB is to be
  215. // allocated.
  216. // [Fcb] -- On successful return, has pointer to newly allocated
  217. // Fcb.
  218. //
  219. // Returns: [STATUS_SUCCESS] -- Successfully allocated FCB
  220. //
  221. // [STATUS_INSUFFICIENT_RESOURCES] -- Out of memory condition
  222. //
  223. //-----------------------------------------------------------------------------
  224. NTSTATUS
  225. DfsAllocateFcb(
  226. IN PDEVICE_OBJECT DeviceObject,
  227. IN PFILE_OBJECT FileObject,
  228. OUT PDFS_FCB *Fcb)
  229. {
  230. NTSTATUS status;
  231. PDFS_VOLUME_OBJECT deviceObject = (PDFS_VOLUME_OBJECT) DeviceObject;
  232. PDFS_FCB relatedFcb = NULL;
  233. PDFS_FCB fcb;
  234. PUNICODE_STRING relatedName;
  235. ULONG length;
  236. length = sizeof(DFS_FCB) +
  237. deviceObject->Provider.DeviceName.Length +
  238. sizeof(UNICODE_PATH_SEP) +
  239. FileObject->FileName.Length +
  240. sizeof(UNICODE_NULL);
  241. if (FileObject->RelatedFileObject != NULL) {
  242. relatedFcb = DfsLookupFcb( FileObject->RelatedFileObject );
  243. if (relatedFcb != NULL) {
  244. length += relatedFcb->FullFileName.Length +
  245. sizeof(UNICODE_PATH_SEP);
  246. relatedName = &relatedFcb->FullFileName;
  247. } else {
  248. length += FileObject->RelatedFileObject->FileName.Length;
  249. relatedName = &FileObject->RelatedFileObject->FileName;
  250. }
  251. } else {
  252. relatedName = NULL;
  253. }
  254. if (length <= MAXUSHORT) {
  255. fcb = (PDFS_FCB) ExAllocatePoolWithTag( NonPagedPool, length, ' sfD' );
  256. if (fcb != NULL) {
  257. RtlZeroMemory( fcb, length );
  258. fcb->NodeTypeCode = DFS_NTC_FCB;
  259. fcb->NodeByteSize = (USHORT)length;
  260. fcb->FullFileName.Length = 0;
  261. fcb->FullFileName.MaximumLength = (USHORT) (length - sizeof(DFS_FCB));
  262. fcb->FullFileName.Buffer = (PWCHAR) (fcb + 1);
  263. if (relatedName == NULL) {
  264. RtlCopyUnicodeString(
  265. &fcb->FullFileName,
  266. &deviceObject->Provider.DeviceName);
  267. } else {
  268. RtlCopyUnicodeString(
  269. &fcb->FullFileName,
  270. relatedName);
  271. }
  272. DfsConcatenateFilePath(
  273. &fcb->FullFileName,
  274. FileObject->FileName.Buffer,
  275. FileObject->FileName.Length);
  276. fcb->FileObject = FileObject;
  277. *Fcb = fcb;
  278. status = STATUS_SUCCESS;
  279. } else {
  280. status = STATUS_INSUFFICIENT_RESOURCES;
  281. }
  282. } else {
  283. status = STATUS_INSUFFICIENT_RESOURCES;
  284. }
  285. return( status );
  286. }
  287. //+----------------------------------------------------------------------------
  288. //
  289. // Function: DfsDestroyFcb
  290. //
  291. // Synopsis: Destroys an FCB allocated by DfsAllocateFcb
  292. //
  293. // Arguments: [Fcb] -- The Fcb to destroy.
  294. //
  295. // Returns: Nothing
  296. //
  297. //-----------------------------------------------------------------------------
  298. VOID
  299. DfsDestroyFcb(
  300. IN PDFS_FCB Fcb)
  301. {
  302. //
  303. // Make sure its gone from our Fcb tables
  304. //
  305. ASSERT( DfsLookupFcb( Fcb->FileObject ) != Fcb );
  306. //
  307. // Now, free it up.
  308. //
  309. ExFreePool( Fcb );
  310. }