Leaked source code of windows server 2003
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.

3096 lines
94 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. openclos.c
  5. Abstract:
  6. This module implements the name cache for file basic and standard information.
  7. Author:
  8. Yun Lin [YunLin] 2-Octorber-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "smbce.h"
  13. #pragma hdrstop
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, MRxSmbIsStreamFile)
  16. #pragma alloc_text(PAGE, MRxSmbCacheFileNotFound)
  17. #pragma alloc_text(PAGE, MRxSmbCreateFileInfoCache)
  18. #pragma alloc_text(PAGE, MRxSmbIsFileInfoCacheFound)
  19. #pragma alloc_text(PAGE, MRxSmbInvalidateFileInfoCache)
  20. #pragma alloc_text(PAGE, MRxSmbUpdateBasicFileInfoCache)
  21. #pragma alloc_text(PAGE, MRxSmbCreateBasicFileInfoCache)
  22. #pragma alloc_text(PAGE, MRxSmbUpdateFileInfoCacheStatus)
  23. #pragma alloc_text(PAGE, MRxSmbCreateStandardFileInfoCache)
  24. #pragma alloc_text(PAGE, MRxSmbUpdateFileInfoCacheFileSize)
  25. #pragma alloc_text(PAGE, MRxSmbUpdateStandardFileInfoCache)
  26. #pragma alloc_text(PAGE, MRxSmbInvalidateFileNotFoundCache)
  27. #pragma alloc_text(PAGE, MRxSmbUpdateBasicFileInfoCacheAll)
  28. #pragma alloc_text(PAGE, MRxSmbInvalidateBasicFileInfoCache)
  29. #pragma alloc_text(PAGE, MRxSmbUpdateBasicFileInfoCacheStatus)
  30. #pragma alloc_text(PAGE, MRxSmbInvalidateStandardFileInfoCache)
  31. #pragma alloc_text(PAGE, MRxSmbInvalidateInternalFileInfoCache)
  32. #pragma alloc_text(PAGE, MRxSmbUpdateStandardFileInfoCacheStatus)
  33. #endif
  34. extern FAST_MUTEX MRxSmbFileInfoCacheLock;
  35. VOID
  36. MRxSmbCreateFileInfoCache(
  37. PRX_CONTEXT RxContext,
  38. PSMBPSE_FILEINFO_BUNDLE FileInfo,
  39. PSMBCEDB_SERVER_ENTRY pServerEntry,
  40. NTSTATUS Status
  41. )
  42. /*++
  43. Routine Description:
  44. This routine creates name cache entry for both file basic and standard information.
  45. Arguments:
  46. RxContext - the RDBSS context
  47. FileInfo - the file information package including basic and standard information
  48. Status - the status returned from server response of query file information
  49. Return Value:
  50. none
  51. --*/
  52. {
  53. PAGED_CODE();
  54. if (!pServerEntry->Server.IsLoopBack) {
  55. MRxSmbCreateBasicFileInfoCache(RxContext,&FileInfo->Basic,pServerEntry,Status);
  56. MRxSmbCreateStandardFileInfoCache(RxContext,&FileInfo->Standard,pServerEntry,Status);
  57. }
  58. }
  59. VOID
  60. MRxSmbCreateBasicFileInfoCache(
  61. PRX_CONTEXT RxContext,
  62. PFILE_BASIC_INFORMATION Basic,
  63. PSMBCEDB_SERVER_ENTRY pServerEntry,
  64. NTSTATUS Status
  65. )
  66. /*++
  67. Routine Description:
  68. This routine creates name cache entry for the file basic information.
  69. Arguments:
  70. RxContext - the RDBSS context
  71. Basic - the file basic information package
  72. Status - the status returned from server response of query file information
  73. Return Value:
  74. none
  75. --*/
  76. {
  77. RxCaptureFcb;
  78. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  79. PNAME_CACHE NameCache = NULL;
  80. PMRX_NET_ROOT NetRoot;
  81. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  82. PNAME_CACHE_CONTROL NameCacheCtl;
  83. RX_NC_CHECK_STATUS NameCacheStatus;
  84. PFILE_BASIC_INFORMATION FileInfoCache = NULL;
  85. PAGED_CODE();
  86. if (pServerEntry->Server.IsLoopBack ||
  87. (MRxSmbIsLongFileName(RxContext) &&
  88. pServerEntry->Server.Dialect != LANMAN21_DIALECT)) {
  89. return;
  90. }
  91. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  92. NetRoot = RxContext->Create.pNetRoot;
  93. } else {
  94. ASSERT(capFcb != NULL);
  95. NetRoot = capFcb->pNetRoot;
  96. }
  97. pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  98. NameCacheCtl = &pNetRootEntry->NameCacheCtlGFABasic;
  99. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  100. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  101. if (NameCache == NULL) {
  102. NameCache = RxNameCacheCreateEntry (
  103. NameCacheCtl,
  104. OriginalFileName,
  105. TRUE); // case insensitive match
  106. }
  107. if (NameCache != NULL) {
  108. FileInfoCache = (PFILE_BASIC_INFORMATION)NameCache->ContextExtension;
  109. *FileInfoCache = *Basic;
  110. NameCache->PriorStatus = Status;
  111. RxNameCacheActivateEntry(
  112. NameCacheCtl,
  113. NameCache,
  114. NAME_CACHE_OBJ_GET_FILE_ATTRIB_LIFETIME,
  115. MRxSmbStatistics.SmbsReceived.LowPart);
  116. //DbgPrint(" Create File Attrib cache : %x %wZ\n",Basic->FileAttributes,OriginalFileName);
  117. //DbgPrint(" Create File Attrib cache : %I64X %I64X %wZ\n",Basic->CreationTime,Basic->LastAccessTime,OriginalFileName);
  118. }
  119. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  120. }
  121. VOID
  122. MRxSmbCreateStandardFileInfoCache(
  123. PRX_CONTEXT RxContext,
  124. PFILE_STANDARD_INFORMATION Standard,
  125. PSMBCEDB_SERVER_ENTRY pServerEntry,
  126. NTSTATUS Status
  127. )
  128. /*++
  129. Routine Description:
  130. This routine creates name cache entry for the file standard information.
  131. Arguments:
  132. RxContext - the RDBSS context
  133. Standard - the file standard information package
  134. Status - the status returned from server response of query file information
  135. Return Value:
  136. none
  137. --*/
  138. {
  139. RxCaptureFcb;
  140. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  141. PNAME_CACHE NameCache = NULL;
  142. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  143. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  144. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAStandard;
  145. PFILE_STANDARD_INFORMATION FileInfoCache = NULL;
  146. PAGED_CODE();
  147. if (pServerEntry->Server.IsLoopBack ||
  148. (MRxSmbIsLongFileName(RxContext) &&
  149. pServerEntry->Server.Dialect != LANMAN21_DIALECT)) {
  150. return;
  151. }
  152. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  153. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  154. if (NameCache == NULL) {
  155. NameCache = RxNameCacheCreateEntry (
  156. NameCacheCtl,
  157. OriginalFileName,
  158. TRUE); // case insensitive match
  159. }
  160. if (NameCache != NULL) {
  161. FileInfoCache = (PFILE_STANDARD_INFORMATION)NameCache->ContextExtension;
  162. *FileInfoCache = *Standard;
  163. NameCache->PriorStatus = Status;
  164. RxNameCacheActivateEntry(
  165. NameCacheCtl,
  166. NameCache,
  167. NAME_CACHE_OBJ_GET_FILE_ATTRIB_LIFETIME,
  168. MRxSmbStatistics.SmbsReceived.LowPart);
  169. //DbgPrint(" Create Standard cache : %I64x %wZ\n",((PFILE_STANDARD_INFORMATION)NameCache->ContextExtension)->EndOfFile,OriginalFileName);
  170. }
  171. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  172. }
  173. VOID
  174. MRxSmbCreateInternalFileInfoCache(
  175. PRX_CONTEXT RxContext,
  176. PFILE_INTERNAL_INFORMATION Internal,
  177. PSMBCEDB_SERVER_ENTRY pServerEntry,
  178. NTSTATUS Status
  179. )
  180. /*++
  181. Routine Description:
  182. This routine creates name cache entry for the file internal information.
  183. Arguments:
  184. RxContext - the RDBSS context
  185. Standard - the file standard information package
  186. Status - the status returned from server response of query file information
  187. Return Value:
  188. none
  189. --*/
  190. {
  191. RxCaptureFcb;
  192. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  193. PNAME_CACHE NameCache = NULL;
  194. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  195. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  196. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAInternal;
  197. PFILE_INTERNAL_INFORMATION FileInfoCache = NULL;
  198. PAGED_CODE();
  199. if (pServerEntry->Server.IsLoopBack) {
  200. return;
  201. }
  202. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  203. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  204. if (NameCache == NULL) {
  205. NameCache = RxNameCacheCreateEntry (
  206. NameCacheCtl,
  207. OriginalFileName,
  208. TRUE); // case insensitive match
  209. }
  210. if (NameCache != NULL) {
  211. FileInfoCache = (PFILE_INTERNAL_INFORMATION)NameCache->ContextExtension;
  212. *FileInfoCache = *Internal;
  213. NameCache->PriorStatus = Status;
  214. RxNameCacheActivateEntry(
  215. NameCacheCtl,
  216. NameCache,
  217. NAME_CACHE_OBJ_GET_FILE_ATTRIB_LIFETIME,
  218. MRxSmbStatistics.SmbsReceived.LowPart);
  219. //DbgPrint(" Create Internal cache : %I64x %wZ\n",((PFILE_INTERNAL_INFORMATION)NameCache->ContextExtension)->IndexNumber,OriginalFileName);
  220. }
  221. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  222. }
  223. VOID
  224. MRxSmbUpdateFileInfoCacheFromDelete(
  225. PRX_CONTEXT RxContext
  226. )
  227. /*++
  228. Routine Description:
  229. This routine updates the status of the name cache entry as STATUS_OBJECT_NAME_NOT_FOUND
  230. for both file basic and standard information.
  231. Arguments:
  232. RxContext - the RDBSS context
  233. Return Value:
  234. none
  235. --*/
  236. {
  237. MRxSmbUpdateBasicFileInfoCacheStatus(RxContext,STATUS_OBJECT_NAME_NOT_FOUND);
  238. MRxSmbUpdateStandardFileInfoCacheStatus(RxContext,STATUS_OBJECT_NAME_NOT_FOUND);
  239. // Trounce FullDirCache
  240. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, FALSE);
  241. }
  242. VOID
  243. MRxSmbUpdateFileInfoCacheStatus(
  244. PRX_CONTEXT RxContext,
  245. NTSTATUS Status
  246. )
  247. /*++
  248. Routine Description:
  249. This routine updates the status of the name cache entry for both file basic and standard information.
  250. Arguments:
  251. RxContext - the RDBSS context
  252. Status - the status needs to be put on the cache
  253. Return Value:
  254. none
  255. --*/
  256. {
  257. MRxSmbUpdateBasicFileInfoCacheStatus(RxContext,Status);
  258. MRxSmbUpdateStandardFileInfoCacheStatus(RxContext,Status);
  259. }
  260. VOID
  261. MRxSmbUpdateBasicFileInfoCacheStatus(
  262. PRX_CONTEXT RxContext,
  263. NTSTATUS Status
  264. )
  265. /*++
  266. Routine Description:
  267. This routine updates the status of the name cache entry for the file basic information.
  268. Arguments:
  269. RxContext - the RDBSS context
  270. Status - the status needs to be put on the cache
  271. Return Value:
  272. none
  273. --*/
  274. {
  275. RxCaptureFcb;
  276. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  277. UNICODE_STRING FileName;
  278. PNAME_CACHE NameCache = NULL;
  279. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  280. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  281. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFABasic;
  282. PAGED_CODE();
  283. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  284. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  285. if (NameCache != NULL) {
  286. NameCache->PriorStatus = Status;
  287. RxNameCacheActivateEntry(NameCacheCtl,
  288. NameCache,
  289. 0,
  290. 0);
  291. //DbgPrint("Update status basic : %x %wZ\n",Status,OriginalFileName);
  292. RxLog(("Update status basic : %x %wZ\n",Status,OriginalFileName));
  293. } else {
  294. RxLog(("Update status basic fails: %x %wZ\n",Status,OriginalFileName));
  295. }
  296. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  297. // if it is a stream file, we invalid the root file name cache needs since we are not
  298. // sure what could happen to the root file on the server
  299. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  300. if (NameCache != NULL) {
  301. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  302. }
  303. //DbgPrint("Update status basic : %x %wZ\n",Status,&FileName);
  304. }
  305. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  306. }
  307. VOID
  308. MRxSmbUpdateStandardFileInfoCacheStatus(
  309. PRX_CONTEXT RxContext,
  310. NTSTATUS Status
  311. )
  312. /*++
  313. Routine Description:
  314. This routine updates the status of the name cache entry for the file standard information.
  315. Arguments:
  316. RxContext - the RDBSS context
  317. Status - the status needs to be put on the cache
  318. Return Value:
  319. none
  320. --*/
  321. {
  322. RxCaptureFcb;
  323. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  324. UNICODE_STRING FileName;
  325. PNAME_CACHE NameCache = NULL;
  326. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  327. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  328. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAStandard;
  329. PAGED_CODE();
  330. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  331. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  332. if (NameCache != NULL) {
  333. NameCache->PriorStatus = Status;
  334. RxNameCacheActivateEntry(NameCacheCtl,
  335. NameCache,
  336. 0,
  337. 0);
  338. }
  339. /*
  340. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  341. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  342. if (NameCache != NULL) {
  343. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  344. }
  345. } */
  346. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  347. }
  348. VOID
  349. MRxSmbInvalidateFileInfoCache(
  350. PRX_CONTEXT RxContext
  351. )
  352. /*++
  353. Routine Description:
  354. This routine invalidates the name cache entry for both file basic and standard information.
  355. Arguments:
  356. RxContext - the RDBSS context
  357. Return Value:
  358. none
  359. --*/
  360. {
  361. PAGED_CODE();
  362. MRxSmbInvalidateBasicFileInfoCache(RxContext);
  363. MRxSmbInvalidateStandardFileInfoCache(RxContext);
  364. MRxSmbInvalidateFullDirectoryCache(RxContext);
  365. // Don't do it here, since this invalidates Full Dir Cache
  366. // when the file is not there.
  367. // MRxSmbInvalidateFullDirectoryCacheParent(RxContext);
  368. }
  369. VOID
  370. MRxSmbInvalidateBasicFileInfoCache(
  371. PRX_CONTEXT RxContext
  372. )
  373. /*++
  374. Routine Description:
  375. This routine invalidates the name cache entry for file basic information.
  376. Arguments:
  377. RxContext - the RDBSS context
  378. Return Value:
  379. none
  380. --*/
  381. {
  382. RxCaptureFcb;
  383. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  384. UNICODE_STRING FileName;
  385. PNAME_CACHE NameCache = NULL;
  386. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  387. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  388. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFABasic;
  389. PAGED_CODE();
  390. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  391. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  392. if (NameCache != NULL) {
  393. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  394. }
  395. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  396. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  397. if (NameCache != NULL) {
  398. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  399. }
  400. }
  401. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  402. }
  403. VOID
  404. MRxSmbInvalidateStandardFileInfoCache(
  405. PRX_CONTEXT RxContext
  406. )
  407. /*++
  408. Routine Description:
  409. This routine invalidates the name cache entry for the file standard information.
  410. Arguments:
  411. RxContext - the RDBSS context
  412. Return Value:
  413. none
  414. --*/
  415. {
  416. RxCaptureFcb;
  417. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  418. UNICODE_STRING FileName;
  419. PNAME_CACHE NameCache = NULL;
  420. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  421. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  422. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAStandard;
  423. PAGED_CODE();
  424. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  425. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  426. if (NameCache != NULL) {
  427. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  428. //DbgPrint("Invalid Standard cache : %I64x %wZ\n",((PFILE_STANDARD_INFORMATION)NameCache->ContextExtension)->EndOfFile,OriginalFileName);
  429. }
  430. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  431. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  432. if (NameCache != NULL) {
  433. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  434. }
  435. }
  436. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  437. }
  438. VOID
  439. MRxSmbInvalidateInternalFileInfoCache(
  440. PRX_CONTEXT RxContext
  441. )
  442. /*++
  443. Routine Description:
  444. This routine invalidates the name cache entry for file internal information.
  445. Arguments:
  446. RxContext - the RDBSS context
  447. Return Value:
  448. none
  449. --*/
  450. {
  451. RxCaptureFcb;
  452. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  453. UNICODE_STRING FileName;
  454. PNAME_CACHE NameCache = NULL;
  455. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  456. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  457. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAInternal;
  458. PAGED_CODE();
  459. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  460. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  461. if (NameCache != NULL) {
  462. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  463. //DbgPrint("Invalid Internal cache : %wZ\n",OriginalFileName);
  464. RxLog(("Invalid Internal cache : %wZ\n",OriginalFileName));
  465. }
  466. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  467. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  468. if (NameCache != NULL) {
  469. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  470. }
  471. }
  472. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  473. }
  474. VOID
  475. MRxSmbUpdateFileInfoCacheFileSize(
  476. PRX_CONTEXT RxContext,
  477. PLARGE_INTEGER FileSize
  478. )
  479. /*++
  480. Routine Description:
  481. This routine updates file size on the name cache entry for the file standard information.
  482. Arguments:
  483. RxContext - the RDBSS context
  484. Return Value:
  485. none
  486. --*/
  487. {
  488. RxCaptureFcb;
  489. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  490. UNICODE_STRING FileName;
  491. PNAME_CACHE NameCache = NULL;
  492. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  493. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  494. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAStandard;
  495. PFILE_STANDARD_INFORMATION FileInfoCache = NULL;
  496. PAGED_CODE();
  497. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  498. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  499. if (NameCache != NULL) {
  500. FileInfoCache = (PFILE_STANDARD_INFORMATION)NameCache->ContextExtension;
  501. FileInfoCache->AllocationSize.QuadPart = FileSize->QuadPart;
  502. FileInfoCache->EndOfFile.QuadPart = FileSize->QuadPart;
  503. RxNameCacheActivateEntry(NameCacheCtl,
  504. NameCache,
  505. 0,
  506. 0);
  507. //DbgPrint("Update File size cache : %I64x %wZ\n",((PFILE_STANDARD_INFORMATION)NameCache->ContextExtension)->EndOfFile,OriginalFileName);
  508. }
  509. /*
  510. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  511. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  512. if (NameCache != NULL) {
  513. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  514. }
  515. }*/
  516. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  517. // Mark FullDir Cache, weak for bdi : Current Invalidate for correctness
  518. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, TRUE);
  519. }
  520. VOID
  521. MRxSmbUpdateBasicFileInfoCache(
  522. PRX_CONTEXT RxContext,
  523. ULONG FileAttributes,
  524. PLARGE_INTEGER pLastWriteTime
  525. )
  526. /*++
  527. Routine Description:
  528. This routine updates file attributs and last write time on the name cache entry
  529. for the file basic information.
  530. Arguments:
  531. RxContext - the RDBSS context
  532. FileAttributes - new file attributes
  533. pLastWriteTime - address of file last write time
  534. Return Value:
  535. none
  536. --*/
  537. {
  538. FILE_BASIC_INFORMATION Basic;
  539. Basic.ChangeTime.QuadPart = 0;
  540. Basic.CreationTime.QuadPart = 0;
  541. Basic.LastWriteTime.QuadPart = 0;
  542. Basic.LastAccessTime.QuadPart = 0;
  543. if (pLastWriteTime != NULL && pLastWriteTime->QuadPart != 0) {
  544. Basic.LastWriteTime = *pLastWriteTime;
  545. }
  546. Basic.FileAttributes = FileAttributes;
  547. MRxSmbUpdateBasicFileInfoCacheAll(RxContext,&Basic);
  548. // Mark FullDir Cache, weak for bdi : Current Invalidate for correctness
  549. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, TRUE);
  550. }
  551. VOID
  552. MRxSmbUpdateBasicFileInfoCacheAll(
  553. PRX_CONTEXT RxContext,
  554. PFILE_BASIC_INFORMATION Basic
  555. )
  556. /*++
  557. Routine Description:
  558. This routine updates the name cache entry for the file basic information.
  559. Arguments:
  560. RxContext - the RDBSS context
  561. Basic - file basic information
  562. Return Value:
  563. none
  564. --*/
  565. {
  566. RxCaptureFcb;
  567. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  568. UNICODE_STRING FileName;
  569. PNAME_CACHE NameCache = NULL;
  570. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  571. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  572. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFABasic;
  573. PFILE_BASIC_INFORMATION BasicFileInfoCache = NULL;
  574. PAGED_CODE();
  575. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  576. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  577. if (NameCache != NULL) {
  578. ULONG SavedAttributes = 0;
  579. BasicFileInfoCache = (PFILE_BASIC_INFORMATION)NameCache->ContextExtension;
  580. if (Basic->CreationTime.QuadPart != 0) {
  581. BasicFileInfoCache->CreationTime = Basic->CreationTime;
  582. }
  583. if (Basic->LastAccessTime.QuadPart != 0) {
  584. BasicFileInfoCache->LastAccessTime = Basic->LastAccessTime;
  585. }
  586. if (Basic->LastWriteTime.QuadPart != 0) {
  587. BasicFileInfoCache->LastWriteTime = Basic->LastWriteTime;
  588. }
  589. SavedAttributes = BasicFileInfoCache->FileAttributes &
  590. ( FILE_ATTRIBUTE_DIRECTORY |
  591. FILE_ATTRIBUTE_ENCRYPTED |
  592. FILE_ATTRIBUTE_COMPRESSED |
  593. FILE_ATTRIBUTE_SPARSE_FILE |
  594. FILE_ATTRIBUTE_REPARSE_POINT );
  595. //DbgPrint("Update File Attrib cache 1: %x %wZ\n",FileAttributes,OriginalFileName);
  596. //DbgPrint("Update File Attrib cache 2: %x %wZ\n",BasicFileInfoCache->FileAttributes,OriginalFileName);
  597. BasicFileInfoCache->FileAttributes = Basic->FileAttributes;
  598. BasicFileInfoCache->FileAttributes |= SavedAttributes;
  599. if (BasicFileInfoCache->FileAttributes & ~FILE_ATTRIBUTE_NORMAL) {
  600. BasicFileInfoCache->FileAttributes &= ~FILE_ATTRIBUTE_NORMAL;
  601. }
  602. RxNameCacheActivateEntry(NameCacheCtl,
  603. NameCache,
  604. 0,
  605. 0);
  606. //DbgPrint("Update File Attrib cache 3: %x %wZ\n",BasicFileInfoCache->FileAttributes,OriginalFileName);
  607. //DbgPrint("Update File Attrib cache : %I64X %I64X %wZ\n",BasicFileInfoCache->CreationTime,BasicFileInfoCache->LastAccessTime,OriginalFileName);
  608. }
  609. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  610. // if it is a stream file, we need to invalid the root file since we are not sure how this
  611. // could affect the root file.
  612. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  613. if (NameCache != NULL) {
  614. // expiring in XX routine
  615. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  616. }
  617. }
  618. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  619. // Mark FullDir Cache, weak for bdi : Current Invalidate for correctness
  620. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, TRUE);
  621. }
  622. VOID
  623. MRxSmbUpdateStandardFileInfoCache(
  624. PRX_CONTEXT RxContext,
  625. PFILE_STANDARD_INFORMATION Standard,
  626. BOOLEAN IsDirectory
  627. )
  628. /*++
  629. Routine Description:
  630. This routine updates the name cache entry for the file standard information.
  631. Arguments:
  632. RxContext - the RDBSS context
  633. Standard - file standard information
  634. IsDirectory - file is a directory
  635. Return Value:
  636. none
  637. --*/
  638. {
  639. RxCaptureFcb;
  640. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  641. UNICODE_STRING FileName;
  642. PNAME_CACHE NameCache = NULL;
  643. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  644. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  645. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAStandard;
  646. PFILE_STANDARD_INFORMATION StandardFileInfoCache = NULL;
  647. PAGED_CODE();
  648. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  649. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  650. if (NameCache != NULL) {
  651. StandardFileInfoCache = (PFILE_STANDARD_INFORMATION)NameCache->ContextExtension;
  652. if (Standard != NULL) {
  653. *StandardFileInfoCache = *Standard;
  654. } else {
  655. StandardFileInfoCache->Directory = IsDirectory;
  656. }
  657. RxNameCacheActivateEntry(NameCacheCtl,
  658. NameCache,
  659. 0,
  660. 0);
  661. //DbgPrint(" Update Standard cache : %I64x %wZ\n",((PFILE_STANDARD_INFORMATION)NameCache->ContextExtension)->EndOfFile,OriginalFileName);
  662. }
  663. /*
  664. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  665. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  666. if (NameCache != NULL) {
  667. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  668. }
  669. } */
  670. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  671. // Mark FullDir Cache, weak for bdi : Current Invalidate for correctness
  672. MRxSmbInvalidateFullDirectoryCacheParent(RxContext, TRUE);
  673. }
  674. BOOLEAN
  675. MRxSmbIsFileInfoCacheFound(
  676. PRX_CONTEXT RxContext,
  677. PSMBPSE_FILEINFO_BUNDLE FileInfo,
  678. NTSTATUS *Status,
  679. PUNICODE_STRING OriginalFileName
  680. )
  681. /*++
  682. Routine Description:
  683. This routine looks for the name cache entry of both file basic and standard information.
  684. Arguments:
  685. RxContext - the RDBSS context
  686. FileInfo - buffer to return file basic and standard information
  687. Status - status retured on the last reponse from server
  688. Return Value:
  689. BOOLEAN - name cache found
  690. --*/
  691. {
  692. PFILE_BASIC_INFORMATION Basic;
  693. PFILE_STANDARD_INFORMATION Standard;
  694. BOOLEAN CacheFound = FALSE;
  695. if (MRxSmbIsBasicFileInfoCacheFound(RxContext,&FileInfo->Basic,Status,OriginalFileName)) {
  696. if (*Status == STATUS_SUCCESS) {
  697. if (MRxSmbIsStandardFileInfoCacheFound(RxContext,&FileInfo->Standard,Status,OriginalFileName)) {
  698. CacheFound = TRUE;
  699. }
  700. } else {
  701. // if an error stored on the file basic information cache, return cache found
  702. CacheFound = TRUE;
  703. }
  704. }
  705. return CacheFound;
  706. }
  707. // these file attributes may be different between streams on a file
  708. ULONG StreamAttributes = FILE_ATTRIBUTE_COMPRESSED |
  709. FILE_ATTRIBUTE_DIRECTORY |
  710. FILE_ATTRIBUTE_SPARSE_FILE;
  711. BOOLEAN
  712. MRxSmbIsBasicFileInfoCacheFound(
  713. PRX_CONTEXT RxContext,
  714. PFILE_BASIC_INFORMATION Basic,
  715. NTSTATUS *Status,
  716. PUNICODE_STRING OriginalFileName
  717. )
  718. /*++
  719. Routine Description:
  720. This routine looks for the name cache entry of the file basic information.
  721. Arguments:
  722. RxContext - the RDBSS context
  723. Basic - buffer to return file basic information
  724. Status - status retured on the last reponse from server
  725. Return Value:
  726. BOOLEAN - name cache found
  727. --*/
  728. {
  729. RxCaptureFcb;
  730. UNICODE_STRING FileName;
  731. PNAME_CACHE NameCache = NULL;
  732. PMRX_NET_ROOT NetRoot;
  733. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  734. PNAME_CACHE_CONTROL NameCacheCtl;
  735. RX_NC_CHECK_STATUS NameCacheStatus;
  736. BOOLEAN CacheFound = FALSE;
  737. BOOLEAN RootFound = FALSE;
  738. ULONG RootAttributes = 0;
  739. NTSTATUS RootStatus = STATUS_SUCCESS;
  740. PAGED_CODE();
  741. if (OriginalFileName == NULL) {
  742. OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  743. }
  744. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  745. NetRoot = RxContext->Create.pNetRoot;
  746. } else {
  747. ASSERT(capFcb != NULL);
  748. NetRoot = capFcb->pNetRoot;
  749. }
  750. pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  751. NameCacheCtl = &pNetRootEntry->NameCacheCtlGFABasic;
  752. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  753. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  754. // check for stream file attribute changes
  755. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  756. if (NameCache != NULL) {
  757. NameCacheStatus = RxNameCacheCheckEntry(
  758. NameCache,
  759. NameCache->Context);
  760. if (NameCacheStatus == RX_NC_SUCCESS) {
  761. RootFound = TRUE;
  762. RootStatus = NameCache->PriorStatus;
  763. RootAttributes = ((PFILE_BASIC_INFORMATION)NameCache->ContextExtension)->FileAttributes & ~StreamAttributes;
  764. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  765. } else {
  766. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  767. }
  768. }
  769. }
  770. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  771. if (NameCache != NULL) {
  772. //
  773. // Found it. Now check entry for not expired.
  774. // Note - The NameCache entry has been pulled off the active list.
  775. //
  776. NameCacheStatus = RxNameCacheCheckEntry(
  777. NameCache,
  778. NameCache->Context);
  779. if (NameCacheStatus == RX_NC_SUCCESS &&
  780. (!RootFound ||
  781. (*Status == RootStatus &&
  782. (Basic->FileAttributes & ~StreamAttributes) == RootAttributes))) {
  783. // The name cache matches if it is not expired and the attributes matches the one of
  784. // the root file if it is a stream file. If this is a match, return the old status,
  785. // file info and reactivate the entry but leave expiration time unchanged.
  786. *Status = NameCache->PriorStatus;
  787. RxNameCacheOpSaved(NameCacheCtl);
  788. *Basic = *((PFILE_BASIC_INFORMATION)NameCache->ContextExtension);
  789. CacheFound = TRUE;
  790. // put the entry back to the active list without changing the expire time
  791. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  792. //DbgPrint(" Found Basic cache : %x %wZ\n",Basic->FileAttributes,OriginalFileName);
  793. //DbgPrint(" Get File Attrib cache : %I64X %I64X %wZ\n",Basic->CreationTime,Basic->LastAccessTime,OriginalFileName);
  794. } else {
  795. // put the entry back to the expire list
  796. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  797. }
  798. } else {
  799. //DbgPrint(" No Basic cache : %wZ\n",OriginalFileName);
  800. }
  801. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  802. return CacheFound;
  803. }
  804. BOOLEAN
  805. MRxSmbIsStandardFileInfoCacheFound(
  806. PRX_CONTEXT RxContext,
  807. PFILE_STANDARD_INFORMATION Standard,
  808. NTSTATUS *Status,
  809. PUNICODE_STRING OriginalFileName
  810. )
  811. /*++
  812. Routine Description:
  813. This routine looks for the name cache entry of the file standard information.
  814. Arguments:
  815. RxContext - the RDBSS context
  816. Standard - buffer to return file standard information
  817. Status - status retured on the last reponse from server
  818. Return Value:
  819. BOOLEAN - name cache found
  820. --*/
  821. {
  822. RxCaptureFcb;
  823. RxCaptureFobx;
  824. UNICODE_STRING FileName;
  825. PNAME_CACHE NameCache = NULL;
  826. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  827. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  828. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAStandard;
  829. RX_NC_CHECK_STATUS NameCacheStatus;
  830. BOOLEAN CacheFound = FALSE;
  831. BOOLEAN RootFound = FALSE;
  832. NTSTATUS RootStatus = STATUS_SUCCESS;
  833. PMRX_SMB_SRV_OPEN smbSrvOpen;
  834. PAGED_CODE();
  835. if (OriginalFileName == NULL) {
  836. OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  837. }
  838. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  839. smbSrvOpen = MRxSmbGetSrvOpenExtension(RxContext->pRelevantSrvOpen);
  840. } else {
  841. smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  842. }
  843. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  844. if (MRxSmbIsStreamFile(OriginalFileName,&FileName)) {
  845. // check for stream file attribute changes
  846. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  847. if (NameCache != NULL) {
  848. NameCacheStatus = RxNameCacheCheckEntry(
  849. NameCache,
  850. NameCache->Context);
  851. if (NameCacheStatus == RX_NC_SUCCESS) {
  852. RootFound = TRUE;
  853. RootStatus = NameCache->PriorStatus;
  854. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  855. } else {
  856. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  857. }
  858. }
  859. }
  860. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  861. if (NameCache != NULL) {
  862. //
  863. // Found it. Now check entry for not expired.
  864. // Note - The NameCache entry has been pulled off the active list.
  865. //
  866. NameCacheStatus = RxNameCacheCheckEntry(
  867. NameCache,
  868. NameCache->Context);
  869. if (NameCacheStatus == RX_NC_SUCCESS &&
  870. (!RootFound || *Status == RootStatus)) {
  871. // The name cache matches if it is not expired and the status matches the one of
  872. // the root file if it is a stream file. If this is a match, return the old status,
  873. // file info and reactivate the entry but leave expiration time unchanged.
  874. *Status = NameCache->PriorStatus;
  875. RxNameCacheOpSaved(NameCacheCtl);
  876. *Standard = *((PFILE_STANDARD_INFORMATION)NameCache->ContextExtension);
  877. if (FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_SUCCESSFUL_OPEN) &&
  878. !FlagOn(smbSrvOpen->Flags,SMB_SRVOPEN_FLAG_NOT_REALLY_OPEN)) {
  879. RxGetFileSizeWithLock((PFCB)capFcb,&Standard->EndOfFile.QuadPart);
  880. }
  881. CacheFound = TRUE;
  882. // put the entry back to the active list without changing the expire time
  883. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  884. //DbgPrint(" Get Standard cache : %I64x %wZ\n",((PFILE_STANDARD_INFORMATION)NameCache->ContextExtension)->EndOfFile,OriginalFileName);
  885. } else {
  886. // put the entry back to the expire list
  887. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  888. }
  889. }
  890. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  891. return CacheFound;
  892. }
  893. BOOLEAN
  894. MRxSmbIsInternalFileInfoCacheFound(
  895. PRX_CONTEXT RxContext,
  896. PFILE_INTERNAL_INFORMATION Internal,
  897. NTSTATUS *Status,
  898. PUNICODE_STRING OriginalFileName
  899. )
  900. /*++
  901. Routine Description:
  902. This routine looks for the name cache entry of the file basic information.
  903. Arguments:
  904. RxContext - the RDBSS context
  905. Basic - buffer to return file basic information
  906. Status - status retured on the last reponse from server
  907. Return Value:
  908. BOOLEAN - name cache found
  909. --*/
  910. {
  911. RxCaptureFcb;
  912. UNICODE_STRING FileName;
  913. PNAME_CACHE NameCache = NULL;
  914. PMRX_NET_ROOT NetRoot;
  915. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  916. PNAME_CACHE_CONTROL NameCacheCtl;
  917. RX_NC_CHECK_STATUS NameCacheStatus;
  918. BOOLEAN CacheFound = FALSE;
  919. PAGED_CODE();
  920. if (OriginalFileName == NULL) {
  921. OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  922. }
  923. //DbgPrint(" Query Internal cache : %wZ\n",OriginalFileName);
  924. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  925. NetRoot = RxContext->Create.pNetRoot;
  926. } else {
  927. ASSERT(capFcb != NULL);
  928. NetRoot = capFcb->pNetRoot;
  929. }
  930. pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  931. NameCacheCtl = &pNetRootEntry->NameCacheCtlGFAInternal;
  932. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  933. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  934. if (NameCache != NULL) {
  935. //
  936. // Found it. Now check entry for not expired.
  937. // Note - The NameCache entry has been pulled off the active list.
  938. //
  939. NameCacheStatus = RxNameCacheCheckEntry(
  940. NameCache,
  941. NameCache->Context);
  942. if (NameCacheStatus == RX_NC_SUCCESS) {
  943. // The name cache matches if it is not expired and the attributes matches the one of
  944. // the root file if it is a stream file. If this is a match, return the old status,
  945. // file info and reactivate the entry but leave expiration time unchanged.
  946. *Status = NameCache->PriorStatus;
  947. RxNameCacheOpSaved(NameCacheCtl);
  948. *Internal = *((PFILE_INTERNAL_INFORMATION)NameCache->ContextExtension);
  949. CacheFound = TRUE;
  950. // put the entry back to the active list without changing the expire time
  951. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  952. //DbgPrint(" Found Internal cache : %I64x %wZ\n",Internal->IndexNumber,OriginalFileName);
  953. } else {
  954. // put the entry back to the expire list
  955. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  956. //DbgPrint("Internal cache expired : %wZ\n",OriginalFileName);
  957. }
  958. } else {
  959. //DbgPrint(" No Internal cache : %wZ\n",OriginalFileName);
  960. }
  961. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  962. return CacheFound;
  963. }
  964. NTSTATUS
  965. MRxSmbGetFileInfoCacheStatus(
  966. PRX_CONTEXT RxContext
  967. )
  968. /*++
  969. Routine Description:
  970. This routine looks for the status of the name cache entry of either file basic or standard information.
  971. Arguments:
  972. RxContext - the RDBSS context
  973. Return Value:
  974. NTSTATUS - statu of the name cache if found, otherwise, STATUS_SUCCESS
  975. --*/
  976. {
  977. RxCaptureFcb;
  978. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  979. PNAME_CACHE NameCache = NULL;
  980. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  981. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  982. PNAME_CACHE_CONTROL NameCacheCtlBasic = &pNetRootEntry->NameCacheCtlGFABasic;
  983. PNAME_CACHE_CONTROL NameCacheCtlStandard = &pNetRootEntry->NameCacheCtlGFAStandard;
  984. NTSTATUS Status = STATUS_MORE_PROCESSING_REQUIRED;
  985. PAGED_CODE();
  986. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  987. NameCache = RxNameCacheFetchEntry(NameCacheCtlBasic,OriginalFileName);
  988. if (NameCache != NULL) {
  989. RX_NC_CHECK_STATUS NameCacheStatus;
  990. //
  991. // Found it. Now check entry for not expired
  992. //
  993. NameCacheStatus = RxNameCacheCheckEntry(NameCache,NameCache->Context);
  994. if (NameCacheStatus == RX_NC_SUCCESS) {
  995. //
  996. // If the cache has not expired, return the previous status.
  997. //
  998. Status = NameCache->PriorStatus;
  999. RxNameCacheOpSaved(NameCacheCtlBasic);
  1000. // put the entry back to the active list without changing the expire time
  1001. RxNameCacheActivateEntry(NameCacheCtlBasic, NameCache, 0, 0);
  1002. //DbgPrint(" Get Basic Status : %x %wZ\n",Status,OriginalFileName);
  1003. RxLog((" Get Basic Status : %x %wZ\n",Status,OriginalFileName));
  1004. } else {
  1005. // put the entry back to the expire list
  1006. RxNameCacheExpireEntry(NameCacheCtlBasic, NameCache);
  1007. }
  1008. } else {
  1009. NameCache = RxNameCacheFetchEntry(NameCacheCtlStandard,OriginalFileName);
  1010. if (NameCache != NULL) {
  1011. RX_NC_CHECK_STATUS NameCacheStatus;
  1012. //
  1013. // Found it. Now check entry for not expired
  1014. //
  1015. NameCacheStatus = RxNameCacheCheckEntry(NameCache,NameCache->Context);
  1016. if (NameCacheStatus == RX_NC_SUCCESS) {
  1017. //
  1018. // If the cache has not expired, return the previous status.
  1019. //
  1020. Status = NameCache->PriorStatus;
  1021. RxNameCacheOpSaved(NameCacheCtlStandard);
  1022. // put the entry back to the active list without changing the expire time
  1023. RxNameCacheActivateEntry(NameCacheCtlStandard, NameCache, 0, 0);
  1024. } else {
  1025. // put the entry back to the expire list
  1026. RxNameCacheExpireEntry(NameCacheCtlStandard, NameCache);
  1027. }
  1028. }
  1029. }
  1030. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1031. return Status;
  1032. }
  1033. BOOLEAN
  1034. MRxSmbIsFileNotFoundCached(
  1035. PRX_CONTEXT RxContext
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This routine checks if the name cache entry exists as File Not Found.
  1040. Arguments:
  1041. RxContext - the RDBSS context
  1042. Return Value:
  1043. BOOLEAN - name cache found
  1044. --*/
  1045. {
  1046. RxCaptureFcb;
  1047. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1048. UNICODE_STRING StreamlessName;
  1049. PNAME_CACHE NameCache = NULL;
  1050. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1051. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1052. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlFNF;
  1053. BOOLEAN CacheFound = FALSE;
  1054. PAGED_CODE();
  1055. // If a file does not exist, its stream doesn't either
  1056. MRxSmbIsStreamFile( OriginalFileName, &StreamlessName );
  1057. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1058. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&StreamlessName);
  1059. if (NameCache != NULL) {
  1060. RX_NC_CHECK_STATUS NameCacheStatus;
  1061. //
  1062. // Found it. Now check entry for not expired.
  1063. // Note - The NameCache entry has been pulled off the active list.
  1064. //
  1065. NameCacheStatus = RxNameCacheCheckEntry(
  1066. NameCache,
  1067. //MRxSmbStatistics.SmbsReceived.LowPart
  1068. NameCache->Context);
  1069. if ((NameCacheStatus == RX_NC_SUCCESS) &&
  1070. (NameCache->PriorStatus == STATUS_OBJECT_NAME_NOT_FOUND)) {
  1071. //
  1072. // This is a match. Return the old status, file info and
  1073. // reactivate the entry but leave expiration time unchanged.
  1074. //
  1075. CacheFound = TRUE;
  1076. // put the entry back to the active list without changing the expire time
  1077. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  1078. } else {
  1079. // put the entry back to the expire list
  1080. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1081. }
  1082. }
  1083. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1084. return CacheFound;
  1085. }
  1086. VOID
  1087. MRxSmbCacheFileNotFound(
  1088. PRX_CONTEXT RxContext
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. This routine creates the name cache entry for File Not Found.
  1093. Arguments:
  1094. RxContext - the RDBSS context
  1095. Return Value:
  1096. BOOLEAN - name cache found
  1097. --*/
  1098. {
  1099. RxCaptureFcb;
  1100. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1101. PNAME_CACHE NameCache = NULL;
  1102. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1103. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1104. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlFNF;
  1105. PAGED_CODE();
  1106. // Never cache stream file opens
  1107. if( MRxSmbIsStreamFile( OriginalFileName, NULL ) )
  1108. {
  1109. return;
  1110. }
  1111. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1112. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  1113. if (NameCache != NULL) {
  1114. NameCache->PriorStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  1115. RxNameCacheActivateEntry(
  1116. NameCacheCtl,
  1117. NameCache,
  1118. NAME_CACHE_OBJ_NAME_NOT_FOUND_LIFETIME,
  1119. MRxSmbStatistics.SmbsReceived.LowPart);
  1120. } else {
  1121. if (FlagOn(NetRoot->Flags,NETROOT_FLAG_UNIQUE_FILE_NAME)) {
  1122. NameCache = RxNameCacheCreateEntry (
  1123. NameCacheCtl,
  1124. OriginalFileName,
  1125. TRUE); // case insensitive match
  1126. if (NameCache != NULL) {
  1127. NameCache->PriorStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  1128. RxNameCacheActivateEntry(
  1129. NameCacheCtl,
  1130. NameCache,
  1131. NAME_CACHE_OBJ_NAME_NOT_FOUND_LIFETIME,
  1132. MRxSmbStatistics.SmbsReceived.LowPart);
  1133. }
  1134. }
  1135. }
  1136. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1137. }
  1138. #if 0
  1139. VOID
  1140. MRxSmbCacheFileNotFoundFromQueryDirectory(
  1141. PRX_CONTEXT RxContext
  1142. )
  1143. /*++
  1144. Routine Description:
  1145. This routine creates the name cache entry for File Not Found.
  1146. Arguments:
  1147. RxContext - the RDBSS context
  1148. Return Value:
  1149. BOOLEAN - name cache found
  1150. --*/
  1151. {
  1152. RxCaptureFcb;
  1153. RxCaptureFobx;
  1154. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1155. PUNICODE_STRING Template = &capFobx->UnicodeQueryTemplate;
  1156. UNICODE_STRING FileName;
  1157. PNAME_CACHE NameCache = NULL;
  1158. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1159. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1160. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlFNF;
  1161. PAGED_CODE();
  1162. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1163. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  1164. if (NameCache != NULL) {
  1165. if ((NameCache == NULL) &&
  1166. (OriginalFileName->Length > sizeof(WCHAR))) {
  1167. //
  1168. // Do lookup now since we may have skipped it at entry.
  1169. //
  1170. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&FileName);
  1171. if (NameCache == NULL) {
  1172. NameCache = RxNameCacheCreateEntry (
  1173. NameCacheCtl,
  1174. OriginalFileName,
  1175. TRUE); // case insensitive match
  1176. }
  1177. }
  1178. if (NameCache != NULL) {
  1179. NameCache->PriorStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  1180. RxNameCacheActivateEntry(
  1181. NameCacheCtl,
  1182. NameCache,
  1183. NAME_CACHE_OBJ_NAME_NOT_FOUND_LIFETIME,
  1184. MRxSmbStatistics.SmbsReceived.LowPart);
  1185. }
  1186. }
  1187. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1188. }
  1189. #endif
  1190. VOID
  1191. MRxSmbInvalidateFileNotFoundCache(
  1192. PRX_CONTEXT RxContext
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. This routine invalidates the name cache entry as File Not Found.
  1197. Arguments:
  1198. RxContext - the RDBSS context
  1199. Return Value:
  1200. BOOLEAN - name cache found
  1201. --*/
  1202. {
  1203. RxCaptureFcb;
  1204. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1205. UNICODE_STRING StreamlessName;
  1206. PNAME_CACHE NameCache = NULL;
  1207. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1208. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1209. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlFNF;
  1210. PAGED_CODE();
  1211. // If we invalidate a stream, this invalidates the associated file entry
  1212. MRxSmbIsStreamFile( OriginalFileName, &StreamlessName );
  1213. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1214. NameCache = RxNameCacheFetchEntry(NameCacheCtl, &StreamlessName);
  1215. if (NameCache != NULL) {
  1216. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1217. }
  1218. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1219. }
  1220. VOID
  1221. MRxSmbInvalidateFileNotFoundCacheForRename(
  1222. PRX_CONTEXT RxContext
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. This routine invalidates the name cache entry as File Not Found.
  1227. Arguments:
  1228. RxContext - the RDBSS context
  1229. Return Value:
  1230. BOOLEAN - name cache found
  1231. --*/
  1232. {
  1233. RxCaptureFcb;
  1234. UNICODE_STRING RenameName;
  1235. UNICODE_STRING StreamlessName;
  1236. PNAME_CACHE NameCache = NULL;
  1237. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1238. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1239. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlFNF;
  1240. PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
  1241. RenameName.Buffer = &RenameInformation->FileName[0];
  1242. RenameName.Length = (USHORT)RenameInformation->FileNameLength;
  1243. //DbgPrint("Invalidate FNF cache %wZ\n", &RenameName);
  1244. PAGED_CODE();
  1245. // If we rename a stream, invalidate the name without the stream
  1246. MRxSmbIsStreamFile( &RenameName, &StreamlessName );
  1247. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1248. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&StreamlessName);
  1249. if (NameCache != NULL) {
  1250. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1251. }
  1252. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1253. }
  1254. BOOLEAN
  1255. MRxSmbIsStreamFile(
  1256. PUNICODE_STRING FileName,
  1257. PUNICODE_STRING AdjustFileName
  1258. )
  1259. /*++
  1260. Routine Description:
  1261. This routine checks if it is a stream file and return the root file name if true.
  1262. Arguments:
  1263. FileName - the file name needs to be parsed
  1264. AdjustFileName - the file name contains only root name of the stream
  1265. Return Value:
  1266. BOOLEAN - stream file
  1267. --*/
  1268. {
  1269. USHORT i;
  1270. BOOLEAN IsStream = FALSE;
  1271. NTSTATUS Status = STATUS_SUCCESS;
  1272. for (i=0;i<FileName->Length/sizeof(WCHAR);i++) {
  1273. if (FileName->Buffer[i] == L':') {
  1274. IsStream = TRUE;
  1275. break;
  1276. }
  1277. }
  1278. if (AdjustFileName != NULL) {
  1279. if (IsStream) {
  1280. AdjustFileName->Length =
  1281. AdjustFileName->MaximumLength = i * sizeof(WCHAR);
  1282. AdjustFileName->Buffer = FileName->Buffer;
  1283. } else {
  1284. AdjustFileName->Length =
  1285. AdjustFileName->MaximumLength = FileName->Length;
  1286. AdjustFileName->Buffer = FileName->Buffer;
  1287. }
  1288. }
  1289. return IsStream;
  1290. }
  1291. BOOLEAN EnableInfoCache = TRUE;
  1292. BOOLEAN
  1293. MRxSmbIsLongFileName(
  1294. PRX_CONTEXT RxContext
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. This routine checks if it is a short file name and return the first part of short name if true.
  1299. Arguments:
  1300. FileName - the file name needs to be parsed
  1301. AdjustFileName - the file name contains only root name of the stream
  1302. Return Value:
  1303. BOOLEAN - stream file
  1304. --*/
  1305. {
  1306. RxCaptureFcb;
  1307. RxCaptureFobx;
  1308. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  1309. BOOLEAN IsLongName = FALSE;
  1310. if (!EnableInfoCache) {
  1311. return TRUE;
  1312. }
  1313. if (FlagOn(smbFcb->MFlags, SMB_FCB_FLAG_LONG_FILE_NAME)) {
  1314. IsLongName = TRUE;
  1315. } else {
  1316. USHORT i;
  1317. USHORT Left = 0;
  1318. USHORT Right = 0;
  1319. OEM_STRING OemString;
  1320. BOOLEAN RightPart = FALSE;
  1321. WCHAR LastChar = 0;
  1322. WCHAR CurrentChar = 0;
  1323. PUNICODE_STRING FileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1324. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
  1325. PSMBCE_NET_ROOT pSmbNetRoot = NULL;
  1326. if (RxContext->MajorFunction == IRP_MJ_CREATE) {
  1327. pVNetRootContext = RxContext->Create.pVNetRoot->Context;
  1328. pSmbNetRoot = &pVNetRootContext->pNetRootEntry->NetRoot;
  1329. } else {
  1330. ASSERT(capFobx != NULL);
  1331. pVNetRootContext = (PSMBCE_V_NET_ROOT_CONTEXT)capFobx->pSrvOpen->pVNetRoot->Context;
  1332. pSmbNetRoot = &pVNetRootContext->pNetRootEntry->NetRoot;
  1333. }
  1334. for (i=0;i<FileName->Length/sizeof(WCHAR);i++) {
  1335. LastChar = CurrentChar;
  1336. CurrentChar = FileName->Buffer[i];
  1337. if (CurrentChar == L'\\') {
  1338. RightPart = FALSE;
  1339. Left = 0;
  1340. Right = 0;
  1341. continue;
  1342. }
  1343. if (CurrentChar == L'.') {
  1344. if (RightPart) {
  1345. IsLongName = TRUE;
  1346. break;
  1347. } else {
  1348. RightPart = TRUE;
  1349. Right = 0;
  1350. continue;
  1351. }
  1352. }
  1353. if (CurrentChar >= L'0' && CurrentChar <= L'9' ||
  1354. CurrentChar >= L'a' && CurrentChar <= L'z' ||
  1355. CurrentChar >= L'A' && CurrentChar <= L'Z' ||
  1356. CurrentChar == L'~' ||
  1357. CurrentChar == L'_' ||
  1358. CurrentChar == L'$' ||
  1359. CurrentChar == L'@') {
  1360. if (RightPart) {
  1361. if (++Right > 3) {
  1362. IsLongName = TRUE;
  1363. break;
  1364. }
  1365. } else {
  1366. if (++Left > 8) {
  1367. IsLongName = TRUE;
  1368. break;
  1369. }
  1370. }
  1371. if (pSmbNetRoot->NetRootFileSystem != NET_ROOT_FILESYSTEM_NTFS) {
  1372. if (CurrentChar >= L'A' && CurrentChar <= L'Z' &&
  1373. LastChar >= L'a' && LastChar <= L'z' ||
  1374. CurrentChar >= L'a' && CurrentChar <= L'z' &&
  1375. LastChar >= L'A' && LastChar <= L'Z') {
  1376. // On FAT volume, name with mixture of cases will be treated as long name
  1377. IsLongName = TRUE;
  1378. break;
  1379. }
  1380. }
  1381. } else {
  1382. // if not, an alternate name may be created by the server which will
  1383. // be different from this name.
  1384. IsLongName = TRUE;
  1385. break;
  1386. }
  1387. }
  1388. }
  1389. if (IsLongName) {
  1390. SetFlag(smbFcb->MFlags, SMB_FCB_FLAG_LONG_FILE_NAME);
  1391. }
  1392. return IsLongName;
  1393. }
  1394. VOID
  1395. MRxSmbCreateSuffix(PUNICODE_STRING Source,
  1396. PUNICODE_STRING Target)
  1397. /*++
  1398. Routine Description:
  1399. This routine creates 'cat.dog' on input of 'a\b\cat.dog'
  1400. ***Note that Target and Source share a buffer after completion, so
  1401. ***changing one will change the other
  1402. Arguments:
  1403. Source, Target are UNICODE Strings
  1404. Return Value:
  1405. VOID
  1406. --*/
  1407. {
  1408. ULONG i;
  1409. PWCH BaseFileName = Source->Buffer;
  1410. PAGED_CODE( );
  1411. for ( i = 0; i < Source->Length / sizeof(WCHAR); i++ ) {
  1412. //
  1413. // If s points to a directory separator, set BaseFileName to
  1414. // the character after the separator.
  1415. //
  1416. if ( Source->Buffer[i] == ((WCHAR)L'\\') ) {
  1417. BaseFileName = &Source->Buffer[i];
  1418. }
  1419. }
  1420. Target->Length = Source->Length -
  1421. ((BaseFileName - Source->Buffer + 1) * sizeof(WCHAR));
  1422. Target->MaximumLength = Target->Length;
  1423. if (Target->Length) {
  1424. Target->Buffer = BaseFileName + 1;
  1425. } else {
  1426. Target->Buffer = NULL;
  1427. }
  1428. return;
  1429. }
  1430. VOID
  1431. MRxSmbCreateParentDirPrefix(PUNICODE_STRING Source,
  1432. PUNICODE_STRING Target)
  1433. /*++
  1434. Routine Description:
  1435. This routine creates 'a\b' on input of 'a\b\cat.dog'
  1436. ***Note that Target and Source share a buffer after completion, so
  1437. ***changing one will change the other
  1438. Arguments:
  1439. Source, Target are UNICODE Strings
  1440. Return Value:
  1441. VOID
  1442. --*/
  1443. {
  1444. ULONG i;
  1445. PWCH BaseFileName = Source->Buffer;
  1446. PAGED_CODE();
  1447. for ( i = 0; i < Source->Length / sizeof(WCHAR); i++ ) {
  1448. //
  1449. // If s points to a directory separator, set BaseFileName to
  1450. // the character after the separator.
  1451. //
  1452. if ( Source->Buffer[i] == ((WCHAR)L'\\') ) {
  1453. BaseFileName = &Source->Buffer[i];
  1454. }
  1455. }
  1456. Target->Length = ((BaseFileName - Source->Buffer) * sizeof(WCHAR));
  1457. Target->MaximumLength = Target->Length;
  1458. Target->Buffer = Source->Buffer;
  1459. return;
  1460. }
  1461. VOID
  1462. MRxSmbCacheFullDirectory(
  1463. PRX_CONTEXT RxContext,
  1464. PVOID Contents,
  1465. ULONG Length,
  1466. PMRX_SMB_FOBX smbFobx
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. This routine creates the name cache entry for Partial Directory.
  1471. Arguments:
  1472. RxContext - the RDBSS context
  1473. Return Value:
  1474. VOID
  1475. --*/
  1476. {
  1477. RxCaptureFcb;
  1478. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1479. PNAME_CACHE NameCache = NULL;
  1480. RX_NC_CHECK_STATUS NameCacheStatus;
  1481. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1482. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1483. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlPartialDir;
  1484. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  1485. #if DBG
  1486. UNICODE_STRING smbtemplate = {0,0,NULL};
  1487. #endif
  1488. PAGED_CODE();
  1489. if (Length > NAME_CACHE_PARTIAL_DIR_BUFFER_SIZE) {
  1490. return;
  1491. }
  1492. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1493. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  1494. // DbgPrint("NameCacheCtl %x\n", (ULONG) NameCacheCtl);
  1495. if (NameCache == NULL) {
  1496. if (FlagOn(NetRoot->Flags,NETROOT_FLAG_UNIQUE_FILE_NAME)) {
  1497. NameCache = RxNameCacheCreateEntry (NameCacheCtl,
  1498. OriginalFileName,
  1499. TRUE); // case insensitive match
  1500. }
  1501. } else {
  1502. RxDbgTrace( 0, Dbg, ("Cache Found, Reactivating... :%wZ: size %ld\n",OriginalFileName,Length));
  1503. SmbLog(LOG,MRxSmbReactivatingCache,
  1504. LOGUSTR(*OriginalFileName)
  1505. LOGULONG(Length));
  1506. //
  1507. // Found it. Now check entry for not expired.
  1508. // Note - The NameCache entry has been pulled off the active list.
  1509. //
  1510. NameCacheStatus = RxNameCacheCheckEntry(NameCache,
  1511. NameCache->Context);
  1512. // The assert below could be false if there are multiple threads trying to cache this directory.
  1513. // ASSERT( NameCacheStatus != RX_NC_SUCCESS);
  1514. // Clean out the Buffers
  1515. RtlZeroMemory(NameCache->ContextExtension, sizeof(FULL_DIR_CACHE));
  1516. }
  1517. if (NameCache != NULL) {
  1518. PFULL_DIR_CACHE Cache = (PFULL_DIR_CACHE)NameCache->ContextExtension;
  1519. ULONG SidLength;
  1520. NameCache->PriorStatus = STATUS_SUCCESS;
  1521. Cache->CharInvalidates = 0;
  1522. Cache->Flags = 0;
  1523. Cache->CharFlags = 0;
  1524. Cache->NiBufferLength = NAME_CACHE_PARTIAL_DIR_BUFFER_SIZE;
  1525. RxDbgTrace( 0, Dbg, ("Cached :%wZ: StrLen %d, BufA %x, Buf0 %x, Contents %x, Length %d\n",OriginalFileName, OriginalFileName->Length, &(Cache->Buffer[0]), Cache->Buffer[0], Contents, Length));
  1526. SmbLog(LOG,MRxSmbCached,
  1527. LOGUSTR(*OriginalFileName)
  1528. LOGXSHORT(OriginalFileName->Length)
  1529. //LOGPTR(&(Cache->Buffer[0])));
  1530. //LOGPTR(Cache->Buffer[0])
  1531. LOGPTR(Contents)
  1532. LOGULONG(Length));
  1533. RtlCopyMemory(&(Cache->smbFobx), // dest
  1534. smbFobx, // source
  1535. sizeof (MRX_SMB_FOBX));
  1536. // Now setup our smbFobx's UnalignedBuffer to Buffer
  1537. // which has the entire server response
  1538. // Assert the following.
  1539. Cache->smbFobx.Enumeration.UnalignedDirEntrySideBuffer = NULL;
  1540. //
  1541. // Put the SID in the Cache entry
  1542. //
  1543. SidLength = SeLengthSid(&smbFcb->Sid);
  1544. RtlCopySid(SidLength,&Cache->Sid,&smbFcb->Sid);
  1545. // Note: All we are saving is the Srv Response bytes.
  1546. // The Cached smbFobx is never visible to anybody else
  1547. // So, we cache using the built in buffer.
  1548. // Also, note that NameCache doesn't support registering
  1549. // free function for Expiration, which forces us to use
  1550. // the static buffer. The following will leak paged pool.
  1551. RtlCopyMemory(
  1552. &(Cache->Buffer[0]), //dst
  1553. smbFobx->Enumeration.UnalignedDirEntrySideBuffer, //Src
  1554. Length);
  1555. // DbgPrint("Name :%wZ: StrLen %d, CI %d, Buf0 %ld Hash %d\n", (PUNICODE_STRING) &(NameCache->Name), NameCache->Name.Length, (ULONG) NameCache->CaseInsensitive, (ULONG) *((PBYTE)(NameCache->ContextExtension) + sizeof (MRX_SMB_FOBX)), NameCache->HashValue);
  1556. {
  1557. BOOLEAN ReturnSingleEntry = FALSE;
  1558. ULONG FileIndex = 0;
  1559. NTSTATUS Status;
  1560. // Now it is time to get Names-Information for
  1561. // PartialDir searches. Use the same SmbFobx, but make
  1562. // sure we get the entire directory.
  1563. if (RxContext->QueryDirectory.ReturnSingleEntry) {
  1564. ReturnSingleEntry = TRUE;
  1565. RxContext->QueryDirectory.ReturnSingleEntry = FALSE;
  1566. }
  1567. if (RxContext->QueryDirectory.FileIndex != 0) {
  1568. FileIndex = RxContext->QueryDirectory.FileIndex;
  1569. RxContext->QueryDirectory.FileIndex = 0;
  1570. }
  1571. ASSERT ((Cache->smbFobx).Enumeration.UnalignedDirEntrySideBuffer == NULL);
  1572. MRxSmbAllocateSideBuffer(RxContext,
  1573. &(Cache->smbFobx),
  1574. TRANS2_FIND_FIRST2,
  1575. &smbtemplate);
  1576. if (Cache->smbFobx.Enumeration.UnalignedDirEntrySideBuffer == NULL) {
  1577. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1578. goto FINALLY;
  1579. }
  1580. RtlCopyMemory(
  1581. (Cache->smbFobx).Enumeration.UnalignedDirEntrySideBuffer,//dst
  1582. smbFobx->Enumeration.UnalignedDirEntrySideBuffer, //Src
  1583. Length);
  1584. // Setup the rest of our smbFobx
  1585. ClearFlag(Cache->smbFobx.Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
  1586. Cache->smbFobx.Enumeration.ResumeInfo = NULL;
  1587. Cache->smbFobx.Enumeration.EndOfSearchReached = TRUE;
  1588. Cache->smbFobx.Enumeration.IsUnicode = TRUE;
  1589. Cache->smbFobx.Enumeration.IsNonNtT2Find = FALSE;
  1590. Cache->smbFobx.Enumeration.FilesReturned =
  1591. smbFobx->Enumeration.FilesReturned;
  1592. Cache->smbFobx.Enumeration.EntryOffset = 0;
  1593. Cache->smbFobx.Enumeration.TotalDataBytesReturned =
  1594. smbFobx->Enumeration.TotalDataBytesReturned;
  1595. Cache->smbFobx.Enumeration.Flags &=
  1596. ~SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST;
  1597. Cache->smbFobx.Enumeration.ErrorStatus =
  1598. RX_MAP_STATUS(SUCCESS);
  1599. // Setup for Names Information
  1600. // Cache->smbFobx.Enumeration.FileNameOffset =
  1601. // (USHORT)FIELD_OFFSET(FILE_NAMES_INFORMATION,FileName[0]);
  1602. // Cache->smbFobx.Enumeration.FileNameLengthOffset =
  1603. // (USHORT)FIELD_OFFSET(FILE_NAMES_INFORMATION,FileNameLength);
  1604. Cache->smbFobx.Enumeration.WildCardsFound =
  1605. smbFobx->Enumeration.WildCardsFound;
  1606. Status = MrxSmbUnalignedDirEntryCopyTail(
  1607. RxContext,
  1608. FileBothDirectoryInformation,
  1609. &(Cache->NiBuffer[0]),
  1610. &(Cache->NiBufferLength),
  1611. &(Cache->smbFobx)
  1612. );
  1613. ASSERT (Status == STATUS_SUCCESS);
  1614. ASSERT ((Cache->smbFobx).Enumeration.UnalignedDirEntrySideBuffer == NULL);
  1615. // The FindFirst must have gotten everything.
  1616. // Now, we reset the smbFobx to its original values
  1617. RtlCopyMemory(&(Cache->smbFobx), // dest
  1618. smbFobx, // source
  1619. sizeof (MRX_SMB_FOBX));
  1620. // Reset the RxContext to the User's spec
  1621. if (ReturnSingleEntry) {
  1622. RxContext->QueryDirectory.ReturnSingleEntry = TRUE;
  1623. }
  1624. if (FileIndex != 0) {
  1625. RxContext->QueryDirectory.FileIndex = FileIndex;
  1626. }
  1627. // Since we copied over the users's smbFobx again, reset this
  1628. // again. We won't use the side buffer to copy the srv's ff response buffer.
  1629. Cache->smbFobx.Enumeration.UnalignedDirEntrySideBuffer = NULL;
  1630. }
  1631. RxNameCacheActivateEntry(
  1632. NameCacheCtl,
  1633. NameCache,
  1634. DIR_CACHE_LIFE_TIME,
  1635. MRxSmbStatistics.SmbsReceived.LowPart);
  1636. RxDbgTrace( 0, Dbg, ("Cached Full Dir :%wZ: size %ld\n",OriginalFileName,Length));
  1637. SmbLog(LOG,MRxSmbCachedFullDir,
  1638. LOGUSTR(*OriginalFileName)
  1639. LOGULONG(Length));
  1640. }
  1641. FINALLY:
  1642. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1643. return;
  1644. }
  1645. VOID
  1646. MRxSmbInvalidateFullDirectoryCache(
  1647. PRX_CONTEXT RxContext
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. This routine invalidates Partial Directory Cache
  1652. Arguments:
  1653. RxContext - the RDBSS context
  1654. Return Value:
  1655. VOID
  1656. --*/
  1657. {
  1658. RxCaptureFcb;
  1659. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1660. PNAME_CACHE NameCache = NULL;
  1661. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1662. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1663. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlPartialDir;
  1664. PAGED_CODE();
  1665. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1666. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  1667. if (NameCache != NULL) {
  1668. //
  1669. // put the entry back to the expire list
  1670. //
  1671. RxDbgTrace( 0, Dbg, ( "Invalidate Full Dir :%wZ: \n", OriginalFileName));
  1672. SmbLog(LOG,MRxSmbInvalidateFullDir,
  1673. LOGUSTR(*OriginalFileName));
  1674. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1675. }
  1676. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1677. return;
  1678. }
  1679. BOOLEAN
  1680. MRxSmbIsFullDirectoryCached(
  1681. PRX_CONTEXT RxContext,
  1682. PVOID Buffer,
  1683. PULONG Length,
  1684. PMRX_SMB_FOBX smbFobx,
  1685. NTSTATUS *Status
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. This routine checks if the name cache entry exists as Partial Directory
  1690. Arguments:
  1691. RxContext - the RDBSS context
  1692. Return Value:
  1693. BOOLEAN - name cache found
  1694. --*/
  1695. {
  1696. RxCaptureFcb;
  1697. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1698. PNAME_CACHE NameCache = NULL;
  1699. RX_NC_CHECK_STATUS NameCacheStatus;
  1700. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1701. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1702. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlPartialDir;
  1703. BOOLEAN CacheFound = FALSE;
  1704. BOOLEAN Expired = FALSE;
  1705. PLIST_ENTRY pListEntry;
  1706. PMRX_SMB_FCB smbFcb = MRxSmbGetFcbExtension(capFcb);
  1707. #if DBG
  1708. UNICODE_STRING smbtemplate = {0,0,NULL};
  1709. #endif
  1710. PAGED_CODE();
  1711. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1712. NameCache = RxNameCacheFetchEntry(NameCacheCtl,OriginalFileName);
  1713. if (NameCache != NULL) {
  1714. //
  1715. // Found it. Now check entry for not expired.
  1716. // Note - The NameCache entry has been pulled off the active list.
  1717. //
  1718. NameCacheStatus = RxNameCacheCheckEntry(NameCache,
  1719. NameCache->Context);
  1720. if (NameCacheStatus == RX_NC_SUCCESS) {
  1721. PFULL_DIR_CACHE Cache = (PFULL_DIR_CACHE)NameCache->ContextExtension;
  1722. //
  1723. // Verify matching SIDs
  1724. //
  1725. if(RtlEqualSid(&smbFcb->Sid,&Cache->Sid)) {
  1726. if (!(Cache->Flags & FLAG_FDC_NAMES_INFO_ONLY)) {
  1727. //
  1728. // This is a match. Return the old status, file info and
  1729. // reactivate the entry but leave expiration time unchanged.
  1730. //
  1731. RxDbgTrace( 0, Dbg, ("Found :%wZ: in FullDirCache\n",OriginalFileName));
  1732. SmbLog(LOG,MRxSmbFoundInFDC,
  1733. LOGUSTR(*OriginalFileName));
  1734. CacheFound = TRUE;
  1735. // Setup the Fobx correctly (to look like just after
  1736. // SmbCeTransact
  1737. // Mark the SmbFobx as satisfied from Full Dir Cache
  1738. smbFobx->Enumeration.Flags |= SMBFOBX_ENUMFLAG_FULL_DIR_CACHE;
  1739. // Allocate SideBuffer
  1740. // Now setup our smbFobx's UnalignedBuffer to Buffer
  1741. // which has the entire response
  1742. ASSERT (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL);
  1743. MRxSmbAllocateSideBuffer(RxContext,
  1744. smbFobx,
  1745. TRANS2_FIND_FIRST2,
  1746. &smbtemplate);
  1747. ASSERT (smbFobx->Enumeration.UnalignedDirEntrySideBuffer != NULL);
  1748. if (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) {
  1749. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1750. NameCache = NULL;
  1751. CacheFound = FALSE;
  1752. goto FINALLY;
  1753. }
  1754. RtlCopyMemory(
  1755. smbFobx->Enumeration.UnalignedDirEntrySideBuffer, //Dst
  1756. &(Cache->Buffer[0]), //Src
  1757. Cache->smbFobx.Enumeration.TotalDataBytesReturned);
  1758. // This handle is bogus, but the handle has been closed
  1759. // since we hit EndOfSearchReached
  1760. smbFobx->Enumeration.SearchHandle =
  1761. Cache->smbFobx.Enumeration.SearchHandle;
  1762. // Doesn't make sense, since EndOfSearchReached is TRUE
  1763. // and Handle has been closed.
  1764. smbFobx->Enumeration.Version =
  1765. Cache->smbFobx.Enumeration.Version;
  1766. ClearFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_SEARCH_HANDLE_OPEN);
  1767. smbFobx->Enumeration.ResumeInfo = NULL;
  1768. smbFobx->Enumeration.EndOfSearchReached = TRUE;
  1769. smbFobx->Enumeration.IsUnicode = TRUE;
  1770. smbFobx->Enumeration.IsNonNtT2Find = FALSE;
  1771. smbFobx->Enumeration.FilesReturned =
  1772. Cache->smbFobx.Enumeration.FilesReturned;
  1773. smbFobx->Enumeration.EntryOffset =
  1774. Cache->smbFobx.Enumeration.EntryOffset;
  1775. ASSERT (smbFobx->Enumeration.EntryOffset == 0);
  1776. smbFobx->Enumeration.TotalDataBytesReturned =
  1777. Cache->smbFobx.Enumeration.TotalDataBytesReturned;
  1778. smbFobx->Enumeration.Flags |= SMBFOBX_ENUMFLAG_SEARCH_NOT_THE_FIRST;
  1779. smbFobx->Enumeration.ErrorStatus = RX_MAP_STATUS(SUCCESS);
  1780. // FileNameOffset and FileNameLengthOffset depends on
  1781. // the FileInformationClass, that must come with the
  1782. // smbFobx already. Don't touch.
  1783. smbFobx->Enumeration.WildCardsFound =
  1784. Cache->smbFobx.Enumeration.WildCardsFound;
  1785. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  1786. // *Length -= Cache->smbFobx.Enumeration.TotalDataBytesReturned;
  1787. } else {
  1788. // Expire this entry and let the user go to the server.
  1789. // On the way back, we'll cache the fresh dir bdi anyways.
  1790. CacheFound = FALSE;
  1791. Expired = TRUE;
  1792. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1793. }
  1794. } else {
  1795. // SIDs did not match so expire the entry
  1796. Expired = TRUE;
  1797. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1798. }
  1799. } else {
  1800. // Expire it!
  1801. Expired = TRUE;
  1802. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  1803. }
  1804. }
  1805. FINALLY:
  1806. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1807. if ((NameCache != NULL) &&
  1808. (NameCacheStatus == RX_NC_SUCCESS) &&
  1809. !(Expired)) {
  1810. *Status = MrxSmbUnalignedDirEntryCopyTail(RxContext,
  1811. FileBothDirectoryInformation,
  1812. Buffer,
  1813. Length,
  1814. smbFobx);
  1815. if (smbFobx->Enumeration.UnalignedDirEntrySideBuffer == NULL) {
  1816. // The FindFirst got everything.
  1817. // Need to fail the FindNext. Mark satisfied out of cache.
  1818. SetFlag(smbFobx->Enumeration.Flags,SMBFOBX_ENUMFLAG_READ_FROM_CACHE);
  1819. }
  1820. }
  1821. return CacheFound;
  1822. }
  1823. VOID
  1824. MRxSmbInvalidateFullDirectoryCacheParent(PRX_CONTEXT RxContext,
  1825. BOOLEAN Benign)
  1826. /*++
  1827. Routine Description:
  1828. This routine invalidates Partial Directory Cache
  1829. Arguments:
  1830. RxContext - the RDBSS context
  1831. Return Value:
  1832. VOID
  1833. --*/
  1834. {
  1835. RxCaptureFcb;
  1836. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1837. UNICODE_STRING ParentDir;
  1838. UNICODE_STRING FileNameSuffix;
  1839. WCHAR InhibitChar;
  1840. ULONG InhibitMask;
  1841. PNAME_CACHE NameCache = NULL;
  1842. RX_NC_CHECK_STATUS NameCacheStatus;
  1843. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1844. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1845. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlPartialDir;
  1846. BOOLEAN ExpireEntry;
  1847. PAGED_CODE();
  1848. MRxSmbCreateParentDirPrefix(OriginalFileName, &ParentDir);
  1849. if(ParentDir.Length == 0) {
  1850. return;
  1851. }
  1852. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1853. NameCache = RxNameCacheFetchEntry(NameCacheCtl, &ParentDir);
  1854. if (NameCache != NULL) {
  1855. //
  1856. // put the entry back to the expire list
  1857. //
  1858. // Found it. Now check entry for not expired.
  1859. // Note - The NameCache entry has been pulled off the active list.
  1860. //
  1861. NameCacheStatus = RxNameCacheCheckEntry(NameCache,
  1862. NameCache->Context);
  1863. if (NameCacheStatus == RX_NC_SUCCESS) {
  1864. BOOLEAN CacheValid = TRUE;
  1865. PFULL_DIR_CACHE Cache = NameCache->ContextExtension;
  1866. // Mark as non-bdi
  1867. Cache->Flags |= FLAG_FDC_NAMES_INFO_ONLY;
  1868. if (!(Benign) &&
  1869. !(MRxSmbIsFileInPartialDirectoryCache(NameCache,OriginalFileName,&CacheValid, NULL))) {
  1870. // Search for that one character etc. and disect cache
  1871. MRxSmbCreateSuffix(OriginalFileName, &FileNameSuffix);
  1872. InhibitChar = RtlUpcaseUnicodeChar(FileNameSuffix.Buffer[0]);
  1873. InhibitMask = 0;
  1874. if ((InhibitChar >= L'A') && (InhibitChar <= L'Z')) {
  1875. InhibitMask = (1 << ((USHORT) InhibitChar - (USHORT)(L'A')));
  1876. } else {
  1877. if ((InhibitChar >= L'0') && (InhibitChar <= L'9')) {
  1878. InhibitMask = 1 << 30;
  1879. }
  1880. else {
  1881. switch (InhibitChar) {
  1882. case L'~': InhibitMask = 1 << 26;
  1883. break;
  1884. case L'_': InhibitMask = 1 << 27;
  1885. break;
  1886. case L'$': InhibitMask = 1 << 28;
  1887. break;
  1888. case L'@': InhibitMask = 1 << 29;
  1889. break;
  1890. default : InhibitMask = 1 << 31;
  1891. break;
  1892. // We didn't find a suitable character to invalidate,
  1893. // We use the 'rest' bit.
  1894. // We HAVE TO remember that a modification has been made:
  1895. // like a file-create or delete that we couldn't record in the
  1896. // first 31 bits. This is so that, if a query comes along for
  1897. // 'test.dat, starting with an apostrophe char (or some Japanese
  1898. // Unicode Char, for that matter), and that file was created
  1899. // just before, we don't say STATUS_OBJECT_NOT_FOUND.
  1900. // We will lookup the 'rest' bit and pass the query on to the server}
  1901. }
  1902. }
  1903. }
  1904. if (!(Cache->CharFlags & InhibitMask)) {
  1905. Cache->CharFlags |= InhibitMask;
  1906. Cache->CharInvalidates++;
  1907. RxDbgTrace( 0, Dbg, ( "Inv Parent Cache :%wZ:%wZ: %x %x\n", OriginalFileName, &ParentDir,Cache->CharFlags,InhibitMask ));
  1908. SmbLog(LOG,MRxSmbInvParentCache,
  1909. LOGUSTR(*OriginalFileName)
  1910. LOGUSTR(ParentDir)
  1911. LOGULONG(Cache->CharFlags)
  1912. LOGULONG(InhibitMask));
  1913. }
  1914. }
  1915. if (Cache->CharInvalidates > MAX_CHAR_INVALIDATES_FULL_DIR) {
  1916. RxDbgTrace( 0, Dbg, ("Expire Cache %x Num Inv %d\n", Cache->CharFlags, Cache->CharInvalidates));
  1917. SmbLog(LOG,MRxSmbExpireCache,
  1918. LOGULONG(Cache->CharFlags)
  1919. LOGXSHORT(Cache->CharInvalidates));
  1920. ExpireEntry = TRUE;
  1921. } else {
  1922. ExpireEntry = FALSE;
  1923. }
  1924. }
  1925. else {
  1926. ExpireEntry = TRUE;
  1927. }
  1928. if(ExpireEntry) {
  1929. RxNameCacheExpireEntry(NameCacheCtl,NameCache);
  1930. }
  1931. else {
  1932. RxNameCacheActivateEntry(NameCacheCtl,NameCache,0,0);
  1933. }
  1934. }
  1935. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  1936. return;
  1937. }
  1938. VOID
  1939. MRxSmbInvalidateFullDirectoryCacheParentForRename(
  1940. PRX_CONTEXT RxContext,
  1941. BOOLEAN Benign
  1942. )
  1943. /*++
  1944. Routine Description:
  1945. This routine invalidates Partial Directory Cache
  1946. Arguments:
  1947. RxContext - the RDBSS context
  1948. Return Value:
  1949. VOID
  1950. --*/
  1951. {
  1952. RxCaptureFcb;
  1953. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  1954. UNICODE_STRING ParentDir;
  1955. UNICODE_STRING FileNameSuffix;
  1956. UNICODE_STRING RenameName = {0,0,NULL};
  1957. WCHAR InhibitChar;
  1958. ULONG InhibitMask;
  1959. PNAME_CACHE NameCache = NULL;
  1960. RX_NC_CHECK_STATUS NameCacheStatus;
  1961. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1962. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  1963. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlPartialDir;
  1964. BOOLEAN ExpireEntry;
  1965. PFILE_RENAME_INFORMATION RenameInformation = RxContext->Info.Buffer;
  1966. PAGED_CODE();
  1967. RenameName.Buffer = &RenameInformation->FileName[0];
  1968. RenameName.Length = (USHORT)RenameInformation->FileNameLength;
  1969. MRxSmbCreateParentDirPrefix(&RenameName, &ParentDir);
  1970. if(ParentDir.Length == 0) {
  1971. return;
  1972. }
  1973. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  1974. NameCache = RxNameCacheFetchEntry(NameCacheCtl, &ParentDir);
  1975. if (NameCache != NULL) {
  1976. //
  1977. // put the entry back to the expire list
  1978. //
  1979. // Found it. Now check entry for not expired.
  1980. // Note - The NameCache entry has been pulled off the active list.
  1981. //
  1982. NameCacheStatus = RxNameCacheCheckEntry(NameCache,
  1983. NameCache->Context);
  1984. if (NameCacheStatus == RX_NC_SUCCESS) {
  1985. BOOLEAN CacheValid = TRUE;
  1986. PFULL_DIR_CACHE Cache = NameCache->ContextExtension;
  1987. // Mark as non-bdi
  1988. Cache->Flags |= FLAG_FDC_NAMES_INFO_ONLY;
  1989. if (!(Benign) &&
  1990. !(MRxSmbIsFileInPartialDirectoryCache(NameCache,&RenameName,&CacheValid, NULL))) {
  1991. // Search for that one character etc. and disect cache
  1992. MRxSmbCreateSuffix(&RenameName, &FileNameSuffix);
  1993. InhibitChar = RtlUpcaseUnicodeChar(FileNameSuffix.Buffer[0]);
  1994. InhibitMask = 0;
  1995. if ((InhibitChar >= L'A') && (InhibitChar <= L'Z')) {
  1996. InhibitMask = (1 << ((USHORT) InhibitChar - (USHORT)(L'A')));
  1997. }
  1998. else {
  1999. if ((InhibitChar >= L'0') && (InhibitChar <= L'9')) {
  2000. InhibitMask = 1 << 30;
  2001. }
  2002. else {
  2003. switch (InhibitChar) {
  2004. case L'~': InhibitMask = 1 << 26;
  2005. break;
  2006. case L'_': InhibitMask = 1 << 27;
  2007. break;
  2008. case L'$': InhibitMask = 1 << 28;
  2009. break;
  2010. case L'@': InhibitMask = 1 << 29;
  2011. break;
  2012. default : InhibitMask = 1 << 31;
  2013. break;
  2014. // We didn't find a suitable character to invalidate,
  2015. // We use the 'rest' bit.
  2016. // We HAVE TO remember that a modification has been made:
  2017. // like a file-create or delete that we couldn't record in the
  2018. // first 31 bits. This is so that, if a query comes along for
  2019. // 'test.dat, starting with an apostrophe char (or some Japanese
  2020. // Unicode Char, for that matter), and that file was created
  2021. // just before, we don't say STATUS_OBJECT_NOT_FOUND.
  2022. // We will lookup the 'rest' bit and pass the query on to the server}
  2023. }
  2024. }
  2025. }
  2026. if (!(Cache->CharFlags & InhibitMask)) {
  2027. Cache->CharFlags |= InhibitMask;
  2028. Cache->CharInvalidates++;
  2029. RxDbgTrace( 0, Dbg, ( "Inv Rename Parent Cache :%wZ:%wZ: %x %x\n", &RenameName, &ParentDir, Cache->CharFlags, InhibitMask ));
  2030. SmbLog(LOG,MRxSmbInvalidateRenameParentCache,
  2031. LOGUSTR(RenameName)
  2032. LOGUSTR(ParentDir)
  2033. LOGULONG(Cache->CharFlags)
  2034. LOGULONG(InhibitMask));
  2035. }
  2036. }
  2037. if (Cache->CharInvalidates > MAX_CHAR_INVALIDATES_FULL_DIR) {
  2038. RxDbgTrace( 0, Dbg, ("Expire Cache %x Num Inv %d\n", Cache->CharFlags, Cache->CharInvalidates));
  2039. SmbLog(LOG,MRxSmbExpireCache,
  2040. LOGULONG(Cache->CharFlags)
  2041. LOGXSHORT(Cache->CharInvalidates));
  2042. ExpireEntry = TRUE;
  2043. } else {
  2044. ExpireEntry = FALSE;
  2045. }
  2046. }
  2047. else {
  2048. ExpireEntry = TRUE;
  2049. }
  2050. if(ExpireEntry) {
  2051. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  2052. }
  2053. else {
  2054. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  2055. }
  2056. }
  2057. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  2058. return;
  2059. }
  2060. BOOLEAN
  2061. MRxSmbIsFileInFullDirectoryCache(
  2062. PRX_CONTEXT RxContext,
  2063. BOOLEAN *FileFound,
  2064. PFILE_BASIC_INFORMATION pBuffer
  2065. )
  2066. /*++
  2067. Routine Description:
  2068. This routine checks if the name cache entry exists as Partial Directory
  2069. Arguments:
  2070. RxContext - the RDBSS context
  2071. Return Value:
  2072. BOOLEAN - name cache found
  2073. --*/
  2074. {
  2075. RxCaptureFcb;
  2076. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  2077. UNICODE_STRING TargetDirPrefix;
  2078. PNAME_CACHE NameCache = NULL;
  2079. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  2080. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry = SmbCeGetAssociatedNetRootEntry(NetRoot);
  2081. PNAME_CACHE_CONTROL NameCacheCtl = &pNetRootEntry->NameCacheCtlPartialDir;
  2082. BOOLEAN CacheFound = FALSE;
  2083. PAGED_CODE();
  2084. *FileFound = FALSE;
  2085. MRxSmbCreateParentDirPrefix(OriginalFileName, &TargetDirPrefix);
  2086. if(TargetDirPrefix.Length == 0) {
  2087. return CacheFound;
  2088. }
  2089. ExAcquireFastMutex(&MRxSmbFileInfoCacheLock);
  2090. NameCache = RxNameCacheFetchEntry(NameCacheCtl,&TargetDirPrefix);
  2091. if (NameCache != NULL) {
  2092. RX_NC_CHECK_STATUS NameCacheStatus;
  2093. //
  2094. // Found it. Now check entry for not expired.
  2095. // Note - The NameCache entry has been pulled off the active list.
  2096. //
  2097. NameCacheStatus = RxNameCacheCheckEntry(NameCache,
  2098. NameCache->Context);
  2099. if (NameCacheStatus == RX_NC_SUCCESS) {
  2100. //
  2101. // This is a match. Return the old status, file info and
  2102. // reactivate the entry but leave expiration time unchanged.
  2103. //
  2104. CacheFound = TRUE;
  2105. *FileFound = MRxSmbIsFileInPartialDirectoryCache(NameCache,
  2106. OriginalFileName,
  2107. &CacheFound,
  2108. pBuffer);
  2109. if (*FileFound) {
  2110. RxDbgTrace( 0, Dbg, ( " Found in FullDirCache :%wZ: :%wZ:\n", OriginalFileName, &TargetDirPrefix));
  2111. SmbLog(LOG,MRxSmbFoundInFDC2,
  2112. LOGUSTR(*OriginalFileName)
  2113. LOGUSTR(TargetDirPrefix));
  2114. }
  2115. RxNameCacheActivateEntry(NameCacheCtl, NameCache, 0, 0);
  2116. }
  2117. else {
  2118. RxNameCacheExpireEntry(NameCacheCtl, NameCache);
  2119. }
  2120. }
  2121. ExReleaseFastMutex(&MRxSmbFileInfoCacheLock);
  2122. return CacheFound;
  2123. }
  2124. BOOLEAN
  2125. MRxSmbIsFileInPartialDirectoryCache (PNAME_CACHE NameCache,
  2126. PUNICODE_STRING OriginalFileName,
  2127. PBOOLEAN CacheValid,
  2128. PFILE_BASIC_INFORMATION pBuffer)
  2129. /*++
  2130. Routine Description:
  2131. This routine checks if the FileName exists in name cache entry
  2132. Arguments:
  2133. NameCache - Partial Directory Cache
  2134. OriginalFileName - PUNICODE_STRING for searching
  2135. Return Value:
  2136. BOOLEAN - File exists in NameCache
  2137. --*/
  2138. {
  2139. PFULL_DIR_CACHE Cache = (PFULL_DIR_CACHE) NameCache->ContextExtension;
  2140. FILE_BOTH_DIR_INFORMATION *pDirInfo =
  2141. (PFILE_BOTH_DIR_INFORMATION) &(Cache->NiBuffer[0]);
  2142. UNICODE_STRING FileNameSuffix;
  2143. WCHAR InhibitChar;
  2144. ULONG InhibitMask = 0;
  2145. MRxSmbCreateSuffix(OriginalFileName, &FileNameSuffix);
  2146. InhibitChar = RtlUpcaseUnicodeChar(FileNameSuffix.Buffer[0]);
  2147. InhibitMask = 0;
  2148. if ((InhibitChar >= L'A') && (InhibitChar <= L'Z')) {
  2149. InhibitMask = (1 << ((USHORT) InhibitChar - (USHORT)(L'A')));
  2150. } else {
  2151. if ((InhibitChar >= L'0') && (InhibitChar <= L'9')) {
  2152. InhibitMask = 1 << 30;
  2153. } else {
  2154. switch (InhibitChar) {
  2155. case L'~': InhibitMask = 1 << 26;
  2156. break;
  2157. case L'_': InhibitMask = 1 << 27;
  2158. break;
  2159. case L'$': InhibitMask = 1 << 28;
  2160. break;
  2161. case L'@': InhibitMask = 1 << 29;
  2162. break;
  2163. default : InhibitMask = 1 << 31;
  2164. break;
  2165. // We didn't find a suitable character to invalidate,
  2166. // We use the 'rest' bit.
  2167. // We HAVE TO remember that a modification has been made:
  2168. // like a file-create or delete that we couldn't record in the
  2169. // first 31 bits. This is so that, if a query comes along for
  2170. // 'test.dat, starting with an apostrophe char (or some Japanese
  2171. // Unicode Char, for that matter), and that file was created
  2172. // just before, we don't say STATUS_OBJECT_NOT_FOUND.
  2173. // We will lookup the 'rest' bit and pass the query on to the server}
  2174. }
  2175. }
  2176. }
  2177. if (Cache->CharFlags & InhibitMask) {
  2178. *CacheValid = FALSE;
  2179. RxDbgTrace( 0, Dbg, ("--------- Cache blown :%wZ: %x Inb Mask %x\n", OriginalFileName, Cache->CharFlags, InhibitMask));
  2180. SmbLog(LOG,MRxSmbCacheBlown,
  2181. LOGUSTR(*OriginalFileName)
  2182. LOGULONG(Cache->CharFlags)
  2183. LOGULONG(InhibitMask));
  2184. return (FALSE);
  2185. }
  2186. while( TRUE ) {
  2187. //DbgPrint( "Checking FileNameSuffix :%wZ: with Entry :%wZ: ",&FileNameSuffix,pDirInfo->FileName);
  2188. if ((pDirInfo->FileNameLength == FileNameSuffix.Length) &&
  2189. RtlEqualMemory(
  2190. FileNameSuffix.Buffer,
  2191. pDirInfo->FileName,
  2192. FileNameSuffix.Length)) {
  2193. //DbgPrint (" TRUE\n");
  2194. // Pass on the Basic Attributes, latest or not.
  2195. // Two cases:
  2196. // Buffer exists: This is from a query
  2197. // In this case, if Creation Time is zero, then the Basic Attributes
  2198. // is invalid. So, we mark CacheValid as FALSE, which is returned to
  2199. // the caller's caller (in fileinfo.c).
  2200. // Note: This case DOES NOT assassinate character.
  2201. // Buffer was NULL: This is from Invalidate
  2202. // Simply set CreationTime to zero to mark File BasicInfo as invalid.
  2203. // However, return TRUE, so that Character assassination doesn't happen.
  2204. if (pBuffer != NULL) {
  2205. if (0 != pDirInfo->CreationTime.QuadPart) {
  2206. pBuffer->CreationTime = pDirInfo->CreationTime;
  2207. pBuffer->LastAccessTime = pDirInfo->LastAccessTime;
  2208. pBuffer->LastWriteTime = pDirInfo->LastWriteTime;
  2209. pBuffer->ChangeTime = pDirInfo->ChangeTime;
  2210. pBuffer->FileAttributes = pDirInfo->FileAttributes;
  2211. } else {
  2212. *CacheValid = FALSE;
  2213. }
  2214. } else {
  2215. pDirInfo->CreationTime.QuadPart = 0;
  2216. SmbLog(LOG,MRxSmbCacheBlown,
  2217. LOGUSTR(*OriginalFileName)
  2218. LOGULONG(Cache->CharFlags)
  2219. LOGULONG(InhibitMask));
  2220. }
  2221. return (TRUE);
  2222. }
  2223. if (0 == pDirInfo->NextEntryOffset) {
  2224. break ;
  2225. }
  2226. pDirInfo = (FILE_BOTH_DIR_INFORMATION *)((PBYTE)pDirInfo +
  2227. pDirInfo->NextEntryOffset) ;
  2228. //DbgPrint (" FALSE\n");
  2229. }
  2230. return (FALSE);
  2231. }
  2232. BOOLEAN
  2233. MRxSmbNonTrivialFileName ( PRX_CONTEXT RxContext )
  2234. /*++
  2235. Routine Description:
  2236. This routine checks if the file name is non-trivial
  2237. Arguments:
  2238. RxContext
  2239. Return Value:
  2240. returns boolean
  2241. --*/
  2242. {
  2243. PUNICODE_STRING OriginalFileName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  2244. PAGED_CODE( );
  2245. return (OriginalFileName->Length > 0);
  2246. }