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

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