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.

848 lines
28 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. cscdfs.c
  5. Abstract:
  6. This module implements the routines for integrating DFS funcitionality with
  7. CSC
  8. Author:
  9. Balan Sethu Raman [SethuR] 23 - January - 1998
  10. Revision History:
  11. Notes:
  12. The CSC/DFS integration poses some interesting problem for transparent
  13. switchover from online to offline operation and viceversa.
  14. The DFS driver ( incorporated into MUP in its current incarnation ) builds
  15. up a logical name space by stitching together varios physical volumes on
  16. different machines. In the normal course of events the CSC framework will
  17. be above the DFS driver in the food chain. In such cases this module
  18. would be redundant and the entire process is contained in the CSC code.
  19. Since this is not an available option owing to the necessity of integrating
  20. the CSC code in its present form this module tries to seamlessly provide
  21. that functionality.
  22. The DFS driver uses specially defined IOCTL's over the SMB protocol to garner
  23. and disperse DFS state information. The SMB protocol contains additional
  24. flag definitions that communicate the type of shares ( DFS aware or otherwise)
  25. to the clients. This information is stored in the redirector data structures.
  26. The DFS driver uses the FsContext2 field of the file object passed to it in
  27. Create calls to communicate the fact that it is a DFS open to the underlying
  28. redirector. This is used to validate opens in the redirector.
  29. With the introduction of CSC as part of the redirector there are some new
  30. wrinkles in the system. Since the DFS driver munges the names passed to it
  31. the name seen by the redirector is very different from the passed in by the
  32. user. If the CSC were to base its database based upon the names passed to
  33. the redirector then a DFS will be required to operate in the offline case.
  34. The DFS driver will persistently store its PKT data structure and do the same
  35. name munging in the offline case. With the introduction of fault tolerant DFS
  36. maintaining the state consistently and persistently will be a very tough
  37. problem.
  38. Another option to consider would be that the CSC database will be maintained
  39. in terms of the path names passed in by the user and not the munged names
  40. passed in by the redirector. This would imply that in the offline state the
  41. CSC code can independently exist to serve files off the DFS namespace without
  42. the DFS driver. The current solution that has been implemented for integrating
  43. CSC and DFS is based on this premise.
  44. In order to make this work we need to establish a mechanism for DFS to pass
  45. in the original name passed into DFS. This is done by usurping the FsContext
  46. field in the file object associated with the IRP that is passed in. DFS
  47. fills in this field with an instance of a DFS defined data structure
  48. (DFS_CSC_NAME_CONTEXT). This data structure contains the original name
  49. passed into DFS alonwith an indication of whether the open was triggerred by
  50. the CSC agent. The DFS driver is responsible for managing the storage
  51. associated with these contexts. When the DFS driver hands over the IRP this
  52. value is filled in and must remain valid till the IRP is completed. On
  53. completion of the IRP the context field would have been overridden by the
  54. underlying driver. The DFS driver cannot rely on the context fields having
  55. the value on return and must take adequate steps to squirrel away the data
  56. in its data structures.
  57. Having thus established the mechanism for DFS to pass in the original name
  58. the next step is to outline the mechanisms for CSC to use it. Since the CSC
  59. database is organized in terms of server/share names we will limit the
  60. discussion to shares with the implicit understanding that the extension to
  61. all file names in the name space is trivial.
  62. The DFS shares that are established for accessing files/folders can be classified
  63. into four categories based on their lifetimes
  64. 1) DFS Share accessed in connected mode only
  65. 2) DFS Share accessed in disconnected mode only
  66. 3) DFS Share established in connected mode but is accessed after transitioning to
  67. disconnected mode
  68. 4) DFS Share established in disconnected mode but is accessed after transitioning
  69. to connected mode.
  70. In the case of connected mode operation we need to ensure that the redirector
  71. consistently manipulates the RDR data structures in terms of the munged name
  72. passed in by the DFS driver and the CSC database in terms of the original
  73. name passed in by the user. As an example consider the following name
  74. \\DfsRoot\DfsShare\foo\bar passed in by the user. This name can be
  75. munged into one of three possible names by the DFS driver.
  76. TBD -- fill in appropriate FTDFS, middle level volume and leaf volume
  77. munged name.
  78. In the current RDR data structures the NET_ROOT_ENTRY claims the first two
  79. components of a name for the CSC database structures. There are two instances
  80. of CSC database handles for the Server ( server and share name in UNC
  81. terminology ) and the root directory. These names were driven off the name
  82. as seen by the redirector ( munged name ). In the modified scheme these will
  83. be driven off the original name passed in by the user. This ensures that no
  84. other code path need be changed in the redirector to facilitate DFS/CSC
  85. integration.
  86. In disconnected mode the names as passed in by the user is passed into the
  87. redirector which passes the appropriate components to CSC. Since CSC is
  88. maintained in terms of original names it works as before.
  89. When the user has modified files on a DFS share it is necessary to ensure
  90. that the DFS name space munging/resolution does not come into play till
  91. the CSC agent has had a chance to ensure that the files have been integrated
  92. This is accomplished by having the redirector preprocess the DFS open requests
  93. in connected mode. If the share has been marked dirty in the CSC database
  94. the redirector munges the name on its own to bypass DFS name resolution and
  95. returns STATUS_REPARSE to the DFS driver.
  96. There is one other situation which needs special treatment. A DFS server/share
  97. cannot be transitioned to disconnected operation by the redirector. Since
  98. the DFS name space is built out of multiple options with a variety of fault
  99. tolerant options the inability to open a file/contact a server in the DFS
  100. namespace cannot lead to transitioning in the redirector. It is left to
  101. the discretion of the DFS driver to implement the appropriate mechanism
  102. --*/
  103. #include "precomp.h"
  104. #pragma hdrstop
  105. #pragma code_seg("PAGE")
  106. NTSTATUS
  107. CscDfsParseDfsPath(
  108. PUNICODE_STRING pDfsPath,
  109. PUNICODE_STRING pServerName,
  110. PUNICODE_STRING pSharePath,
  111. PUNICODE_STRING pFilePathRelativeToShare)
  112. /*++
  113. Routine Description:
  114. This routine parses the DFS path into a share path and a file path
  115. Arguments:
  116. pDfsPath -- the DFS path
  117. pServerName -- the name of the server
  118. pSharePath -- the share path
  119. pFilePathRelativeToShare -- file path relative to share
  120. Return Value:
  121. STATUS_SUCCESS -- successful
  122. STATUS_OBJECT_PATH_INVALID -- the path supplied was invalid
  123. Notes:
  124. Either pServerName or pSharePath or pFilePathRelativeToShare can be NULL
  125. --*/
  126. {
  127. NTSTATUS Status = STATUS_SUCCESS;
  128. PWCHAR pTempPathString;
  129. ULONG NumberOfBackSlashesSkipped;
  130. ULONG TempPathLengthInChars;
  131. ULONG SharePathLengthInChars;
  132. pTempPathString = pDfsPath->Buffer;
  133. TempPathLengthInChars = pDfsPath->Length / sizeof(WCHAR);
  134. if (pServerName != NULL) {
  135. pServerName->Length = pServerName->MaximumLength = 0;
  136. pServerName->Buffer = NULL;
  137. }
  138. if (pSharePath != NULL) {
  139. pSharePath->Length = pSharePath->MaximumLength = 0;
  140. pSharePath->Buffer = NULL;
  141. }
  142. if (pFilePathRelativeToShare != NULL) {
  143. pFilePathRelativeToShare->Length = pFilePathRelativeToShare->MaximumLength = 0;
  144. pFilePathRelativeToShare->Buffer = NULL;
  145. }
  146. // Skip till after the third backslash or the end of the name
  147. // whichever comes first.
  148. // The name we are interested in is of the form \server\share\
  149. // with the last backslash being optional.
  150. NumberOfBackSlashesSkipped = 0;
  151. SharePathLengthInChars = 0;
  152. while (TempPathLengthInChars > 0) {
  153. if (*pTempPathString++ == L'\\') {
  154. NumberOfBackSlashesSkipped++;
  155. if (NumberOfBackSlashesSkipped == 2) {
  156. if (pServerName != NULL) {
  157. pServerName->Length = (USHORT)SharePathLengthInChars * sizeof(WCHAR);
  158. pServerName->MaximumLength = pServerName->Length;
  159. pServerName->Buffer = pDfsPath->Buffer;
  160. }
  161. } else if (NumberOfBackSlashesSkipped == 3) {
  162. break;
  163. }
  164. }
  165. TempPathLengthInChars--;
  166. SharePathLengthInChars++;
  167. }
  168. if (NumberOfBackSlashesSkipped >= 2) {
  169. if (pSharePath != NULL) {
  170. pSharePath->Length = (USHORT)SharePathLengthInChars * sizeof(WCHAR);
  171. pSharePath->MaximumLength = pSharePath->Length;
  172. pSharePath->Buffer = pDfsPath->Buffer;
  173. }
  174. if ((pFilePathRelativeToShare != NULL) &&
  175. (NumberOfBackSlashesSkipped == 3)) {
  176. pFilePathRelativeToShare->Length =
  177. pDfsPath->Length - ((USHORT)SharePathLengthInChars * sizeof(WCHAR));
  178. pFilePathRelativeToShare->MaximumLength = pFilePathRelativeToShare->Length;
  179. pFilePathRelativeToShare->Buffer = pDfsPath->Buffer + SharePathLengthInChars;
  180. }
  181. Status = STATUS_SUCCESS;
  182. } else {
  183. Status = STATUS_OBJECT_PATH_INVALID;
  184. }
  185. return Status;
  186. }
  187. PDFS_NAME_CONTEXT
  188. CscIsValidDfsNameContext(
  189. PVOID pFsContext)
  190. /*++
  191. Routine Description:
  192. This routine determines if the supplied context is a valid DFS_NAME_CONTEXT
  193. Arguments:
  194. pFsContext - the supplied context
  195. Return Value:
  196. valid context ponter if the supplied context is a valid DFS_NAME_CONTEXT
  197. instance, otherwise NULL
  198. Notes:
  199. --*/
  200. {
  201. PDFS_NAME_CONTEXT pValidDfsNameContext = NULL;
  202. if (pFsContext != NULL) {
  203. pValidDfsNameContext = pFsContext;
  204. }
  205. return pValidDfsNameContext;
  206. }
  207. NTSTATUS
  208. CscGrabPathFromDfs(
  209. PFILE_OBJECT pFileObject,
  210. PDFS_NAME_CONTEXT pDfsNameContext)
  211. /*++
  212. Routine Description:
  213. This routine modifies the file object in preparation for returning
  214. STATUS_REPARSE
  215. Arguments:
  216. pFileObject - the file object
  217. pDfsNameContext - the DFS_NAME_CONTEXT instance
  218. Return Value:
  219. STATUS_REPARSE if everything is successful
  220. Notes:
  221. --*/
  222. {
  223. NTSTATUS Status;
  224. USHORT DeviceNameLength,ReparsePathLength;
  225. PWSTR pFileNameBuffer;
  226. DeviceNameLength = wcslen(DD_NFS_DEVICE_NAME_U) *
  227. sizeof(WCHAR);
  228. ReparsePathLength = DeviceNameLength +
  229. pDfsNameContext->UNCFileName.Length;
  230. if (pDfsNameContext->UNCFileName.Buffer[0] != L'\\') {
  231. ReparsePathLength += sizeof(WCHAR);
  232. }
  233. pFileNameBuffer = RxAllocatePoolWithTag(
  234. PagedPool | POOL_COLD_ALLOCATION,
  235. ReparsePathLength,
  236. RX_MISC_POOLTAG);
  237. if (pFileNameBuffer != NULL) {
  238. // Copy the device name
  239. RtlCopyMemory(
  240. pFileNameBuffer,
  241. DD_NFS_DEVICE_NAME_U,
  242. DeviceNameLength);
  243. if (pDfsNameContext->UNCFileName.Buffer[0] != L'\\') {
  244. DeviceNameLength += sizeof(WCHAR);
  245. pFileNameBuffer[DeviceNameLength/sizeof(WCHAR)]
  246. = L'\\';
  247. }
  248. // Copy the new name
  249. RtlCopyMemory(
  250. ((PBYTE)pFileNameBuffer +
  251. DeviceNameLength),
  252. pDfsNameContext->UNCFileName.Buffer,
  253. pDfsNameContext->UNCFileName.Length);
  254. if (pFileObject->FileName.Buffer != NULL)
  255. ExFreePool(pFileObject->FileName.Buffer);
  256. pFileObject->FileName.Buffer = pFileNameBuffer;
  257. pFileObject->FileName.Length = ReparsePathLength;
  258. pFileObject->FileName.MaximumLength =
  259. pFileObject->FileName.Length;
  260. Status = STATUS_REPARSE;
  261. } else {
  262. Status = STATUS_INSUFFICIENT_RESOURCES;
  263. }
  264. return Status;
  265. }
  266. NTSTATUS
  267. CscPreProcessCreateIrp(
  268. PIRP pIrp)
  269. /*++
  270. Routine Description:
  271. This routine determines if the CSC/Redirector should defeat the DFS
  272. name resolution scheme
  273. Arguments:
  274. pIrp - the IRP
  275. Return Value:
  276. This routine bases this determination on whether there are dirty files
  277. corresponding to this DFS share name. If there are the name is claimed by
  278. the redirector by changing the file name to the new value and returning
  279. STATUS_REPARSE. In all other cases STATUS_SUCCESS is returned.
  280. Notes:
  281. This routine assumes that the name passed in the DFS_NAME_CONTEXT is a
  282. name in the following format irrespective of whether the user specifies a
  283. drive letter based name or a UNC name.
  284. \DfsRoot\DfsShare\ ....
  285. --*/
  286. {
  287. NTSTATUS Status;
  288. PIO_STACK_LOCATION pIrpSp;
  289. PFILE_OBJECT pFileObject;
  290. PDFS_NAME_CONTEXT pDfsNameContext;
  291. if(!MRxSmbIsCscEnabled ||
  292. !fShadow
  293. ) {
  294. return(STATUS_SUCCESS);
  295. }
  296. Status = STATUS_SUCCESS;
  297. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  298. pFileObject = pIrpSp->FileObject;
  299. pDfsNameContext = CscIsValidDfsNameContext(pFileObject->FsContext);
  300. if ((pDfsNameContext != NULL) &&
  301. (pDfsNameContext->NameContextType != DFS_CSCAGENT_NAME_CONTEXT)) {
  302. UNICODE_STRING ShareName;
  303. UNICODE_STRING ServerName;
  304. Status = CscDfsParseDfsPath(
  305. &pDfsNameContext->UNCFileName,
  306. &ServerName,
  307. &ShareName,
  308. NULL);
  309. // Locate the share name / server name in the database.
  310. if (Status == STATUS_SUCCESS) {
  311. // At this stage the given path name has been parsed into the
  312. // relevant components, i.e., the server name, the share name
  313. // ( also includes the server name ) and the file name relative
  314. // to the share. Of these the first two components are valuable
  315. // in determining whether the given path has to be grabbed from
  316. // DFS.
  317. Status = STATUS_MORE_PROCESSING_REQUIRED;
  318. // If a server entry exists in the connection engine database
  319. // for the given server name and it had been marked for
  320. // disconnected operation then the path needs to be grabbed from
  321. // DFS. This will take into account those cases wherein there
  322. // is some connectivity but the DFS root has been explicitly
  323. // marked for disconnected operation.
  324. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  325. PSMBCEDB_SERVER_ENTRY pServerEntry;
  326. SmbCeAcquireResource();
  327. pServerEntry = SmbCeFindServerEntry(
  328. &ServerName,
  329. SMBCEDB_FILE_SERVER,
  330. NULL);
  331. SmbCeReleaseResource();
  332. if (pServerEntry != NULL) {
  333. if (SmbCeIsServerInDisconnectedMode(pServerEntry)) {
  334. Status = STATUS_REPARSE;
  335. }
  336. SmbCeDereferenceServerEntry(pServerEntry);
  337. }
  338. }
  339. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  340. // If no server entry exists or it has not been transitioned into
  341. // disconnected mode we check the CSC database for an entry
  342. // corresponding to the given share name. If one exists and there
  343. // are no transports available then the name needs to be grabbed.
  344. // This takes into account all the cases wherein there is no
  345. // net connectivity.
  346. SHADOWINFO ShadowInfo;
  347. DWORD CscServerStatus;
  348. EnterShadowCrit();
  349. CscServerStatus = FindCreateShareForNt(
  350. &ShareName,
  351. FALSE,
  352. &ShadowInfo,
  353. NULL);
  354. LeaveShadowCrit();
  355. if ( CscServerStatus == SRET_OK ) {
  356. PSMBCE_TRANSPORT_ARRAY pTransportArray;
  357. // If an entry corresponding to the dfs root exists in the
  358. // CSC database transition to using it either if it is marked
  359. // dirty or there are no transports.
  360. pTransportArray = SmbCeReferenceTransportArray();
  361. SmbCeDereferenceTransportArray(pTransportArray);
  362. if (pTransportArray == NULL) {
  363. Status = STATUS_REPARSE;
  364. }
  365. }
  366. }
  367. // if the status value is STATUS_REPARSE one of the rule applications
  368. // was successful and we do the appropriate name munging to grab
  369. // the DFS path
  370. // If the status value is still STATUS_MORE_PROCESSING_REQUIRED
  371. // it implies that none of our rules for reparsing the DFS path
  372. // was successful. We map the status back to STATUS_SUCCESS to
  373. // resume the connected mode of operation
  374. if (Status == STATUS_REPARSE) {
  375. if (pDfsNameContext->Flags & DFS_FLAG_LAST_ALTERNATE) {
  376. Status = CscGrabPathFromDfs(
  377. pFileObject,
  378. pDfsNameContext);
  379. } else {
  380. Status = STATUS_NETWORK_UNREACHABLE;
  381. }
  382. } else if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  383. Status = STATUS_SUCCESS;
  384. }
  385. }
  386. }
  387. return Status;
  388. }
  389. NTSTATUS
  390. CscDfsDoDfsNameMapping(
  391. IN PUNICODE_STRING pDfsPrefix,
  392. IN PUNICODE_STRING pActualPrefix,
  393. IN PUNICODE_STRING pNameToMap,
  394. IN BOOL fResolvedNameToDFSName,
  395. OUT PUNICODE_STRING pResult
  396. )
  397. /*++
  398. Routine Description:
  399. Given the DfsPrefix and it's corresponding actualprefix, this routine maps a resolved
  400. name to the corresponding DFS name or viceversa
  401. As an example if \\csctest\dfs\ntfs is actually resolved to \\dkruse1\ntfs
  402. then \\csctest\dfs\ntfs\dir1\foo.txt resolves to \\dkruse1\ntfs\dir1\foo.txt.
  403. The DFS prefix in this case is \ntfs and the Actual prefix is \.
  404. Thus, given an actual path \dir1\foo.txt, this routine reverse maps it to
  405. \ntfs\dir1\foo.txt or viceversa
  406. Arguments:
  407. pDfsPrefix Dfs Name prefix
  408. pActaulPrefix Corresponding actual prefix
  409. pNameToMap Actual name
  410. fResolvedNameToDFSName If true, we are converting resolved name to DFS name, else viceversa
  411. pResult Output DFS name
  412. Return Value:
  413. STATUS_SUCCESS if successful, NT error code otherwise
  414. Notes:
  415. This routine is used by CSC to obtain a DFS name from an actual name or viceversa. It is used to get the
  416. DFS name of a rename name so that the CSC database can do the manipulations in terms
  417. of the DFS names. It is also used to get the info from the server using the real name
  418. while createing entries in the CSC database in the DFS namespace.
  419. --*/
  420. {
  421. NTSTATUS Status = STATUS_NO_SUCH_FILE;
  422. PUNICODE_STRING pSourcePrefix=pActualPrefix , pDestPrefix=pDfsPrefix;
  423. UNICODE_STRING NameToCopy;
  424. memset(pResult, 0, sizeof(UNICODE_STRING));
  425. if (fResolvedNameToDFSName)
  426. {
  427. // converting resolved name to DFS name
  428. pSourcePrefix=pActualPrefix;
  429. pDestPrefix=pDfsPrefix;
  430. }
  431. else
  432. {
  433. // converting DFS name to resolved name
  434. pSourcePrefix=pDfsPrefix;
  435. pDestPrefix=pActualPrefix;
  436. }
  437. // DbgPrint("CscDoDfsnamemapping: DestPrefix=%wZ SourcePrefix=%wZ NameToMap=%wZ\n",
  438. // pDestPrefix, pSourcePrefix, pNameToMap);
  439. //mathc the prefix
  440. if (RtlPrefixUnicodeString(pSourcePrefix, pNameToMap, TRUE))
  441. {
  442. ASSERT(pNameToMap->Length >= pSourcePrefix->Length);
  443. // Calculate the max length.
  444. pResult->MaximumLength = pDestPrefix->Length + pNameToMap->Length - pSourcePrefix->Length+2;
  445. pResult->Buffer = (PWCHAR)AllocMem(pResult->MaximumLength);
  446. if (pResult->Buffer)
  447. {
  448. // set the initial length
  449. pResult->Length = pDestPrefix->Length;
  450. memcpy(pResult->Buffer, pDestPrefix->Buffer, pDestPrefix->Length);
  451. // if there isn't a terminating backslash, put it in there
  452. if (pResult->Buffer[pResult->Length/sizeof(USHORT)-1] != L'\\')
  453. {
  454. pResult->Buffer[pResult->Length/sizeof(USHORT)] = L'\\';
  455. pResult->Length += 2;
  456. }
  457. NameToCopy.Buffer = pNameToMap->Buffer+pSourcePrefix->Length/sizeof(USHORT);
  458. NameToCopy.Length = pNameToMap->Length-pSourcePrefix->Length;
  459. // DbgPrint("CscDoDfsNameMapping: Copying %wZ\n", &NameToCopy);
  460. // now copy the nametomap without the sourceprefix, into the buffer
  461. memcpy( pResult->Buffer+pResult->Length/sizeof(USHORT),
  462. NameToCopy.Buffer,
  463. NameToCopy.Length);
  464. pResult->Length += NameToCopy.Length;
  465. ASSERT(pResult->Length <= pResult->MaximumLength);
  466. // DbgPrint("CscDoDfsNameMapping: pResult %wZ\n", pResult);
  467. Status = STATUS_SUCCESS;
  468. }
  469. else
  470. {
  471. Status = STATUS_INSUFFICIENT_RESOURCES;
  472. }
  473. }
  474. return Status;
  475. }
  476. NTSTATUS
  477. CscDfsObtainReverseMapping(
  478. IN PUNICODE_STRING pDfsPath,
  479. IN PUNICODE_STRING pResolvedPath,
  480. OUT PUNICODE_STRING pReverseMappingDfs,
  481. OUT PUNICODE_STRING pReverseMappingActual)
  482. /*++
  483. Routine Description:
  484. This routine obtains the mapping strings which allow csc to map a resolved path
  485. to a DFS path
  486. As an example if \\csctest\dfs\ntfs is actually resolved to \\dkruse1\ntfs
  487. then \\csctest\dfs\ntfs\dir1\foo.txt resolves to \\dkruse1\ntfs\dir1\foo.txt.
  488. The DFS prefix in this case is \ntfs and the Actual prefix is \.
  489. Arguments:
  490. pDfsPath Path relative to the root of the DFS share
  491. pResolvedPath Path relative to the actual share
  492. pReverseMappingDfs
  493. pReverseMappingActual
  494. Return Value:
  495. STATUS_SUCCESS if successful, NT error code otherwise
  496. Notes:
  497. --*/
  498. {
  499. NTSTATUS Status=STATUS_INSUFFICIENT_RESOURCES;
  500. PWCHAR pDfs, pActual;
  501. WCHAR wDfs, wActual;
  502. DWORD cbDfs=0, cbActual=0;
  503. UNICODE_STRING uniSavResolved, uniSavDfs;
  504. BOOL fSavedResolved = FALSE, fSavedDfs = FALSE;
  505. // take care of the root
  506. if (pResolvedPath->Length == 0)
  507. {
  508. uniSavResolved = *pResolvedPath;
  509. pResolvedPath->Length = pResolvedPath->MaximumLength = 2;
  510. pResolvedPath->Buffer = L"\\";
  511. fSavedResolved = TRUE;
  512. }
  513. // take care of the root
  514. if (pDfsPath->Length == 0)
  515. {
  516. uniSavDfs = *pDfsPath;
  517. pDfsPath->Length = pDfsPath->MaximumLength = 2;
  518. pDfsPath->Buffer = L"\\";
  519. fSavedDfs = TRUE;
  520. }
  521. memset(pReverseMappingDfs, 0, sizeof(UNICODE_STRING));
  522. memset(pReverseMappingActual, 0, sizeof(UNICODE_STRING));
  523. // point to the end of each string
  524. pDfs = (PWCHAR)((LPBYTE)(pDfsPath->Buffer)+pDfsPath->Length - 2);
  525. cbDfs = pDfsPath->Length;
  526. pActual = (PWCHAR)((LPBYTE)(pResolvedPath->Buffer)+pResolvedPath->Length - 2);
  527. cbActual = pResolvedPath->Length;
  528. // DbgPrint("CscDfsObtainReverseMapping: In DfsPath=%wZ ResolvedPath=%wZ\n", pDfsPath, pResolvedPath);
  529. pReverseMappingDfs->MaximumLength = pReverseMappingDfs->Length = (USHORT)cbDfs;
  530. pReverseMappingActual->MaximumLength = pReverseMappingActual->Length = (USHORT)cbActual;
  531. for (;;)
  532. {
  533. // do an upcase comparison
  534. wDfs = RtlUpcaseUnicodeChar(*pDfs);
  535. wActual = RtlUpcaseUnicodeChar(*pActual);
  536. if (wDfs != wActual)
  537. {
  538. ASSERT(pReverseMappingDfs->Length && pReverseMappingActual->Length);
  539. break;
  540. }
  541. // if we reached a backslash, checkpoint the path upto this point
  542. if (wDfs == (WCHAR)'\\')
  543. {
  544. pReverseMappingDfs->MaximumLength = pReverseMappingDfs->Length = (USHORT)cbDfs;
  545. pReverseMappingActual->MaximumLength = pReverseMappingActual->Length = (USHORT)cbActual;
  546. }
  547. if ((pDfs == pDfsPath->Buffer)||(pActual == pResolvedPath->Buffer))
  548. {
  549. break;
  550. }
  551. --pDfs;--pActual;
  552. cbDfs -= 2; cbActual -= 2;
  553. }
  554. pReverseMappingDfs->Buffer = (PWCHAR)RxAllocatePoolWithTag(NonPagedPool, pReverseMappingDfs->Length, RX_MISC_POOLTAG);
  555. if (pReverseMappingDfs->Buffer)
  556. {
  557. pReverseMappingActual->Buffer = (PWCHAR)RxAllocatePoolWithTag(NonPagedPool, pReverseMappingActual->Length, RX_MISC_POOLTAG);
  558. if (pReverseMappingActual->Buffer)
  559. {
  560. memcpy(pReverseMappingDfs->Buffer, pDfsPath->Buffer, pReverseMappingDfs->Length);
  561. memcpy(pReverseMappingActual->Buffer, pResolvedPath->Buffer, pReverseMappingActual->Length);
  562. // DbgPrint("CscDfsObtainReverseMapping: out DfsPrefix=%wZ ActualPrefix=%wZ\n", pReverseMappingDfs, pReverseMappingActual);
  563. Status = STATUS_SUCCESS;
  564. }
  565. }
  566. if (Status != STATUS_SUCCESS)
  567. {
  568. if (pReverseMappingDfs->Buffer)
  569. {
  570. FreeMem(pReverseMappingDfs->Buffer);
  571. }
  572. pReverseMappingDfs->Buffer = NULL;
  573. if (pReverseMappingActual->Buffer)
  574. {
  575. FreeMem(pReverseMappingActual->Buffer);
  576. }
  577. pReverseMappingActual->Buffer = NULL;
  578. }
  579. if (fSavedResolved)
  580. {
  581. *pResolvedPath = uniSavResolved;
  582. }
  583. if (fSavedDfs)
  584. {
  585. *pDfsPath = uniSavDfs;
  586. }
  587. return Status;
  588. }
  589. NTSTATUS
  590. CscDfsStripLeadingServerShare(
  591. IN PUNICODE_STRING pDfsRootPath
  592. )
  593. /*++
  594. Routine Description:
  595. This routine strips the leading server-share of a DFS root path. Thus when Dfs sends down a path
  596. relative to the root such as \server\share\foo.txt, this routien makes the path \foo.txt
  597. Arguments:
  598. pDfsRootPath Path relative to the root of the DFS share
  599. Return Value:
  600. STATUS_SUCCESS if successful, NT error code otherwise
  601. Notes:
  602. --*/
  603. {
  604. ULONG cnt = 0, i;
  605. DbgPrint("Stripping %wZ \n", pDfsRootPath);
  606. for (i=0; ;++i)
  607. {
  608. if (i*sizeof(WCHAR) > pDfsRootPath->Length)
  609. {
  610. return STATUS_UNSUCCESSFUL;
  611. }
  612. if (pDfsRootPath->Buffer[i] == '\\')
  613. {
  614. // if this is the 3rd slash then we have successfully stripped the name
  615. if (cnt == 2)
  616. {
  617. break;
  618. }
  619. cnt++;
  620. }
  621. }
  622. pDfsRootPath->Buffer = &pDfsRootPath->Buffer[i];
  623. pDfsRootPath->Length -= (USHORT)(i * sizeof(WCHAR));
  624. DbgPrint("Stripped name %wZ \n", pDfsRootPath);
  625. return STATUS_SUCCESS;
  626. }