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.

2528 lines
76 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. volmount.c
  5. Abstract:
  6. This file contains the implementation for the Volume Mount Point API.
  7. Author:
  8. Norbert P. Kusters (norbertk) 22-Dec-1997
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #include "initguid.h"
  13. #include "mountmgr.h"
  14. // NOTE, this structure is here because it was not defined in NTIOAPI.H.
  15. // This should be taken out in the future.
  16. // This is stolen from NTFS.H
  17. typedef struct _REPARSE_INDEX_KEY {
  18. //
  19. // The tag of the reparse point.
  20. //
  21. ULONG FileReparseTag;
  22. //
  23. // The file record Id where the reparse point is set.
  24. //
  25. LARGE_INTEGER FileId;
  26. } REPARSE_INDEX_KEY, *PREPARSE_INDEX_KEY;
  27. HANDLE
  28. WINAPI
  29. FindFirstVolumeA(
  30. LPSTR lpszVolumeName,
  31. DWORD cchBufferLength
  32. )
  33. {
  34. ANSI_STRING ansiVolumeName;
  35. UNICODE_STRING unicodeVolumeName;
  36. HANDLE h;
  37. NTSTATUS status;
  38. ansiVolumeName.Buffer = lpszVolumeName;
  39. ansiVolumeName.MaximumLength = (USHORT) (cchBufferLength - 1);
  40. unicodeVolumeName.Buffer = NULL;
  41. unicodeVolumeName.MaximumLength = 0;
  42. try {
  43. unicodeVolumeName.MaximumLength = (ansiVolumeName.MaximumLength + 1)*
  44. sizeof(WCHAR);
  45. unicodeVolumeName.Buffer =
  46. RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  47. unicodeVolumeName.MaximumLength);
  48. if (!unicodeVolumeName.Buffer) {
  49. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  50. h = INVALID_HANDLE_VALUE;
  51. leave;
  52. }
  53. h = FindFirstVolumeW(unicodeVolumeName.Buffer, cchBufferLength);
  54. if (h != INVALID_HANDLE_VALUE) {
  55. RtlInitUnicodeString(&unicodeVolumeName, unicodeVolumeName.Buffer);
  56. status = BasepUnicodeStringTo8BitString(&ansiVolumeName,
  57. &unicodeVolumeName, FALSE);
  58. if (!NT_SUCCESS(status)) {
  59. BaseSetLastNTError(status);
  60. h = INVALID_HANDLE_VALUE;
  61. leave;
  62. }
  63. ansiVolumeName.Buffer[ansiVolumeName.Length] = 0;
  64. }
  65. } finally {
  66. if (unicodeVolumeName.Buffer) {
  67. RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeName.Buffer);
  68. }
  69. }
  70. return h;
  71. }
  72. HANDLE
  73. WINAPI
  74. FindFirstVolumeW(
  75. LPWSTR lpszVolumeName,
  76. DWORD cchBufferLength
  77. )
  78. /*++
  79. Routine Description:
  80. This routine kicks off the enumeration of all volumes in the system.
  81. Arguments:
  82. lpszVolumeName - Returns the first volume name in the system.
  83. cchBufferLength - Supplies the size of the preceeding buffer.
  84. Return Value:
  85. A valid handle or INVALID_HANDLE_VALUE.
  86. --*/
  87. {
  88. HANDLE h;
  89. MOUNTMGR_MOUNT_POINT point;
  90. PMOUNTMGR_MOUNT_POINTS points;
  91. BOOL b;
  92. DWORD bytes;
  93. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0,
  94. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  95. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  96. INVALID_HANDLE_VALUE);
  97. if (h == INVALID_HANDLE_VALUE) {
  98. return INVALID_HANDLE_VALUE;
  99. }
  100. RtlZeroMemory(&point, sizeof(point));
  101. points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  102. sizeof(MOUNTMGR_MOUNT_POINTS));
  103. if (!points) {
  104. CloseHandle(h);
  105. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  106. return INVALID_HANDLE_VALUE;
  107. }
  108. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, &point, sizeof(point),
  109. points, sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
  110. while (!b && GetLastError() == ERROR_MORE_DATA) {
  111. bytes = points->Size;
  112. RtlFreeHeap(RtlProcessHeap(), 0, points);
  113. points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), bytes);
  114. if (!points) {
  115. CloseHandle(h);
  116. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  117. return INVALID_HANDLE_VALUE;
  118. }
  119. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, &point,
  120. sizeof(point), points, bytes, &bytes, NULL);
  121. }
  122. CloseHandle(h);
  123. if (!b) {
  124. RtlFreeHeap(RtlProcessHeap(), 0, points);
  125. return INVALID_HANDLE_VALUE;
  126. }
  127. b = FindNextVolumeW((HANDLE) points, lpszVolumeName, cchBufferLength);
  128. if (!b) {
  129. RtlFreeHeap(RtlProcessHeap(), 0, points);
  130. return INVALID_HANDLE_VALUE;
  131. }
  132. return (HANDLE) points;
  133. }
  134. BOOL
  135. WINAPI
  136. FindNextVolumeA(
  137. HANDLE hFindVolume,
  138. LPSTR lpszVolumeName,
  139. DWORD cchBufferLength
  140. )
  141. {
  142. ANSI_STRING ansiVolumeName;
  143. UNICODE_STRING unicodeVolumeName;
  144. BOOL b;
  145. NTSTATUS status;
  146. ansiVolumeName.Buffer = lpszVolumeName;
  147. ansiVolumeName.MaximumLength = (USHORT) (cchBufferLength - 1);
  148. unicodeVolumeName.Buffer = NULL;
  149. unicodeVolumeName.MaximumLength = 0;
  150. try {
  151. unicodeVolumeName.MaximumLength = (ansiVolumeName.MaximumLength + 1)*
  152. sizeof(WCHAR);
  153. unicodeVolumeName.Buffer =
  154. RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  155. unicodeVolumeName.MaximumLength);
  156. if (!unicodeVolumeName.Buffer) {
  157. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  158. b = FALSE;
  159. leave;
  160. }
  161. b = FindNextVolumeW(hFindVolume, unicodeVolumeName.Buffer,
  162. cchBufferLength);
  163. if (b) {
  164. RtlInitUnicodeString(&unicodeVolumeName, unicodeVolumeName.Buffer);
  165. status = BasepUnicodeStringTo8BitString(&ansiVolumeName,
  166. &unicodeVolumeName, FALSE);
  167. if (!NT_SUCCESS(status)) {
  168. BaseSetLastNTError(status);
  169. b = FALSE;
  170. leave;
  171. }
  172. ansiVolumeName.Buffer[ansiVolumeName.Length] = 0;
  173. }
  174. } finally {
  175. if (unicodeVolumeName.Buffer) {
  176. RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeName.Buffer);
  177. }
  178. }
  179. return b;
  180. }
  181. BOOL
  182. WINAPI
  183. FindNextVolumeW(
  184. HANDLE hFindVolume,
  185. LPWSTR lpszVolumeName,
  186. DWORD cchBufferLength
  187. )
  188. /*++
  189. Routine Description:
  190. This routine continues the enumeration of all volumes in the system.
  191. Arguments:
  192. hFindVolume - Supplies the find volume handle.
  193. lpszVolumeName - Returns the first volume name in the system.
  194. cchBufferLength - Supplies the size of the preceeding buffer.
  195. Return Value:
  196. FALSE - Failure. The error code is returned in GetLastError().
  197. TRUE - Success.
  198. --*/
  199. {
  200. PMOUNTMGR_MOUNT_POINTS points = hFindVolume;
  201. DWORD i, j;
  202. PMOUNTMGR_MOUNT_POINT point, point2;
  203. UNICODE_STRING symName, symName2, devName, devName2;
  204. for (i = 0; i < points->NumberOfMountPoints; i++) {
  205. point = &points->MountPoints[i];
  206. if (!point->SymbolicLinkNameOffset) {
  207. continue;
  208. }
  209. symName.Length = symName.MaximumLength = point->SymbolicLinkNameLength;
  210. symName.Buffer = (PWSTR) ((PCHAR) points +
  211. point->SymbolicLinkNameOffset);
  212. if (!MOUNTMGR_IS_NT_VOLUME_NAME(&symName)) {
  213. point->SymbolicLinkNameOffset = 0;
  214. continue;
  215. }
  216. devName.Length = devName.MaximumLength = point->DeviceNameLength;
  217. devName.Buffer = (PWSTR) ((PCHAR) points +
  218. point->DeviceNameOffset);
  219. for (j = i + 1; j < points->NumberOfMountPoints; j++) {
  220. point2 = &points->MountPoints[j];
  221. if (!point2->SymbolicLinkNameOffset) {
  222. continue;
  223. }
  224. symName2.Length = symName2.MaximumLength =
  225. point2->SymbolicLinkNameLength;
  226. symName2.Buffer = (PWSTR) ((PCHAR) points +
  227. point2->SymbolicLinkNameOffset);
  228. if (!MOUNTMGR_IS_NT_VOLUME_NAME(&symName2)) {
  229. point2->SymbolicLinkNameOffset = 0;
  230. continue;
  231. }
  232. devName2.Length = devName2.MaximumLength =
  233. point2->DeviceNameLength;
  234. devName2.Buffer = (PWSTR) ((PCHAR) points +
  235. point2->DeviceNameOffset);
  236. if (RtlEqualUnicodeString(&devName, &devName2, TRUE)) {
  237. point2->SymbolicLinkNameOffset = 0;
  238. }
  239. }
  240. break;
  241. }
  242. if (i == points->NumberOfMountPoints) {
  243. SetLastError(ERROR_NO_MORE_FILES);
  244. return FALSE;
  245. }
  246. if (cchBufferLength*sizeof(WCHAR) < point->SymbolicLinkNameLength +
  247. 2*sizeof(WCHAR)) {
  248. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  249. return FALSE;
  250. }
  251. RtlCopyMemory(lpszVolumeName, (PCHAR) points +
  252. point->SymbolicLinkNameOffset,
  253. point->SymbolicLinkNameLength);
  254. lpszVolumeName[1] = '\\';
  255. lpszVolumeName[point->SymbolicLinkNameLength/sizeof(WCHAR)] = '\\';
  256. lpszVolumeName[point->SymbolicLinkNameLength/sizeof(WCHAR) + 1] = 0;
  257. point->SymbolicLinkNameOffset = 0;
  258. return TRUE;
  259. }
  260. BOOL
  261. WINAPI
  262. FindVolumeClose(
  263. HANDLE hFindVolume
  264. )
  265. {
  266. RtlFreeHeap(RtlProcessHeap(), 0, hFindVolume);
  267. return TRUE;
  268. }
  269. HANDLE
  270. WINAPI
  271. FindFirstVolumeMountPointA(
  272. LPCSTR lpszRootPathName,
  273. LPSTR lpszVolumeMountPoint,
  274. DWORD cchBufferLength
  275. )
  276. {
  277. PUNICODE_STRING unicodeRootPathName;
  278. ANSI_STRING ansiVolumeMountPoint;
  279. UNICODE_STRING unicodeVolumeMountPoint;
  280. HANDLE h;
  281. NTSTATUS status;
  282. unicodeRootPathName =
  283. Basep8BitStringToStaticUnicodeString(lpszRootPathName);
  284. if (!unicodeRootPathName) {
  285. return INVALID_HANDLE_VALUE;
  286. }
  287. ansiVolumeMountPoint.Buffer = lpszVolumeMountPoint;
  288. ansiVolumeMountPoint.MaximumLength = (USHORT) (cchBufferLength - 1);
  289. unicodeVolumeMountPoint.Buffer = NULL;
  290. unicodeVolumeMountPoint.MaximumLength = 0;
  291. try {
  292. unicodeVolumeMountPoint.MaximumLength =
  293. (ansiVolumeMountPoint.MaximumLength + 1)*sizeof(WCHAR);
  294. unicodeVolumeMountPoint.Buffer =
  295. RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  296. unicodeVolumeMountPoint.MaximumLength);
  297. if (!unicodeVolumeMountPoint.Buffer) {
  298. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  299. return INVALID_HANDLE_VALUE;
  300. }
  301. h = FindFirstVolumeMountPointW(unicodeRootPathName->Buffer,
  302. unicodeVolumeMountPoint.Buffer,
  303. cchBufferLength);
  304. if (h != INVALID_HANDLE_VALUE) {
  305. RtlInitUnicodeString(&unicodeVolumeMountPoint,
  306. unicodeVolumeMountPoint.Buffer);
  307. status = BasepUnicodeStringTo8BitString(&ansiVolumeMountPoint,
  308. &unicodeVolumeMountPoint,
  309. FALSE);
  310. if (!NT_SUCCESS(status)) {
  311. BaseSetLastNTError(status);
  312. h = INVALID_HANDLE_VALUE;
  313. leave;
  314. }
  315. ansiVolumeMountPoint.Buffer[ansiVolumeMountPoint.Length] = 0;
  316. }
  317. } finally {
  318. if (unicodeVolumeMountPoint.Buffer) {
  319. RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeMountPoint.Buffer);
  320. }
  321. }
  322. return h;
  323. }
  324. BOOL
  325. FindNextVolumeMountPointHelper(
  326. HANDLE hFindVolumeMountPoint,
  327. LPWSTR lpszVolumeMountPoint,
  328. DWORD cchBufferLength,
  329. BOOL FirstTimeCalled
  330. )
  331. /*++
  332. Routine Description:
  333. This routine continues the enumeration of all volume mount point on the
  334. given volume.
  335. Arguments:
  336. hFindVolumeMountPoint - Supplies the handle for the enumeration.
  337. lpszVolumeMountPoint - Returns the volume mount point.
  338. cchBufferLength - Supplies the volume mount point buffer length.
  339. FirstTimeCalled - Supplies whether or not this is being called
  340. from FindFirst or from FindNext.
  341. Return Value:
  342. FALSE - Failure.
  343. TRUE - Success.
  344. --*/
  345. {
  346. REPARSE_INDEX_KEY reparseKey;
  347. UNICODE_STRING reparseName;
  348. NTSTATUS status;
  349. IO_STATUS_BLOCK ioStatus;
  350. FILE_REPARSE_POINT_INFORMATION reparseInfo;
  351. UNICODE_STRING fileId;
  352. OBJECT_ATTRIBUTES oa;
  353. HANDLE h;
  354. PREPARSE_DATA_BUFFER reparse;
  355. BOOL b;
  356. DWORD bytes;
  357. UNICODE_STRING mountName;
  358. DWORD nameInfoSize;
  359. PFILE_NAME_INFORMATION nameInfo;
  360. for (;;) {
  361. if (FirstTimeCalled) {
  362. FirstTimeCalled = FALSE;
  363. RtlZeroMemory(&reparseKey, sizeof(reparseKey));
  364. reparseKey.FileReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
  365. reparseName.Length = reparseName.MaximumLength = sizeof(reparseKey);
  366. reparseName.Buffer = (PWCHAR) &reparseKey;
  367. status = NtQueryDirectoryFile(hFindVolumeMountPoint,
  368. NULL, NULL, NULL, &ioStatus,
  369. &reparseInfo, sizeof(reparseInfo),
  370. FileReparsePointInformation, TRUE,
  371. &reparseName, FALSE);
  372. } else {
  373. status = NtQueryDirectoryFile(hFindVolumeMountPoint,
  374. NULL, NULL, NULL, &ioStatus,
  375. &reparseInfo, sizeof(reparseInfo),
  376. FileReparsePointInformation, TRUE,
  377. NULL, FALSE);
  378. }
  379. if (!NT_SUCCESS(status)) {
  380. BaseSetLastNTError(status);
  381. return FALSE;
  382. }
  383. if (reparseInfo.Tag != IO_REPARSE_TAG_MOUNT_POINT) {
  384. SetLastError(ERROR_NO_MORE_FILES);
  385. return FALSE;
  386. }
  387. fileId.Length = sizeof(reparseInfo.FileReference);
  388. fileId.MaximumLength = fileId.Length;
  389. fileId.Buffer = (PWSTR) &reparseInfo.FileReference;
  390. InitializeObjectAttributes(&oa, &fileId, 0, hFindVolumeMountPoint,
  391. NULL);
  392. status = NtOpenFile(&h, FILE_GENERIC_READ, &oa, &ioStatus,
  393. FILE_SHARE_READ | FILE_SHARE_WRITE,
  394. FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT);
  395. if (!NT_SUCCESS(status)) {
  396. BaseSetLastNTError(status);
  397. return FALSE;
  398. }
  399. reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  400. MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  401. if (!reparse) {
  402. CloseHandle(h);
  403. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  404. return FALSE;
  405. }
  406. b = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
  407. MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, NULL);
  408. if (!b || reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
  409. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  410. CloseHandle(h);
  411. return FALSE;
  412. }
  413. mountName.Length = mountName.MaximumLength =
  414. reparse->MountPointReparseBuffer.SubstituteNameLength;
  415. mountName.Buffer = (PWSTR)
  416. ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
  417. reparse->MountPointReparseBuffer.SubstituteNameOffset);
  418. if (!MOUNTMGR_IS_NT_VOLUME_NAME_WB(&mountName)) {
  419. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  420. CloseHandle(h);
  421. continue;
  422. }
  423. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  424. nameInfoSize = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) +
  425. (cchBufferLength - 1)*sizeof(WCHAR);
  426. nameInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  427. nameInfoSize);
  428. if (!nameInfo) {
  429. CloseHandle(h);
  430. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  431. return FALSE;
  432. }
  433. status = NtQueryInformationFile(h, &ioStatus, nameInfo, nameInfoSize,
  434. FileNameInformation);
  435. if (!NT_SUCCESS(status)) {
  436. RtlFreeHeap(RtlProcessHeap(), 0, nameInfo);
  437. CloseHandle(h);
  438. BaseSetLastNTError(status);
  439. return FALSE;
  440. }
  441. RtlCopyMemory(lpszVolumeMountPoint, &nameInfo->FileName[1],
  442. nameInfo->FileNameLength - sizeof(WCHAR));
  443. lpszVolumeMountPoint[nameInfo->FileNameLength/sizeof(WCHAR) - 1] = '\\';
  444. lpszVolumeMountPoint[nameInfo->FileNameLength/sizeof(WCHAR)] = 0;
  445. RtlFreeHeap(RtlProcessHeap(), 0, nameInfo);
  446. CloseHandle(h);
  447. break;
  448. }
  449. return TRUE;
  450. }
  451. HANDLE
  452. WINAPI
  453. FindFirstVolumeMountPointW(
  454. LPCWSTR lpszRootPathName,
  455. LPWSTR lpszVolumeMountPoint,
  456. DWORD cchBufferLength
  457. )
  458. /*++
  459. Routine Description:
  460. This routine kicks off the enumeration of all volume mount point on the
  461. given volume.
  462. Arguments:
  463. lpszRootPathName - Supplies the root path name.
  464. lpszVolumeMountPoint - Returns the volume mount point.
  465. cchBufferLength - Supplies the volume mount point buffer length.
  466. Return Value:
  467. A handle or INVALID_HANDLE_VALUE.
  468. --*/
  469. {
  470. UNICODE_STRING unicodeRootPathName;
  471. UNICODE_STRING reparseSuffix, reparseName;
  472. HANDLE h;
  473. BOOL b;
  474. NTSTATUS Status;
  475. ULONG TotalSize;
  476. Status = RtlInitUnicodeStringEx(&unicodeRootPathName, lpszRootPathName);
  477. if( !NT_SUCCESS(Status) ) {
  478. BaseSetLastNTError(Status);
  479. return INVALID_HANDLE_VALUE;
  480. }
  481. if (unicodeRootPathName.Buffer[
  482. unicodeRootPathName.Length/sizeof(WCHAR) - 1] != '\\') {
  483. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  484. return INVALID_HANDLE_VALUE;
  485. }
  486. RtlInitUnicodeString(&reparseSuffix,
  487. L"$Extend\\$Reparse:$R:$INDEX_ALLOCATION");
  488. TotalSize = unicodeRootPathName.Length + reparseSuffix.Length + sizeof(WCHAR);
  489. if( TotalSize > MAXUSHORT ) {
  490. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  491. return INVALID_HANDLE_VALUE;
  492. }
  493. reparseName.MaximumLength = (USHORT)TotalSize;
  494. reparseName.Length = 0;
  495. reparseName.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  496. reparseName.MaximumLength);
  497. if (!reparseName.Buffer) {
  498. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  499. return INVALID_HANDLE_VALUE;
  500. }
  501. RtlCopyUnicodeString(&reparseName, &unicodeRootPathName);
  502. RtlAppendUnicodeStringToString(&reparseName, &reparseSuffix);
  503. reparseName.Buffer[reparseName.Length/sizeof(WCHAR)] = 0;
  504. h = CreateFileW(reparseName.Buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
  505. OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
  506. SECURITY_IMPERSONATION, NULL);
  507. RtlFreeHeap(RtlProcessHeap(), 0, reparseName.Buffer);
  508. if (h == INVALID_HANDLE_VALUE) {
  509. return INVALID_HANDLE_VALUE;
  510. }
  511. b = FindNextVolumeMountPointHelper(h, lpszVolumeMountPoint,
  512. cchBufferLength, TRUE);
  513. if (!b) {
  514. CloseHandle(h);
  515. return INVALID_HANDLE_VALUE;
  516. }
  517. return h;
  518. }
  519. BOOL
  520. WINAPI
  521. FindNextVolumeMountPointA(
  522. HANDLE hFindVolumeMountPoint,
  523. LPSTR lpszVolumeMountPoint,
  524. DWORD cchBufferLength
  525. )
  526. {
  527. ANSI_STRING ansiVolumeMountPoint;
  528. UNICODE_STRING unicodeVolumeMountPoint;
  529. BOOL b;
  530. NTSTATUS status;
  531. ansiVolumeMountPoint.Buffer = lpszVolumeMountPoint;
  532. ansiVolumeMountPoint.MaximumLength = (USHORT) (cchBufferLength - 1);
  533. unicodeVolumeMountPoint.Buffer = NULL;
  534. unicodeVolumeMountPoint.MaximumLength = 0;
  535. try {
  536. unicodeVolumeMountPoint.MaximumLength =
  537. (ansiVolumeMountPoint.MaximumLength + 1)*sizeof(WCHAR);
  538. unicodeVolumeMountPoint.Buffer =
  539. RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  540. unicodeVolumeMountPoint.MaximumLength);
  541. if (!unicodeVolumeMountPoint.Buffer) {
  542. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  543. b = FALSE;
  544. leave;
  545. }
  546. b = FindNextVolumeMountPointW(hFindVolumeMountPoint,
  547. unicodeVolumeMountPoint.Buffer,
  548. cchBufferLength);
  549. if (b) {
  550. RtlInitUnicodeString(&unicodeVolumeMountPoint,
  551. unicodeVolumeMountPoint.Buffer);
  552. status = BasepUnicodeStringTo8BitString(&ansiVolumeMountPoint,
  553. &unicodeVolumeMountPoint,
  554. FALSE);
  555. if (!NT_SUCCESS(status)) {
  556. BaseSetLastNTError(status);
  557. b = FALSE;
  558. leave;
  559. }
  560. ansiVolumeMountPoint.Buffer[ansiVolumeMountPoint.Length] = 0;
  561. }
  562. } finally {
  563. if (unicodeVolumeMountPoint.Buffer) {
  564. RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeMountPoint.Buffer);
  565. }
  566. }
  567. return b;
  568. }
  569. BOOL
  570. IsThisAVolumeName(
  571. LPCWSTR Name,
  572. PBOOLEAN IsVolume
  573. )
  574. /*++
  575. Routine Description:
  576. This routine takes the given NT name and determines whether or not
  577. the name points to a volume.
  578. Arguments:
  579. Name - Supplies the name.
  580. IsVolume - Returns whether or not the given name is a volume.
  581. Return Value:
  582. FALSE - Failure.
  583. TRUE - Success.
  584. --*/
  585. {
  586. UNICODE_STRING name;
  587. PMOUNTMGR_MOUNT_POINT point;
  588. MOUNTMGR_MOUNT_POINTS points;
  589. HANDLE h;
  590. BOOL b;
  591. DWORD bytes;
  592. RtlInitUnicodeString(&name, Name);
  593. if (name.Buffer[name.Length/sizeof(WCHAR) - 1] == '\\') {
  594. name.Length -= sizeof(WCHAR);
  595. }
  596. point = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  597. name.Length + sizeof(MOUNTMGR_MOUNT_POINT));
  598. if (!point) {
  599. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  600. return FALSE;
  601. }
  602. RtlZeroMemory(point, sizeof(MOUNTMGR_MOUNT_POINT));
  603. point->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  604. point->DeviceNameLength = name.Length;
  605. RtlCopyMemory((PCHAR) point + point->DeviceNameOffset, name.Buffer,
  606. point->DeviceNameLength);
  607. if (name.Length >= 4 && name.Buffer[1] == '\\') {
  608. ((PWSTR) ((PCHAR) point + point->DeviceNameOffset))[1] = '?';
  609. }
  610. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ |
  611. FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  612. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  613. if (h == INVALID_HANDLE_VALUE) {
  614. RtlFreeHeap(RtlProcessHeap(), 0, point);
  615. return FALSE;
  616. }
  617. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
  618. name.Length + sizeof(MOUNTMGR_MOUNT_POINT),
  619. &points, sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
  620. if (b) {
  621. if (points.NumberOfMountPoints) {
  622. *IsVolume = TRUE;
  623. } else {
  624. *IsVolume = FALSE;
  625. }
  626. } else {
  627. if (GetLastError() == ERROR_MORE_DATA) {
  628. *IsVolume = TRUE;
  629. } else {
  630. *IsVolume = FALSE;
  631. }
  632. }
  633. CloseHandle(h);
  634. RtlFreeHeap(RtlProcessHeap(), 0, point);
  635. return TRUE;
  636. }
  637. BOOL
  638. WINAPI
  639. FindNextVolumeMountPointW(
  640. HANDLE hFindVolumeMountPoint,
  641. LPWSTR lpszVolumeMountPoint,
  642. DWORD cchBufferLength
  643. )
  644. /*++
  645. Routine Description:
  646. This routine continues the enumeration of all volume mount point on the
  647. given volume.
  648. Arguments:
  649. hFindVolumeMountPoint - Supplies the handle for the enumeration.
  650. lpszVolumeMountPoint - Returns the volume mount point.
  651. cchBufferLength - Supplies the volume mount point buffer length.
  652. Return Value:
  653. FALSE - Failure.
  654. TRUE - Success.
  655. --*/
  656. {
  657. return FindNextVolumeMountPointHelper(hFindVolumeMountPoint,
  658. lpszVolumeMountPoint,
  659. cchBufferLength, FALSE);
  660. }
  661. BOOL
  662. WINAPI
  663. FindVolumeMountPointClose(
  664. HANDLE hFindVolumeMountPoint
  665. )
  666. {
  667. return CloseHandle(hFindVolumeMountPoint);
  668. }
  669. BOOL
  670. WINAPI
  671. GetVolumeNameForVolumeMountPointA(
  672. LPCSTR lpszVolumeMountPoint,
  673. LPSTR lpszVolumeName,
  674. DWORD cchBufferLength
  675. )
  676. {
  677. PUNICODE_STRING unicodeVolumeMountPoint;
  678. ANSI_STRING ansiVolumeName;
  679. UNICODE_STRING unicodeVolumeName;
  680. BOOL b;
  681. NTSTATUS status;
  682. unicodeVolumeMountPoint =
  683. Basep8BitStringToStaticUnicodeString(lpszVolumeMountPoint);
  684. if (!unicodeVolumeMountPoint) {
  685. return FALSE;
  686. }
  687. ansiVolumeName.Buffer = lpszVolumeName;
  688. ansiVolumeName.MaximumLength = (USHORT) (cchBufferLength - 1);
  689. unicodeVolumeName.Buffer = NULL;
  690. unicodeVolumeName.MaximumLength = 0;
  691. try {
  692. unicodeVolumeName.MaximumLength =
  693. (ansiVolumeName.MaximumLength + 1)*sizeof(WCHAR);
  694. unicodeVolumeName.Buffer =
  695. RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  696. unicodeVolumeName.MaximumLength);
  697. if (!unicodeVolumeName.Buffer) {
  698. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  699. b = FALSE;
  700. leave;
  701. }
  702. b = GetVolumeNameForVolumeMountPointW(unicodeVolumeMountPoint->Buffer,
  703. unicodeVolumeName.Buffer,
  704. cchBufferLength);
  705. if (b) {
  706. RtlInitUnicodeString(&unicodeVolumeName,
  707. unicodeVolumeName.Buffer);
  708. status = BasepUnicodeStringTo8BitString(&ansiVolumeName,
  709. &unicodeVolumeName,
  710. FALSE);
  711. if (!NT_SUCCESS(status)) {
  712. BaseSetLastNTError(status);
  713. b = FALSE;
  714. leave;
  715. }
  716. ansiVolumeName.Buffer[ansiVolumeName.Length] = 0;
  717. }
  718. } finally {
  719. if (unicodeVolumeName.Buffer) {
  720. RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumeName.Buffer);
  721. }
  722. }
  723. return b;
  724. }
  725. BOOL
  726. GetVolumeNameForRoot(
  727. LPCWSTR DeviceName,
  728. LPWSTR lpszVolumeName,
  729. DWORD cchBufferLength
  730. )
  731. /*++
  732. Routine Description:
  733. This routine queries the volume name for the given NT device name.
  734. Arguments:
  735. DeviceName - Supplies a DOS device name terminated by a '\'.
  736. lpszVolumeName - Returns the volume name pointed to by the DOS
  737. device name.
  738. cchBufferLength - Supplies the size of the preceeding buffer.
  739. Return Value:
  740. FALSE - Failure. The error code is returned in GetLastError().
  741. TRUE - Success.
  742. --*/
  743. {
  744. NTSTATUS status;
  745. UNICODE_STRING devicePath, symName;
  746. OBJECT_ATTRIBUTES oa;
  747. HANDLE h;
  748. IO_STATUS_BLOCK ioStatus;
  749. WCHAR buffer[MAX_PATH];
  750. PMOUNTDEV_NAME name;
  751. BOOL b;
  752. DWORD bytes, i;
  753. PMOUNTMGR_MOUNT_POINT point;
  754. PMOUNTMGR_MOUNT_POINTS points;
  755. if (GetDriveTypeW(DeviceName) == DRIVE_REMOTE) {
  756. SetLastError(ERROR_PATH_NOT_FOUND);
  757. return FALSE;
  758. }
  759. if (!RtlDosPathNameToNtPathName_U(DeviceName, &devicePath, NULL, NULL)) {
  760. SetLastError(ERROR_PATH_NOT_FOUND);
  761. return FALSE;
  762. }
  763. if (devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 1] == '\\') {
  764. devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 1] = 0;
  765. devicePath.Length -= sizeof(WCHAR);
  766. }
  767. if (devicePath.Length >= 2*sizeof(WCHAR) &&
  768. devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 1] == ':') {
  769. devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 2] = (WCHAR)
  770. toupper(devicePath.Buffer[devicePath.Length/sizeof(WCHAR) - 2]);
  771. }
  772. InitializeObjectAttributes(&oa, &devicePath, OBJ_CASE_INSENSITIVE,
  773. NULL, NULL);
  774. status = NtOpenFile(&h, FILE_READ_ATTRIBUTES | SYNCHRONIZE, &oa,
  775. &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
  776. FILE_SYNCHRONOUS_IO_ALERT);
  777. if (!NT_SUCCESS(status)) {
  778. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  779. SetLastError(RtlNtStatusToDosError(status));
  780. return FALSE;
  781. }
  782. name = (PMOUNTDEV_NAME) buffer;
  783. b = DeviceIoControl(h, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, name,
  784. MAX_PATH*sizeof(WCHAR), &bytes, NULL);
  785. NtClose(h);
  786. if (!b) {
  787. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  788. return FALSE;
  789. }
  790. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  791. devicePath.Length = name->NameLength;
  792. devicePath.MaximumLength = devicePath.Length + sizeof(WCHAR);
  793. devicePath.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  794. MAKE_TAG(TMP_TAG),
  795. devicePath.MaximumLength);
  796. if (!devicePath.Buffer) {
  797. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  798. return FALSE;
  799. }
  800. RtlCopyMemory(devicePath.Buffer, name->Name, name->NameLength);
  801. devicePath.Buffer[devicePath.Length/sizeof(WCHAR)] = 0;
  802. point = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  803. devicePath.Length + sizeof(MOUNTMGR_MOUNT_POINT));
  804. if (!point) {
  805. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  806. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  807. return FALSE;
  808. }
  809. RtlZeroMemory(point, sizeof(MOUNTMGR_MOUNT_POINT));
  810. point->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  811. point->DeviceNameLength = devicePath.Length;
  812. RtlCopyMemory((PCHAR) point + point->DeviceNameOffset,
  813. devicePath.Buffer, point->DeviceNameLength);
  814. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  815. points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  816. sizeof(MOUNTMGR_MOUNT_POINTS));
  817. if (!points) {
  818. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  819. RtlFreeHeap(RtlProcessHeap(), 0, point);
  820. return FALSE;
  821. }
  822. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0,
  823. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  824. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  825. INVALID_HANDLE_VALUE);
  826. if (h == INVALID_HANDLE_VALUE) {
  827. RtlFreeHeap(RtlProcessHeap(), 0, points);
  828. RtlFreeHeap(RtlProcessHeap(), 0, point);
  829. return FALSE;
  830. }
  831. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
  832. devicePath.Length + sizeof(MOUNTMGR_MOUNT_POINT),
  833. points, sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
  834. while (!b && GetLastError() == ERROR_MORE_DATA) {
  835. bytes = points->Size;
  836. RtlFreeHeap(RtlProcessHeap(), 0, points);
  837. points = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), bytes);
  838. if (!points) {
  839. CloseHandle(h);
  840. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  841. RtlFreeHeap(RtlProcessHeap(), 0, point);
  842. return FALSE;
  843. }
  844. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
  845. devicePath.Length + sizeof(MOUNTMGR_MOUNT_POINT),
  846. points, bytes, &bytes, NULL);
  847. }
  848. CloseHandle(h);
  849. RtlFreeHeap(RtlProcessHeap(), 0, point);
  850. if (!b) {
  851. RtlFreeHeap(RtlProcessHeap(), 0, points);
  852. SetLastError(ERROR_INVALID_PARAMETER);
  853. return FALSE;
  854. }
  855. for (i = 0; i < points->NumberOfMountPoints; i++) {
  856. symName.Length = symName.MaximumLength =
  857. points->MountPoints[i].SymbolicLinkNameLength;
  858. symName.Buffer = (PWSTR) ((PCHAR) points +
  859. points->MountPoints[i].SymbolicLinkNameOffset);
  860. if (MOUNTMGR_IS_NT_VOLUME_NAME(&symName)) {
  861. break;
  862. }
  863. }
  864. if (i == points->NumberOfMountPoints) {
  865. RtlFreeHeap(RtlProcessHeap(), 0, points);
  866. SetLastError(ERROR_INVALID_PARAMETER);
  867. return FALSE;
  868. }
  869. if (cchBufferLength*sizeof(WCHAR) < symName.Length + 2*sizeof(WCHAR)) {
  870. RtlFreeHeap(RtlProcessHeap(), 0, points);
  871. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  872. return FALSE;
  873. }
  874. RtlCopyMemory(lpszVolumeName, symName.Buffer, symName.Length);
  875. lpszVolumeName[1] = '\\';
  876. lpszVolumeName[symName.Length/sizeof(WCHAR)] = '\\';
  877. lpszVolumeName[symName.Length/sizeof(WCHAR) + 1] = 0;
  878. RtlFreeHeap(RtlProcessHeap(), 0, points);
  879. return TRUE;
  880. }
  881. BOOL
  882. BasepGetVolumeNameFromReparsePoint(
  883. LPCWSTR lpszVolumeMountPoint,
  884. LPWSTR lpszVolumeName,
  885. DWORD cchBufferLength,
  886. PBOOL ResultOfOpen
  887. )
  888. {
  889. HANDLE h;
  890. PREPARSE_DATA_BUFFER reparse;
  891. BOOL b;
  892. DWORD bytes;
  893. UNICODE_STRING mountName;
  894. WCHAR c;
  895. h = CreateFileW(lpszVolumeMountPoint, 0, FILE_SHARE_READ |
  896. FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  897. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT |
  898. FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE);
  899. if (h == INVALID_HANDLE_VALUE) {
  900. if (ResultOfOpen) {
  901. *ResultOfOpen = FALSE;
  902. }
  903. if (lpszVolumeName && cchBufferLength >= 1) {
  904. *lpszVolumeName = 0;
  905. }
  906. return FALSE;
  907. }
  908. if (ResultOfOpen) {
  909. *ResultOfOpen = TRUE;
  910. }
  911. reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  912. MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  913. if (!reparse) {
  914. CloseHandle(h);
  915. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  916. if (lpszVolumeName && cchBufferLength >= 1) {
  917. *lpszVolumeName = 0;
  918. }
  919. return FALSE;
  920. }
  921. b = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
  922. MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, NULL);
  923. CloseHandle(h);
  924. if (!b || reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
  925. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  926. if (lpszVolumeName && cchBufferLength >= 1) {
  927. *lpszVolumeName = 0;
  928. }
  929. return FALSE;
  930. }
  931. if (cchBufferLength*sizeof(WCHAR) <
  932. reparse->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR)) {
  933. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  934. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  935. if (lpszVolumeName && cchBufferLength >= 1) {
  936. *lpszVolumeName = 0;
  937. }
  938. return FALSE;
  939. }
  940. RtlCopyMemory(lpszVolumeName,
  941. (PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
  942. reparse->MountPointReparseBuffer.SubstituteNameOffset,
  943. reparse->MountPointReparseBuffer.SubstituteNameLength);
  944. c = lpszVolumeName[1];
  945. lpszVolumeName[1] = '\\';
  946. lpszVolumeName[reparse->MountPointReparseBuffer.SubstituteNameLength/
  947. sizeof(WCHAR)] = 0;
  948. mountName.Length = mountName.MaximumLength =
  949. reparse->MountPointReparseBuffer.SubstituteNameLength;
  950. mountName.Buffer = lpszVolumeName;
  951. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  952. if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&mountName)) {
  953. /*
  954. ** Note that we deliberately choose to NOT zero the first character
  955. ** of the returned buffer. The call from GetVolumePathNameW() is able
  956. ** to handle the case where we found a directory junction instead of
  957. ** a mountpoint. The other caller GetVolumeNameForVolumeMountPointW()
  958. ** zaps the first char in the event of failure.
  959. */
  960. lpszVolumeName[1] = c;
  961. SetLastError(ERROR_INVALID_PARAMETER);
  962. return FALSE;
  963. }
  964. return TRUE;
  965. }
  966. BOOL
  967. BasepGetVolumeNameForVolumeMountPoint(
  968. LPCWSTR lpszVolumeMountPoint,
  969. LPWSTR lpszVolumeName,
  970. DWORD cchBufferLength,
  971. PBOOL ResultOfOpen
  972. )
  973. /*++
  974. Routine Description:
  975. This routine returns the volume name for a given volume mount point.
  976. Arguments:
  977. lpszVolumeMountPoint - Supplies the volume mount point.
  978. lpszVolumeName - Returns the volume name.
  979. cchBufferLength - Supplies the size of the volume name buffer.
  980. Return Value:
  981. FALSE - Failure.
  982. TRUE - Success.
  983. --*/
  984. {
  985. UNICODE_STRING unicodeVolumeMountPoint;
  986. BOOL b;
  987. if (ResultOfOpen) {
  988. *ResultOfOpen = TRUE;
  989. }
  990. RtlInitUnicodeString(&unicodeVolumeMountPoint, lpszVolumeMountPoint);
  991. if (unicodeVolumeMountPoint.Buffer[
  992. unicodeVolumeMountPoint.Length/sizeof(WCHAR) - 1] != '\\') {
  993. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  994. if (lpszVolumeName && cchBufferLength >= 1) {
  995. *lpszVolumeName = 0;
  996. }
  997. return FALSE;
  998. }
  999. if (unicodeVolumeMountPoint.Length == 6 &&
  1000. unicodeVolumeMountPoint.Buffer[1] == ':') {
  1001. b = GetVolumeNameForRoot(lpszVolumeMountPoint, lpszVolumeName,
  1002. cchBufferLength);
  1003. if (!b && lpszVolumeName && cchBufferLength >= 1) {
  1004. *lpszVolumeName = 0;
  1005. }
  1006. return b;
  1007. }
  1008. if (unicodeVolumeMountPoint.Length == 14 &&
  1009. unicodeVolumeMountPoint.Buffer[0] == '\\' &&
  1010. unicodeVolumeMountPoint.Buffer[1] == '\\' &&
  1011. (unicodeVolumeMountPoint.Buffer[2] == '.' ||
  1012. unicodeVolumeMountPoint.Buffer[2] == '?') &&
  1013. unicodeVolumeMountPoint.Buffer[3] == '\\' &&
  1014. unicodeVolumeMountPoint.Buffer[5] == ':') {
  1015. b = GetVolumeNameForRoot(lpszVolumeMountPoint + 4,
  1016. lpszVolumeName, cchBufferLength);
  1017. if (!b && lpszVolumeName && cchBufferLength >= 1) {
  1018. *lpszVolumeName = 0;
  1019. }
  1020. return b;
  1021. }
  1022. if (GetVolumeNameForRoot(lpszVolumeMountPoint, lpszVolumeName,
  1023. cchBufferLength)) {
  1024. return TRUE;
  1025. }
  1026. b = BasepGetVolumeNameFromReparsePoint(lpszVolumeMountPoint,
  1027. lpszVolumeName, cchBufferLength,
  1028. ResultOfOpen);
  1029. return b;
  1030. }
  1031. BOOL
  1032. WINAPI
  1033. GetVolumeNameForVolumeMountPointW(
  1034. LPCWSTR lpszVolumeMountPoint,
  1035. LPWSTR lpszVolumeName,
  1036. DWORD cchBufferLength
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine returns the volume name for a given volume mount point.
  1041. Arguments:
  1042. lpszVolumeMountPoint - Supplies the volume mount point.
  1043. lpszVolumeName - Returns the volume name.
  1044. cchBufferLength - Supplies the size of the volume name buffer.
  1045. Return Value:
  1046. FALSE - Failure.
  1047. TRUE - Success.
  1048. --*/
  1049. {
  1050. BOOL b = BasepGetVolumeNameForVolumeMountPoint(lpszVolumeMountPoint,
  1051. lpszVolumeName,
  1052. cchBufferLength, NULL);
  1053. if (!b && lpszVolumeName && cchBufferLength >= 1) {
  1054. *lpszVolumeName = 0;
  1055. }
  1056. return b;
  1057. }
  1058. BOOL
  1059. WINAPI
  1060. SetVolumeMountPointA(
  1061. LPCSTR lpszVolumeMountPoint,
  1062. LPCSTR lpszVolumeName
  1063. )
  1064. {
  1065. PUNICODE_STRING unicodeVolumeMountPoint;
  1066. UNICODE_STRING unicodeVolumeName;
  1067. BOOL b;
  1068. unicodeVolumeMountPoint = Basep8BitStringToStaticUnicodeString(
  1069. lpszVolumeMountPoint);
  1070. if (!unicodeVolumeMountPoint) {
  1071. return FALSE;
  1072. }
  1073. if (!Basep8BitStringToDynamicUnicodeString(&unicodeVolumeName,
  1074. lpszVolumeName)) {
  1075. return FALSE;
  1076. }
  1077. b = SetVolumeMountPointW(unicodeVolumeMountPoint->Buffer,
  1078. unicodeVolumeName.Buffer);
  1079. RtlFreeUnicodeString(&unicodeVolumeName);
  1080. return b;
  1081. }
  1082. BOOL
  1083. SetVolumeNameForRoot(
  1084. LPCWSTR DeviceName,
  1085. LPCWSTR lpszVolumeName
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. This routine sets the volume name for the given DOS device name.
  1090. Arguments:
  1091. DeviceName - Supplies a DOS device name terminated by a '\'.
  1092. lpszVolumeName - Supplies the volume name that the DOS device name
  1093. will point to.
  1094. Return Value:
  1095. FALSE - Failure. The error code is returned in GetLastError().
  1096. TRUE - Success.
  1097. --*/
  1098. {
  1099. UNICODE_STRING devicePath, volumeName;
  1100. DWORD inputLength;
  1101. PMOUNTMGR_CREATE_POINT_INPUT input;
  1102. HANDLE h;
  1103. BOOL b;
  1104. DWORD bytes;
  1105. devicePath.Length = 28;
  1106. devicePath.MaximumLength = devicePath.Length + sizeof(WCHAR);
  1107. devicePath.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1108. devicePath.MaximumLength);
  1109. if (!devicePath.Buffer) {
  1110. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1111. return FALSE;
  1112. }
  1113. RtlCopyMemory(devicePath.Buffer, L"\\DosDevices\\", 24);
  1114. devicePath.Buffer[12] = (WCHAR)toupper(DeviceName[0]);
  1115. devicePath.Buffer[13] = ':';
  1116. devicePath.Buffer[14] = 0;
  1117. RtlInitUnicodeString(&volumeName, lpszVolumeName);
  1118. volumeName.Length -= sizeof(WCHAR);
  1119. inputLength = sizeof(MOUNTMGR_CREATE_POINT_INPUT) + devicePath.Length +
  1120. volumeName.Length;
  1121. input = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), inputLength);
  1122. if (!input) {
  1123. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  1124. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1125. return FALSE;
  1126. }
  1127. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  1128. input->SymbolicLinkNameLength = devicePath.Length;
  1129. input->DeviceNameOffset = input->SymbolicLinkNameOffset +
  1130. input->SymbolicLinkNameLength;
  1131. input->DeviceNameLength = volumeName.Length;
  1132. RtlCopyMemory((PCHAR) input + input->SymbolicLinkNameOffset,
  1133. devicePath.Buffer, input->SymbolicLinkNameLength);
  1134. RtlCopyMemory((PCHAR) input + input->DeviceNameOffset, volumeName.Buffer,
  1135. input->DeviceNameLength);
  1136. ((PWSTR) ((PCHAR) input + input->DeviceNameOffset))[1] = '?';
  1137. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  1138. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
  1139. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1140. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  1141. if (h == INVALID_HANDLE_VALUE) {
  1142. RtlFreeHeap(RtlProcessHeap(), 0, input);
  1143. return FALSE;
  1144. }
  1145. b = DeviceIoControl(h, IOCTL_MOUNTMGR_CREATE_POINT, input, inputLength,
  1146. NULL, 0, &bytes, NULL);
  1147. CloseHandle(h);
  1148. RtlFreeHeap(RtlProcessHeap(), 0, input);
  1149. return b;
  1150. }
  1151. VOID
  1152. NotifyMountMgr(
  1153. LPCWSTR lpszVolumeMountPoint,
  1154. LPCWSTR lpszVolumeName,
  1155. BOOL IsPointCreated
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. This routine notifies the mount mgr that a volume mount point was
  1160. created or deleted so that the mount mgr can update the remote database on
  1161. the volume where the mount point was created or deleted.
  1162. Arguments:
  1163. lpszVolumeMountPoint - Supplies the directory where the volume mount
  1164. point resides.
  1165. lpszVolumeName - Supplies the volume name.
  1166. IsPointCreated - Supplies wheter or not the point was created or
  1167. deleted.
  1168. Return Value:
  1169. None.
  1170. --*/
  1171. {
  1172. UNICODE_STRING unicodeSourceVolumeName;
  1173. UNICODE_STRING unicodeTargetVolumeName;
  1174. DWORD inputSize;
  1175. PMOUNTMGR_VOLUME_MOUNT_POINT input;
  1176. HANDLE h;
  1177. DWORD ioControl, bytes;
  1178. if (!RtlDosPathNameToNtPathName_U(lpszVolumeMountPoint,
  1179. &unicodeSourceVolumeName, NULL, NULL)) {
  1180. return;
  1181. }
  1182. RtlInitUnicodeString(&unicodeTargetVolumeName, lpszVolumeName);
  1183. unicodeSourceVolumeName.Length -= sizeof(WCHAR);
  1184. unicodeTargetVolumeName.Length -= sizeof(WCHAR);
  1185. inputSize = sizeof(MOUNTMGR_VOLUME_MOUNT_POINT) +
  1186. unicodeSourceVolumeName.Length +
  1187. unicodeTargetVolumeName.Length;
  1188. input = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), inputSize);
  1189. if (!input) {
  1190. RtlFreeHeap(RtlProcessHeap(), 0, unicodeSourceVolumeName.Buffer);
  1191. return;
  1192. }
  1193. input->SourceVolumeNameOffset = sizeof(MOUNTMGR_VOLUME_MOUNT_POINT);
  1194. input->SourceVolumeNameLength = unicodeSourceVolumeName.Length;
  1195. input->TargetVolumeNameOffset = input->SourceVolumeNameOffset +
  1196. input->SourceVolumeNameLength;
  1197. input->TargetVolumeNameLength = unicodeTargetVolumeName.Length;
  1198. RtlCopyMemory((PCHAR) input + input->SourceVolumeNameOffset,
  1199. unicodeSourceVolumeName.Buffer,
  1200. input->SourceVolumeNameLength);
  1201. RtlCopyMemory((PCHAR) input + input->TargetVolumeNameOffset,
  1202. unicodeTargetVolumeName.Buffer,
  1203. input->TargetVolumeNameLength);
  1204. ((PWSTR) ((PCHAR) input + input->TargetVolumeNameOffset))[1] = '?';
  1205. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
  1206. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1207. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  1208. if (h == INVALID_HANDLE_VALUE) {
  1209. RtlFreeHeap(RtlProcessHeap(), 0, input);
  1210. RtlFreeHeap(RtlProcessHeap(), 0, unicodeSourceVolumeName.Buffer);
  1211. return;
  1212. }
  1213. if (IsPointCreated) {
  1214. ioControl = IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED;
  1215. } else {
  1216. ioControl = IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED;
  1217. }
  1218. DeviceIoControl(h, ioControl, input, inputSize, NULL, 0, &bytes, NULL);
  1219. CloseHandle(h);
  1220. RtlFreeHeap(RtlProcessHeap(), 0, input);
  1221. RtlFreeHeap(RtlProcessHeap(), 0, unicodeSourceVolumeName.Buffer);
  1222. }
  1223. BOOL
  1224. WINAPI
  1225. SetVolumeMountPointW(
  1226. LPCWSTR lpszVolumeMountPoint,
  1227. LPCWSTR lpszVolumeName
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. This routine sets a mount point on the given directory pointed to by
  1232. 'VolumeMountPoint' which points to the volume given by 'VolumeName'.
  1233. In the case when 'VolumeMountPoint' is of the form "D:\", the drive
  1234. letter for the given volume is set to 'D:'.
  1235. Arguments:
  1236. lpszVolumeMountPoint - Supplies the directory where the volume mount
  1237. point will reside.
  1238. lpszVolumeName - Supplies the volume name.
  1239. Return Value:
  1240. FALSE - Failure.
  1241. TRUE - Success.
  1242. --*/
  1243. {
  1244. UNICODE_STRING unicodeVolumeMountPoint;
  1245. UNICODE_STRING unicodeVolumeName;
  1246. BOOLEAN isVolume;
  1247. BOOL b;
  1248. WCHAR volumeMountPointVolumePrefix[MAX_PATH];
  1249. HANDLE h;
  1250. PREPARSE_DATA_BUFFER reparse;
  1251. DWORD bytes;
  1252. if (GetVolumeNameForVolumeMountPointW(lpszVolumeMountPoint,
  1253. volumeMountPointVolumePrefix,
  1254. MAX_PATH) ||
  1255. GetLastError() == ERROR_FILENAME_EXCED_RANGE) {
  1256. SetLastError(ERROR_DIR_NOT_EMPTY);
  1257. return FALSE;
  1258. }
  1259. RtlInitUnicodeString(&unicodeVolumeMountPoint, lpszVolumeMountPoint);
  1260. RtlInitUnicodeString(&unicodeVolumeName, lpszVolumeName);
  1261. if (unicodeVolumeMountPoint.Length == 0 ||
  1262. unicodeVolumeName.Length == 0) {
  1263. SetLastError(ERROR_INVALID_PARAMETER);
  1264. return FALSE;
  1265. }
  1266. if (unicodeVolumeMountPoint.Buffer[
  1267. unicodeVolumeMountPoint.Length/sizeof(WCHAR) - 1] != '\\' ||
  1268. unicodeVolumeName.Buffer[
  1269. unicodeVolumeName.Length/sizeof(WCHAR) - 1] != '\\') {
  1270. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  1271. return FALSE;
  1272. }
  1273. if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&unicodeVolumeName)) {
  1274. SetLastError(ERROR_INVALID_PARAMETER);
  1275. return FALSE;
  1276. }
  1277. if (!IsThisAVolumeName(lpszVolumeName, &isVolume)) {
  1278. return FALSE;
  1279. }
  1280. if (!isVolume) {
  1281. SetLastError(ERROR_INVALID_PARAMETER);
  1282. return FALSE;
  1283. }
  1284. if (unicodeVolumeMountPoint.Length == 6 &&
  1285. unicodeVolumeMountPoint.Buffer[1] == ':') {
  1286. return SetVolumeNameForRoot(lpszVolumeMountPoint, lpszVolumeName);
  1287. }
  1288. if (unicodeVolumeMountPoint.Length == 14 &&
  1289. unicodeVolumeMountPoint.Buffer[0] == '\\' &&
  1290. unicodeVolumeMountPoint.Buffer[1] == '\\' &&
  1291. (unicodeVolumeMountPoint.Buffer[2] == '.' ||
  1292. unicodeVolumeMountPoint.Buffer[2] == '?') &&
  1293. unicodeVolumeMountPoint.Buffer[3] == '\\' &&
  1294. unicodeVolumeMountPoint.Buffer[5] == ':') {
  1295. return SetVolumeNameForRoot(lpszVolumeMountPoint + 4, lpszVolumeName);
  1296. }
  1297. if (GetDriveTypeW(lpszVolumeMountPoint) != DRIVE_FIXED) {
  1298. SetLastError(ERROR_INVALID_PARAMETER);
  1299. return FALSE;
  1300. }
  1301. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
  1302. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1303. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  1304. if (h == INVALID_HANDLE_VALUE) {
  1305. return FALSE;
  1306. }
  1307. CloseHandle(h);
  1308. h = CreateFileW(lpszVolumeMountPoint, GENERIC_READ | GENERIC_WRITE,
  1309. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1310. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OPEN_REPARSE_POINT |
  1311. FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE);
  1312. if (h == INVALID_HANDLE_VALUE) {
  1313. return FALSE;
  1314. }
  1315. reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1316. MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  1317. if (!reparse) {
  1318. CloseHandle(h);
  1319. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1320. return FALSE;
  1321. }
  1322. reparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
  1323. reparse->ReparseDataLength = (USHORT) (FIELD_OFFSET(REPARSE_DATA_BUFFER,
  1324. MountPointReparseBuffer.PathBuffer) -
  1325. REPARSE_DATA_BUFFER_HEADER_SIZE +
  1326. unicodeVolumeName.Length + 2*sizeof(WCHAR));
  1327. reparse->Reserved = 0;
  1328. reparse->MountPointReparseBuffer.SubstituteNameOffset = 0;
  1329. reparse->MountPointReparseBuffer.SubstituteNameLength = unicodeVolumeName.Length;
  1330. reparse->MountPointReparseBuffer.PrintNameOffset =
  1331. reparse->MountPointReparseBuffer.SubstituteNameLength +
  1332. sizeof(WCHAR);
  1333. reparse->MountPointReparseBuffer.PrintNameLength = 0;
  1334. CopyMemory(reparse->MountPointReparseBuffer.PathBuffer,
  1335. unicodeVolumeName.Buffer,
  1336. reparse->MountPointReparseBuffer.SubstituteNameLength);
  1337. reparse->MountPointReparseBuffer.PathBuffer[1] = '?';
  1338. reparse->MountPointReparseBuffer.PathBuffer[
  1339. unicodeVolumeName.Length/sizeof(WCHAR)] = 0;
  1340. reparse->MountPointReparseBuffer.PathBuffer[
  1341. unicodeVolumeName.Length/sizeof(WCHAR) + 1] = 0;
  1342. b = DeviceIoControl(h, FSCTL_SET_REPARSE_POINT, reparse,
  1343. REPARSE_DATA_BUFFER_HEADER_SIZE +
  1344. reparse->ReparseDataLength, NULL, 0, &bytes, NULL);
  1345. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  1346. CloseHandle(h);
  1347. if (b) {
  1348. NotifyMountMgr(lpszVolumeMountPoint, lpszVolumeName, TRUE);
  1349. }
  1350. return b;
  1351. }
  1352. BOOL
  1353. WINAPI
  1354. DeleteVolumeMountPointA(
  1355. LPCSTR lpszVolumeMountPoint
  1356. )
  1357. {
  1358. PUNICODE_STRING unicodeVolumeMountPoint;
  1359. BOOL b;
  1360. unicodeVolumeMountPoint = Basep8BitStringToStaticUnicodeString(
  1361. lpszVolumeMountPoint);
  1362. if (!unicodeVolumeMountPoint) {
  1363. return FALSE;
  1364. }
  1365. b = DeleteVolumeMountPointW(unicodeVolumeMountPoint->Buffer);
  1366. return b;
  1367. }
  1368. BOOL
  1369. DeleteVolumeNameForRoot(
  1370. LPCWSTR DeviceName
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. This routine deletes the given DOS device name.
  1375. Arguments:
  1376. DeviceName - Supplies a DOS device name terminated by a '\'.
  1377. Return Value:
  1378. FALSE - Failure. The error code is returned in GetLastError().
  1379. TRUE - Success.
  1380. --*/
  1381. {
  1382. UNICODE_STRING devicePath;
  1383. DWORD inputLength;
  1384. PMOUNTMGR_MOUNT_POINT input;
  1385. DWORD outputLength;
  1386. PMOUNTMGR_MOUNT_POINTS output;
  1387. HANDLE h;
  1388. BOOL b;
  1389. DWORD bytes;
  1390. devicePath.Length = 28;
  1391. devicePath.MaximumLength = devicePath.Length + sizeof(WCHAR);
  1392. devicePath.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1393. devicePath.MaximumLength);
  1394. if (!devicePath.Buffer) {
  1395. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1396. return FALSE;
  1397. }
  1398. RtlCopyMemory(devicePath.Buffer, L"\\DosDevices\\", 24);
  1399. devicePath.Buffer[12] = (WCHAR)toupper(DeviceName[0]);
  1400. devicePath.Buffer[13] = ':';
  1401. devicePath.Buffer[14] = 0;
  1402. inputLength = sizeof(MOUNTMGR_MOUNT_POINT) + devicePath.Length;
  1403. input = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), inputLength);
  1404. if (!input) {
  1405. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  1406. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1407. return FALSE;
  1408. }
  1409. RtlZeroMemory(input, sizeof(MOUNTMGR_MOUNT_POINT));
  1410. input->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1411. input->SymbolicLinkNameLength = devicePath.Length;
  1412. RtlCopyMemory((PCHAR) input + input->SymbolicLinkNameOffset,
  1413. devicePath.Buffer, input->SymbolicLinkNameLength);
  1414. RtlFreeHeap(RtlProcessHeap(), 0, devicePath.Buffer);
  1415. outputLength = sizeof(MOUNTMGR_MOUNT_POINTS) + 3*MAX_PATH*sizeof(WCHAR);
  1416. output = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1417. outputLength);
  1418. if (!output) {
  1419. RtlFreeHeap(RtlProcessHeap(), 0, input);
  1420. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1421. return FALSE;
  1422. }
  1423. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
  1424. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1425. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  1426. if (h == INVALID_HANDLE_VALUE) {
  1427. RtlFreeHeap(RtlProcessHeap(), 0, output);
  1428. RtlFreeHeap(RtlProcessHeap(), 0, input);
  1429. return FALSE;
  1430. }
  1431. b = DeviceIoControl(h, IOCTL_MOUNTMGR_DELETE_POINTS, input, inputLength,
  1432. output, outputLength, &bytes, NULL);
  1433. CloseHandle(h);
  1434. RtlFreeHeap(RtlProcessHeap(), 0, output);
  1435. RtlFreeHeap(RtlProcessHeap(), 0, input);
  1436. return b;
  1437. }
  1438. BOOL
  1439. WINAPI
  1440. DeleteVolumeMountPointW(
  1441. LPCWSTR lpszVolumeMountPoint
  1442. )
  1443. /*++
  1444. Routine Description:
  1445. This routine removes the NTFS junction point from the given directory
  1446. or remove the drive letter symbolic link pointing to the given volume.
  1447. Arguments:
  1448. lpszVolumeMountPoint - Supplies the volume mount piont.
  1449. Return Value:
  1450. FALSE - Failure.
  1451. TRUE - Success.
  1452. --*/
  1453. {
  1454. UNICODE_STRING unicodeVolumeMountPoint;
  1455. HANDLE h;
  1456. PREPARSE_DATA_BUFFER reparse;
  1457. BOOL b;
  1458. DWORD bytes;
  1459. UNICODE_STRING substituteName;
  1460. RtlInitUnicodeString(&unicodeVolumeMountPoint, lpszVolumeMountPoint);
  1461. if (unicodeVolumeMountPoint.Buffer[
  1462. unicodeVolumeMountPoint.Length/sizeof(WCHAR) - 1] != '\\') {
  1463. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  1464. return FALSE;
  1465. }
  1466. if (unicodeVolumeMountPoint.Length == 6 &&
  1467. unicodeVolumeMountPoint.Buffer[1] == ':') {
  1468. return DeleteVolumeNameForRoot(lpszVolumeMountPoint);
  1469. }
  1470. if (unicodeVolumeMountPoint.Length == 14 &&
  1471. unicodeVolumeMountPoint.Buffer[0] == '\\' &&
  1472. unicodeVolumeMountPoint.Buffer[1] == '\\' &&
  1473. (unicodeVolumeMountPoint.Buffer[2] == '.' ||
  1474. unicodeVolumeMountPoint.Buffer[2] == '?') &&
  1475. unicodeVolumeMountPoint.Buffer[3] == '\\' &&
  1476. unicodeVolumeMountPoint.Buffer[5] == ':') {
  1477. return DeleteVolumeNameForRoot(lpszVolumeMountPoint + 4);
  1478. }
  1479. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
  1480. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1481. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  1482. if (h == INVALID_HANDLE_VALUE) {
  1483. return FALSE;
  1484. }
  1485. CloseHandle(h);
  1486. h = CreateFileW(lpszVolumeMountPoint, GENERIC_READ | GENERIC_WRITE,
  1487. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1488. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |
  1489. FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
  1490. INVALID_HANDLE_VALUE);
  1491. if (h == INVALID_HANDLE_VALUE) {
  1492. return FALSE;
  1493. }
  1494. reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1495. MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  1496. if (!reparse) {
  1497. CloseHandle(h);
  1498. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1499. return FALSE;
  1500. }
  1501. b = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse,
  1502. MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytes, NULL);
  1503. if (!b || reparse->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT) {
  1504. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  1505. CloseHandle(h);
  1506. return FALSE;
  1507. }
  1508. substituteName.MaximumLength = substituteName.Length =
  1509. reparse->MountPointReparseBuffer.SubstituteNameLength;
  1510. substituteName.Buffer = (PWSTR)
  1511. ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
  1512. reparse->MountPointReparseBuffer.SubstituteNameOffset);
  1513. if (!MOUNTMGR_IS_NT_VOLUME_NAME_WB(&substituteName)) {
  1514. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  1515. CloseHandle(h);
  1516. SetLastError(ERROR_INVALID_PARAMETER);
  1517. return FALSE;
  1518. }
  1519. reparse->ReparseDataLength = 0;
  1520. b = DeviceIoControl(h, FSCTL_DELETE_REPARSE_POINT, reparse,
  1521. REPARSE_DATA_BUFFER_HEADER_SIZE, NULL, 0, &bytes,
  1522. NULL);
  1523. CloseHandle(h);
  1524. if (b) {
  1525. substituteName.Buffer[1] = '\\';
  1526. substituteName.Buffer[substituteName.Length/sizeof(WCHAR)] = 0;
  1527. NotifyMountMgr(lpszVolumeMountPoint, substituteName.Buffer,
  1528. FALSE);
  1529. }
  1530. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  1531. return b;
  1532. }
  1533. BOOL
  1534. WINAPI
  1535. GetVolumePathNameA(
  1536. LPCSTR lpszFileName,
  1537. LPSTR lpszVolumePathName,
  1538. DWORD cchBufferLength
  1539. )
  1540. {
  1541. PUNICODE_STRING unicodeFileName;
  1542. ANSI_STRING ansiVolumePathName;
  1543. UNICODE_STRING unicodeVolumePathName;
  1544. BOOL b;
  1545. NTSTATUS status;
  1546. unicodeFileName = Basep8BitStringToStaticUnicodeString(lpszFileName);
  1547. if (!unicodeFileName) {
  1548. return FALSE;
  1549. }
  1550. ansiVolumePathName.Buffer = lpszVolumePathName;
  1551. ansiVolumePathName.MaximumLength = (USHORT) (cchBufferLength - 1);
  1552. unicodeVolumePathName.Buffer = NULL;
  1553. unicodeVolumePathName.MaximumLength = 0;
  1554. try {
  1555. unicodeVolumePathName.MaximumLength =
  1556. (ansiVolumePathName.MaximumLength + 1)*sizeof(WCHAR);
  1557. unicodeVolumePathName.Buffer =
  1558. RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1559. unicodeVolumePathName.MaximumLength);
  1560. if (!unicodeVolumePathName.Buffer) {
  1561. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1562. b = FALSE;
  1563. leave;
  1564. }
  1565. b = GetVolumePathNameW(unicodeFileName->Buffer,
  1566. unicodeVolumePathName.Buffer,
  1567. cchBufferLength);
  1568. if (b) {
  1569. RtlInitUnicodeString(&unicodeVolumePathName,
  1570. unicodeVolumePathName.Buffer);
  1571. status = BasepUnicodeStringTo8BitString(&ansiVolumePathName,
  1572. &unicodeVolumePathName,
  1573. FALSE);
  1574. if (!NT_SUCCESS(status)) {
  1575. BaseSetLastNTError(status);
  1576. b = FALSE;
  1577. leave;
  1578. }
  1579. ansiVolumePathName.Buffer[ansiVolumePathName.Length] = 0;
  1580. }
  1581. } finally {
  1582. if (unicodeVolumePathName.Buffer) {
  1583. RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumePathName.Buffer);
  1584. }
  1585. }
  1586. return b;
  1587. }
  1588. BOOL
  1589. WINAPI
  1590. GetVolumePathNameW(
  1591. LPCWSTR lpszFileName,
  1592. LPWSTR lpszVolumePathName,
  1593. DWORD cchBufferLength
  1594. )
  1595. /*++
  1596. Routine Description:
  1597. This routine will return a full path whose prefix is the longest prefix
  1598. that represents a volume.
  1599. Arguments:
  1600. lpszFileName - Supplies the file name.
  1601. lpszVolumePathName - Returns the volume path name.
  1602. cchBufferLength - Supplies the volume path name buffer length.
  1603. Return Value:
  1604. FALSE - Failure.
  1605. TRUE - Success.
  1606. --*/
  1607. {
  1608. DWORD fullPathLength;
  1609. PWSTR fullPath, p;
  1610. WCHAR c;
  1611. UNICODE_STRING name, dosName, prefix;
  1612. BOOL b, resultOfOpen;
  1613. PWSTR volumeName;
  1614. DWORD i;
  1615. WCHAR driveLetterPath[10];
  1616. fullPathLength = GetFullPathNameW(lpszFileName, 0, NULL, NULL);
  1617. if (!fullPathLength) {
  1618. return FALSE;
  1619. }
  1620. fullPathLength += 10;
  1621. fullPath = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1622. fullPathLength*sizeof(WCHAR));
  1623. if (!fullPath) {
  1624. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1625. return FALSE;
  1626. }
  1627. if (!GetFullPathNameW(lpszFileName, fullPathLength, fullPath, &p)) {
  1628. RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
  1629. return FALSE;
  1630. }
  1631. RtlInitUnicodeString(&name, fullPath);
  1632. //
  1633. // Append a trailing backslash to start the search.
  1634. //
  1635. if (name.Buffer[(name.Length/sizeof(WCHAR)) - 1] != '\\') {
  1636. name.Length += sizeof(WCHAR);
  1637. name.Buffer[(name.Length/sizeof(WCHAR)) - 1] = '\\';
  1638. name.Buffer[name.Length/sizeof(WCHAR)] = 0;
  1639. }
  1640. volumeName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1641. MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  1642. if (!volumeName) {
  1643. RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
  1644. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1645. return FALSE;
  1646. }
  1647. p = NULL;
  1648. c = 0;
  1649. for (;;) {
  1650. b = BasepGetVolumeNameForVolumeMountPoint(
  1651. name.Buffer, volumeName, MAXIMUM_REPARSE_DATA_BUFFER_SIZE/
  1652. sizeof(WCHAR), &resultOfOpen);
  1653. if (b) {
  1654. break;
  1655. }
  1656. if (!resultOfOpen && GetLastError() == ERROR_ACCESS_DENIED) {
  1657. resultOfOpen = TRUE;
  1658. }
  1659. if (*volumeName) {
  1660. if (fullPath[0] == '\\' && fullPath[1] == '\\') {
  1661. goto DontDoJunctionRecursionOverNetwork;
  1662. }
  1663. if (fullPath[1] == ':') {
  1664. driveLetterPath[0] = fullPath[0];
  1665. driveLetterPath[1] = ':';
  1666. driveLetterPath[2] = '\\';
  1667. driveLetterPath[3] = 0;
  1668. if (GetDriveType((LPCSTR) driveLetterPath) == DRIVE_REMOTE) {
  1669. goto DontDoJunctionRecursionOverNetwork;
  1670. }
  1671. }
  1672. RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
  1673. if (volumeName[0] == '\\' && volumeName[1] == '?' &&
  1674. volumeName[2] == '?' && volumeName[3] == '\\') {
  1675. if (volumeName[4] && volumeName[5] == ':') {
  1676. RtlInitUnicodeString(&name, volumeName);
  1677. MoveMemory(volumeName, volumeName + 4,
  1678. name.Length - 3*sizeof(WCHAR));
  1679. } else {
  1680. volumeName[1] = '\\';
  1681. }
  1682. b = GetVolumePathNameW(volumeName, lpszVolumePathName,
  1683. cchBufferLength);
  1684. } else {
  1685. RtlInitUnicodeString(&name, volumeName);
  1686. RtlInitUnicodeString(&prefix, L"\\\\?\\GLOBALROOT");
  1687. dosName.Length = name.Length + prefix.Length;
  1688. dosName.MaximumLength = dosName.Length + sizeof(WCHAR);
  1689. dosName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  1690. MAKE_TAG(TMP_TAG),
  1691. dosName.MaximumLength);
  1692. if (!dosName.Buffer) {
  1693. RtlFreeHeap(RtlProcessHeap(), 0, volumeName);
  1694. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1695. return FALSE;
  1696. }
  1697. CopyMemory(dosName.Buffer, prefix.Buffer, prefix.Length);
  1698. CopyMemory((PCHAR) dosName.Buffer + prefix.Length,
  1699. name.Buffer, name.Length);
  1700. dosName.Buffer[dosName.Length/sizeof(WCHAR)] = 0;
  1701. b = GetVolumePathNameW(dosName.Buffer, lpszVolumePathName,
  1702. cchBufferLength);
  1703. RtlFreeHeap(RtlProcessHeap(), 0, dosName.Buffer);
  1704. }
  1705. RtlFreeHeap(RtlProcessHeap(), 0, volumeName);
  1706. return b;
  1707. }
  1708. DontDoJunctionRecursionOverNetwork:
  1709. if (!resultOfOpen && p) {
  1710. *p = c;
  1711. RtlInitUnicodeString(&name, fullPath);
  1712. break;
  1713. }
  1714. if (name.Length <= sizeof(WCHAR)) {
  1715. break;
  1716. }
  1717. for (i = name.Length/sizeof(WCHAR) - 2; i > 0; i--) {
  1718. if (name.Buffer[i] == '\\') {
  1719. break;
  1720. }
  1721. }
  1722. if (!i) {
  1723. break;
  1724. }
  1725. if (resultOfOpen) {
  1726. p = &name.Buffer[i + 1];
  1727. c = *p;
  1728. *p = 0;
  1729. } else {
  1730. name.Buffer[i + 1] = 0;
  1731. }
  1732. RtlInitUnicodeString(&name, fullPath);
  1733. }
  1734. RtlFreeHeap(RtlProcessHeap(), 0, volumeName);
  1735. if (!resultOfOpen && !p) {
  1736. RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
  1737. return FALSE;
  1738. }
  1739. if (cchBufferLength*sizeof(WCHAR) < name.Length + sizeof(WCHAR)) {
  1740. RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
  1741. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1742. return FALSE;
  1743. }
  1744. RtlCopyMemory(lpszVolumePathName, name.Buffer, name.Length);
  1745. lpszVolumePathName[name.Length/sizeof(WCHAR)] = 0;
  1746. RtlFreeHeap(RtlProcessHeap(), 0, fullPath);
  1747. return TRUE;
  1748. }
  1749. BOOL
  1750. GetVolumePathNamesForVolumeNameA(
  1751. LPCSTR lpszVolumeName,
  1752. LPSTR lpszVolumePathNames,
  1753. DWORD cchBufferLength,
  1754. PDWORD lpcchReturnLength
  1755. )
  1756. {
  1757. PUNICODE_STRING unicodeVolumeName;
  1758. ANSI_STRING ansiVolumePathNames;
  1759. UNICODE_STRING unicodeVolumePathNames;
  1760. BOOL b;
  1761. NTSTATUS status;
  1762. DWORD len;
  1763. unicodeVolumeName = Basep8BitStringToStaticUnicodeString(lpszVolumeName);
  1764. if (!unicodeVolumeName) {
  1765. return FALSE;
  1766. }
  1767. ansiVolumePathNames.Buffer = lpszVolumePathNames;
  1768. ansiVolumePathNames.MaximumLength = (USHORT) cchBufferLength;
  1769. unicodeVolumePathNames.Buffer = NULL;
  1770. unicodeVolumePathNames.MaximumLength = 0;
  1771. try {
  1772. unicodeVolumePathNames.MaximumLength =
  1773. ansiVolumePathNames.MaximumLength*sizeof(WCHAR);
  1774. if (unicodeVolumePathNames.MaximumLength) {
  1775. unicodeVolumePathNames.Buffer =
  1776. RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1777. unicodeVolumePathNames.MaximumLength);
  1778. if (!unicodeVolumePathNames.Buffer) {
  1779. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1780. b = FALSE;
  1781. leave;
  1782. }
  1783. } else {
  1784. unicodeVolumePathNames.Buffer = NULL;
  1785. }
  1786. b = GetVolumePathNamesForVolumeNameW(unicodeVolumeName->Buffer,
  1787. unicodeVolumePathNames.Buffer,
  1788. cchBufferLength, &len);
  1789. if (b || GetLastError() == ERROR_MORE_DATA) {
  1790. if (b) {
  1791. unicodeVolumePathNames.Length = (USHORT) len*sizeof(WCHAR);
  1792. } else {
  1793. unicodeVolumePathNames.Length = (USHORT)
  1794. cchBufferLength*sizeof(WCHAR);
  1795. }
  1796. status = BasepUnicodeStringTo8BitString(&ansiVolumePathNames,
  1797. &unicodeVolumePathNames,
  1798. FALSE);
  1799. if (!NT_SUCCESS(status)) {
  1800. BaseSetLastNTError(status);
  1801. b = FALSE;
  1802. leave;
  1803. }
  1804. if (lpcchReturnLength) {
  1805. if (b) {
  1806. *lpcchReturnLength = ansiVolumePathNames.Length;
  1807. } else {
  1808. // Give an upper bound for the ANSI length since we
  1809. // don't actually know it.
  1810. *lpcchReturnLength = 2*len;
  1811. }
  1812. }
  1813. }
  1814. } finally {
  1815. if (unicodeVolumePathNames.Buffer) {
  1816. RtlFreeHeap(RtlProcessHeap(), 0, unicodeVolumePathNames.Buffer);
  1817. }
  1818. }
  1819. return b;
  1820. }
  1821. BOOL
  1822. GetVolumePathNamesForVolumeNameW(
  1823. LPCWSTR lpszVolumeName,
  1824. LPWSTR lpszVolumePathNames,
  1825. DWORD cchBufferLength,
  1826. PDWORD lpcchReturnLength
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This routine returns a Multi-Sz list of volume path names for the
  1831. given volume name. The returned 'lpcchReturnLength' will include the
  1832. extra tailing null characteristic of a Multi-Sz unless ERROR_MORE_DATA
  1833. is returned in which case the list returned is as long as possible
  1834. and may contain a part of a volume path.
  1835. Arguments:
  1836. lpszVolumeName - Supplies the volume name.
  1837. lpszVolumePathNames - Returns the volume path names.
  1838. cchBufferLength - Supplies the size of the return buffer.
  1839. lpcchReturnLength - Returns the number of characters copied back to the
  1840. return buffer on success or the total number
  1841. of characters necessary for the buffer on
  1842. ERROR_MORE_DATA.
  1843. Return Value:
  1844. FALSE - Failure.
  1845. TRUE - Success.
  1846. --*/
  1847. {
  1848. UNICODE_STRING unicodeVolumeName;
  1849. PMOUNTMGR_TARGET_NAME targetName;
  1850. HANDLE h;
  1851. BOOL b;
  1852. DWORD bytes, len, i, j, n;
  1853. PMOUNTMGR_VOLUME_PATHS volumePaths;
  1854. RtlInitUnicodeString(&unicodeVolumeName, lpszVolumeName);
  1855. if (unicodeVolumeName.Buffer[unicodeVolumeName.Length/sizeof(WCHAR) - 1] !=
  1856. '\\') {
  1857. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  1858. return FALSE;
  1859. }
  1860. if (!MOUNTMGR_IS_DOS_VOLUME_NAME_WB(&unicodeVolumeName)) {
  1861. SetLastError(ERROR_INVALID_PARAMETER);
  1862. return FALSE;
  1863. }
  1864. targetName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1865. MAX_PATH*sizeof(WCHAR));
  1866. if (!targetName) {
  1867. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1868. return FALSE;
  1869. }
  1870. ZeroMemory(targetName, MAX_PATH*sizeof(WCHAR));
  1871. targetName->DeviceNameLength = unicodeVolumeName.Length - sizeof(WCHAR);
  1872. RtlCopyMemory(targetName->DeviceName, lpszVolumeName,
  1873. targetName->DeviceNameLength);
  1874. targetName->DeviceName[1] = '?';
  1875. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, 0, FILE_SHARE_READ |
  1876. FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  1877. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  1878. if (h == INVALID_HANDLE_VALUE) {
  1879. RtlFreeHeap(RtlProcessHeap(), 0, targetName);
  1880. return FALSE;
  1881. }
  1882. len = sizeof(MOUNTMGR_VOLUME_PATHS);
  1883. volumePaths = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), len);
  1884. if (!volumePaths) {
  1885. CloseHandle(h);
  1886. RtlFreeHeap(RtlProcessHeap(), 0, targetName);
  1887. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1888. return FALSE;
  1889. }
  1890. for (;;) {
  1891. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS,
  1892. targetName, MAX_PATH*sizeof(WCHAR), volumePaths,
  1893. len, &bytes, NULL);
  1894. if (b) {
  1895. break;
  1896. }
  1897. if (GetLastError() != ERROR_MORE_DATA) {
  1898. RtlFreeHeap(RtlProcessHeap(), 0, volumePaths);
  1899. RtlFreeHeap(RtlProcessHeap(), 0, targetName);
  1900. return FALSE;
  1901. }
  1902. len = sizeof(MOUNTMGR_VOLUME_PATHS) + volumePaths->MultiSzLength;
  1903. RtlFreeHeap(RtlProcessHeap(), 0, volumePaths);
  1904. volumePaths = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  1905. len);
  1906. if (!volumePaths) {
  1907. CloseHandle(h);
  1908. RtlFreeHeap(RtlProcessHeap(), 0, targetName);
  1909. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1910. return FALSE;
  1911. }
  1912. }
  1913. CloseHandle(h);
  1914. RtlFreeHeap(RtlProcessHeap(), 0, targetName);
  1915. n = 0;
  1916. for (i = 0, j = 0; i < cchBufferLength &&
  1917. j < volumePaths->MultiSzLength/sizeof(WCHAR) - 1; i++, j++) {
  1918. if (!volumePaths->MultiSz[j]) {
  1919. n++;
  1920. lpszVolumePathNames[i++] = '\\';
  1921. if (i == cchBufferLength) {
  1922. break;
  1923. }
  1924. }
  1925. lpszVolumePathNames[i] = volumePaths->MultiSz[j];
  1926. }
  1927. for (; j < volumePaths->MultiSzLength/sizeof(WCHAR) - 1; j++) {
  1928. if (!volumePaths->MultiSz[j]) {
  1929. n++;
  1930. }
  1931. }
  1932. if (i < cchBufferLength) {
  1933. b = TRUE;
  1934. lpszVolumePathNames[i++] = 0;
  1935. if (lpcchReturnLength) {
  1936. *lpcchReturnLength = i;
  1937. }
  1938. } else {
  1939. b = FALSE;
  1940. SetLastError(ERROR_MORE_DATA);
  1941. if (lpcchReturnLength) {
  1942. *lpcchReturnLength = volumePaths->MultiSzLength/sizeof(WCHAR) + n;
  1943. }
  1944. }
  1945. RtlFreeHeap(RtlProcessHeap(), 0, volumePaths);
  1946. return b;
  1947. }